drm/vc4: txp: Protect device resources
[platform/kernel/linux-starfive.git] / drivers / counter / 104-quad-8.c
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
25 static unsigned int base[max_num_isa_dev(QUAD8_EXTENT)];
26 static unsigned int num_quad8;
27 module_param_hw_array(base, uint, ioport, &num_quad8, 0);
28 MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");
29
30 static unsigned int irq[max_num_isa_dev(QUAD8_EXTENT)];
31 module_param_hw_array(irq, uint, irq, NULL, 0);
32 MODULE_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  */
53 struct 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
110 static 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
129 static 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
161 static 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
203 static 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
210 static 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
240 static 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
302 static 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
319 static const enum counter_synapse_action quad8_index_actions_list[] = {
320         COUNTER_SYNAPSE_ACTION_NONE,
321         COUNTER_SYNAPSE_ACTION_RISING_EDGE,
322 };
323
324 static 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
331 static 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
390 enum {
391         QUAD8_EVENT_CARRY = 0,
392         QUAD8_EVENT_COMPARE = 1,
393         QUAD8_EVENT_CARRY_BORROW = 2,
394         QUAD8_EVENT_INDEX = 3,
395 };
396
397 static 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
454 static 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
477 static 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
488 static const char *const quad8_index_polarity_modes[] = {
489         "negative",
490         "positive"
491 };
492
493 static 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
505 static 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
529 static const char *const quad8_synchronous_modes[] = {
530         "non-synchronous",
531         "synchronous"
532 };
533
534 static 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
546 static 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
576 static 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
585 static 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
610 static 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
658 static 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
668 static 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
691 static 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
696 static 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
707 static 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
717 static 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
733 static 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
752 static 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
777 static 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
803 static 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
814 static 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
841 static 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
871 static 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
883 static 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
909 static 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
920 static 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
946 static 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
957 static DEFINE_COUNTER_ENUM(quad8_index_pol_enum, quad8_index_polarity_modes);
958 static DEFINE_COUNTER_ENUM(quad8_synch_mode_enum, quad8_synchronous_modes);
959
960 static 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
983 static 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
1028 static 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
1035 static 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
1042 static DEFINE_COUNTER_AVAILABLE(quad8_count_mode_available, quad8_cnt_modes);
1043
1044 static DEFINE_COUNTER_ENUM(quad8_error_noise_enum, quad8_noise_error_states);
1045
1046 static 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
1072 static 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
1083 static 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
1126 static 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
1203 static struct isa_driver quad8_driver = {
1204         .probe = quad8_probe,
1205         .driver = {
1206                 .name = "104-quad-8"
1207         }
1208 };
1209
1210 module_isa_driver(quad8_driver, num_quad8);
1211
1212 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
1213 MODULE_DESCRIPTION("ACCES 104-QUAD-8 driver");
1214 MODULE_LICENSE("GPL v2");