104-quad-8.c (34871B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Counter driver for the ACCES 104-QUAD-8 4 * Copyright (C) 2016 William Breathitt Gray 5 * 6 * This driver supports the ACCES 104-QUAD-8 and ACCES 104-QUAD-4. 7 */ 8#include <linux/bitops.h> 9#include <linux/counter.h> 10#include <linux/device.h> 11#include <linux/errno.h> 12#include <linux/io.h> 13#include <linux/ioport.h> 14#include <linux/interrupt.h> 15#include <linux/isa.h> 16#include <linux/kernel.h> 17#include <linux/list.h> 18#include <linux/module.h> 19#include <linux/moduleparam.h> 20#include <linux/types.h> 21#include <linux/spinlock.h> 22 23#define QUAD8_EXTENT 32 24 25static unsigned int base[max_num_isa_dev(QUAD8_EXTENT)]; 26static unsigned int num_quad8; 27module_param_hw_array(base, uint, ioport, &num_quad8, 0); 28MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses"); 29 30static unsigned int irq[max_num_isa_dev(QUAD8_EXTENT)]; 31module_param_hw_array(irq, uint, irq, NULL, 0); 32MODULE_PARM_DESC(irq, "ACCES 104-QUAD-8 interrupt line numbers"); 33 34#define QUAD8_NUM_COUNTERS 8 35 36/** 37 * struct quad8 - device private data structure 38 * @lock: lock to prevent clobbering device states during R/W ops 39 * @counter: instance of the counter_device 40 * @fck_prescaler: array of filter clock prescaler configurations 41 * @preset: array of preset values 42 * @count_mode: array of count mode configurations 43 * @quadrature_mode: array of quadrature mode configurations 44 * @quadrature_scale: array of quadrature mode scale configurations 45 * @ab_enable: array of A and B inputs enable configurations 46 * @preset_enable: array of set_to_preset_on_index attribute configurations 47 * @irq_trigger: array of current IRQ trigger function configurations 48 * @synchronous_mode: array of index function synchronous mode configurations 49 * @index_polarity: array of index function polarity configurations 50 * @cable_fault_enable: differential encoder cable status enable configurations 51 * @base: base port address of the device 52 */ 53struct quad8 { 54 spinlock_t lock; 55 unsigned int fck_prescaler[QUAD8_NUM_COUNTERS]; 56 unsigned int preset[QUAD8_NUM_COUNTERS]; 57 unsigned int count_mode[QUAD8_NUM_COUNTERS]; 58 unsigned int quadrature_mode[QUAD8_NUM_COUNTERS]; 59 unsigned int quadrature_scale[QUAD8_NUM_COUNTERS]; 60 unsigned int ab_enable[QUAD8_NUM_COUNTERS]; 61 unsigned int preset_enable[QUAD8_NUM_COUNTERS]; 62 unsigned int irq_trigger[QUAD8_NUM_COUNTERS]; 63 unsigned int synchronous_mode[QUAD8_NUM_COUNTERS]; 64 unsigned int index_polarity[QUAD8_NUM_COUNTERS]; 65 unsigned int cable_fault_enable; 66 unsigned int base; 67}; 68 69#define QUAD8_REG_INTERRUPT_STATUS 0x10 70#define QUAD8_REG_CHAN_OP 0x11 71#define QUAD8_REG_INDEX_INTERRUPT 0x12 72#define QUAD8_REG_INDEX_INPUT_LEVELS 0x16 73#define QUAD8_DIFF_ENCODER_CABLE_STATUS 0x17 74/* Borrow Toggle flip-flop */ 75#define QUAD8_FLAG_BT BIT(0) 76/* Carry Toggle flip-flop */ 77#define QUAD8_FLAG_CT BIT(1) 78/* Error flag */ 79#define QUAD8_FLAG_E BIT(4) 80/* Up/Down flag */ 81#define QUAD8_FLAG_UD BIT(5) 82/* Reset and Load Signal Decoders */ 83#define QUAD8_CTR_RLD 0x00 84/* Counter Mode Register */ 85#define QUAD8_CTR_CMR 0x20 86/* Input / Output Control Register */ 87#define QUAD8_CTR_IOR 0x40 88/* Index Control Register */ 89#define QUAD8_CTR_IDR 0x60 90/* Reset Byte Pointer (three byte data pointer) */ 91#define QUAD8_RLD_RESET_BP 0x01 92/* Reset Counter */ 93#define QUAD8_RLD_RESET_CNTR 0x02 94/* Reset Borrow Toggle, Carry Toggle, Compare Toggle, and Sign flags */ 95#define QUAD8_RLD_RESET_FLAGS 0x04 96/* Reset Error flag */ 97#define QUAD8_RLD_RESET_E 0x06 98/* Preset Register to Counter */ 99#define QUAD8_RLD_PRESET_CNTR 0x08 100/* Transfer Counter to Output Latch */ 101#define QUAD8_RLD_CNTR_OUT 0x10 102/* Transfer Preset Register LSB to FCK Prescaler */ 103#define QUAD8_RLD_PRESET_PSC 0x18 104#define QUAD8_CHAN_OP_RESET_COUNTERS 0x01 105#define QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC 0x04 106#define QUAD8_CMR_QUADRATURE_X1 0x08 107#define QUAD8_CMR_QUADRATURE_X2 0x10 108#define QUAD8_CMR_QUADRATURE_X4 0x18 109 110static int quad8_signal_read(struct counter_device *counter, 111 struct counter_signal *signal, 112 enum counter_signal_level *level) 113{ 114 const struct quad8 *const priv = counter_priv(counter); 115 unsigned int state; 116 117 /* Only Index signal levels can be read */ 118 if (signal->id < 16) 119 return -EINVAL; 120 121 state = inb(priv->base + QUAD8_REG_INDEX_INPUT_LEVELS) 122 & BIT(signal->id - 16); 123 124 *level = (state) ? COUNTER_SIGNAL_LEVEL_HIGH : COUNTER_SIGNAL_LEVEL_LOW; 125 126 return 0; 127} 128 129static int quad8_count_read(struct counter_device *counter, 130 struct counter_count *count, u64 *val) 131{ 132 struct quad8 *const priv = counter_priv(counter); 133 const int base_offset = priv->base + 2 * count->id; 134 unsigned int flags; 135 unsigned int borrow; 136 unsigned int carry; 137 unsigned long irqflags; 138 int i; 139 140 flags = inb(base_offset + 1); 141 borrow = flags & QUAD8_FLAG_BT; 142 carry = !!(flags & QUAD8_FLAG_CT); 143 144 /* Borrow XOR Carry effectively doubles count range */ 145 *val = (unsigned long)(borrow ^ carry) << 24; 146 147 spin_lock_irqsave(&priv->lock, irqflags); 148 149 /* Reset Byte Pointer; transfer Counter to Output Latch */ 150 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT, 151 base_offset + 1); 152 153 for (i = 0; i < 3; i++) 154 *val |= (unsigned long)inb(base_offset) << (8 * i); 155 156 spin_unlock_irqrestore(&priv->lock, irqflags); 157 158 return 0; 159} 160 161static int quad8_count_write(struct counter_device *counter, 162 struct counter_count *count, u64 val) 163{ 164 struct quad8 *const priv = counter_priv(counter); 165 const int base_offset = priv->base + 2 * count->id; 166 unsigned long irqflags; 167 int i; 168 169 /* Only 24-bit values are supported */ 170 if (val > 0xFFFFFF) 171 return -ERANGE; 172 173 spin_lock_irqsave(&priv->lock, irqflags); 174 175 /* Reset Byte Pointer */ 176 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 177 178 /* Counter can only be set via Preset Register */ 179 for (i = 0; i < 3; i++) 180 outb(val >> (8 * i), base_offset); 181 182 /* Transfer Preset Register to Counter */ 183 outb(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, base_offset + 1); 184 185 /* Reset Byte Pointer */ 186 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 187 188 /* Set Preset Register back to original value */ 189 val = priv->preset[count->id]; 190 for (i = 0; i < 3; i++) 191 outb(val >> (8 * i), base_offset); 192 193 /* Reset Borrow, Carry, Compare, and Sign flags */ 194 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1); 195 /* Reset Error flag */ 196 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1); 197 198 spin_unlock_irqrestore(&priv->lock, irqflags); 199 200 return 0; 201} 202 203static const enum counter_function quad8_count_functions_list[] = { 204 COUNTER_FUNCTION_PULSE_DIRECTION, 205 COUNTER_FUNCTION_QUADRATURE_X1_A, 206 COUNTER_FUNCTION_QUADRATURE_X2_A, 207 COUNTER_FUNCTION_QUADRATURE_X4, 208}; 209 210static int quad8_function_read(struct counter_device *counter, 211 struct counter_count *count, 212 enum counter_function *function) 213{ 214 struct quad8 *const priv = counter_priv(counter); 215 const int id = count->id; 216 unsigned long irqflags; 217 218 spin_lock_irqsave(&priv->lock, irqflags); 219 220 if (priv->quadrature_mode[id]) 221 switch (priv->quadrature_scale[id]) { 222 case 0: 223 *function = COUNTER_FUNCTION_QUADRATURE_X1_A; 224 break; 225 case 1: 226 *function = COUNTER_FUNCTION_QUADRATURE_X2_A; 227 break; 228 case 2: 229 *function = COUNTER_FUNCTION_QUADRATURE_X4; 230 break; 231 } 232 else 233 *function = COUNTER_FUNCTION_PULSE_DIRECTION; 234 235 spin_unlock_irqrestore(&priv->lock, irqflags); 236 237 return 0; 238} 239 240static int quad8_function_write(struct counter_device *counter, 241 struct counter_count *count, 242 enum counter_function function) 243{ 244 struct quad8 *const priv = counter_priv(counter); 245 const int id = count->id; 246 unsigned int *const quadrature_mode = priv->quadrature_mode + id; 247 unsigned int *const scale = priv->quadrature_scale + id; 248 unsigned int *const synchronous_mode = priv->synchronous_mode + id; 249 const int base_offset = priv->base + 2 * id + 1; 250 unsigned long irqflags; 251 unsigned int mode_cfg; 252 unsigned int idr_cfg; 253 254 spin_lock_irqsave(&priv->lock, irqflags); 255 256 mode_cfg = priv->count_mode[id] << 1; 257 idr_cfg = priv->index_polarity[id] << 1; 258 259 if (function == COUNTER_FUNCTION_PULSE_DIRECTION) { 260 *quadrature_mode = 0; 261 262 /* Quadrature scaling only available in quadrature mode */ 263 *scale = 0; 264 265 /* Synchronous function not supported in non-quadrature mode */ 266 if (*synchronous_mode) { 267 *synchronous_mode = 0; 268 /* Disable synchronous function mode */ 269 outb(QUAD8_CTR_IDR | idr_cfg, base_offset); 270 } 271 } else { 272 *quadrature_mode = 1; 273 274 switch (function) { 275 case COUNTER_FUNCTION_QUADRATURE_X1_A: 276 *scale = 0; 277 mode_cfg |= QUAD8_CMR_QUADRATURE_X1; 278 break; 279 case COUNTER_FUNCTION_QUADRATURE_X2_A: 280 *scale = 1; 281 mode_cfg |= QUAD8_CMR_QUADRATURE_X2; 282 break; 283 case COUNTER_FUNCTION_QUADRATURE_X4: 284 *scale = 2; 285 mode_cfg |= QUAD8_CMR_QUADRATURE_X4; 286 break; 287 default: 288 /* should never reach this path */ 289 spin_unlock_irqrestore(&priv->lock, irqflags); 290 return -EINVAL; 291 } 292 } 293 294 /* Load mode configuration to Counter Mode Register */ 295 outb(QUAD8_CTR_CMR | mode_cfg, base_offset); 296 297 spin_unlock_irqrestore(&priv->lock, irqflags); 298 299 return 0; 300} 301 302static int quad8_direction_read(struct counter_device *counter, 303 struct counter_count *count, 304 enum counter_count_direction *direction) 305{ 306 const struct quad8 *const priv = counter_priv(counter); 307 unsigned int ud_flag; 308 const unsigned int flag_addr = priv->base + 2 * count->id + 1; 309 310 /* U/D flag: nonzero = up, zero = down */ 311 ud_flag = inb(flag_addr) & QUAD8_FLAG_UD; 312 313 *direction = (ud_flag) ? COUNTER_COUNT_DIRECTION_FORWARD : 314 COUNTER_COUNT_DIRECTION_BACKWARD; 315 316 return 0; 317} 318 319static const enum counter_synapse_action quad8_index_actions_list[] = { 320 COUNTER_SYNAPSE_ACTION_NONE, 321 COUNTER_SYNAPSE_ACTION_RISING_EDGE, 322}; 323 324static const enum counter_synapse_action quad8_synapse_actions_list[] = { 325 COUNTER_SYNAPSE_ACTION_NONE, 326 COUNTER_SYNAPSE_ACTION_RISING_EDGE, 327 COUNTER_SYNAPSE_ACTION_FALLING_EDGE, 328 COUNTER_SYNAPSE_ACTION_BOTH_EDGES, 329}; 330 331static int quad8_action_read(struct counter_device *counter, 332 struct counter_count *count, 333 struct counter_synapse *synapse, 334 enum counter_synapse_action *action) 335{ 336 struct quad8 *const priv = counter_priv(counter); 337 int err; 338 enum counter_function function; 339 const size_t signal_a_id = count->synapses[0].signal->id; 340 enum counter_count_direction direction; 341 342 /* Handle Index signals */ 343 if (synapse->signal->id >= 16) { 344 if (priv->preset_enable[count->id]) 345 *action = COUNTER_SYNAPSE_ACTION_RISING_EDGE; 346 else 347 *action = COUNTER_SYNAPSE_ACTION_NONE; 348 349 return 0; 350 } 351 352 err = quad8_function_read(counter, count, &function); 353 if (err) 354 return err; 355 356 /* Default action mode */ 357 *action = COUNTER_SYNAPSE_ACTION_NONE; 358 359 /* Determine action mode based on current count function mode */ 360 switch (function) { 361 case COUNTER_FUNCTION_PULSE_DIRECTION: 362 if (synapse->signal->id == signal_a_id) 363 *action = COUNTER_SYNAPSE_ACTION_RISING_EDGE; 364 return 0; 365 case COUNTER_FUNCTION_QUADRATURE_X1_A: 366 if (synapse->signal->id == signal_a_id) { 367 err = quad8_direction_read(counter, count, &direction); 368 if (err) 369 return err; 370 371 if (direction == COUNTER_COUNT_DIRECTION_FORWARD) 372 *action = COUNTER_SYNAPSE_ACTION_RISING_EDGE; 373 else 374 *action = COUNTER_SYNAPSE_ACTION_FALLING_EDGE; 375 } 376 return 0; 377 case COUNTER_FUNCTION_QUADRATURE_X2_A: 378 if (synapse->signal->id == signal_a_id) 379 *action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES; 380 return 0; 381 case COUNTER_FUNCTION_QUADRATURE_X4: 382 *action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES; 383 return 0; 384 default: 385 /* should never reach this path */ 386 return -EINVAL; 387 } 388} 389 390enum { 391 QUAD8_EVENT_CARRY = 0, 392 QUAD8_EVENT_COMPARE = 1, 393 QUAD8_EVENT_CARRY_BORROW = 2, 394 QUAD8_EVENT_INDEX = 3, 395}; 396 397static int quad8_events_configure(struct counter_device *counter) 398{ 399 struct quad8 *const priv = counter_priv(counter); 400 unsigned long irq_enabled = 0; 401 unsigned long irqflags; 402 struct counter_event_node *event_node; 403 unsigned int next_irq_trigger; 404 unsigned long ior_cfg; 405 unsigned long base_offset; 406 407 spin_lock_irqsave(&priv->lock, irqflags); 408 409 list_for_each_entry(event_node, &counter->events_list, l) { 410 switch (event_node->event) { 411 case COUNTER_EVENT_OVERFLOW: 412 next_irq_trigger = QUAD8_EVENT_CARRY; 413 break; 414 case COUNTER_EVENT_THRESHOLD: 415 next_irq_trigger = QUAD8_EVENT_COMPARE; 416 break; 417 case COUNTER_EVENT_OVERFLOW_UNDERFLOW: 418 next_irq_trigger = QUAD8_EVENT_CARRY_BORROW; 419 break; 420 case COUNTER_EVENT_INDEX: 421 next_irq_trigger = QUAD8_EVENT_INDEX; 422 break; 423 default: 424 /* should never reach this path */ 425 spin_unlock_irqrestore(&priv->lock, irqflags); 426 return -EINVAL; 427 } 428 429 /* Skip configuration if it is the same as previously set */ 430 if (priv->irq_trigger[event_node->channel] == next_irq_trigger) 431 continue; 432 433 /* Save new IRQ function configuration */ 434 priv->irq_trigger[event_node->channel] = next_irq_trigger; 435 436 /* Load configuration to I/O Control Register */ 437 ior_cfg = priv->ab_enable[event_node->channel] | 438 priv->preset_enable[event_node->channel] << 1 | 439 priv->irq_trigger[event_node->channel] << 3; 440 base_offset = priv->base + 2 * event_node->channel + 1; 441 outb(QUAD8_CTR_IOR | ior_cfg, base_offset); 442 443 /* Enable IRQ line */ 444 irq_enabled |= BIT(event_node->channel); 445 } 446 447 outb(irq_enabled, priv->base + QUAD8_REG_INDEX_INTERRUPT); 448 449 spin_unlock_irqrestore(&priv->lock, irqflags); 450 451 return 0; 452} 453 454static int quad8_watch_validate(struct counter_device *counter, 455 const struct counter_watch *watch) 456{ 457 struct counter_event_node *event_node; 458 459 if (watch->channel > QUAD8_NUM_COUNTERS - 1) 460 return -EINVAL; 461 462 switch (watch->event) { 463 case COUNTER_EVENT_OVERFLOW: 464 case COUNTER_EVENT_THRESHOLD: 465 case COUNTER_EVENT_OVERFLOW_UNDERFLOW: 466 case COUNTER_EVENT_INDEX: 467 list_for_each_entry(event_node, &counter->next_events_list, l) 468 if (watch->channel == event_node->channel && 469 watch->event != event_node->event) 470 return -EINVAL; 471 return 0; 472 default: 473 return -EINVAL; 474 } 475} 476 477static const struct counter_ops quad8_ops = { 478 .signal_read = quad8_signal_read, 479 .count_read = quad8_count_read, 480 .count_write = quad8_count_write, 481 .function_read = quad8_function_read, 482 .function_write = quad8_function_write, 483 .action_read = quad8_action_read, 484 .events_configure = quad8_events_configure, 485 .watch_validate = quad8_watch_validate, 486}; 487 488static const char *const quad8_index_polarity_modes[] = { 489 "negative", 490 "positive" 491}; 492 493static int quad8_index_polarity_get(struct counter_device *counter, 494 struct counter_signal *signal, 495 u32 *index_polarity) 496{ 497 const struct quad8 *const priv = counter_priv(counter); 498 const size_t channel_id = signal->id - 16; 499 500 *index_polarity = priv->index_polarity[channel_id]; 501 502 return 0; 503} 504 505static int quad8_index_polarity_set(struct counter_device *counter, 506 struct counter_signal *signal, 507 u32 index_polarity) 508{ 509 struct quad8 *const priv = counter_priv(counter); 510 const size_t channel_id = signal->id - 16; 511 const int base_offset = priv->base + 2 * channel_id + 1; 512 unsigned long irqflags; 513 unsigned int idr_cfg = index_polarity << 1; 514 515 spin_lock_irqsave(&priv->lock, irqflags); 516 517 idr_cfg |= priv->synchronous_mode[channel_id]; 518 519 priv->index_polarity[channel_id] = index_polarity; 520 521 /* Load Index Control configuration to Index Control Register */ 522 outb(QUAD8_CTR_IDR | idr_cfg, base_offset); 523 524 spin_unlock_irqrestore(&priv->lock, irqflags); 525 526 return 0; 527} 528 529static const char *const quad8_synchronous_modes[] = { 530 "non-synchronous", 531 "synchronous" 532}; 533 534static int quad8_synchronous_mode_get(struct counter_device *counter, 535 struct counter_signal *signal, 536 u32 *synchronous_mode) 537{ 538 const struct quad8 *const priv = counter_priv(counter); 539 const size_t channel_id = signal->id - 16; 540 541 *synchronous_mode = priv->synchronous_mode[channel_id]; 542 543 return 0; 544} 545 546static int quad8_synchronous_mode_set(struct counter_device *counter, 547 struct counter_signal *signal, 548 u32 synchronous_mode) 549{ 550 struct quad8 *const priv = counter_priv(counter); 551 const size_t channel_id = signal->id - 16; 552 const int base_offset = priv->base + 2 * channel_id + 1; 553 unsigned long irqflags; 554 unsigned int idr_cfg = synchronous_mode; 555 556 spin_lock_irqsave(&priv->lock, irqflags); 557 558 idr_cfg |= priv->index_polarity[channel_id] << 1; 559 560 /* Index function must be non-synchronous in non-quadrature mode */ 561 if (synchronous_mode && !priv->quadrature_mode[channel_id]) { 562 spin_unlock_irqrestore(&priv->lock, irqflags); 563 return -EINVAL; 564 } 565 566 priv->synchronous_mode[channel_id] = synchronous_mode; 567 568 /* Load Index Control configuration to Index Control Register */ 569 outb(QUAD8_CTR_IDR | idr_cfg, base_offset); 570 571 spin_unlock_irqrestore(&priv->lock, irqflags); 572 573 return 0; 574} 575 576static int quad8_count_floor_read(struct counter_device *counter, 577 struct counter_count *count, u64 *floor) 578{ 579 /* Only a floor of 0 is supported */ 580 *floor = 0; 581 582 return 0; 583} 584 585static int quad8_count_mode_read(struct counter_device *counter, 586 struct counter_count *count, 587 enum counter_count_mode *cnt_mode) 588{ 589 const struct quad8 *const priv = counter_priv(counter); 590 591 /* Map 104-QUAD-8 count mode to Generic Counter count mode */ 592 switch (priv->count_mode[count->id]) { 593 case 0: 594 *cnt_mode = COUNTER_COUNT_MODE_NORMAL; 595 break; 596 case 1: 597 *cnt_mode = COUNTER_COUNT_MODE_RANGE_LIMIT; 598 break; 599 case 2: 600 *cnt_mode = COUNTER_COUNT_MODE_NON_RECYCLE; 601 break; 602 case 3: 603 *cnt_mode = COUNTER_COUNT_MODE_MODULO_N; 604 break; 605 } 606 607 return 0; 608} 609 610static int quad8_count_mode_write(struct counter_device *counter, 611 struct counter_count *count, 612 enum counter_count_mode cnt_mode) 613{ 614 struct quad8 *const priv = counter_priv(counter); 615 unsigned int count_mode; 616 unsigned int mode_cfg; 617 const int base_offset = priv->base + 2 * count->id + 1; 618 unsigned long irqflags; 619 620 /* Map Generic Counter count mode to 104-QUAD-8 count mode */ 621 switch (cnt_mode) { 622 case COUNTER_COUNT_MODE_NORMAL: 623 count_mode = 0; 624 break; 625 case COUNTER_COUNT_MODE_RANGE_LIMIT: 626 count_mode = 1; 627 break; 628 case COUNTER_COUNT_MODE_NON_RECYCLE: 629 count_mode = 2; 630 break; 631 case COUNTER_COUNT_MODE_MODULO_N: 632 count_mode = 3; 633 break; 634 default: 635 /* should never reach this path */ 636 return -EINVAL; 637 } 638 639 spin_lock_irqsave(&priv->lock, irqflags); 640 641 priv->count_mode[count->id] = count_mode; 642 643 /* Set count mode configuration value */ 644 mode_cfg = count_mode << 1; 645 646 /* Add quadrature mode configuration */ 647 if (priv->quadrature_mode[count->id]) 648 mode_cfg |= (priv->quadrature_scale[count->id] + 1) << 3; 649 650 /* Load mode configuration to Counter Mode Register */ 651 outb(QUAD8_CTR_CMR | mode_cfg, base_offset); 652 653 spin_unlock_irqrestore(&priv->lock, irqflags); 654 655 return 0; 656} 657 658static int quad8_count_enable_read(struct counter_device *counter, 659 struct counter_count *count, u8 *enable) 660{ 661 const struct quad8 *const priv = counter_priv(counter); 662 663 *enable = priv->ab_enable[count->id]; 664 665 return 0; 666} 667 668static int quad8_count_enable_write(struct counter_device *counter, 669 struct counter_count *count, u8 enable) 670{ 671 struct quad8 *const priv = counter_priv(counter); 672 const int base_offset = priv->base + 2 * count->id; 673 unsigned long irqflags; 674 unsigned int ior_cfg; 675 676 spin_lock_irqsave(&priv->lock, irqflags); 677 678 priv->ab_enable[count->id] = enable; 679 680 ior_cfg = enable | priv->preset_enable[count->id] << 1 | 681 priv->irq_trigger[count->id] << 3; 682 683 /* Load I/O control configuration */ 684 outb(QUAD8_CTR_IOR | ior_cfg, base_offset + 1); 685 686 spin_unlock_irqrestore(&priv->lock, irqflags); 687 688 return 0; 689} 690 691static const char *const quad8_noise_error_states[] = { 692 "No excessive noise is present at the count inputs", 693 "Excessive noise is present at the count inputs" 694}; 695 696static int quad8_error_noise_get(struct counter_device *counter, 697 struct counter_count *count, u32 *noise_error) 698{ 699 const struct quad8 *const priv = counter_priv(counter); 700 const int base_offset = priv->base + 2 * count->id + 1; 701 702 *noise_error = !!(inb(base_offset) & QUAD8_FLAG_E); 703 704 return 0; 705} 706 707static int quad8_count_preset_read(struct counter_device *counter, 708 struct counter_count *count, u64 *preset) 709{ 710 const struct quad8 *const priv = counter_priv(counter); 711 712 *preset = priv->preset[count->id]; 713 714 return 0; 715} 716 717static void quad8_preset_register_set(struct quad8 *const priv, const int id, 718 const unsigned int preset) 719{ 720 const unsigned int base_offset = priv->base + 2 * id; 721 int i; 722 723 priv->preset[id] = preset; 724 725 /* Reset Byte Pointer */ 726 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 727 728 /* Set Preset Register */ 729 for (i = 0; i < 3; i++) 730 outb(preset >> (8 * i), base_offset); 731} 732 733static int quad8_count_preset_write(struct counter_device *counter, 734 struct counter_count *count, u64 preset) 735{ 736 struct quad8 *const priv = counter_priv(counter); 737 unsigned long irqflags; 738 739 /* Only 24-bit values are supported */ 740 if (preset > 0xFFFFFF) 741 return -ERANGE; 742 743 spin_lock_irqsave(&priv->lock, irqflags); 744 745 quad8_preset_register_set(priv, count->id, preset); 746 747 spin_unlock_irqrestore(&priv->lock, irqflags); 748 749 return 0; 750} 751 752static int quad8_count_ceiling_read(struct counter_device *counter, 753 struct counter_count *count, u64 *ceiling) 754{ 755 struct quad8 *const priv = counter_priv(counter); 756 unsigned long irqflags; 757 758 spin_lock_irqsave(&priv->lock, irqflags); 759 760 /* Range Limit and Modulo-N count modes use preset value as ceiling */ 761 switch (priv->count_mode[count->id]) { 762 case 1: 763 case 3: 764 *ceiling = priv->preset[count->id]; 765 break; 766 default: 767 /* By default 0x1FFFFFF (25 bits unsigned) is maximum count */ 768 *ceiling = 0x1FFFFFF; 769 break; 770 } 771 772 spin_unlock_irqrestore(&priv->lock, irqflags); 773 774 return 0; 775} 776 777static int quad8_count_ceiling_write(struct counter_device *counter, 778 struct counter_count *count, u64 ceiling) 779{ 780 struct quad8 *const priv = counter_priv(counter); 781 unsigned long irqflags; 782 783 /* Only 24-bit values are supported */ 784 if (ceiling > 0xFFFFFF) 785 return -ERANGE; 786 787 spin_lock_irqsave(&priv->lock, irqflags); 788 789 /* Range Limit and Modulo-N count modes use preset value as ceiling */ 790 switch (priv->count_mode[count->id]) { 791 case 1: 792 case 3: 793 quad8_preset_register_set(priv, count->id, ceiling); 794 spin_unlock_irqrestore(&priv->lock, irqflags); 795 return 0; 796 } 797 798 spin_unlock_irqrestore(&priv->lock, irqflags); 799 800 return -EINVAL; 801} 802 803static int quad8_count_preset_enable_read(struct counter_device *counter, 804 struct counter_count *count, 805 u8 *preset_enable) 806{ 807 const struct quad8 *const priv = counter_priv(counter); 808 809 *preset_enable = !priv->preset_enable[count->id]; 810 811 return 0; 812} 813 814static int quad8_count_preset_enable_write(struct counter_device *counter, 815 struct counter_count *count, 816 u8 preset_enable) 817{ 818 struct quad8 *const priv = counter_priv(counter); 819 const int base_offset = priv->base + 2 * count->id + 1; 820 unsigned long irqflags; 821 unsigned int ior_cfg; 822 823 /* Preset enable is active low in Input/Output Control register */ 824 preset_enable = !preset_enable; 825 826 spin_lock_irqsave(&priv->lock, irqflags); 827 828 priv->preset_enable[count->id] = preset_enable; 829 830 ior_cfg = priv->ab_enable[count->id] | preset_enable << 1 | 831 priv->irq_trigger[count->id] << 3; 832 833 /* Load I/O control configuration to Input / Output Control Register */ 834 outb(QUAD8_CTR_IOR | ior_cfg, base_offset); 835 836 spin_unlock_irqrestore(&priv->lock, irqflags); 837 838 return 0; 839} 840 841static int quad8_signal_cable_fault_read(struct counter_device *counter, 842 struct counter_signal *signal, 843 u8 *cable_fault) 844{ 845 struct quad8 *const priv = counter_priv(counter); 846 const size_t channel_id = signal->id / 2; 847 unsigned long irqflags; 848 bool disabled; 849 unsigned int status; 850 851 spin_lock_irqsave(&priv->lock, irqflags); 852 853 disabled = !(priv->cable_fault_enable & BIT(channel_id)); 854 855 if (disabled) { 856 spin_unlock_irqrestore(&priv->lock, irqflags); 857 return -EINVAL; 858 } 859 860 /* Logic 0 = cable fault */ 861 status = inb(priv->base + QUAD8_DIFF_ENCODER_CABLE_STATUS); 862 863 spin_unlock_irqrestore(&priv->lock, irqflags); 864 865 /* Mask respective channel and invert logic */ 866 *cable_fault = !(status & BIT(channel_id)); 867 868 return 0; 869} 870 871static int quad8_signal_cable_fault_enable_read(struct counter_device *counter, 872 struct counter_signal *signal, 873 u8 *enable) 874{ 875 const struct quad8 *const priv = counter_priv(counter); 876 const size_t channel_id = signal->id / 2; 877 878 *enable = !!(priv->cable_fault_enable & BIT(channel_id)); 879 880 return 0; 881} 882 883static int quad8_signal_cable_fault_enable_write(struct counter_device *counter, 884 struct counter_signal *signal, 885 u8 enable) 886{ 887 struct quad8 *const priv = counter_priv(counter); 888 const size_t channel_id = signal->id / 2; 889 unsigned long irqflags; 890 unsigned int cable_fault_enable; 891 892 spin_lock_irqsave(&priv->lock, irqflags); 893 894 if (enable) 895 priv->cable_fault_enable |= BIT(channel_id); 896 else 897 priv->cable_fault_enable &= ~BIT(channel_id); 898 899 /* Enable is active low in Differential Encoder Cable Status register */ 900 cable_fault_enable = ~priv->cable_fault_enable; 901 902 outb(cable_fault_enable, priv->base + QUAD8_DIFF_ENCODER_CABLE_STATUS); 903 904 spin_unlock_irqrestore(&priv->lock, irqflags); 905 906 return 0; 907} 908 909static int quad8_signal_fck_prescaler_read(struct counter_device *counter, 910 struct counter_signal *signal, 911 u8 *prescaler) 912{ 913 const struct quad8 *const priv = counter_priv(counter); 914 915 *prescaler = priv->fck_prescaler[signal->id / 2]; 916 917 return 0; 918} 919 920static int quad8_signal_fck_prescaler_write(struct counter_device *counter, 921 struct counter_signal *signal, 922 u8 prescaler) 923{ 924 struct quad8 *const priv = counter_priv(counter); 925 const size_t channel_id = signal->id / 2; 926 const int base_offset = priv->base + 2 * channel_id; 927 unsigned long irqflags; 928 929 spin_lock_irqsave(&priv->lock, irqflags); 930 931 priv->fck_prescaler[channel_id] = prescaler; 932 933 /* Reset Byte Pointer */ 934 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 935 936 /* Set filter clock factor */ 937 outb(prescaler, base_offset); 938 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC, 939 base_offset + 1); 940 941 spin_unlock_irqrestore(&priv->lock, irqflags); 942 943 return 0; 944} 945 946static struct counter_comp quad8_signal_ext[] = { 947 COUNTER_COMP_SIGNAL_BOOL("cable_fault", quad8_signal_cable_fault_read, 948 NULL), 949 COUNTER_COMP_SIGNAL_BOOL("cable_fault_enable", 950 quad8_signal_cable_fault_enable_read, 951 quad8_signal_cable_fault_enable_write), 952 COUNTER_COMP_SIGNAL_U8("filter_clock_prescaler", 953 quad8_signal_fck_prescaler_read, 954 quad8_signal_fck_prescaler_write) 955}; 956 957static DEFINE_COUNTER_ENUM(quad8_index_pol_enum, quad8_index_polarity_modes); 958static DEFINE_COUNTER_ENUM(quad8_synch_mode_enum, quad8_synchronous_modes); 959 960static struct counter_comp quad8_index_ext[] = { 961 COUNTER_COMP_SIGNAL_ENUM("index_polarity", quad8_index_polarity_get, 962 quad8_index_polarity_set, 963 quad8_index_pol_enum), 964 COUNTER_COMP_SIGNAL_ENUM("synchronous_mode", quad8_synchronous_mode_get, 965 quad8_synchronous_mode_set, 966 quad8_synch_mode_enum), 967}; 968 969#define QUAD8_QUAD_SIGNAL(_id, _name) { \ 970 .id = (_id), \ 971 .name = (_name), \ 972 .ext = quad8_signal_ext, \ 973 .num_ext = ARRAY_SIZE(quad8_signal_ext) \ 974} 975 976#define QUAD8_INDEX_SIGNAL(_id, _name) { \ 977 .id = (_id), \ 978 .name = (_name), \ 979 .ext = quad8_index_ext, \ 980 .num_ext = ARRAY_SIZE(quad8_index_ext) \ 981} 982 983static struct counter_signal quad8_signals[] = { 984 QUAD8_QUAD_SIGNAL(0, "Channel 1 Quadrature A"), 985 QUAD8_QUAD_SIGNAL(1, "Channel 1 Quadrature B"), 986 QUAD8_QUAD_SIGNAL(2, "Channel 2 Quadrature A"), 987 QUAD8_QUAD_SIGNAL(3, "Channel 2 Quadrature B"), 988 QUAD8_QUAD_SIGNAL(4, "Channel 3 Quadrature A"), 989 QUAD8_QUAD_SIGNAL(5, "Channel 3 Quadrature B"), 990 QUAD8_QUAD_SIGNAL(6, "Channel 4 Quadrature A"), 991 QUAD8_QUAD_SIGNAL(7, "Channel 4 Quadrature B"), 992 QUAD8_QUAD_SIGNAL(8, "Channel 5 Quadrature A"), 993 QUAD8_QUAD_SIGNAL(9, "Channel 5 Quadrature B"), 994 QUAD8_QUAD_SIGNAL(10, "Channel 6 Quadrature A"), 995 QUAD8_QUAD_SIGNAL(11, "Channel 6 Quadrature B"), 996 QUAD8_QUAD_SIGNAL(12, "Channel 7 Quadrature A"), 997 QUAD8_QUAD_SIGNAL(13, "Channel 7 Quadrature B"), 998 QUAD8_QUAD_SIGNAL(14, "Channel 8 Quadrature A"), 999 QUAD8_QUAD_SIGNAL(15, "Channel 8 Quadrature B"), 1000 QUAD8_INDEX_SIGNAL(16, "Channel 1 Index"), 1001 QUAD8_INDEX_SIGNAL(17, "Channel 2 Index"), 1002 QUAD8_INDEX_SIGNAL(18, "Channel 3 Index"), 1003 QUAD8_INDEX_SIGNAL(19, "Channel 4 Index"), 1004 QUAD8_INDEX_SIGNAL(20, "Channel 5 Index"), 1005 QUAD8_INDEX_SIGNAL(21, "Channel 6 Index"), 1006 QUAD8_INDEX_SIGNAL(22, "Channel 7 Index"), 1007 QUAD8_INDEX_SIGNAL(23, "Channel 8 Index") 1008}; 1009 1010#define QUAD8_COUNT_SYNAPSES(_id) { \ 1011 { \ 1012 .actions_list = quad8_synapse_actions_list, \ 1013 .num_actions = ARRAY_SIZE(quad8_synapse_actions_list), \ 1014 .signal = quad8_signals + 2 * (_id) \ 1015 }, \ 1016 { \ 1017 .actions_list = quad8_synapse_actions_list, \ 1018 .num_actions = ARRAY_SIZE(quad8_synapse_actions_list), \ 1019 .signal = quad8_signals + 2 * (_id) + 1 \ 1020 }, \ 1021 { \ 1022 .actions_list = quad8_index_actions_list, \ 1023 .num_actions = ARRAY_SIZE(quad8_index_actions_list), \ 1024 .signal = quad8_signals + 2 * (_id) + 16 \ 1025 } \ 1026} 1027 1028static struct counter_synapse quad8_count_synapses[][3] = { 1029 QUAD8_COUNT_SYNAPSES(0), QUAD8_COUNT_SYNAPSES(1), 1030 QUAD8_COUNT_SYNAPSES(2), QUAD8_COUNT_SYNAPSES(3), 1031 QUAD8_COUNT_SYNAPSES(4), QUAD8_COUNT_SYNAPSES(5), 1032 QUAD8_COUNT_SYNAPSES(6), QUAD8_COUNT_SYNAPSES(7) 1033}; 1034 1035static const enum counter_count_mode quad8_cnt_modes[] = { 1036 COUNTER_COUNT_MODE_NORMAL, 1037 COUNTER_COUNT_MODE_RANGE_LIMIT, 1038 COUNTER_COUNT_MODE_NON_RECYCLE, 1039 COUNTER_COUNT_MODE_MODULO_N, 1040}; 1041 1042static DEFINE_COUNTER_AVAILABLE(quad8_count_mode_available, quad8_cnt_modes); 1043 1044static DEFINE_COUNTER_ENUM(quad8_error_noise_enum, quad8_noise_error_states); 1045 1046static struct counter_comp quad8_count_ext[] = { 1047 COUNTER_COMP_CEILING(quad8_count_ceiling_read, 1048 quad8_count_ceiling_write), 1049 COUNTER_COMP_FLOOR(quad8_count_floor_read, NULL), 1050 COUNTER_COMP_COUNT_MODE(quad8_count_mode_read, quad8_count_mode_write, 1051 quad8_count_mode_available), 1052 COUNTER_COMP_DIRECTION(quad8_direction_read), 1053 COUNTER_COMP_ENABLE(quad8_count_enable_read, quad8_count_enable_write), 1054 COUNTER_COMP_COUNT_ENUM("error_noise", quad8_error_noise_get, NULL, 1055 quad8_error_noise_enum), 1056 COUNTER_COMP_PRESET(quad8_count_preset_read, quad8_count_preset_write), 1057 COUNTER_COMP_PRESET_ENABLE(quad8_count_preset_enable_read, 1058 quad8_count_preset_enable_write), 1059}; 1060 1061#define QUAD8_COUNT(_id, _cntname) { \ 1062 .id = (_id), \ 1063 .name = (_cntname), \ 1064 .functions_list = quad8_count_functions_list, \ 1065 .num_functions = ARRAY_SIZE(quad8_count_functions_list), \ 1066 .synapses = quad8_count_synapses[(_id)], \ 1067 .num_synapses = 2, \ 1068 .ext = quad8_count_ext, \ 1069 .num_ext = ARRAY_SIZE(quad8_count_ext) \ 1070} 1071 1072static struct counter_count quad8_counts[] = { 1073 QUAD8_COUNT(0, "Channel 1 Count"), 1074 QUAD8_COUNT(1, "Channel 2 Count"), 1075 QUAD8_COUNT(2, "Channel 3 Count"), 1076 QUAD8_COUNT(3, "Channel 4 Count"), 1077 QUAD8_COUNT(4, "Channel 5 Count"), 1078 QUAD8_COUNT(5, "Channel 6 Count"), 1079 QUAD8_COUNT(6, "Channel 7 Count"), 1080 QUAD8_COUNT(7, "Channel 8 Count") 1081}; 1082 1083static irqreturn_t quad8_irq_handler(int irq, void *private) 1084{ 1085 struct counter_device *counter = private; 1086 struct quad8 *const priv = counter_priv(counter); 1087 const unsigned long base = priv->base; 1088 unsigned long irq_status; 1089 unsigned long channel; 1090 u8 event; 1091 1092 irq_status = inb(base + QUAD8_REG_INTERRUPT_STATUS); 1093 if (!irq_status) 1094 return IRQ_NONE; 1095 1096 for_each_set_bit(channel, &irq_status, QUAD8_NUM_COUNTERS) { 1097 switch (priv->irq_trigger[channel]) { 1098 case QUAD8_EVENT_CARRY: 1099 event = COUNTER_EVENT_OVERFLOW; 1100 break; 1101 case QUAD8_EVENT_COMPARE: 1102 event = COUNTER_EVENT_THRESHOLD; 1103 break; 1104 case QUAD8_EVENT_CARRY_BORROW: 1105 event = COUNTER_EVENT_OVERFLOW_UNDERFLOW; 1106 break; 1107 case QUAD8_EVENT_INDEX: 1108 event = COUNTER_EVENT_INDEX; 1109 break; 1110 default: 1111 /* should never reach this path */ 1112 WARN_ONCE(true, "invalid interrupt trigger function %u configured for channel %lu\n", 1113 priv->irq_trigger[channel], channel); 1114 continue; 1115 } 1116 1117 counter_push_event(counter, event, channel); 1118 } 1119 1120 /* Clear pending interrupts on device */ 1121 outb(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC, base + QUAD8_REG_CHAN_OP); 1122 1123 return IRQ_HANDLED; 1124} 1125 1126static int quad8_probe(struct device *dev, unsigned int id) 1127{ 1128 struct counter_device *counter; 1129 struct quad8 *priv; 1130 int i, j; 1131 unsigned int base_offset; 1132 int err; 1133 1134 if (!devm_request_region(dev, base[id], QUAD8_EXTENT, dev_name(dev))) { 1135 dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", 1136 base[id], base[id] + QUAD8_EXTENT); 1137 return -EBUSY; 1138 } 1139 1140 counter = devm_counter_alloc(dev, sizeof(*priv)); 1141 if (!counter) 1142 return -ENOMEM; 1143 priv = counter_priv(counter); 1144 1145 /* Initialize Counter device and driver data */ 1146 counter->name = dev_name(dev); 1147 counter->parent = dev; 1148 counter->ops = &quad8_ops; 1149 counter->counts = quad8_counts; 1150 counter->num_counts = ARRAY_SIZE(quad8_counts); 1151 counter->signals = quad8_signals; 1152 counter->num_signals = ARRAY_SIZE(quad8_signals); 1153 priv->base = base[id]; 1154 1155 spin_lock_init(&priv->lock); 1156 1157 /* Reset Index/Interrupt Register */ 1158 outb(0x00, base[id] + QUAD8_REG_INDEX_INTERRUPT); 1159 /* Reset all counters and disable interrupt function */ 1160 outb(QUAD8_CHAN_OP_RESET_COUNTERS, base[id] + QUAD8_REG_CHAN_OP); 1161 /* Set initial configuration for all counters */ 1162 for (i = 0; i < QUAD8_NUM_COUNTERS; i++) { 1163 base_offset = base[id] + 2 * i; 1164 /* Reset Byte Pointer */ 1165 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 1166 /* Reset filter clock factor */ 1167 outb(0, base_offset); 1168 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC, 1169 base_offset + 1); 1170 /* Reset Byte Pointer */ 1171 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 1172 /* Reset Preset Register */ 1173 for (j = 0; j < 3; j++) 1174 outb(0x00, base_offset); 1175 /* Reset Borrow, Carry, Compare, and Sign flags */ 1176 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1); 1177 /* Reset Error flag */ 1178 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1); 1179 /* Binary encoding; Normal count; non-quadrature mode */ 1180 outb(QUAD8_CTR_CMR, base_offset + 1); 1181 /* Disable A and B inputs; preset on index; FLG1 as Carry */ 1182 outb(QUAD8_CTR_IOR, base_offset + 1); 1183 /* Disable index function; negative index polarity */ 1184 outb(QUAD8_CTR_IDR, base_offset + 1); 1185 } 1186 /* Disable Differential Encoder Cable Status for all channels */ 1187 outb(0xFF, base[id] + QUAD8_DIFF_ENCODER_CABLE_STATUS); 1188 /* Enable all counters and enable interrupt function */ 1189 outb(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC, base[id] + QUAD8_REG_CHAN_OP); 1190 1191 err = devm_request_irq(&counter->dev, irq[id], quad8_irq_handler, 1192 IRQF_SHARED, counter->name, counter); 1193 if (err) 1194 return err; 1195 1196 err = devm_counter_add(dev, counter); 1197 if (err < 0) 1198 return dev_err_probe(dev, err, "Failed to add counter\n"); 1199 1200 return 0; 1201} 1202 1203static struct isa_driver quad8_driver = { 1204 .probe = quad8_probe, 1205 .driver = { 1206 .name = "104-quad-8" 1207 } 1208}; 1209 1210module_isa_driver(quad8_driver, num_quad8); 1211 1212MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 1213MODULE_DESCRIPTION("ACCES 104-QUAD-8 driver"); 1214MODULE_LICENSE("GPL v2");