1 // SPDX-License-Identifier: GPL-2.0
3 * Counter driver for the ACCES 104-QUAD-8
4 * Copyright (C) 2016 William Breathitt Gray
6 * This driver supports the ACCES 104-QUAD-8 and ACCES 104-QUAD-4.
8 #include <linux/bitops.h>
9 #include <linux/counter.h>
10 #include <linux/device.h>
11 #include <linux/errno.h>
12 #include <linux/iio/iio.h>
13 #include <linux/iio/types.h>
15 #include <linux/ioport.h>
16 #include <linux/isa.h>
17 #include <linux/kernel.h>
18 #include <linux/module.h>
19 #include <linux/moduleparam.h>
20 #include <linux/types.h>
22 #define QUAD8_EXTENT 32
24 static unsigned int base
[max_num_isa_dev(QUAD8_EXTENT
)];
25 static unsigned int num_quad8
;
26 module_param_array(base
, uint
, &num_quad8
, 0);
27 MODULE_PARM_DESC(base
, "ACCES 104-QUAD-8 base addresses");
29 #define QUAD8_NUM_COUNTERS 8
32 * struct quad8_iio - IIO device private data structure
33 * @counter: instance of the counter_device
34 * @fck_prescaler: array of filter clock prescaler configurations
35 * @preset: array of preset values
36 * @count_mode: array of count mode configurations
37 * @quadrature_mode: array of quadrature mode configurations
38 * @quadrature_scale: array of quadrature mode scale configurations
39 * @ab_enable: array of A and B inputs enable configurations
40 * @preset_enable: array of set_to_preset_on_index attribute configurations
41 * @synchronous_mode: array of index function synchronous mode configurations
42 * @index_polarity: array of index function polarity configurations
43 * @cable_fault_enable: differential encoder cable status enable configurations
44 * @base: base port address of the IIO device
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
;
61 #define QUAD8_REG_CHAN_OP 0x11
62 #define QUAD8_REG_INDEX_INPUT_LEVELS 0x16
63 #define QUAD8_DIFF_ENCODER_CABLE_STATUS 0x17
64 /* Borrow Toggle flip-flop */
65 #define QUAD8_FLAG_BT BIT(0)
66 /* Carry Toggle flip-flop */
67 #define QUAD8_FLAG_CT BIT(1)
69 #define QUAD8_FLAG_E BIT(4)
71 #define QUAD8_FLAG_UD BIT(5)
72 /* Reset and Load Signal Decoders */
73 #define QUAD8_CTR_RLD 0x00
74 /* Counter Mode Register */
75 #define QUAD8_CTR_CMR 0x20
76 /* Input / Output Control Register */
77 #define QUAD8_CTR_IOR 0x40
78 /* Index Control Register */
79 #define QUAD8_CTR_IDR 0x60
80 /* Reset Byte Pointer (three byte data pointer) */
81 #define QUAD8_RLD_RESET_BP 0x01
83 #define QUAD8_RLD_RESET_CNTR 0x02
84 /* Reset Borrow Toggle, Carry Toggle, Compare Toggle, and Sign flags */
85 #define QUAD8_RLD_RESET_FLAGS 0x04
86 /* Reset Error flag */
87 #define QUAD8_RLD_RESET_E 0x06
88 /* Preset Register to Counter */
89 #define QUAD8_RLD_PRESET_CNTR 0x08
90 /* Transfer Counter to Output Latch */
91 #define QUAD8_RLD_CNTR_OUT 0x10
92 /* Transfer Preset Register LSB to FCK Prescaler */
93 #define QUAD8_RLD_PRESET_PSC 0x18
94 #define QUAD8_CHAN_OP_ENABLE_COUNTERS 0x00
95 #define QUAD8_CHAN_OP_RESET_COUNTERS 0x01
96 #define QUAD8_CMR_QUADRATURE_X1 0x08
97 #define QUAD8_CMR_QUADRATURE_X2 0x10
98 #define QUAD8_CMR_QUADRATURE_X4 0x18
101 static int quad8_read_raw(struct iio_dev
*indio_dev
,
102 struct iio_chan_spec
const *chan
, int *val
, int *val2
, long mask
)
104 struct quad8_iio
*const priv
= iio_priv(indio_dev
);
105 const int base_offset
= priv
->base
+ 2 * chan
->channel
;
112 case IIO_CHAN_INFO_RAW
:
113 if (chan
->type
== IIO_INDEX
) {
114 *val
= !!(inb(priv
->base
+ QUAD8_REG_INDEX_INPUT_LEVELS
)
115 & BIT(chan
->channel
));
119 flags
= inb(base_offset
+ 1);
120 borrow
= flags
& QUAD8_FLAG_BT
;
121 carry
= !!(flags
& QUAD8_FLAG_CT
);
123 /* Borrow XOR Carry effectively doubles count range */
124 *val
= (borrow
^ carry
) << 24;
126 /* Reset Byte Pointer; transfer Counter to Output Latch */
127 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
| QUAD8_RLD_CNTR_OUT
,
130 for (i
= 0; i
< 3; i
++)
131 *val
|= (unsigned int)inb(base_offset
) << (8 * i
);
134 case IIO_CHAN_INFO_ENABLE
:
135 *val
= priv
->ab_enable
[chan
->channel
];
137 case IIO_CHAN_INFO_SCALE
:
139 *val2
= priv
->quadrature_scale
[chan
->channel
];
140 return IIO_VAL_FRACTIONAL_LOG2
;
146 static int quad8_write_raw(struct iio_dev
*indio_dev
,
147 struct iio_chan_spec
const *chan
, int val
, int val2
, long mask
)
149 struct quad8_iio
*const priv
= iio_priv(indio_dev
);
150 const int base_offset
= priv
->base
+ 2 * chan
->channel
;
152 unsigned int ior_cfg
;
155 case IIO_CHAN_INFO_RAW
:
156 if (chan
->type
== IIO_INDEX
)
159 /* Only 24-bit values are supported */
160 if ((unsigned int)val
> 0xFFFFFF)
163 /* Reset Byte Pointer */
164 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
, base_offset
+ 1);
166 /* Counter can only be set via Preset Register */
167 for (i
= 0; i
< 3; i
++)
168 outb(val
>> (8 * i
), base_offset
);
170 /* Transfer Preset Register to Counter */
171 outb(QUAD8_CTR_RLD
| QUAD8_RLD_PRESET_CNTR
, base_offset
+ 1);
173 /* Reset Byte Pointer */
174 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
, base_offset
+ 1);
176 /* Set Preset Register back to original value */
177 val
= priv
->preset
[chan
->channel
];
178 for (i
= 0; i
< 3; i
++)
179 outb(val
>> (8 * i
), base_offset
);
181 /* Reset Borrow, Carry, Compare, and Sign flags */
182 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_FLAGS
, base_offset
+ 1);
183 /* Reset Error flag */
184 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_E
, base_offset
+ 1);
187 case IIO_CHAN_INFO_ENABLE
:
188 /* only boolean values accepted */
189 if (val
< 0 || val
> 1)
192 priv
->ab_enable
[chan
->channel
] = val
;
194 ior_cfg
= val
| priv
->preset_enable
[chan
->channel
] << 1;
196 /* Load I/O control configuration */
197 outb(QUAD8_CTR_IOR
| ior_cfg
, base_offset
+ 1);
200 case IIO_CHAN_INFO_SCALE
:
201 /* Quadrature scaling only available in quadrature mode */
202 if (!priv
->quadrature_mode
[chan
->channel
] && (val2
|| val
!= 1))
205 /* Only three gain states (1, 0.5, 0.25) */
206 if (val
== 1 && !val2
)
207 priv
->quadrature_scale
[chan
->channel
] = 0;
211 priv
->quadrature_scale
[chan
->channel
] = 1;
214 priv
->quadrature_scale
[chan
->channel
] = 2;
228 static const struct iio_info quad8_info
= {
229 .read_raw
= quad8_read_raw
,
230 .write_raw
= quad8_write_raw
233 static ssize_t
quad8_read_preset(struct iio_dev
*indio_dev
, uintptr_t private,
234 const struct iio_chan_spec
*chan
, char *buf
)
236 const struct quad8_iio
*const priv
= iio_priv(indio_dev
);
238 return snprintf(buf
, PAGE_SIZE
, "%u\n", priv
->preset
[chan
->channel
]);
241 static ssize_t
quad8_write_preset(struct iio_dev
*indio_dev
, uintptr_t private,
242 const struct iio_chan_spec
*chan
, const char *buf
, size_t len
)
244 struct quad8_iio
*const priv
= iio_priv(indio_dev
);
245 const int base_offset
= priv
->base
+ 2 * chan
->channel
;
250 ret
= kstrtouint(buf
, 0, &preset
);
254 /* Only 24-bit values are supported */
255 if (preset
> 0xFFFFFF)
258 priv
->preset
[chan
->channel
] = preset
;
260 /* Reset Byte Pointer */
261 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
, base_offset
+ 1);
263 /* Set Preset Register */
264 for (i
= 0; i
< 3; i
++)
265 outb(preset
>> (8 * i
), base_offset
);
270 static ssize_t
quad8_read_set_to_preset_on_index(struct iio_dev
*indio_dev
,
271 uintptr_t private, const struct iio_chan_spec
*chan
, char *buf
)
273 const struct quad8_iio
*const priv
= iio_priv(indio_dev
);
275 return snprintf(buf
, PAGE_SIZE
, "%u\n",
276 !priv
->preset_enable
[chan
->channel
]);
279 static ssize_t
quad8_write_set_to_preset_on_index(struct iio_dev
*indio_dev
,
280 uintptr_t private, const struct iio_chan_spec
*chan
, const char *buf
,
283 struct quad8_iio
*const priv
= iio_priv(indio_dev
);
284 const int base_offset
= priv
->base
+ 2 * chan
->channel
+ 1;
287 unsigned int ior_cfg
;
289 ret
= kstrtobool(buf
, &preset_enable
);
293 /* Preset enable is active low in Input/Output Control register */
294 preset_enable
= !preset_enable
;
296 priv
->preset_enable
[chan
->channel
] = preset_enable
;
298 ior_cfg
= priv
->ab_enable
[chan
->channel
] |
299 (unsigned int)preset_enable
<< 1;
301 /* Load I/O control configuration to Input / Output Control Register */
302 outb(QUAD8_CTR_IOR
| ior_cfg
, base_offset
);
307 static const char *const quad8_noise_error_states
[] = {
308 "No excessive noise is present at the count inputs",
309 "Excessive noise is present at the count inputs"
312 static int quad8_get_noise_error(struct iio_dev
*indio_dev
,
313 const struct iio_chan_spec
*chan
)
315 struct quad8_iio
*const priv
= iio_priv(indio_dev
);
316 const int base_offset
= priv
->base
+ 2 * chan
->channel
+ 1;
318 return !!(inb(base_offset
) & QUAD8_FLAG_E
);
321 static const struct iio_enum quad8_noise_error_enum
= {
322 .items
= quad8_noise_error_states
,
323 .num_items
= ARRAY_SIZE(quad8_noise_error_states
),
324 .get
= quad8_get_noise_error
327 static const char *const quad8_count_direction_states
[] = {
332 static int quad8_get_count_direction(struct iio_dev
*indio_dev
,
333 const struct iio_chan_spec
*chan
)
335 struct quad8_iio
*const priv
= iio_priv(indio_dev
);
336 const int base_offset
= priv
->base
+ 2 * chan
->channel
+ 1;
338 return !!(inb(base_offset
) & QUAD8_FLAG_UD
);
341 static const struct iio_enum quad8_count_direction_enum
= {
342 .items
= quad8_count_direction_states
,
343 .num_items
= ARRAY_SIZE(quad8_count_direction_states
),
344 .get
= quad8_get_count_direction
347 static const char *const quad8_count_modes
[] = {
354 static int quad8_set_count_mode(struct iio_dev
*indio_dev
,
355 const struct iio_chan_spec
*chan
, unsigned int cnt_mode
)
357 struct quad8_iio
*const priv
= iio_priv(indio_dev
);
358 unsigned int mode_cfg
= cnt_mode
<< 1;
359 const int base_offset
= priv
->base
+ 2 * chan
->channel
+ 1;
361 priv
->count_mode
[chan
->channel
] = cnt_mode
;
363 /* Add quadrature mode configuration */
364 if (priv
->quadrature_mode
[chan
->channel
])
365 mode_cfg
|= (priv
->quadrature_scale
[chan
->channel
] + 1) << 3;
367 /* Load mode configuration to Counter Mode Register */
368 outb(QUAD8_CTR_CMR
| mode_cfg
, base_offset
);
373 static int quad8_get_count_mode(struct iio_dev
*indio_dev
,
374 const struct iio_chan_spec
*chan
)
376 const struct quad8_iio
*const priv
= iio_priv(indio_dev
);
378 return priv
->count_mode
[chan
->channel
];
381 static const struct iio_enum quad8_count_mode_enum
= {
382 .items
= quad8_count_modes
,
383 .num_items
= ARRAY_SIZE(quad8_count_modes
),
384 .set
= quad8_set_count_mode
,
385 .get
= quad8_get_count_mode
388 static const char *const quad8_synchronous_modes
[] = {
393 static int quad8_set_synchronous_mode(struct iio_dev
*indio_dev
,
394 const struct iio_chan_spec
*chan
, unsigned int synchronous_mode
)
396 struct quad8_iio
*const priv
= iio_priv(indio_dev
);
397 const unsigned int idr_cfg
= synchronous_mode
|
398 priv
->index_polarity
[chan
->channel
] << 1;
399 const int base_offset
= priv
->base
+ 2 * chan
->channel
+ 1;
401 /* Index function must be non-synchronous in non-quadrature mode */
402 if (synchronous_mode
&& !priv
->quadrature_mode
[chan
->channel
])
405 priv
->synchronous_mode
[chan
->channel
] = synchronous_mode
;
407 /* Load Index Control configuration to Index Control Register */
408 outb(QUAD8_CTR_IDR
| idr_cfg
, base_offset
);
413 static int quad8_get_synchronous_mode(struct iio_dev
*indio_dev
,
414 const struct iio_chan_spec
*chan
)
416 const struct quad8_iio
*const priv
= iio_priv(indio_dev
);
418 return priv
->synchronous_mode
[chan
->channel
];
421 static const struct iio_enum quad8_synchronous_mode_enum
= {
422 .items
= quad8_synchronous_modes
,
423 .num_items
= ARRAY_SIZE(quad8_synchronous_modes
),
424 .set
= quad8_set_synchronous_mode
,
425 .get
= quad8_get_synchronous_mode
428 static const char *const quad8_quadrature_modes
[] = {
433 static int quad8_set_quadrature_mode(struct iio_dev
*indio_dev
,
434 const struct iio_chan_spec
*chan
, unsigned int quadrature_mode
)
436 struct quad8_iio
*const priv
= iio_priv(indio_dev
);
437 unsigned int mode_cfg
= priv
->count_mode
[chan
->channel
] << 1;
438 const int base_offset
= priv
->base
+ 2 * chan
->channel
+ 1;
441 mode_cfg
|= (priv
->quadrature_scale
[chan
->channel
] + 1) << 3;
443 /* Quadrature scaling only available in quadrature mode */
444 priv
->quadrature_scale
[chan
->channel
] = 0;
446 /* Synchronous function not supported in non-quadrature mode */
447 if (priv
->synchronous_mode
[chan
->channel
])
448 quad8_set_synchronous_mode(indio_dev
, chan
, 0);
451 priv
->quadrature_mode
[chan
->channel
] = quadrature_mode
;
453 /* Load mode configuration to Counter Mode Register */
454 outb(QUAD8_CTR_CMR
| mode_cfg
, base_offset
);
459 static int quad8_get_quadrature_mode(struct iio_dev
*indio_dev
,
460 const struct iio_chan_spec
*chan
)
462 const struct quad8_iio
*const priv
= iio_priv(indio_dev
);
464 return priv
->quadrature_mode
[chan
->channel
];
467 static const struct iio_enum quad8_quadrature_mode_enum
= {
468 .items
= quad8_quadrature_modes
,
469 .num_items
= ARRAY_SIZE(quad8_quadrature_modes
),
470 .set
= quad8_set_quadrature_mode
,
471 .get
= quad8_get_quadrature_mode
474 static const char *const quad8_index_polarity_modes
[] = {
479 static int quad8_set_index_polarity(struct iio_dev
*indio_dev
,
480 const struct iio_chan_spec
*chan
, unsigned int index_polarity
)
482 struct quad8_iio
*const priv
= iio_priv(indio_dev
);
483 const unsigned int idr_cfg
= priv
->synchronous_mode
[chan
->channel
] |
485 const int base_offset
= priv
->base
+ 2 * chan
->channel
+ 1;
487 priv
->index_polarity
[chan
->channel
] = index_polarity
;
489 /* Load Index Control configuration to Index Control Register */
490 outb(QUAD8_CTR_IDR
| idr_cfg
, base_offset
);
495 static int quad8_get_index_polarity(struct iio_dev
*indio_dev
,
496 const struct iio_chan_spec
*chan
)
498 const struct quad8_iio
*const priv
= iio_priv(indio_dev
);
500 return priv
->index_polarity
[chan
->channel
];
503 static const struct iio_enum quad8_index_polarity_enum
= {
504 .items
= quad8_index_polarity_modes
,
505 .num_items
= ARRAY_SIZE(quad8_index_polarity_modes
),
506 .set
= quad8_set_index_polarity
,
507 .get
= quad8_get_index_polarity
510 static const struct iio_chan_spec_ext_info quad8_count_ext_info
[] = {
513 .shared
= IIO_SEPARATE
,
514 .read
= quad8_read_preset
,
515 .write
= quad8_write_preset
518 .name
= "set_to_preset_on_index",
519 .shared
= IIO_SEPARATE
,
520 .read
= quad8_read_set_to_preset_on_index
,
521 .write
= quad8_write_set_to_preset_on_index
523 IIO_ENUM("noise_error", IIO_SEPARATE
, &quad8_noise_error_enum
),
524 IIO_ENUM_AVAILABLE("noise_error", &quad8_noise_error_enum
),
525 IIO_ENUM("count_direction", IIO_SEPARATE
, &quad8_count_direction_enum
),
526 IIO_ENUM_AVAILABLE("count_direction", &quad8_count_direction_enum
),
527 IIO_ENUM("count_mode", IIO_SEPARATE
, &quad8_count_mode_enum
),
528 IIO_ENUM_AVAILABLE("count_mode", &quad8_count_mode_enum
),
529 IIO_ENUM("quadrature_mode", IIO_SEPARATE
, &quad8_quadrature_mode_enum
),
530 IIO_ENUM_AVAILABLE("quadrature_mode", &quad8_quadrature_mode_enum
),
534 static const struct iio_chan_spec_ext_info quad8_index_ext_info
[] = {
535 IIO_ENUM("synchronous_mode", IIO_SEPARATE
,
536 &quad8_synchronous_mode_enum
),
537 IIO_ENUM_AVAILABLE("synchronous_mode", &quad8_synchronous_mode_enum
),
538 IIO_ENUM("index_polarity", IIO_SEPARATE
, &quad8_index_polarity_enum
),
539 IIO_ENUM_AVAILABLE("index_polarity", &quad8_index_polarity_enum
),
543 #define QUAD8_COUNT_CHAN(_chan) { \
545 .channel = (_chan), \
546 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
547 BIT(IIO_CHAN_INFO_ENABLE) | BIT(IIO_CHAN_INFO_SCALE), \
548 .ext_info = quad8_count_ext_info, \
552 #define QUAD8_INDEX_CHAN(_chan) { \
554 .channel = (_chan), \
555 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
556 .ext_info = quad8_index_ext_info, \
560 static const struct iio_chan_spec quad8_channels
[] = {
561 QUAD8_COUNT_CHAN(0), QUAD8_INDEX_CHAN(0),
562 QUAD8_COUNT_CHAN(1), QUAD8_INDEX_CHAN(1),
563 QUAD8_COUNT_CHAN(2), QUAD8_INDEX_CHAN(2),
564 QUAD8_COUNT_CHAN(3), QUAD8_INDEX_CHAN(3),
565 QUAD8_COUNT_CHAN(4), QUAD8_INDEX_CHAN(4),
566 QUAD8_COUNT_CHAN(5), QUAD8_INDEX_CHAN(5),
567 QUAD8_COUNT_CHAN(6), QUAD8_INDEX_CHAN(6),
568 QUAD8_COUNT_CHAN(7), QUAD8_INDEX_CHAN(7)
571 static int quad8_signal_read(struct counter_device
*counter
,
572 struct counter_signal
*signal
, enum counter_signal_value
*val
)
574 const struct quad8_iio
*const priv
= counter
->priv
;
577 /* Only Index signal levels can be read */
581 state
= inb(priv
->base
+ QUAD8_REG_INDEX_INPUT_LEVELS
)
582 & BIT(signal
->id
- 16);
584 *val
= (state
) ? COUNTER_SIGNAL_HIGH
: COUNTER_SIGNAL_LOW
;
589 static int quad8_count_read(struct counter_device
*counter
,
590 struct counter_count
*count
, unsigned long *val
)
592 const struct quad8_iio
*const priv
= counter
->priv
;
593 const int base_offset
= priv
->base
+ 2 * count
->id
;
599 flags
= inb(base_offset
+ 1);
600 borrow
= flags
& QUAD8_FLAG_BT
;
601 carry
= !!(flags
& QUAD8_FLAG_CT
);
603 /* Borrow XOR Carry effectively doubles count range */
604 *val
= (unsigned long)(borrow
^ carry
) << 24;
606 /* Reset Byte Pointer; transfer Counter to Output Latch */
607 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
| QUAD8_RLD_CNTR_OUT
,
610 for (i
= 0; i
< 3; i
++)
611 *val
|= (unsigned long)inb(base_offset
) << (8 * i
);
616 static int quad8_count_write(struct counter_device
*counter
,
617 struct counter_count
*count
, unsigned long val
)
619 const struct quad8_iio
*const priv
= counter
->priv
;
620 const int base_offset
= priv
->base
+ 2 * count
->id
;
623 /* Only 24-bit values are supported */
627 /* Reset Byte Pointer */
628 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
, base_offset
+ 1);
630 /* Counter can only be set via Preset Register */
631 for (i
= 0; i
< 3; i
++)
632 outb(val
>> (8 * i
), base_offset
);
634 /* Transfer Preset Register to Counter */
635 outb(QUAD8_CTR_RLD
| QUAD8_RLD_PRESET_CNTR
, base_offset
+ 1);
637 /* Reset Byte Pointer */
638 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
, base_offset
+ 1);
640 /* Set Preset Register back to original value */
641 val
= priv
->preset
[count
->id
];
642 for (i
= 0; i
< 3; i
++)
643 outb(val
>> (8 * i
), base_offset
);
645 /* Reset Borrow, Carry, Compare, and Sign flags */
646 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_FLAGS
, base_offset
+ 1);
647 /* Reset Error flag */
648 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_E
, base_offset
+ 1);
653 enum quad8_count_function
{
654 QUAD8_COUNT_FUNCTION_PULSE_DIRECTION
= 0,
655 QUAD8_COUNT_FUNCTION_QUADRATURE_X1
,
656 QUAD8_COUNT_FUNCTION_QUADRATURE_X2
,
657 QUAD8_COUNT_FUNCTION_QUADRATURE_X4
660 static enum counter_count_function quad8_count_functions_list
[] = {
661 [QUAD8_COUNT_FUNCTION_PULSE_DIRECTION
] = COUNTER_COUNT_FUNCTION_PULSE_DIRECTION
,
662 [QUAD8_COUNT_FUNCTION_QUADRATURE_X1
] = COUNTER_COUNT_FUNCTION_QUADRATURE_X1_A
,
663 [QUAD8_COUNT_FUNCTION_QUADRATURE_X2
] = COUNTER_COUNT_FUNCTION_QUADRATURE_X2_A
,
664 [QUAD8_COUNT_FUNCTION_QUADRATURE_X4
] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4
667 static int quad8_function_get(struct counter_device
*counter
,
668 struct counter_count
*count
, size_t *function
)
670 const struct quad8_iio
*const priv
= counter
->priv
;
671 const int id
= count
->id
;
672 const unsigned int quadrature_mode
= priv
->quadrature_mode
[id
];
673 const unsigned int scale
= priv
->quadrature_scale
[id
];
678 *function
= QUAD8_COUNT_FUNCTION_QUADRATURE_X1
;
681 *function
= QUAD8_COUNT_FUNCTION_QUADRATURE_X2
;
684 *function
= QUAD8_COUNT_FUNCTION_QUADRATURE_X4
;
688 *function
= QUAD8_COUNT_FUNCTION_PULSE_DIRECTION
;
693 static int quad8_function_set(struct counter_device
*counter
,
694 struct counter_count
*count
, size_t function
)
696 struct quad8_iio
*const priv
= counter
->priv
;
697 const int id
= count
->id
;
698 unsigned int *const quadrature_mode
= priv
->quadrature_mode
+ id
;
699 unsigned int *const scale
= priv
->quadrature_scale
+ id
;
700 unsigned int mode_cfg
= priv
->count_mode
[id
] << 1;
701 unsigned int *const synchronous_mode
= priv
->synchronous_mode
+ id
;
702 const unsigned int idr_cfg
= priv
->index_polarity
[id
] << 1;
703 const int base_offset
= priv
->base
+ 2 * id
+ 1;
705 if (function
== QUAD8_COUNT_FUNCTION_PULSE_DIRECTION
) {
706 *quadrature_mode
= 0;
708 /* Quadrature scaling only available in quadrature mode */
711 /* Synchronous function not supported in non-quadrature mode */
712 if (*synchronous_mode
) {
713 *synchronous_mode
= 0;
714 /* Disable synchronous function mode */
715 outb(QUAD8_CTR_IDR
| idr_cfg
, base_offset
);
718 *quadrature_mode
= 1;
721 case QUAD8_COUNT_FUNCTION_QUADRATURE_X1
:
723 mode_cfg
|= QUAD8_CMR_QUADRATURE_X1
;
725 case QUAD8_COUNT_FUNCTION_QUADRATURE_X2
:
727 mode_cfg
|= QUAD8_CMR_QUADRATURE_X2
;
729 case QUAD8_COUNT_FUNCTION_QUADRATURE_X4
:
731 mode_cfg
|= QUAD8_CMR_QUADRATURE_X4
;
736 /* Load mode configuration to Counter Mode Register */
737 outb(QUAD8_CTR_CMR
| mode_cfg
, base_offset
);
742 static void quad8_direction_get(struct counter_device
*counter
,
743 struct counter_count
*count
, enum counter_count_direction
*direction
)
745 const struct quad8_iio
*const priv
= counter
->priv
;
746 unsigned int ud_flag
;
747 const unsigned int flag_addr
= priv
->base
+ 2 * count
->id
+ 1;
749 /* U/D flag: nonzero = up, zero = down */
750 ud_flag
= inb(flag_addr
) & QUAD8_FLAG_UD
;
752 *direction
= (ud_flag
) ? COUNTER_COUNT_DIRECTION_FORWARD
:
753 COUNTER_COUNT_DIRECTION_BACKWARD
;
756 enum quad8_synapse_action
{
757 QUAD8_SYNAPSE_ACTION_NONE
= 0,
758 QUAD8_SYNAPSE_ACTION_RISING_EDGE
,
759 QUAD8_SYNAPSE_ACTION_FALLING_EDGE
,
760 QUAD8_SYNAPSE_ACTION_BOTH_EDGES
763 static enum counter_synapse_action quad8_index_actions_list
[] = {
764 [QUAD8_SYNAPSE_ACTION_NONE
] = COUNTER_SYNAPSE_ACTION_NONE
,
765 [QUAD8_SYNAPSE_ACTION_RISING_EDGE
] = COUNTER_SYNAPSE_ACTION_RISING_EDGE
768 static enum counter_synapse_action quad8_synapse_actions_list
[] = {
769 [QUAD8_SYNAPSE_ACTION_NONE
] = COUNTER_SYNAPSE_ACTION_NONE
,
770 [QUAD8_SYNAPSE_ACTION_RISING_EDGE
] = COUNTER_SYNAPSE_ACTION_RISING_EDGE
,
771 [QUAD8_SYNAPSE_ACTION_FALLING_EDGE
] = COUNTER_SYNAPSE_ACTION_FALLING_EDGE
,
772 [QUAD8_SYNAPSE_ACTION_BOTH_EDGES
] = COUNTER_SYNAPSE_ACTION_BOTH_EDGES
775 static int quad8_action_get(struct counter_device
*counter
,
776 struct counter_count
*count
, struct counter_synapse
*synapse
,
779 struct quad8_iio
*const priv
= counter
->priv
;
782 const size_t signal_a_id
= count
->synapses
[0].signal
->id
;
783 enum counter_count_direction direction
;
785 /* Handle Index signals */
786 if (synapse
->signal
->id
>= 16) {
787 if (priv
->preset_enable
[count
->id
])
788 *action
= QUAD8_SYNAPSE_ACTION_RISING_EDGE
;
790 *action
= QUAD8_SYNAPSE_ACTION_NONE
;
795 err
= quad8_function_get(counter
, count
, &function
);
799 /* Default action mode */
800 *action
= QUAD8_SYNAPSE_ACTION_NONE
;
802 /* Determine action mode based on current count function mode */
804 case QUAD8_COUNT_FUNCTION_PULSE_DIRECTION
:
805 if (synapse
->signal
->id
== signal_a_id
)
806 *action
= QUAD8_SYNAPSE_ACTION_RISING_EDGE
;
808 case QUAD8_COUNT_FUNCTION_QUADRATURE_X1
:
809 if (synapse
->signal
->id
== signal_a_id
) {
810 quad8_direction_get(counter
, count
, &direction
);
812 if (direction
== COUNTER_COUNT_DIRECTION_FORWARD
)
813 *action
= QUAD8_SYNAPSE_ACTION_RISING_EDGE
;
815 *action
= QUAD8_SYNAPSE_ACTION_FALLING_EDGE
;
818 case QUAD8_COUNT_FUNCTION_QUADRATURE_X2
:
819 if (synapse
->signal
->id
== signal_a_id
)
820 *action
= QUAD8_SYNAPSE_ACTION_BOTH_EDGES
;
822 case QUAD8_COUNT_FUNCTION_QUADRATURE_X4
:
823 *action
= QUAD8_SYNAPSE_ACTION_BOTH_EDGES
;
830 static const struct counter_ops quad8_ops
= {
831 .signal_read
= quad8_signal_read
,
832 .count_read
= quad8_count_read
,
833 .count_write
= quad8_count_write
,
834 .function_get
= quad8_function_get
,
835 .function_set
= quad8_function_set
,
836 .action_get
= quad8_action_get
839 static int quad8_index_polarity_get(struct counter_device
*counter
,
840 struct counter_signal
*signal
, size_t *index_polarity
)
842 const struct quad8_iio
*const priv
= counter
->priv
;
843 const size_t channel_id
= signal
->id
- 16;
845 *index_polarity
= priv
->index_polarity
[channel_id
];
850 static int quad8_index_polarity_set(struct counter_device
*counter
,
851 struct counter_signal
*signal
, size_t index_polarity
)
853 struct quad8_iio
*const priv
= counter
->priv
;
854 const size_t channel_id
= signal
->id
- 16;
855 const unsigned int idr_cfg
= priv
->synchronous_mode
[channel_id
] |
857 const int base_offset
= priv
->base
+ 2 * channel_id
+ 1;
859 priv
->index_polarity
[channel_id
] = index_polarity
;
861 /* Load Index Control configuration to Index Control Register */
862 outb(QUAD8_CTR_IDR
| idr_cfg
, base_offset
);
867 static struct counter_signal_enum_ext quad8_index_pol_enum
= {
868 .items
= quad8_index_polarity_modes
,
869 .num_items
= ARRAY_SIZE(quad8_index_polarity_modes
),
870 .get
= quad8_index_polarity_get
,
871 .set
= quad8_index_polarity_set
874 static int quad8_synchronous_mode_get(struct counter_device
*counter
,
875 struct counter_signal
*signal
, size_t *synchronous_mode
)
877 const struct quad8_iio
*const priv
= counter
->priv
;
878 const size_t channel_id
= signal
->id
- 16;
880 *synchronous_mode
= priv
->synchronous_mode
[channel_id
];
885 static int quad8_synchronous_mode_set(struct counter_device
*counter
,
886 struct counter_signal
*signal
, size_t synchronous_mode
)
888 struct quad8_iio
*const priv
= counter
->priv
;
889 const size_t channel_id
= signal
->id
- 16;
890 const unsigned int idr_cfg
= synchronous_mode
|
891 priv
->index_polarity
[channel_id
] << 1;
892 const int base_offset
= priv
->base
+ 2 * channel_id
+ 1;
894 /* Index function must be non-synchronous in non-quadrature mode */
895 if (synchronous_mode
&& !priv
->quadrature_mode
[channel_id
])
898 priv
->synchronous_mode
[channel_id
] = synchronous_mode
;
900 /* Load Index Control configuration to Index Control Register */
901 outb(QUAD8_CTR_IDR
| idr_cfg
, base_offset
);
906 static struct counter_signal_enum_ext quad8_syn_mode_enum
= {
907 .items
= quad8_synchronous_modes
,
908 .num_items
= ARRAY_SIZE(quad8_synchronous_modes
),
909 .get
= quad8_synchronous_mode_get
,
910 .set
= quad8_synchronous_mode_set
913 static ssize_t
quad8_count_floor_read(struct counter_device
*counter
,
914 struct counter_count
*count
, void *private, char *buf
)
916 /* Only a floor of 0 is supported */
917 return sprintf(buf
, "0\n");
920 static int quad8_count_mode_get(struct counter_device
*counter
,
921 struct counter_count
*count
, size_t *cnt_mode
)
923 const struct quad8_iio
*const priv
= counter
->priv
;
925 /* Map 104-QUAD-8 count mode to Generic Counter count mode */
926 switch (priv
->count_mode
[count
->id
]) {
928 *cnt_mode
= COUNTER_COUNT_MODE_NORMAL
;
931 *cnt_mode
= COUNTER_COUNT_MODE_RANGE_LIMIT
;
934 *cnt_mode
= COUNTER_COUNT_MODE_NON_RECYCLE
;
937 *cnt_mode
= COUNTER_COUNT_MODE_MODULO_N
;
944 static int quad8_count_mode_set(struct counter_device
*counter
,
945 struct counter_count
*count
, size_t cnt_mode
)
947 struct quad8_iio
*const priv
= counter
->priv
;
948 unsigned int mode_cfg
;
949 const int base_offset
= priv
->base
+ 2 * count
->id
+ 1;
951 /* Map Generic Counter count mode to 104-QUAD-8 count mode */
953 case COUNTER_COUNT_MODE_NORMAL
:
956 case COUNTER_COUNT_MODE_RANGE_LIMIT
:
959 case COUNTER_COUNT_MODE_NON_RECYCLE
:
962 case COUNTER_COUNT_MODE_MODULO_N
:
967 priv
->count_mode
[count
->id
] = cnt_mode
;
969 /* Set count mode configuration value */
970 mode_cfg
= cnt_mode
<< 1;
972 /* Add quadrature mode configuration */
973 if (priv
->quadrature_mode
[count
->id
])
974 mode_cfg
|= (priv
->quadrature_scale
[count
->id
] + 1) << 3;
976 /* Load mode configuration to Counter Mode Register */
977 outb(QUAD8_CTR_CMR
| mode_cfg
, base_offset
);
982 static struct counter_count_enum_ext quad8_cnt_mode_enum
= {
983 .items
= counter_count_mode_str
,
984 .num_items
= ARRAY_SIZE(counter_count_mode_str
),
985 .get
= quad8_count_mode_get
,
986 .set
= quad8_count_mode_set
989 static ssize_t
quad8_count_direction_read(struct counter_device
*counter
,
990 struct counter_count
*count
, void *priv
, char *buf
)
992 enum counter_count_direction dir
;
994 quad8_direction_get(counter
, count
, &dir
);
996 return sprintf(buf
, "%s\n", counter_count_direction_str
[dir
]);
999 static ssize_t
quad8_count_enable_read(struct counter_device
*counter
,
1000 struct counter_count
*count
, void *private, char *buf
)
1002 const struct quad8_iio
*const priv
= counter
->priv
;
1004 return sprintf(buf
, "%u\n", priv
->ab_enable
[count
->id
]);
1007 static ssize_t
quad8_count_enable_write(struct counter_device
*counter
,
1008 struct counter_count
*count
, void *private, const char *buf
, size_t len
)
1010 struct quad8_iio
*const priv
= counter
->priv
;
1011 const int base_offset
= priv
->base
+ 2 * count
->id
;
1014 unsigned int ior_cfg
;
1016 err
= kstrtobool(buf
, &ab_enable
);
1020 priv
->ab_enable
[count
->id
] = ab_enable
;
1022 ior_cfg
= ab_enable
| priv
->preset_enable
[count
->id
] << 1;
1024 /* Load I/O control configuration */
1025 outb(QUAD8_CTR_IOR
| ior_cfg
, base_offset
+ 1);
1030 static int quad8_error_noise_get(struct counter_device
*counter
,
1031 struct counter_count
*count
, size_t *noise_error
)
1033 const struct quad8_iio
*const priv
= counter
->priv
;
1034 const int base_offset
= priv
->base
+ 2 * count
->id
+ 1;
1036 *noise_error
= !!(inb(base_offset
) & QUAD8_FLAG_E
);
1041 static struct counter_count_enum_ext quad8_error_noise_enum
= {
1042 .items
= quad8_noise_error_states
,
1043 .num_items
= ARRAY_SIZE(quad8_noise_error_states
),
1044 .get
= quad8_error_noise_get
1047 static ssize_t
quad8_count_preset_read(struct counter_device
*counter
,
1048 struct counter_count
*count
, void *private, char *buf
)
1050 const struct quad8_iio
*const priv
= counter
->priv
;
1052 return sprintf(buf
, "%u\n", priv
->preset
[count
->id
]);
1055 static ssize_t
quad8_count_preset_write(struct counter_device
*counter
,
1056 struct counter_count
*count
, void *private, const char *buf
, size_t len
)
1058 struct quad8_iio
*const priv
= counter
->priv
;
1059 const int base_offset
= priv
->base
+ 2 * count
->id
;
1060 unsigned int preset
;
1064 ret
= kstrtouint(buf
, 0, &preset
);
1068 /* Only 24-bit values are supported */
1069 if (preset
> 0xFFFFFF)
1072 priv
->preset
[count
->id
] = preset
;
1074 /* Reset Byte Pointer */
1075 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
, base_offset
+ 1);
1077 /* Set Preset Register */
1078 for (i
= 0; i
< 3; i
++)
1079 outb(preset
>> (8 * i
), base_offset
);
1084 static ssize_t
quad8_count_ceiling_read(struct counter_device
*counter
,
1085 struct counter_count
*count
, void *private, char *buf
)
1087 const struct quad8_iio
*const priv
= counter
->priv
;
1089 /* Range Limit and Modulo-N count modes use preset value as ceiling */
1090 switch (priv
->count_mode
[count
->id
]) {
1093 return quad8_count_preset_read(counter
, count
, private, buf
);
1096 /* By default 0x1FFFFFF (25 bits unsigned) is maximum count */
1097 return sprintf(buf
, "33554431\n");
1100 static ssize_t
quad8_count_ceiling_write(struct counter_device
*counter
,
1101 struct counter_count
*count
, void *private, const char *buf
, size_t len
)
1103 struct quad8_iio
*const priv
= counter
->priv
;
1105 /* Range Limit and Modulo-N count modes use preset value as ceiling */
1106 switch (priv
->count_mode
[count
->id
]) {
1109 return quad8_count_preset_write(counter
, count
, private, buf
,
1116 static ssize_t
quad8_count_preset_enable_read(struct counter_device
*counter
,
1117 struct counter_count
*count
, void *private, char *buf
)
1119 const struct quad8_iio
*const priv
= counter
->priv
;
1121 return sprintf(buf
, "%u\n", !priv
->preset_enable
[count
->id
]);
1124 static ssize_t
quad8_count_preset_enable_write(struct counter_device
*counter
,
1125 struct counter_count
*count
, void *private, const char *buf
, size_t len
)
1127 struct quad8_iio
*const priv
= counter
->priv
;
1128 const int base_offset
= priv
->base
+ 2 * count
->id
+ 1;
1131 unsigned int ior_cfg
;
1133 ret
= kstrtobool(buf
, &preset_enable
);
1137 /* Preset enable is active low in Input/Output Control register */
1138 preset_enable
= !preset_enable
;
1140 priv
->preset_enable
[count
->id
] = preset_enable
;
1142 ior_cfg
= priv
->ab_enable
[count
->id
] | (unsigned int)preset_enable
<< 1;
1144 /* Load I/O control configuration to Input / Output Control Register */
1145 outb(QUAD8_CTR_IOR
| ior_cfg
, base_offset
);
1150 static ssize_t
quad8_signal_cable_fault_read(struct counter_device
*counter
,
1151 struct counter_signal
*signal
,
1152 void *private, char *buf
)
1154 const struct quad8_iio
*const priv
= counter
->priv
;
1155 const size_t channel_id
= signal
->id
/ 2;
1156 const bool disabled
= !(priv
->cable_fault_enable
& BIT(channel_id
));
1157 unsigned int status
;
1163 /* Logic 0 = cable fault */
1164 status
= inb(priv
->base
+ QUAD8_DIFF_ENCODER_CABLE_STATUS
);
1166 /* Mask respective channel and invert logic */
1167 fault
= !(status
& BIT(channel_id
));
1169 return sprintf(buf
, "%u\n", fault
);
1172 static ssize_t
quad8_signal_cable_fault_enable_read(
1173 struct counter_device
*counter
, struct counter_signal
*signal
,
1174 void *private, char *buf
)
1176 const struct quad8_iio
*const priv
= counter
->priv
;
1177 const size_t channel_id
= signal
->id
/ 2;
1178 const unsigned int enb
= !!(priv
->cable_fault_enable
& BIT(channel_id
));
1180 return sprintf(buf
, "%u\n", enb
);
1183 static ssize_t
quad8_signal_cable_fault_enable_write(
1184 struct counter_device
*counter
, struct counter_signal
*signal
,
1185 void *private, const char *buf
, size_t len
)
1187 struct quad8_iio
*const priv
= counter
->priv
;
1188 const size_t channel_id
= signal
->id
/ 2;
1191 unsigned int cable_fault_enable
;
1193 ret
= kstrtobool(buf
, &enable
);
1198 priv
->cable_fault_enable
|= BIT(channel_id
);
1200 priv
->cable_fault_enable
&= ~BIT(channel_id
);
1202 /* Enable is active low in Differential Encoder Cable Status register */
1203 cable_fault_enable
= ~priv
->cable_fault_enable
;
1205 outb(cable_fault_enable
, priv
->base
+ QUAD8_DIFF_ENCODER_CABLE_STATUS
);
1210 static ssize_t
quad8_signal_fck_prescaler_read(struct counter_device
*counter
,
1211 struct counter_signal
*signal
, void *private, char *buf
)
1213 const struct quad8_iio
*const priv
= counter
->priv
;
1214 const size_t channel_id
= signal
->id
/ 2;
1216 return sprintf(buf
, "%u\n", priv
->fck_prescaler
[channel_id
]);
1219 static ssize_t
quad8_signal_fck_prescaler_write(struct counter_device
*counter
,
1220 struct counter_signal
*signal
, void *private, const char *buf
,
1223 struct quad8_iio
*const priv
= counter
->priv
;
1224 const size_t channel_id
= signal
->id
/ 2;
1225 const int base_offset
= priv
->base
+ 2 * channel_id
;
1229 ret
= kstrtou8(buf
, 0, &prescaler
);
1233 priv
->fck_prescaler
[channel_id
] = prescaler
;
1235 /* Reset Byte Pointer */
1236 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
, base_offset
+ 1);
1238 /* Set filter clock factor */
1239 outb(prescaler
, base_offset
);
1240 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
| QUAD8_RLD_PRESET_PSC
,
1246 static const struct counter_signal_ext quad8_signal_ext
[] = {
1248 .name
= "cable_fault",
1249 .read
= quad8_signal_cable_fault_read
1252 .name
= "cable_fault_enable",
1253 .read
= quad8_signal_cable_fault_enable_read
,
1254 .write
= quad8_signal_cable_fault_enable_write
1257 .name
= "filter_clock_prescaler",
1258 .read
= quad8_signal_fck_prescaler_read
,
1259 .write
= quad8_signal_fck_prescaler_write
1263 static const struct counter_signal_ext quad8_index_ext
[] = {
1264 COUNTER_SIGNAL_ENUM("index_polarity", &quad8_index_pol_enum
),
1265 COUNTER_SIGNAL_ENUM_AVAILABLE("index_polarity", &quad8_index_pol_enum
),
1266 COUNTER_SIGNAL_ENUM("synchronous_mode", &quad8_syn_mode_enum
),
1267 COUNTER_SIGNAL_ENUM_AVAILABLE("synchronous_mode", &quad8_syn_mode_enum
)
1270 #define QUAD8_QUAD_SIGNAL(_id, _name) { \
1273 .ext = quad8_signal_ext, \
1274 .num_ext = ARRAY_SIZE(quad8_signal_ext) \
1277 #define QUAD8_INDEX_SIGNAL(_id, _name) { \
1280 .ext = quad8_index_ext, \
1281 .num_ext = ARRAY_SIZE(quad8_index_ext) \
1284 static struct counter_signal quad8_signals
[] = {
1285 QUAD8_QUAD_SIGNAL(0, "Channel 1 Quadrature A"),
1286 QUAD8_QUAD_SIGNAL(1, "Channel 1 Quadrature B"),
1287 QUAD8_QUAD_SIGNAL(2, "Channel 2 Quadrature A"),
1288 QUAD8_QUAD_SIGNAL(3, "Channel 2 Quadrature B"),
1289 QUAD8_QUAD_SIGNAL(4, "Channel 3 Quadrature A"),
1290 QUAD8_QUAD_SIGNAL(5, "Channel 3 Quadrature B"),
1291 QUAD8_QUAD_SIGNAL(6, "Channel 4 Quadrature A"),
1292 QUAD8_QUAD_SIGNAL(7, "Channel 4 Quadrature B"),
1293 QUAD8_QUAD_SIGNAL(8, "Channel 5 Quadrature A"),
1294 QUAD8_QUAD_SIGNAL(9, "Channel 5 Quadrature B"),
1295 QUAD8_QUAD_SIGNAL(10, "Channel 6 Quadrature A"),
1296 QUAD8_QUAD_SIGNAL(11, "Channel 6 Quadrature B"),
1297 QUAD8_QUAD_SIGNAL(12, "Channel 7 Quadrature A"),
1298 QUAD8_QUAD_SIGNAL(13, "Channel 7 Quadrature B"),
1299 QUAD8_QUAD_SIGNAL(14, "Channel 8 Quadrature A"),
1300 QUAD8_QUAD_SIGNAL(15, "Channel 8 Quadrature B"),
1301 QUAD8_INDEX_SIGNAL(16, "Channel 1 Index"),
1302 QUAD8_INDEX_SIGNAL(17, "Channel 2 Index"),
1303 QUAD8_INDEX_SIGNAL(18, "Channel 3 Index"),
1304 QUAD8_INDEX_SIGNAL(19, "Channel 4 Index"),
1305 QUAD8_INDEX_SIGNAL(20, "Channel 5 Index"),
1306 QUAD8_INDEX_SIGNAL(21, "Channel 6 Index"),
1307 QUAD8_INDEX_SIGNAL(22, "Channel 7 Index"),
1308 QUAD8_INDEX_SIGNAL(23, "Channel 8 Index")
1311 #define QUAD8_COUNT_SYNAPSES(_id) { \
1313 .actions_list = quad8_synapse_actions_list, \
1314 .num_actions = ARRAY_SIZE(quad8_synapse_actions_list), \
1315 .signal = quad8_signals + 2 * (_id) \
1318 .actions_list = quad8_synapse_actions_list, \
1319 .num_actions = ARRAY_SIZE(quad8_synapse_actions_list), \
1320 .signal = quad8_signals + 2 * (_id) + 1 \
1323 .actions_list = quad8_index_actions_list, \
1324 .num_actions = ARRAY_SIZE(quad8_index_actions_list), \
1325 .signal = quad8_signals + 2 * (_id) + 16 \
1329 static struct counter_synapse quad8_count_synapses
[][3] = {
1330 QUAD8_COUNT_SYNAPSES(0), QUAD8_COUNT_SYNAPSES(1),
1331 QUAD8_COUNT_SYNAPSES(2), QUAD8_COUNT_SYNAPSES(3),
1332 QUAD8_COUNT_SYNAPSES(4), QUAD8_COUNT_SYNAPSES(5),
1333 QUAD8_COUNT_SYNAPSES(6), QUAD8_COUNT_SYNAPSES(7)
1336 static const struct counter_count_ext quad8_count_ext
[] = {
1339 .read
= quad8_count_ceiling_read
,
1340 .write
= quad8_count_ceiling_write
1344 .read
= quad8_count_floor_read
1346 COUNTER_COUNT_ENUM("count_mode", &quad8_cnt_mode_enum
),
1347 COUNTER_COUNT_ENUM_AVAILABLE("count_mode", &quad8_cnt_mode_enum
),
1349 .name
= "direction",
1350 .read
= quad8_count_direction_read
1354 .read
= quad8_count_enable_read
,
1355 .write
= quad8_count_enable_write
1357 COUNTER_COUNT_ENUM("error_noise", &quad8_error_noise_enum
),
1358 COUNTER_COUNT_ENUM_AVAILABLE("error_noise", &quad8_error_noise_enum
),
1361 .read
= quad8_count_preset_read
,
1362 .write
= quad8_count_preset_write
1365 .name
= "preset_enable",
1366 .read
= quad8_count_preset_enable_read
,
1367 .write
= quad8_count_preset_enable_write
1371 #define QUAD8_COUNT(_id, _cntname) { \
1373 .name = (_cntname), \
1374 .functions_list = quad8_count_functions_list, \
1375 .num_functions = ARRAY_SIZE(quad8_count_functions_list), \
1376 .synapses = quad8_count_synapses[(_id)], \
1377 .num_synapses = 2, \
1378 .ext = quad8_count_ext, \
1379 .num_ext = ARRAY_SIZE(quad8_count_ext) \
1382 static struct counter_count quad8_counts
[] = {
1383 QUAD8_COUNT(0, "Channel 1 Count"),
1384 QUAD8_COUNT(1, "Channel 2 Count"),
1385 QUAD8_COUNT(2, "Channel 3 Count"),
1386 QUAD8_COUNT(3, "Channel 4 Count"),
1387 QUAD8_COUNT(4, "Channel 5 Count"),
1388 QUAD8_COUNT(5, "Channel 6 Count"),
1389 QUAD8_COUNT(6, "Channel 7 Count"),
1390 QUAD8_COUNT(7, "Channel 8 Count")
1393 static int quad8_probe(struct device
*dev
, unsigned int id
)
1395 struct iio_dev
*indio_dev
;
1396 struct quad8_iio
*quad8iio
;
1398 unsigned int base_offset
;
1401 if (!devm_request_region(dev
, base
[id
], QUAD8_EXTENT
, dev_name(dev
))) {
1402 dev_err(dev
, "Unable to lock port addresses (0x%X-0x%X)\n",
1403 base
[id
], base
[id
] + QUAD8_EXTENT
);
1407 /* Allocate IIO device; this also allocates driver data structure */
1408 indio_dev
= devm_iio_device_alloc(dev
, sizeof(*quad8iio
));
1412 /* Initialize IIO device */
1413 indio_dev
->info
= &quad8_info
;
1414 indio_dev
->modes
= INDIO_DIRECT_MODE
;
1415 indio_dev
->num_channels
= ARRAY_SIZE(quad8_channels
);
1416 indio_dev
->channels
= quad8_channels
;
1417 indio_dev
->name
= dev_name(dev
);
1418 indio_dev
->dev
.parent
= dev
;
1420 /* Initialize Counter device and driver data */
1421 quad8iio
= iio_priv(indio_dev
);
1422 quad8iio
->counter
.name
= dev_name(dev
);
1423 quad8iio
->counter
.parent
= dev
;
1424 quad8iio
->counter
.ops
= &quad8_ops
;
1425 quad8iio
->counter
.counts
= quad8_counts
;
1426 quad8iio
->counter
.num_counts
= ARRAY_SIZE(quad8_counts
);
1427 quad8iio
->counter
.signals
= quad8_signals
;
1428 quad8iio
->counter
.num_signals
= ARRAY_SIZE(quad8_signals
);
1429 quad8iio
->counter
.priv
= quad8iio
;
1430 quad8iio
->base
= base
[id
];
1432 /* Reset all counters and disable interrupt function */
1433 outb(QUAD8_CHAN_OP_RESET_COUNTERS
, base
[id
] + QUAD8_REG_CHAN_OP
);
1434 /* Set initial configuration for all counters */
1435 for (i
= 0; i
< QUAD8_NUM_COUNTERS
; i
++) {
1436 base_offset
= base
[id
] + 2 * i
;
1437 /* Reset Byte Pointer */
1438 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
, base_offset
+ 1);
1439 /* Reset filter clock factor */
1440 outb(0, base_offset
);
1441 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
| QUAD8_RLD_PRESET_PSC
,
1443 /* Reset Byte Pointer */
1444 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
, base_offset
+ 1);
1445 /* Reset Preset Register */
1446 for (j
= 0; j
< 3; j
++)
1447 outb(0x00, base_offset
);
1448 /* Reset Borrow, Carry, Compare, and Sign flags */
1449 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_FLAGS
, base_offset
+ 1);
1450 /* Reset Error flag */
1451 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_E
, base_offset
+ 1);
1452 /* Binary encoding; Normal count; non-quadrature mode */
1453 outb(QUAD8_CTR_CMR
, base_offset
+ 1);
1454 /* Disable A and B inputs; preset on index; FLG1 as Carry */
1455 outb(QUAD8_CTR_IOR
, base_offset
+ 1);
1456 /* Disable index function; negative index polarity */
1457 outb(QUAD8_CTR_IDR
, base_offset
+ 1);
1459 /* Disable Differential Encoder Cable Status for all channels */
1460 outb(0xFF, base
[id
] + QUAD8_DIFF_ENCODER_CABLE_STATUS
);
1461 /* Enable all counters */
1462 outb(QUAD8_CHAN_OP_ENABLE_COUNTERS
, base
[id
] + QUAD8_REG_CHAN_OP
);
1464 /* Register IIO device */
1465 err
= devm_iio_device_register(dev
, indio_dev
);
1469 /* Register Counter device */
1470 return devm_counter_register(dev
, &quad8iio
->counter
);
1473 static struct isa_driver quad8_driver
= {
1474 .probe
= quad8_probe
,
1476 .name
= "104-quad-8"
1480 module_isa_driver(quad8_driver
, num_quad8
);
1482 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
1483 MODULE_DESCRIPTION("ACCES 104-QUAD-8 IIO driver");
1484 MODULE_LICENSE("GPL v2");