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