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 * @preset: array of preset values
35 * @count_mode: array of count mode configurations
36 * @quadrature_mode: array of quadrature mode configurations
37 * @quadrature_scale: array of quadrature mode scale configurations
38 * @ab_enable: array of A and B inputs enable configurations
39 * @preset_enable: array of set_to_preset_on_index attribute configurations
40 * @synchronous_mode: array of index function synchronous mode configurations
41 * @index_polarity: array of index function polarity configurations
42 * @base: base port address of the IIO device
45 struct counter_device counter
;
46 unsigned int preset
[QUAD8_NUM_COUNTERS
];
47 unsigned int count_mode
[QUAD8_NUM_COUNTERS
];
48 unsigned int quadrature_mode
[QUAD8_NUM_COUNTERS
];
49 unsigned int quadrature_scale
[QUAD8_NUM_COUNTERS
];
50 unsigned int ab_enable
[QUAD8_NUM_COUNTERS
];
51 unsigned int preset_enable
[QUAD8_NUM_COUNTERS
];
52 unsigned int synchronous_mode
[QUAD8_NUM_COUNTERS
];
53 unsigned int index_polarity
[QUAD8_NUM_COUNTERS
];
57 #define QUAD8_REG_CHAN_OP 0x11
58 #define QUAD8_REG_INDEX_INPUT_LEVELS 0x16
59 /* Borrow Toggle flip-flop */
60 #define QUAD8_FLAG_BT BIT(0)
61 /* Carry Toggle flip-flop */
62 #define QUAD8_FLAG_CT BIT(1)
64 #define QUAD8_FLAG_E BIT(4)
66 #define QUAD8_FLAG_UD BIT(5)
67 /* Reset and Load Signal Decoders */
68 #define QUAD8_CTR_RLD 0x00
69 /* Counter Mode Register */
70 #define QUAD8_CTR_CMR 0x20
71 /* Input / Output Control Register */
72 #define QUAD8_CTR_IOR 0x40
73 /* Index Control Register */
74 #define QUAD8_CTR_IDR 0x60
75 /* Reset Byte Pointer (three byte data pointer) */
76 #define QUAD8_RLD_RESET_BP 0x01
78 #define QUAD8_RLD_RESET_CNTR 0x02
79 /* Reset Borrow Toggle, Carry Toggle, Compare Toggle, and Sign flags */
80 #define QUAD8_RLD_RESET_FLAGS 0x04
81 /* Reset Error flag */
82 #define QUAD8_RLD_RESET_E 0x06
83 /* Preset Register to Counter */
84 #define QUAD8_RLD_PRESET_CNTR 0x08
85 /* Transfer Counter to Output Latch */
86 #define QUAD8_RLD_CNTR_OUT 0x10
87 #define QUAD8_CHAN_OP_ENABLE_COUNTERS 0x00
88 #define QUAD8_CHAN_OP_RESET_COUNTERS 0x01
89 #define QUAD8_CMR_QUADRATURE_X1 0x08
90 #define QUAD8_CMR_QUADRATURE_X2 0x10
91 #define QUAD8_CMR_QUADRATURE_X4 0x18
94 static int quad8_read_raw(struct iio_dev
*indio_dev
,
95 struct iio_chan_spec
const *chan
, int *val
, int *val2
, long mask
)
97 struct quad8_iio
*const priv
= iio_priv(indio_dev
);
98 const int base_offset
= priv
->base
+ 2 * chan
->channel
;
105 case IIO_CHAN_INFO_RAW
:
106 if (chan
->type
== IIO_INDEX
) {
107 *val
= !!(inb(priv
->base
+ QUAD8_REG_INDEX_INPUT_LEVELS
)
108 & BIT(chan
->channel
));
112 flags
= inb(base_offset
+ 1);
113 borrow
= flags
& QUAD8_FLAG_BT
;
114 carry
= !!(flags
& QUAD8_FLAG_CT
);
116 /* Borrow XOR Carry effectively doubles count range */
117 *val
= (borrow
^ carry
) << 24;
119 /* Reset Byte Pointer; transfer Counter to Output Latch */
120 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
| QUAD8_RLD_CNTR_OUT
,
123 for (i
= 0; i
< 3; i
++)
124 *val
|= (unsigned int)inb(base_offset
) << (8 * i
);
127 case IIO_CHAN_INFO_ENABLE
:
128 *val
= priv
->ab_enable
[chan
->channel
];
130 case IIO_CHAN_INFO_SCALE
:
132 *val2
= priv
->quadrature_scale
[chan
->channel
];
133 return IIO_VAL_FRACTIONAL_LOG2
;
139 static int quad8_write_raw(struct iio_dev
*indio_dev
,
140 struct iio_chan_spec
const *chan
, int val
, int val2
, long mask
)
142 struct quad8_iio
*const priv
= iio_priv(indio_dev
);
143 const int base_offset
= priv
->base
+ 2 * chan
->channel
;
145 unsigned int ior_cfg
;
148 case IIO_CHAN_INFO_RAW
:
149 if (chan
->type
== IIO_INDEX
)
152 /* Only 24-bit values are supported */
153 if ((unsigned int)val
> 0xFFFFFF)
156 /* Reset Byte Pointer */
157 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
, base_offset
+ 1);
159 /* Counter can only be set via Preset Register */
160 for (i
= 0; i
< 3; i
++)
161 outb(val
>> (8 * i
), base_offset
);
163 /* Transfer Preset Register to Counter */
164 outb(QUAD8_CTR_RLD
| QUAD8_RLD_PRESET_CNTR
, base_offset
+ 1);
166 /* Reset Byte Pointer */
167 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
, base_offset
+ 1);
169 /* Set Preset Register back to original value */
170 val
= priv
->preset
[chan
->channel
];
171 for (i
= 0; i
< 3; i
++)
172 outb(val
>> (8 * i
), base_offset
);
174 /* Reset Borrow, Carry, Compare, and Sign flags */
175 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_FLAGS
, base_offset
+ 1);
176 /* Reset Error flag */
177 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_E
, base_offset
+ 1);
180 case IIO_CHAN_INFO_ENABLE
:
181 /* only boolean values accepted */
182 if (val
< 0 || val
> 1)
185 priv
->ab_enable
[chan
->channel
] = val
;
187 ior_cfg
= val
| priv
->preset_enable
[chan
->channel
] << 1;
189 /* Load I/O control configuration */
190 outb(QUAD8_CTR_IOR
| ior_cfg
, base_offset
+ 1);
193 case IIO_CHAN_INFO_SCALE
:
194 /* Quadrature scaling only available in quadrature mode */
195 if (!priv
->quadrature_mode
[chan
->channel
] && (val2
|| val
!= 1))
198 /* Only three gain states (1, 0.5, 0.25) */
199 if (val
== 1 && !val2
)
200 priv
->quadrature_scale
[chan
->channel
] = 0;
204 priv
->quadrature_scale
[chan
->channel
] = 1;
207 priv
->quadrature_scale
[chan
->channel
] = 2;
221 static const struct iio_info quad8_info
= {
222 .read_raw
= quad8_read_raw
,
223 .write_raw
= quad8_write_raw
226 static ssize_t
quad8_read_preset(struct iio_dev
*indio_dev
, uintptr_t private,
227 const struct iio_chan_spec
*chan
, char *buf
)
229 const struct quad8_iio
*const priv
= iio_priv(indio_dev
);
231 return snprintf(buf
, PAGE_SIZE
, "%u\n", priv
->preset
[chan
->channel
]);
234 static ssize_t
quad8_write_preset(struct iio_dev
*indio_dev
, uintptr_t private,
235 const struct iio_chan_spec
*chan
, const char *buf
, size_t len
)
237 struct quad8_iio
*const priv
= iio_priv(indio_dev
);
238 const int base_offset
= priv
->base
+ 2 * chan
->channel
;
243 ret
= kstrtouint(buf
, 0, &preset
);
247 /* Only 24-bit values are supported */
248 if (preset
> 0xFFFFFF)
251 priv
->preset
[chan
->channel
] = preset
;
253 /* Reset Byte Pointer */
254 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
, base_offset
+ 1);
256 /* Set Preset Register */
257 for (i
= 0; i
< 3; i
++)
258 outb(preset
>> (8 * i
), base_offset
);
263 static ssize_t
quad8_read_set_to_preset_on_index(struct iio_dev
*indio_dev
,
264 uintptr_t private, const struct iio_chan_spec
*chan
, char *buf
)
266 const struct quad8_iio
*const priv
= iio_priv(indio_dev
);
268 return snprintf(buf
, PAGE_SIZE
, "%u\n",
269 !priv
->preset_enable
[chan
->channel
]);
272 static ssize_t
quad8_write_set_to_preset_on_index(struct iio_dev
*indio_dev
,
273 uintptr_t private, const struct iio_chan_spec
*chan
, const char *buf
,
276 struct quad8_iio
*const priv
= iio_priv(indio_dev
);
277 const int base_offset
= priv
->base
+ 2 * chan
->channel
+ 1;
280 unsigned int ior_cfg
;
282 ret
= kstrtobool(buf
, &preset_enable
);
286 /* Preset enable is active low in Input/Output Control register */
287 preset_enable
= !preset_enable
;
289 priv
->preset_enable
[chan
->channel
] = preset_enable
;
291 ior_cfg
= priv
->ab_enable
[chan
->channel
] |
292 (unsigned int)preset_enable
<< 1;
294 /* Load I/O control configuration to Input / Output Control Register */
295 outb(QUAD8_CTR_IOR
| ior_cfg
, base_offset
);
300 static const char *const quad8_noise_error_states
[] = {
301 "No excessive noise is present at the count inputs",
302 "Excessive noise is present at the count inputs"
305 static int quad8_get_noise_error(struct iio_dev
*indio_dev
,
306 const struct iio_chan_spec
*chan
)
308 struct quad8_iio
*const priv
= iio_priv(indio_dev
);
309 const int base_offset
= priv
->base
+ 2 * chan
->channel
+ 1;
311 return !!(inb(base_offset
) & QUAD8_FLAG_E
);
314 static const struct iio_enum quad8_noise_error_enum
= {
315 .items
= quad8_noise_error_states
,
316 .num_items
= ARRAY_SIZE(quad8_noise_error_states
),
317 .get
= quad8_get_noise_error
320 static const char *const quad8_count_direction_states
[] = {
325 static int quad8_get_count_direction(struct iio_dev
*indio_dev
,
326 const struct iio_chan_spec
*chan
)
328 struct quad8_iio
*const priv
= iio_priv(indio_dev
);
329 const int base_offset
= priv
->base
+ 2 * chan
->channel
+ 1;
331 return !!(inb(base_offset
) & QUAD8_FLAG_UD
);
334 static const struct iio_enum quad8_count_direction_enum
= {
335 .items
= quad8_count_direction_states
,
336 .num_items
= ARRAY_SIZE(quad8_count_direction_states
),
337 .get
= quad8_get_count_direction
340 static const char *const quad8_count_modes
[] = {
347 static int quad8_set_count_mode(struct iio_dev
*indio_dev
,
348 const struct iio_chan_spec
*chan
, unsigned int cnt_mode
)
350 struct quad8_iio
*const priv
= iio_priv(indio_dev
);
351 unsigned int mode_cfg
= cnt_mode
<< 1;
352 const int base_offset
= priv
->base
+ 2 * chan
->channel
+ 1;
354 priv
->count_mode
[chan
->channel
] = cnt_mode
;
356 /* Add quadrature mode configuration */
357 if (priv
->quadrature_mode
[chan
->channel
])
358 mode_cfg
|= (priv
->quadrature_scale
[chan
->channel
] + 1) << 3;
360 /* Load mode configuration to Counter Mode Register */
361 outb(QUAD8_CTR_CMR
| mode_cfg
, base_offset
);
366 static int quad8_get_count_mode(struct iio_dev
*indio_dev
,
367 const struct iio_chan_spec
*chan
)
369 const struct quad8_iio
*const priv
= iio_priv(indio_dev
);
371 return priv
->count_mode
[chan
->channel
];
374 static const struct iio_enum quad8_count_mode_enum
= {
375 .items
= quad8_count_modes
,
376 .num_items
= ARRAY_SIZE(quad8_count_modes
),
377 .set
= quad8_set_count_mode
,
378 .get
= quad8_get_count_mode
381 static const char *const quad8_synchronous_modes
[] = {
386 static int quad8_set_synchronous_mode(struct iio_dev
*indio_dev
,
387 const struct iio_chan_spec
*chan
, unsigned int synchronous_mode
)
389 struct quad8_iio
*const priv
= iio_priv(indio_dev
);
390 const unsigned int idr_cfg
= synchronous_mode
|
391 priv
->index_polarity
[chan
->channel
] << 1;
392 const int base_offset
= priv
->base
+ 2 * chan
->channel
+ 1;
394 /* Index function must be non-synchronous in non-quadrature mode */
395 if (synchronous_mode
&& !priv
->quadrature_mode
[chan
->channel
])
398 priv
->synchronous_mode
[chan
->channel
] = synchronous_mode
;
400 /* Load Index Control configuration to Index Control Register */
401 outb(QUAD8_CTR_IDR
| idr_cfg
, base_offset
);
406 static int quad8_get_synchronous_mode(struct iio_dev
*indio_dev
,
407 const struct iio_chan_spec
*chan
)
409 const struct quad8_iio
*const priv
= iio_priv(indio_dev
);
411 return priv
->synchronous_mode
[chan
->channel
];
414 static const struct iio_enum quad8_synchronous_mode_enum
= {
415 .items
= quad8_synchronous_modes
,
416 .num_items
= ARRAY_SIZE(quad8_synchronous_modes
),
417 .set
= quad8_set_synchronous_mode
,
418 .get
= quad8_get_synchronous_mode
421 static const char *const quad8_quadrature_modes
[] = {
426 static int quad8_set_quadrature_mode(struct iio_dev
*indio_dev
,
427 const struct iio_chan_spec
*chan
, unsigned int quadrature_mode
)
429 struct quad8_iio
*const priv
= iio_priv(indio_dev
);
430 unsigned int mode_cfg
= priv
->count_mode
[chan
->channel
] << 1;
431 const int base_offset
= priv
->base
+ 2 * chan
->channel
+ 1;
434 mode_cfg
|= (priv
->quadrature_scale
[chan
->channel
] + 1) << 3;
436 /* Quadrature scaling only available in quadrature mode */
437 priv
->quadrature_scale
[chan
->channel
] = 0;
439 /* Synchronous function not supported in non-quadrature mode */
440 if (priv
->synchronous_mode
[chan
->channel
])
441 quad8_set_synchronous_mode(indio_dev
, chan
, 0);
444 priv
->quadrature_mode
[chan
->channel
] = quadrature_mode
;
446 /* Load mode configuration to Counter Mode Register */
447 outb(QUAD8_CTR_CMR
| mode_cfg
, base_offset
);
452 static int quad8_get_quadrature_mode(struct iio_dev
*indio_dev
,
453 const struct iio_chan_spec
*chan
)
455 const struct quad8_iio
*const priv
= iio_priv(indio_dev
);
457 return priv
->quadrature_mode
[chan
->channel
];
460 static const struct iio_enum quad8_quadrature_mode_enum
= {
461 .items
= quad8_quadrature_modes
,
462 .num_items
= ARRAY_SIZE(quad8_quadrature_modes
),
463 .set
= quad8_set_quadrature_mode
,
464 .get
= quad8_get_quadrature_mode
467 static const char *const quad8_index_polarity_modes
[] = {
472 static int quad8_set_index_polarity(struct iio_dev
*indio_dev
,
473 const struct iio_chan_spec
*chan
, unsigned int index_polarity
)
475 struct quad8_iio
*const priv
= iio_priv(indio_dev
);
476 const unsigned int idr_cfg
= priv
->synchronous_mode
[chan
->channel
] |
478 const int base_offset
= priv
->base
+ 2 * chan
->channel
+ 1;
480 priv
->index_polarity
[chan
->channel
] = index_polarity
;
482 /* Load Index Control configuration to Index Control Register */
483 outb(QUAD8_CTR_IDR
| idr_cfg
, base_offset
);
488 static int quad8_get_index_polarity(struct iio_dev
*indio_dev
,
489 const struct iio_chan_spec
*chan
)
491 const struct quad8_iio
*const priv
= iio_priv(indio_dev
);
493 return priv
->index_polarity
[chan
->channel
];
496 static const struct iio_enum quad8_index_polarity_enum
= {
497 .items
= quad8_index_polarity_modes
,
498 .num_items
= ARRAY_SIZE(quad8_index_polarity_modes
),
499 .set
= quad8_set_index_polarity
,
500 .get
= quad8_get_index_polarity
503 static const struct iio_chan_spec_ext_info quad8_count_ext_info
[] = {
506 .shared
= IIO_SEPARATE
,
507 .read
= quad8_read_preset
,
508 .write
= quad8_write_preset
511 .name
= "set_to_preset_on_index",
512 .shared
= IIO_SEPARATE
,
513 .read
= quad8_read_set_to_preset_on_index
,
514 .write
= quad8_write_set_to_preset_on_index
516 IIO_ENUM("noise_error", IIO_SEPARATE
, &quad8_noise_error_enum
),
517 IIO_ENUM_AVAILABLE("noise_error", &quad8_noise_error_enum
),
518 IIO_ENUM("count_direction", IIO_SEPARATE
, &quad8_count_direction_enum
),
519 IIO_ENUM_AVAILABLE("count_direction", &quad8_count_direction_enum
),
520 IIO_ENUM("count_mode", IIO_SEPARATE
, &quad8_count_mode_enum
),
521 IIO_ENUM_AVAILABLE("count_mode", &quad8_count_mode_enum
),
522 IIO_ENUM("quadrature_mode", IIO_SEPARATE
, &quad8_quadrature_mode_enum
),
523 IIO_ENUM_AVAILABLE("quadrature_mode", &quad8_quadrature_mode_enum
),
527 static const struct iio_chan_spec_ext_info quad8_index_ext_info
[] = {
528 IIO_ENUM("synchronous_mode", IIO_SEPARATE
,
529 &quad8_synchronous_mode_enum
),
530 IIO_ENUM_AVAILABLE("synchronous_mode", &quad8_synchronous_mode_enum
),
531 IIO_ENUM("index_polarity", IIO_SEPARATE
, &quad8_index_polarity_enum
),
532 IIO_ENUM_AVAILABLE("index_polarity", &quad8_index_polarity_enum
),
536 #define QUAD8_COUNT_CHAN(_chan) { \
538 .channel = (_chan), \
539 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
540 BIT(IIO_CHAN_INFO_ENABLE) | BIT(IIO_CHAN_INFO_SCALE), \
541 .ext_info = quad8_count_ext_info, \
545 #define QUAD8_INDEX_CHAN(_chan) { \
547 .channel = (_chan), \
548 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
549 .ext_info = quad8_index_ext_info, \
553 static const struct iio_chan_spec quad8_channels
[] = {
554 QUAD8_COUNT_CHAN(0), QUAD8_INDEX_CHAN(0),
555 QUAD8_COUNT_CHAN(1), QUAD8_INDEX_CHAN(1),
556 QUAD8_COUNT_CHAN(2), QUAD8_INDEX_CHAN(2),
557 QUAD8_COUNT_CHAN(3), QUAD8_INDEX_CHAN(3),
558 QUAD8_COUNT_CHAN(4), QUAD8_INDEX_CHAN(4),
559 QUAD8_COUNT_CHAN(5), QUAD8_INDEX_CHAN(5),
560 QUAD8_COUNT_CHAN(6), QUAD8_INDEX_CHAN(6),
561 QUAD8_COUNT_CHAN(7), QUAD8_INDEX_CHAN(7)
564 static int quad8_signal_read(struct counter_device
*counter
,
565 struct counter_signal
*signal
, enum counter_signal_value
*val
)
567 const struct quad8_iio
*const priv
= counter
->priv
;
570 /* Only Index signal levels can be read */
574 state
= inb(priv
->base
+ QUAD8_REG_INDEX_INPUT_LEVELS
)
575 & BIT(signal
->id
- 16);
577 *val
= (state
) ? COUNTER_SIGNAL_HIGH
: COUNTER_SIGNAL_LOW
;
582 static int quad8_count_read(struct counter_device
*counter
,
583 struct counter_count
*count
, unsigned long *val
)
585 const struct quad8_iio
*const priv
= counter
->priv
;
586 const int base_offset
= priv
->base
+ 2 * count
->id
;
592 flags
= inb(base_offset
+ 1);
593 borrow
= flags
& QUAD8_FLAG_BT
;
594 carry
= !!(flags
& QUAD8_FLAG_CT
);
596 /* Borrow XOR Carry effectively doubles count range */
597 *val
= (unsigned long)(borrow
^ carry
) << 24;
599 /* Reset Byte Pointer; transfer Counter to Output Latch */
600 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
| QUAD8_RLD_CNTR_OUT
,
603 for (i
= 0; i
< 3; i
++)
604 *val
|= (unsigned long)inb(base_offset
) << (8 * i
);
609 static int quad8_count_write(struct counter_device
*counter
,
610 struct counter_count
*count
, unsigned long val
)
612 const struct quad8_iio
*const priv
= counter
->priv
;
613 const int base_offset
= priv
->base
+ 2 * count
->id
;
616 /* Only 24-bit values are supported */
620 /* Reset Byte Pointer */
621 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
, base_offset
+ 1);
623 /* Counter can only be set via Preset Register */
624 for (i
= 0; i
< 3; i
++)
625 outb(val
>> (8 * i
), base_offset
);
627 /* Transfer Preset Register to Counter */
628 outb(QUAD8_CTR_RLD
| QUAD8_RLD_PRESET_CNTR
, base_offset
+ 1);
630 /* Reset Byte Pointer */
631 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
, base_offset
+ 1);
633 /* Set Preset Register back to original value */
634 val
= priv
->preset
[count
->id
];
635 for (i
= 0; i
< 3; i
++)
636 outb(val
>> (8 * i
), base_offset
);
638 /* Reset Borrow, Carry, Compare, and Sign flags */
639 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_FLAGS
, base_offset
+ 1);
640 /* Reset Error flag */
641 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_E
, base_offset
+ 1);
646 enum quad8_count_function
{
647 QUAD8_COUNT_FUNCTION_PULSE_DIRECTION
= 0,
648 QUAD8_COUNT_FUNCTION_QUADRATURE_X1
,
649 QUAD8_COUNT_FUNCTION_QUADRATURE_X2
,
650 QUAD8_COUNT_FUNCTION_QUADRATURE_X4
653 static enum counter_count_function quad8_count_functions_list
[] = {
654 [QUAD8_COUNT_FUNCTION_PULSE_DIRECTION
] = COUNTER_COUNT_FUNCTION_PULSE_DIRECTION
,
655 [QUAD8_COUNT_FUNCTION_QUADRATURE_X1
] = COUNTER_COUNT_FUNCTION_QUADRATURE_X1_A
,
656 [QUAD8_COUNT_FUNCTION_QUADRATURE_X2
] = COUNTER_COUNT_FUNCTION_QUADRATURE_X2_A
,
657 [QUAD8_COUNT_FUNCTION_QUADRATURE_X4
] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4
660 static int quad8_function_get(struct counter_device
*counter
,
661 struct counter_count
*count
, size_t *function
)
663 const struct quad8_iio
*const priv
= counter
->priv
;
664 const int id
= count
->id
;
665 const unsigned int quadrature_mode
= priv
->quadrature_mode
[id
];
666 const unsigned int scale
= priv
->quadrature_scale
[id
];
671 *function
= QUAD8_COUNT_FUNCTION_QUADRATURE_X1
;
674 *function
= QUAD8_COUNT_FUNCTION_QUADRATURE_X2
;
677 *function
= QUAD8_COUNT_FUNCTION_QUADRATURE_X4
;
681 *function
= QUAD8_COUNT_FUNCTION_PULSE_DIRECTION
;
686 static int quad8_function_set(struct counter_device
*counter
,
687 struct counter_count
*count
, size_t function
)
689 struct quad8_iio
*const priv
= counter
->priv
;
690 const int id
= count
->id
;
691 unsigned int *const quadrature_mode
= priv
->quadrature_mode
+ id
;
692 unsigned int *const scale
= priv
->quadrature_scale
+ id
;
693 unsigned int mode_cfg
= priv
->count_mode
[id
] << 1;
694 unsigned int *const synchronous_mode
= priv
->synchronous_mode
+ id
;
695 const unsigned int idr_cfg
= priv
->index_polarity
[id
] << 1;
696 const int base_offset
= priv
->base
+ 2 * id
+ 1;
698 if (function
== QUAD8_COUNT_FUNCTION_PULSE_DIRECTION
) {
699 *quadrature_mode
= 0;
701 /* Quadrature scaling only available in quadrature mode */
704 /* Synchronous function not supported in non-quadrature mode */
705 if (*synchronous_mode
) {
706 *synchronous_mode
= 0;
707 /* Disable synchronous function mode */
708 outb(QUAD8_CTR_IDR
| idr_cfg
, base_offset
);
711 *quadrature_mode
= 1;
714 case QUAD8_COUNT_FUNCTION_QUADRATURE_X1
:
716 mode_cfg
|= QUAD8_CMR_QUADRATURE_X1
;
718 case QUAD8_COUNT_FUNCTION_QUADRATURE_X2
:
720 mode_cfg
|= QUAD8_CMR_QUADRATURE_X2
;
722 case QUAD8_COUNT_FUNCTION_QUADRATURE_X4
:
724 mode_cfg
|= QUAD8_CMR_QUADRATURE_X4
;
729 /* Load mode configuration to Counter Mode Register */
730 outb(QUAD8_CTR_CMR
| mode_cfg
, base_offset
);
735 static void quad8_direction_get(struct counter_device
*counter
,
736 struct counter_count
*count
, enum counter_count_direction
*direction
)
738 const struct quad8_iio
*const priv
= counter
->priv
;
739 unsigned int ud_flag
;
740 const unsigned int flag_addr
= priv
->base
+ 2 * count
->id
+ 1;
742 /* U/D flag: nonzero = up, zero = down */
743 ud_flag
= inb(flag_addr
) & QUAD8_FLAG_UD
;
745 *direction
= (ud_flag
) ? COUNTER_COUNT_DIRECTION_FORWARD
:
746 COUNTER_COUNT_DIRECTION_BACKWARD
;
749 enum quad8_synapse_action
{
750 QUAD8_SYNAPSE_ACTION_NONE
= 0,
751 QUAD8_SYNAPSE_ACTION_RISING_EDGE
,
752 QUAD8_SYNAPSE_ACTION_FALLING_EDGE
,
753 QUAD8_SYNAPSE_ACTION_BOTH_EDGES
756 static enum counter_synapse_action quad8_index_actions_list
[] = {
757 [QUAD8_SYNAPSE_ACTION_NONE
] = COUNTER_SYNAPSE_ACTION_NONE
,
758 [QUAD8_SYNAPSE_ACTION_RISING_EDGE
] = COUNTER_SYNAPSE_ACTION_RISING_EDGE
761 static enum counter_synapse_action quad8_synapse_actions_list
[] = {
762 [QUAD8_SYNAPSE_ACTION_NONE
] = COUNTER_SYNAPSE_ACTION_NONE
,
763 [QUAD8_SYNAPSE_ACTION_RISING_EDGE
] = COUNTER_SYNAPSE_ACTION_RISING_EDGE
,
764 [QUAD8_SYNAPSE_ACTION_FALLING_EDGE
] = COUNTER_SYNAPSE_ACTION_FALLING_EDGE
,
765 [QUAD8_SYNAPSE_ACTION_BOTH_EDGES
] = COUNTER_SYNAPSE_ACTION_BOTH_EDGES
768 static int quad8_action_get(struct counter_device
*counter
,
769 struct counter_count
*count
, struct counter_synapse
*synapse
,
772 struct quad8_iio
*const priv
= counter
->priv
;
775 const size_t signal_a_id
= count
->synapses
[0].signal
->id
;
776 enum counter_count_direction direction
;
778 /* Handle Index signals */
779 if (synapse
->signal
->id
>= 16) {
780 if (priv
->preset_enable
[count
->id
])
781 *action
= QUAD8_SYNAPSE_ACTION_RISING_EDGE
;
783 *action
= QUAD8_SYNAPSE_ACTION_NONE
;
788 err
= quad8_function_get(counter
, count
, &function
);
792 /* Default action mode */
793 *action
= QUAD8_SYNAPSE_ACTION_NONE
;
795 /* Determine action mode based on current count function mode */
797 case QUAD8_COUNT_FUNCTION_PULSE_DIRECTION
:
798 if (synapse
->signal
->id
== signal_a_id
)
799 *action
= QUAD8_SYNAPSE_ACTION_RISING_EDGE
;
801 case QUAD8_COUNT_FUNCTION_QUADRATURE_X1
:
802 if (synapse
->signal
->id
== signal_a_id
) {
803 quad8_direction_get(counter
, count
, &direction
);
805 if (direction
== COUNTER_COUNT_DIRECTION_FORWARD
)
806 *action
= QUAD8_SYNAPSE_ACTION_RISING_EDGE
;
808 *action
= QUAD8_SYNAPSE_ACTION_FALLING_EDGE
;
811 case QUAD8_COUNT_FUNCTION_QUADRATURE_X2
:
812 if (synapse
->signal
->id
== signal_a_id
)
813 *action
= QUAD8_SYNAPSE_ACTION_BOTH_EDGES
;
815 case QUAD8_COUNT_FUNCTION_QUADRATURE_X4
:
816 *action
= QUAD8_SYNAPSE_ACTION_BOTH_EDGES
;
823 static const struct counter_ops quad8_ops
= {
824 .signal_read
= quad8_signal_read
,
825 .count_read
= quad8_count_read
,
826 .count_write
= quad8_count_write
,
827 .function_get
= quad8_function_get
,
828 .function_set
= quad8_function_set
,
829 .action_get
= quad8_action_get
832 static int quad8_index_polarity_get(struct counter_device
*counter
,
833 struct counter_signal
*signal
, size_t *index_polarity
)
835 const struct quad8_iio
*const priv
= counter
->priv
;
836 const size_t channel_id
= signal
->id
- 16;
838 *index_polarity
= priv
->index_polarity
[channel_id
];
843 static int quad8_index_polarity_set(struct counter_device
*counter
,
844 struct counter_signal
*signal
, size_t index_polarity
)
846 struct quad8_iio
*const priv
= counter
->priv
;
847 const size_t channel_id
= signal
->id
- 16;
848 const unsigned int idr_cfg
= priv
->synchronous_mode
[channel_id
] |
850 const int base_offset
= priv
->base
+ 2 * channel_id
+ 1;
852 priv
->index_polarity
[channel_id
] = index_polarity
;
854 /* Load Index Control configuration to Index Control Register */
855 outb(QUAD8_CTR_IDR
| idr_cfg
, base_offset
);
860 static struct counter_signal_enum_ext quad8_index_pol_enum
= {
861 .items
= quad8_index_polarity_modes
,
862 .num_items
= ARRAY_SIZE(quad8_index_polarity_modes
),
863 .get
= quad8_index_polarity_get
,
864 .set
= quad8_index_polarity_set
867 static int quad8_synchronous_mode_get(struct counter_device
*counter
,
868 struct counter_signal
*signal
, size_t *synchronous_mode
)
870 const struct quad8_iio
*const priv
= counter
->priv
;
871 const size_t channel_id
= signal
->id
- 16;
873 *synchronous_mode
= priv
->synchronous_mode
[channel_id
];
878 static int quad8_synchronous_mode_set(struct counter_device
*counter
,
879 struct counter_signal
*signal
, size_t synchronous_mode
)
881 struct quad8_iio
*const priv
= counter
->priv
;
882 const size_t channel_id
= signal
->id
- 16;
883 const unsigned int idr_cfg
= synchronous_mode
|
884 priv
->index_polarity
[channel_id
] << 1;
885 const int base_offset
= priv
->base
+ 2 * channel_id
+ 1;
887 /* Index function must be non-synchronous in non-quadrature mode */
888 if (synchronous_mode
&& !priv
->quadrature_mode
[channel_id
])
891 priv
->synchronous_mode
[channel_id
] = synchronous_mode
;
893 /* Load Index Control configuration to Index Control Register */
894 outb(QUAD8_CTR_IDR
| idr_cfg
, base_offset
);
899 static struct counter_signal_enum_ext quad8_syn_mode_enum
= {
900 .items
= quad8_synchronous_modes
,
901 .num_items
= ARRAY_SIZE(quad8_synchronous_modes
),
902 .get
= quad8_synchronous_mode_get
,
903 .set
= quad8_synchronous_mode_set
906 static ssize_t
quad8_count_floor_read(struct counter_device
*counter
,
907 struct counter_count
*count
, void *private, char *buf
)
909 /* Only a floor of 0 is supported */
910 return sprintf(buf
, "0\n");
913 static int quad8_count_mode_get(struct counter_device
*counter
,
914 struct counter_count
*count
, size_t *cnt_mode
)
916 const struct quad8_iio
*const priv
= counter
->priv
;
918 /* Map 104-QUAD-8 count mode to Generic Counter count mode */
919 switch (priv
->count_mode
[count
->id
]) {
921 *cnt_mode
= COUNTER_COUNT_MODE_NORMAL
;
924 *cnt_mode
= COUNTER_COUNT_MODE_RANGE_LIMIT
;
927 *cnt_mode
= COUNTER_COUNT_MODE_NON_RECYCLE
;
930 *cnt_mode
= COUNTER_COUNT_MODE_MODULO_N
;
937 static int quad8_count_mode_set(struct counter_device
*counter
,
938 struct counter_count
*count
, size_t cnt_mode
)
940 struct quad8_iio
*const priv
= counter
->priv
;
941 unsigned int mode_cfg
;
942 const int base_offset
= priv
->base
+ 2 * count
->id
+ 1;
944 /* Map Generic Counter count mode to 104-QUAD-8 count mode */
946 case COUNTER_COUNT_MODE_NORMAL
:
949 case COUNTER_COUNT_MODE_RANGE_LIMIT
:
952 case COUNTER_COUNT_MODE_NON_RECYCLE
:
955 case COUNTER_COUNT_MODE_MODULO_N
:
960 priv
->count_mode
[count
->id
] = cnt_mode
;
962 /* Set count mode configuration value */
963 mode_cfg
= cnt_mode
<< 1;
965 /* Add quadrature mode configuration */
966 if (priv
->quadrature_mode
[count
->id
])
967 mode_cfg
|= (priv
->quadrature_scale
[count
->id
] + 1) << 3;
969 /* Load mode configuration to Counter Mode Register */
970 outb(QUAD8_CTR_CMR
| mode_cfg
, base_offset
);
975 static struct counter_count_enum_ext quad8_cnt_mode_enum
= {
976 .items
= counter_count_mode_str
,
977 .num_items
= ARRAY_SIZE(counter_count_mode_str
),
978 .get
= quad8_count_mode_get
,
979 .set
= quad8_count_mode_set
982 static ssize_t
quad8_count_direction_read(struct counter_device
*counter
,
983 struct counter_count
*count
, void *priv
, char *buf
)
985 enum counter_count_direction dir
;
987 quad8_direction_get(counter
, count
, &dir
);
989 return sprintf(buf
, "%s\n", counter_count_direction_str
[dir
]);
992 static ssize_t
quad8_count_enable_read(struct counter_device
*counter
,
993 struct counter_count
*count
, void *private, char *buf
)
995 const struct quad8_iio
*const priv
= counter
->priv
;
997 return sprintf(buf
, "%u\n", priv
->ab_enable
[count
->id
]);
1000 static ssize_t
quad8_count_enable_write(struct counter_device
*counter
,
1001 struct counter_count
*count
, void *private, const char *buf
, size_t len
)
1003 struct quad8_iio
*const priv
= counter
->priv
;
1004 const int base_offset
= priv
->base
+ 2 * count
->id
;
1007 unsigned int ior_cfg
;
1009 err
= kstrtobool(buf
, &ab_enable
);
1013 priv
->ab_enable
[count
->id
] = ab_enable
;
1015 ior_cfg
= ab_enable
| priv
->preset_enable
[count
->id
] << 1;
1017 /* Load I/O control configuration */
1018 outb(QUAD8_CTR_IOR
| ior_cfg
, base_offset
+ 1);
1023 static int quad8_error_noise_get(struct counter_device
*counter
,
1024 struct counter_count
*count
, size_t *noise_error
)
1026 const struct quad8_iio
*const priv
= counter
->priv
;
1027 const int base_offset
= priv
->base
+ 2 * count
->id
+ 1;
1029 *noise_error
= !!(inb(base_offset
) & QUAD8_FLAG_E
);
1034 static struct counter_count_enum_ext quad8_error_noise_enum
= {
1035 .items
= quad8_noise_error_states
,
1036 .num_items
= ARRAY_SIZE(quad8_noise_error_states
),
1037 .get
= quad8_error_noise_get
1040 static ssize_t
quad8_count_preset_read(struct counter_device
*counter
,
1041 struct counter_count
*count
, void *private, char *buf
)
1043 const struct quad8_iio
*const priv
= counter
->priv
;
1045 return sprintf(buf
, "%u\n", priv
->preset
[count
->id
]);
1048 static ssize_t
quad8_count_preset_write(struct counter_device
*counter
,
1049 struct counter_count
*count
, void *private, const char *buf
, size_t len
)
1051 struct quad8_iio
*const priv
= counter
->priv
;
1052 const int base_offset
= priv
->base
+ 2 * count
->id
;
1053 unsigned int preset
;
1057 ret
= kstrtouint(buf
, 0, &preset
);
1061 /* Only 24-bit values are supported */
1062 if (preset
> 0xFFFFFF)
1065 priv
->preset
[count
->id
] = preset
;
1067 /* Reset Byte Pointer */
1068 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
, base_offset
+ 1);
1070 /* Set Preset Register */
1071 for (i
= 0; i
< 3; i
++)
1072 outb(preset
>> (8 * i
), base_offset
);
1077 static ssize_t
quad8_count_ceiling_read(struct counter_device
*counter
,
1078 struct counter_count
*count
, void *private, char *buf
)
1080 const struct quad8_iio
*const priv
= counter
->priv
;
1082 /* Range Limit and Modulo-N count modes use preset value as ceiling */
1083 switch (priv
->count_mode
[count
->id
]) {
1086 return quad8_count_preset_read(counter
, count
, private, buf
);
1089 /* By default 0x1FFFFFF (25 bits unsigned) is maximum count */
1090 return sprintf(buf
, "33554431\n");
1093 static ssize_t
quad8_count_ceiling_write(struct counter_device
*counter
,
1094 struct counter_count
*count
, void *private, const char *buf
, size_t len
)
1096 struct quad8_iio
*const priv
= counter
->priv
;
1098 /* Range Limit and Modulo-N count modes use preset value as ceiling */
1099 switch (priv
->count_mode
[count
->id
]) {
1102 return quad8_count_preset_write(counter
, count
, private, buf
,
1109 static ssize_t
quad8_count_preset_enable_read(struct counter_device
*counter
,
1110 struct counter_count
*count
, void *private, char *buf
)
1112 const struct quad8_iio
*const priv
= counter
->priv
;
1114 return sprintf(buf
, "%u\n", !priv
->preset_enable
[count
->id
]);
1117 static ssize_t
quad8_count_preset_enable_write(struct counter_device
*counter
,
1118 struct counter_count
*count
, void *private, const char *buf
, size_t len
)
1120 struct quad8_iio
*const priv
= counter
->priv
;
1121 const int base_offset
= priv
->base
+ 2 * count
->id
+ 1;
1124 unsigned int ior_cfg
;
1126 ret
= kstrtobool(buf
, &preset_enable
);
1130 /* Preset enable is active low in Input/Output Control register */
1131 preset_enable
= !preset_enable
;
1133 priv
->preset_enable
[count
->id
] = preset_enable
;
1135 ior_cfg
= priv
->ab_enable
[count
->id
] | (unsigned int)preset_enable
<< 1;
1137 /* Load I/O control configuration to Input / Output Control Register */
1138 outb(QUAD8_CTR_IOR
| ior_cfg
, base_offset
);
1143 static const struct counter_signal_ext quad8_index_ext
[] = {
1144 COUNTER_SIGNAL_ENUM("index_polarity", &quad8_index_pol_enum
),
1145 COUNTER_SIGNAL_ENUM_AVAILABLE("index_polarity", &quad8_index_pol_enum
),
1146 COUNTER_SIGNAL_ENUM("synchronous_mode", &quad8_syn_mode_enum
),
1147 COUNTER_SIGNAL_ENUM_AVAILABLE("synchronous_mode", &quad8_syn_mode_enum
)
1150 #define QUAD8_QUAD_SIGNAL(_id, _name) { \
1155 #define QUAD8_INDEX_SIGNAL(_id, _name) { \
1158 .ext = quad8_index_ext, \
1159 .num_ext = ARRAY_SIZE(quad8_index_ext) \
1162 static struct counter_signal quad8_signals
[] = {
1163 QUAD8_QUAD_SIGNAL(0, "Channel 1 Quadrature A"),
1164 QUAD8_QUAD_SIGNAL(1, "Channel 1 Quadrature B"),
1165 QUAD8_QUAD_SIGNAL(2, "Channel 2 Quadrature A"),
1166 QUAD8_QUAD_SIGNAL(3, "Channel 2 Quadrature B"),
1167 QUAD8_QUAD_SIGNAL(4, "Channel 3 Quadrature A"),
1168 QUAD8_QUAD_SIGNAL(5, "Channel 3 Quadrature B"),
1169 QUAD8_QUAD_SIGNAL(6, "Channel 4 Quadrature A"),
1170 QUAD8_QUAD_SIGNAL(7, "Channel 4 Quadrature B"),
1171 QUAD8_QUAD_SIGNAL(8, "Channel 5 Quadrature A"),
1172 QUAD8_QUAD_SIGNAL(9, "Channel 5 Quadrature B"),
1173 QUAD8_QUAD_SIGNAL(10, "Channel 6 Quadrature A"),
1174 QUAD8_QUAD_SIGNAL(11, "Channel 6 Quadrature B"),
1175 QUAD8_QUAD_SIGNAL(12, "Channel 7 Quadrature A"),
1176 QUAD8_QUAD_SIGNAL(13, "Channel 7 Quadrature B"),
1177 QUAD8_QUAD_SIGNAL(14, "Channel 8 Quadrature A"),
1178 QUAD8_QUAD_SIGNAL(15, "Channel 8 Quadrature B"),
1179 QUAD8_INDEX_SIGNAL(16, "Channel 1 Index"),
1180 QUAD8_INDEX_SIGNAL(17, "Channel 2 Index"),
1181 QUAD8_INDEX_SIGNAL(18, "Channel 3 Index"),
1182 QUAD8_INDEX_SIGNAL(19, "Channel 4 Index"),
1183 QUAD8_INDEX_SIGNAL(20, "Channel 5 Index"),
1184 QUAD8_INDEX_SIGNAL(21, "Channel 6 Index"),
1185 QUAD8_INDEX_SIGNAL(22, "Channel 7 Index"),
1186 QUAD8_INDEX_SIGNAL(23, "Channel 8 Index")
1189 #define QUAD8_COUNT_SYNAPSES(_id) { \
1191 .actions_list = quad8_synapse_actions_list, \
1192 .num_actions = ARRAY_SIZE(quad8_synapse_actions_list), \
1193 .signal = quad8_signals + 2 * (_id) \
1196 .actions_list = quad8_synapse_actions_list, \
1197 .num_actions = ARRAY_SIZE(quad8_synapse_actions_list), \
1198 .signal = quad8_signals + 2 * (_id) + 1 \
1201 .actions_list = quad8_index_actions_list, \
1202 .num_actions = ARRAY_SIZE(quad8_index_actions_list), \
1203 .signal = quad8_signals + 2 * (_id) + 16 \
1207 static struct counter_synapse quad8_count_synapses
[][3] = {
1208 QUAD8_COUNT_SYNAPSES(0), QUAD8_COUNT_SYNAPSES(1),
1209 QUAD8_COUNT_SYNAPSES(2), QUAD8_COUNT_SYNAPSES(3),
1210 QUAD8_COUNT_SYNAPSES(4), QUAD8_COUNT_SYNAPSES(5),
1211 QUAD8_COUNT_SYNAPSES(6), QUAD8_COUNT_SYNAPSES(7)
1214 static const struct counter_count_ext quad8_count_ext
[] = {
1217 .read
= quad8_count_ceiling_read
,
1218 .write
= quad8_count_ceiling_write
1222 .read
= quad8_count_floor_read
1224 COUNTER_COUNT_ENUM("count_mode", &quad8_cnt_mode_enum
),
1225 COUNTER_COUNT_ENUM_AVAILABLE("count_mode", &quad8_cnt_mode_enum
),
1227 .name
= "direction",
1228 .read
= quad8_count_direction_read
1232 .read
= quad8_count_enable_read
,
1233 .write
= quad8_count_enable_write
1235 COUNTER_COUNT_ENUM("error_noise", &quad8_error_noise_enum
),
1236 COUNTER_COUNT_ENUM_AVAILABLE("error_noise", &quad8_error_noise_enum
),
1239 .read
= quad8_count_preset_read
,
1240 .write
= quad8_count_preset_write
1243 .name
= "preset_enable",
1244 .read
= quad8_count_preset_enable_read
,
1245 .write
= quad8_count_preset_enable_write
1249 #define QUAD8_COUNT(_id, _cntname) { \
1251 .name = (_cntname), \
1252 .functions_list = quad8_count_functions_list, \
1253 .num_functions = ARRAY_SIZE(quad8_count_functions_list), \
1254 .synapses = quad8_count_synapses[(_id)], \
1255 .num_synapses = 2, \
1256 .ext = quad8_count_ext, \
1257 .num_ext = ARRAY_SIZE(quad8_count_ext) \
1260 static struct counter_count quad8_counts
[] = {
1261 QUAD8_COUNT(0, "Channel 1 Count"),
1262 QUAD8_COUNT(1, "Channel 2 Count"),
1263 QUAD8_COUNT(2, "Channel 3 Count"),
1264 QUAD8_COUNT(3, "Channel 4 Count"),
1265 QUAD8_COUNT(4, "Channel 5 Count"),
1266 QUAD8_COUNT(5, "Channel 6 Count"),
1267 QUAD8_COUNT(6, "Channel 7 Count"),
1268 QUAD8_COUNT(7, "Channel 8 Count")
1271 static int quad8_probe(struct device
*dev
, unsigned int id
)
1273 struct iio_dev
*indio_dev
;
1274 struct quad8_iio
*quad8iio
;
1276 unsigned int base_offset
;
1279 if (!devm_request_region(dev
, base
[id
], QUAD8_EXTENT
, dev_name(dev
))) {
1280 dev_err(dev
, "Unable to lock port addresses (0x%X-0x%X)\n",
1281 base
[id
], base
[id
] + QUAD8_EXTENT
);
1285 /* Allocate IIO device; this also allocates driver data structure */
1286 indio_dev
= devm_iio_device_alloc(dev
, sizeof(*quad8iio
));
1290 /* Initialize IIO device */
1291 indio_dev
->info
= &quad8_info
;
1292 indio_dev
->modes
= INDIO_DIRECT_MODE
;
1293 indio_dev
->num_channels
= ARRAY_SIZE(quad8_channels
);
1294 indio_dev
->channels
= quad8_channels
;
1295 indio_dev
->name
= dev_name(dev
);
1296 indio_dev
->dev
.parent
= dev
;
1298 /* Initialize Counter device and driver data */
1299 quad8iio
= iio_priv(indio_dev
);
1300 quad8iio
->counter
.name
= dev_name(dev
);
1301 quad8iio
->counter
.parent
= dev
;
1302 quad8iio
->counter
.ops
= &quad8_ops
;
1303 quad8iio
->counter
.counts
= quad8_counts
;
1304 quad8iio
->counter
.num_counts
= ARRAY_SIZE(quad8_counts
);
1305 quad8iio
->counter
.signals
= quad8_signals
;
1306 quad8iio
->counter
.num_signals
= ARRAY_SIZE(quad8_signals
);
1307 quad8iio
->counter
.priv
= quad8iio
;
1308 quad8iio
->base
= base
[id
];
1310 /* Reset all counters and disable interrupt function */
1311 outb(QUAD8_CHAN_OP_RESET_COUNTERS
, base
[id
] + QUAD8_REG_CHAN_OP
);
1312 /* Set initial configuration for all counters */
1313 for (i
= 0; i
< QUAD8_NUM_COUNTERS
; i
++) {
1314 base_offset
= base
[id
] + 2 * i
;
1315 /* Reset Byte Pointer */
1316 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
, base_offset
+ 1);
1317 /* Reset Preset Register */
1318 for (j
= 0; j
< 3; j
++)
1319 outb(0x00, base_offset
);
1320 /* Reset Borrow, Carry, Compare, and Sign flags */
1321 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_FLAGS
, base_offset
+ 1);
1322 /* Reset Error flag */
1323 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_E
, base_offset
+ 1);
1324 /* Binary encoding; Normal count; non-quadrature mode */
1325 outb(QUAD8_CTR_CMR
, base_offset
+ 1);
1326 /* Disable A and B inputs; preset on index; FLG1 as Carry */
1327 outb(QUAD8_CTR_IOR
, base_offset
+ 1);
1328 /* Disable index function; negative index polarity */
1329 outb(QUAD8_CTR_IDR
, base_offset
+ 1);
1331 /* Enable all counters */
1332 outb(QUAD8_CHAN_OP_ENABLE_COUNTERS
, base
[id
] + QUAD8_REG_CHAN_OP
);
1334 /* Register IIO device */
1335 err
= devm_iio_device_register(dev
, indio_dev
);
1339 /* Register Counter device */
1340 return devm_counter_register(dev
, &quad8iio
->counter
);
1343 static struct isa_driver quad8_driver
= {
1344 .probe
= quad8_probe
,
1346 .name
= "104-quad-8"
1350 module_isa_driver(quad8_driver
, num_quad8
);
1352 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
1353 MODULE_DESCRIPTION("ACCES 104-QUAD-8 IIO driver");
1354 MODULE_LICENSE("GPL v2");