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
, struct counter_signal_read_value
*val
)
567 const struct quad8_iio
*const priv
= counter
->priv
;
569 enum counter_signal_level level
;
571 /* Only Index signal levels can be read */
575 state
= inb(priv
->base
+ QUAD8_REG_INDEX_INPUT_LEVELS
)
576 & BIT(signal
->id
- 16);
578 level
= (state
) ? COUNTER_SIGNAL_LEVEL_HIGH
: COUNTER_SIGNAL_LEVEL_LOW
;
580 counter_signal_read_value_set(val
, COUNTER_SIGNAL_LEVEL
, &level
);
585 static int quad8_count_read(struct counter_device
*counter
,
586 struct counter_count
*count
, struct counter_count_read_value
*val
)
588 const struct quad8_iio
*const priv
= counter
->priv
;
589 const int base_offset
= priv
->base
+ 2 * count
->id
;
593 unsigned long position
;
596 flags
= inb(base_offset
+ 1);
597 borrow
= flags
& QUAD8_FLAG_BT
;
598 carry
= !!(flags
& QUAD8_FLAG_CT
);
600 /* Borrow XOR Carry effectively doubles count range */
601 position
= (unsigned long)(borrow
^ carry
) << 24;
603 /* Reset Byte Pointer; transfer Counter to Output Latch */
604 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
| QUAD8_RLD_CNTR_OUT
,
607 for (i
= 0; i
< 3; i
++)
608 position
|= (unsigned long)inb(base_offset
) << (8 * i
);
610 counter_count_read_value_set(val
, COUNTER_COUNT_POSITION
, &position
);
615 static int quad8_count_write(struct counter_device
*counter
,
616 struct counter_count
*count
, struct counter_count_write_value
*val
)
618 const struct quad8_iio
*const priv
= counter
->priv
;
619 const int base_offset
= priv
->base
+ 2 * count
->id
;
621 unsigned long position
;
624 err
= counter_count_write_value_get(&position
, COUNTER_COUNT_POSITION
,
629 /* Only 24-bit values are supported */
630 if (position
> 0xFFFFFF)
633 /* Reset Byte Pointer */
634 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
, base_offset
+ 1);
636 /* Counter can only be set via Preset Register */
637 for (i
= 0; i
< 3; i
++)
638 outb(position
>> (8 * i
), base_offset
);
640 /* Transfer Preset Register to Counter */
641 outb(QUAD8_CTR_RLD
| QUAD8_RLD_PRESET_CNTR
, base_offset
+ 1);
643 /* Reset Byte Pointer */
644 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
, base_offset
+ 1);
646 /* Set Preset Register back to original value */
647 position
= priv
->preset
[count
->id
];
648 for (i
= 0; i
< 3; i
++)
649 outb(position
>> (8 * i
), base_offset
);
651 /* Reset Borrow, Carry, Compare, and Sign flags */
652 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_FLAGS
, base_offset
+ 1);
653 /* Reset Error flag */
654 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_E
, base_offset
+ 1);
659 enum quad8_count_function
{
660 QUAD8_COUNT_FUNCTION_PULSE_DIRECTION
= 0,
661 QUAD8_COUNT_FUNCTION_QUADRATURE_X1
,
662 QUAD8_COUNT_FUNCTION_QUADRATURE_X2
,
663 QUAD8_COUNT_FUNCTION_QUADRATURE_X4
666 static enum counter_count_function quad8_count_functions_list
[] = {
667 [QUAD8_COUNT_FUNCTION_PULSE_DIRECTION
] = COUNTER_COUNT_FUNCTION_PULSE_DIRECTION
,
668 [QUAD8_COUNT_FUNCTION_QUADRATURE_X1
] = COUNTER_COUNT_FUNCTION_QUADRATURE_X1_A
,
669 [QUAD8_COUNT_FUNCTION_QUADRATURE_X2
] = COUNTER_COUNT_FUNCTION_QUADRATURE_X2_A
,
670 [QUAD8_COUNT_FUNCTION_QUADRATURE_X4
] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4
673 static int quad8_function_get(struct counter_device
*counter
,
674 struct counter_count
*count
, size_t *function
)
676 const struct quad8_iio
*const priv
= counter
->priv
;
677 const int id
= count
->id
;
678 const unsigned int quadrature_mode
= priv
->quadrature_mode
[id
];
679 const unsigned int scale
= priv
->quadrature_scale
[id
];
684 *function
= QUAD8_COUNT_FUNCTION_QUADRATURE_X1
;
687 *function
= QUAD8_COUNT_FUNCTION_QUADRATURE_X2
;
690 *function
= QUAD8_COUNT_FUNCTION_QUADRATURE_X4
;
694 *function
= QUAD8_COUNT_FUNCTION_PULSE_DIRECTION
;
699 static int quad8_function_set(struct counter_device
*counter
,
700 struct counter_count
*count
, size_t function
)
702 struct quad8_iio
*const priv
= counter
->priv
;
703 const int id
= count
->id
;
704 unsigned int *const quadrature_mode
= priv
->quadrature_mode
+ id
;
705 unsigned int *const scale
= priv
->quadrature_scale
+ id
;
706 unsigned int mode_cfg
= priv
->count_mode
[id
] << 1;
707 unsigned int *const synchronous_mode
= priv
->synchronous_mode
+ id
;
708 const unsigned int idr_cfg
= priv
->index_polarity
[id
] << 1;
709 const int base_offset
= priv
->base
+ 2 * id
+ 1;
711 if (function
== QUAD8_COUNT_FUNCTION_PULSE_DIRECTION
) {
712 *quadrature_mode
= 0;
714 /* Quadrature scaling only available in quadrature mode */
717 /* Synchronous function not supported in non-quadrature mode */
718 if (*synchronous_mode
) {
719 *synchronous_mode
= 0;
720 /* Disable synchronous function mode */
721 outb(QUAD8_CTR_IDR
| idr_cfg
, base_offset
);
724 *quadrature_mode
= 1;
727 case QUAD8_COUNT_FUNCTION_QUADRATURE_X1
:
729 mode_cfg
|= QUAD8_CMR_QUADRATURE_X1
;
731 case QUAD8_COUNT_FUNCTION_QUADRATURE_X2
:
733 mode_cfg
|= QUAD8_CMR_QUADRATURE_X2
;
735 case QUAD8_COUNT_FUNCTION_QUADRATURE_X4
:
737 mode_cfg
|= QUAD8_CMR_QUADRATURE_X4
;
742 /* Load mode configuration to Counter Mode Register */
743 outb(QUAD8_CTR_CMR
| mode_cfg
, base_offset
);
748 static void quad8_direction_get(struct counter_device
*counter
,
749 struct counter_count
*count
, enum counter_count_direction
*direction
)
751 const struct quad8_iio
*const priv
= counter
->priv
;
752 unsigned int ud_flag
;
753 const unsigned int flag_addr
= priv
->base
+ 2 * count
->id
+ 1;
755 /* U/D flag: nonzero = up, zero = down */
756 ud_flag
= inb(flag_addr
) & QUAD8_FLAG_UD
;
758 *direction
= (ud_flag
) ? COUNTER_COUNT_DIRECTION_FORWARD
:
759 COUNTER_COUNT_DIRECTION_BACKWARD
;
762 enum quad8_synapse_action
{
763 QUAD8_SYNAPSE_ACTION_NONE
= 0,
764 QUAD8_SYNAPSE_ACTION_RISING_EDGE
,
765 QUAD8_SYNAPSE_ACTION_FALLING_EDGE
,
766 QUAD8_SYNAPSE_ACTION_BOTH_EDGES
769 static enum counter_synapse_action quad8_index_actions_list
[] = {
770 [QUAD8_SYNAPSE_ACTION_NONE
] = COUNTER_SYNAPSE_ACTION_NONE
,
771 [QUAD8_SYNAPSE_ACTION_RISING_EDGE
] = COUNTER_SYNAPSE_ACTION_RISING_EDGE
774 static enum counter_synapse_action quad8_synapse_actions_list
[] = {
775 [QUAD8_SYNAPSE_ACTION_NONE
] = COUNTER_SYNAPSE_ACTION_NONE
,
776 [QUAD8_SYNAPSE_ACTION_RISING_EDGE
] = COUNTER_SYNAPSE_ACTION_RISING_EDGE
,
777 [QUAD8_SYNAPSE_ACTION_FALLING_EDGE
] = COUNTER_SYNAPSE_ACTION_FALLING_EDGE
,
778 [QUAD8_SYNAPSE_ACTION_BOTH_EDGES
] = COUNTER_SYNAPSE_ACTION_BOTH_EDGES
781 static int quad8_action_get(struct counter_device
*counter
,
782 struct counter_count
*count
, struct counter_synapse
*synapse
,
785 struct quad8_iio
*const priv
= counter
->priv
;
788 const size_t signal_a_id
= count
->synapses
[0].signal
->id
;
789 enum counter_count_direction direction
;
791 /* Handle Index signals */
792 if (synapse
->signal
->id
>= 16) {
793 if (priv
->preset_enable
[count
->id
])
794 *action
= QUAD8_SYNAPSE_ACTION_RISING_EDGE
;
796 *action
= QUAD8_SYNAPSE_ACTION_NONE
;
801 err
= quad8_function_get(counter
, count
, &function
);
805 /* Default action mode */
806 *action
= QUAD8_SYNAPSE_ACTION_NONE
;
808 /* Determine action mode based on current count function mode */
810 case QUAD8_COUNT_FUNCTION_PULSE_DIRECTION
:
811 if (synapse
->signal
->id
== signal_a_id
)
812 *action
= QUAD8_SYNAPSE_ACTION_RISING_EDGE
;
814 case QUAD8_COUNT_FUNCTION_QUADRATURE_X1
:
815 if (synapse
->signal
->id
== signal_a_id
) {
816 quad8_direction_get(counter
, count
, &direction
);
818 if (direction
== COUNTER_COUNT_DIRECTION_FORWARD
)
819 *action
= QUAD8_SYNAPSE_ACTION_RISING_EDGE
;
821 *action
= QUAD8_SYNAPSE_ACTION_FALLING_EDGE
;
824 case QUAD8_COUNT_FUNCTION_QUADRATURE_X2
:
825 if (synapse
->signal
->id
== signal_a_id
)
826 *action
= QUAD8_SYNAPSE_ACTION_BOTH_EDGES
;
828 case QUAD8_COUNT_FUNCTION_QUADRATURE_X4
:
829 *action
= QUAD8_SYNAPSE_ACTION_BOTH_EDGES
;
836 const struct counter_ops quad8_ops
= {
837 .signal_read
= quad8_signal_read
,
838 .count_read
= quad8_count_read
,
839 .count_write
= quad8_count_write
,
840 .function_get
= quad8_function_get
,
841 .function_set
= quad8_function_set
,
842 .action_get
= quad8_action_get
845 static int quad8_index_polarity_get(struct counter_device
*counter
,
846 struct counter_signal
*signal
, size_t *index_polarity
)
848 const struct quad8_iio
*const priv
= counter
->priv
;
849 const size_t channel_id
= signal
->id
- 16;
851 *index_polarity
= priv
->index_polarity
[channel_id
];
856 static int quad8_index_polarity_set(struct counter_device
*counter
,
857 struct counter_signal
*signal
, size_t index_polarity
)
859 struct quad8_iio
*const priv
= counter
->priv
;
860 const size_t channel_id
= signal
->id
- 16;
861 const unsigned int idr_cfg
= priv
->synchronous_mode
[channel_id
] |
863 const int base_offset
= priv
->base
+ 2 * channel_id
+ 1;
865 priv
->index_polarity
[channel_id
] = index_polarity
;
867 /* Load Index Control configuration to Index Control Register */
868 outb(QUAD8_CTR_IDR
| idr_cfg
, base_offset
);
873 static struct counter_signal_enum_ext quad8_index_pol_enum
= {
874 .items
= quad8_index_polarity_modes
,
875 .num_items
= ARRAY_SIZE(quad8_index_polarity_modes
),
876 .get
= quad8_index_polarity_get
,
877 .set
= quad8_index_polarity_set
880 static int quad8_synchronous_mode_get(struct counter_device
*counter
,
881 struct counter_signal
*signal
, size_t *synchronous_mode
)
883 const struct quad8_iio
*const priv
= counter
->priv
;
884 const size_t channel_id
= signal
->id
- 16;
886 *synchronous_mode
= priv
->synchronous_mode
[channel_id
];
891 static int quad8_synchronous_mode_set(struct counter_device
*counter
,
892 struct counter_signal
*signal
, size_t synchronous_mode
)
894 struct quad8_iio
*const priv
= counter
->priv
;
895 const size_t channel_id
= signal
->id
- 16;
896 const unsigned int idr_cfg
= synchronous_mode
|
897 priv
->index_polarity
[channel_id
] << 1;
898 const int base_offset
= priv
->base
+ 2 * channel_id
+ 1;
900 /* Index function must be non-synchronous in non-quadrature mode */
901 if (synchronous_mode
&& !priv
->quadrature_mode
[channel_id
])
904 priv
->synchronous_mode
[channel_id
] = synchronous_mode
;
906 /* Load Index Control configuration to Index Control Register */
907 outb(QUAD8_CTR_IDR
| idr_cfg
, base_offset
);
912 static struct counter_signal_enum_ext quad8_syn_mode_enum
= {
913 .items
= quad8_synchronous_modes
,
914 .num_items
= ARRAY_SIZE(quad8_synchronous_modes
),
915 .get
= quad8_synchronous_mode_get
,
916 .set
= quad8_synchronous_mode_set
919 static ssize_t
quad8_count_floor_read(struct counter_device
*counter
,
920 struct counter_count
*count
, void *private, char *buf
)
922 /* Only a floor of 0 is supported */
923 return sprintf(buf
, "0\n");
926 static int quad8_count_mode_get(struct counter_device
*counter
,
927 struct counter_count
*count
, size_t *cnt_mode
)
929 const struct quad8_iio
*const priv
= counter
->priv
;
931 /* Map 104-QUAD-8 count mode to Generic Counter count mode */
932 switch (priv
->count_mode
[count
->id
]) {
934 *cnt_mode
= COUNTER_COUNT_MODE_NORMAL
;
937 *cnt_mode
= COUNTER_COUNT_MODE_RANGE_LIMIT
;
940 *cnt_mode
= COUNTER_COUNT_MODE_NON_RECYCLE
;
943 *cnt_mode
= COUNTER_COUNT_MODE_MODULO_N
;
950 static int quad8_count_mode_set(struct counter_device
*counter
,
951 struct counter_count
*count
, size_t cnt_mode
)
953 struct quad8_iio
*const priv
= counter
->priv
;
954 unsigned int mode_cfg
;
955 const int base_offset
= priv
->base
+ 2 * count
->id
+ 1;
957 /* Map Generic Counter count mode to 104-QUAD-8 count mode */
959 case COUNTER_COUNT_MODE_NORMAL
:
962 case COUNTER_COUNT_MODE_RANGE_LIMIT
:
965 case COUNTER_COUNT_MODE_NON_RECYCLE
:
968 case COUNTER_COUNT_MODE_MODULO_N
:
973 priv
->count_mode
[count
->id
] = cnt_mode
;
975 /* Set count mode configuration value */
976 mode_cfg
= cnt_mode
<< 1;
978 /* Add quadrature mode configuration */
979 if (priv
->quadrature_mode
[count
->id
])
980 mode_cfg
|= (priv
->quadrature_scale
[count
->id
] + 1) << 3;
982 /* Load mode configuration to Counter Mode Register */
983 outb(QUAD8_CTR_CMR
| mode_cfg
, base_offset
);
988 static struct counter_count_enum_ext quad8_cnt_mode_enum
= {
989 .items
= counter_count_mode_str
,
990 .num_items
= ARRAY_SIZE(counter_count_mode_str
),
991 .get
= quad8_count_mode_get
,
992 .set
= quad8_count_mode_set
995 static ssize_t
quad8_count_direction_read(struct counter_device
*counter
,
996 struct counter_count
*count
, void *priv
, char *buf
)
998 enum counter_count_direction dir
;
1000 quad8_direction_get(counter
, count
, &dir
);
1002 return sprintf(buf
, "%s\n", counter_count_direction_str
[dir
]);
1005 static ssize_t
quad8_count_enable_read(struct counter_device
*counter
,
1006 struct counter_count
*count
, void *private, char *buf
)
1008 const struct quad8_iio
*const priv
= counter
->priv
;
1010 return sprintf(buf
, "%u\n", priv
->ab_enable
[count
->id
]);
1013 static ssize_t
quad8_count_enable_write(struct counter_device
*counter
,
1014 struct counter_count
*count
, void *private, const char *buf
, size_t len
)
1016 struct quad8_iio
*const priv
= counter
->priv
;
1017 const int base_offset
= priv
->base
+ 2 * count
->id
;
1020 unsigned int ior_cfg
;
1022 err
= kstrtobool(buf
, &ab_enable
);
1026 priv
->ab_enable
[count
->id
] = ab_enable
;
1028 ior_cfg
= ab_enable
| priv
->preset_enable
[count
->id
] << 1;
1030 /* Load I/O control configuration */
1031 outb(QUAD8_CTR_IOR
| ior_cfg
, base_offset
+ 1);
1036 static int quad8_error_noise_get(struct counter_device
*counter
,
1037 struct counter_count
*count
, size_t *noise_error
)
1039 const struct quad8_iio
*const priv
= counter
->priv
;
1040 const int base_offset
= priv
->base
+ 2 * count
->id
+ 1;
1042 *noise_error
= !!(inb(base_offset
) & QUAD8_FLAG_E
);
1047 static struct counter_count_enum_ext quad8_error_noise_enum
= {
1048 .items
= quad8_noise_error_states
,
1049 .num_items
= ARRAY_SIZE(quad8_noise_error_states
),
1050 .get
= quad8_error_noise_get
1053 static ssize_t
quad8_count_preset_read(struct counter_device
*counter
,
1054 struct counter_count
*count
, void *private, char *buf
)
1056 const struct quad8_iio
*const priv
= counter
->priv
;
1058 return sprintf(buf
, "%u\n", priv
->preset
[count
->id
]);
1061 static ssize_t
quad8_count_preset_write(struct counter_device
*counter
,
1062 struct counter_count
*count
, void *private, const char *buf
, size_t len
)
1064 struct quad8_iio
*const priv
= counter
->priv
;
1065 const int base_offset
= priv
->base
+ 2 * count
->id
;
1066 unsigned int preset
;
1070 ret
= kstrtouint(buf
, 0, &preset
);
1074 /* Only 24-bit values are supported */
1075 if (preset
> 0xFFFFFF)
1078 priv
->preset
[count
->id
] = preset
;
1080 /* Reset Byte Pointer */
1081 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
, base_offset
+ 1);
1083 /* Set Preset Register */
1084 for (i
= 0; i
< 3; i
++)
1085 outb(preset
>> (8 * i
), base_offset
);
1090 static ssize_t
quad8_count_ceiling_read(struct counter_device
*counter
,
1091 struct counter_count
*count
, void *private, char *buf
)
1093 const struct quad8_iio
*const priv
= counter
->priv
;
1095 /* Range Limit and Modulo-N count modes use preset value as ceiling */
1096 switch (priv
->count_mode
[count
->id
]) {
1099 return quad8_count_preset_read(counter
, count
, private, buf
);
1102 /* By default 0x1FFFFFF (25 bits unsigned) is maximum count */
1103 return sprintf(buf
, "33554431\n");
1106 static ssize_t
quad8_count_ceiling_write(struct counter_device
*counter
,
1107 struct counter_count
*count
, void *private, const char *buf
, size_t len
)
1109 struct quad8_iio
*const priv
= counter
->priv
;
1111 /* Range Limit and Modulo-N count modes use preset value as ceiling */
1112 switch (priv
->count_mode
[count
->id
]) {
1115 return quad8_count_preset_write(counter
, count
, private, buf
,
1122 static ssize_t
quad8_count_preset_enable_read(struct counter_device
*counter
,
1123 struct counter_count
*count
, void *private, char *buf
)
1125 const struct quad8_iio
*const priv
= counter
->priv
;
1127 return sprintf(buf
, "%u\n", !priv
->preset_enable
[count
->id
]);
1130 static ssize_t
quad8_count_preset_enable_write(struct counter_device
*counter
,
1131 struct counter_count
*count
, void *private, const char *buf
, size_t len
)
1133 struct quad8_iio
*const priv
= counter
->priv
;
1134 const int base_offset
= priv
->base
+ 2 * count
->id
+ 1;
1137 unsigned int ior_cfg
;
1139 ret
= kstrtobool(buf
, &preset_enable
);
1143 /* Preset enable is active low in Input/Output Control register */
1144 preset_enable
= !preset_enable
;
1146 priv
->preset_enable
[count
->id
] = preset_enable
;
1148 ior_cfg
= priv
->ab_enable
[count
->id
] | (unsigned int)preset_enable
<< 1;
1150 /* Load I/O control configuration to Input / Output Control Register */
1151 outb(QUAD8_CTR_IOR
| ior_cfg
, base_offset
);
1156 static const struct counter_signal_ext quad8_index_ext
[] = {
1157 COUNTER_SIGNAL_ENUM("index_polarity", &quad8_index_pol_enum
),
1158 COUNTER_SIGNAL_ENUM_AVAILABLE("index_polarity", &quad8_index_pol_enum
),
1159 COUNTER_SIGNAL_ENUM("synchronous_mode", &quad8_syn_mode_enum
),
1160 COUNTER_SIGNAL_ENUM_AVAILABLE("synchronous_mode", &quad8_syn_mode_enum
)
1163 #define QUAD8_QUAD_SIGNAL(_id, _name) { \
1168 #define QUAD8_INDEX_SIGNAL(_id, _name) { \
1171 .ext = quad8_index_ext, \
1172 .num_ext = ARRAY_SIZE(quad8_index_ext) \
1175 static struct counter_signal quad8_signals
[] = {
1176 QUAD8_QUAD_SIGNAL(0, "Channel 1 Quadrature A"),
1177 QUAD8_QUAD_SIGNAL(1, "Channel 1 Quadrature B"),
1178 QUAD8_QUAD_SIGNAL(2, "Channel 2 Quadrature A"),
1179 QUAD8_QUAD_SIGNAL(3, "Channel 2 Quadrature B"),
1180 QUAD8_QUAD_SIGNAL(4, "Channel 3 Quadrature A"),
1181 QUAD8_QUAD_SIGNAL(5, "Channel 3 Quadrature B"),
1182 QUAD8_QUAD_SIGNAL(6, "Channel 4 Quadrature A"),
1183 QUAD8_QUAD_SIGNAL(7, "Channel 4 Quadrature B"),
1184 QUAD8_QUAD_SIGNAL(8, "Channel 5 Quadrature A"),
1185 QUAD8_QUAD_SIGNAL(9, "Channel 5 Quadrature B"),
1186 QUAD8_QUAD_SIGNAL(10, "Channel 6 Quadrature A"),
1187 QUAD8_QUAD_SIGNAL(11, "Channel 6 Quadrature B"),
1188 QUAD8_QUAD_SIGNAL(12, "Channel 7 Quadrature A"),
1189 QUAD8_QUAD_SIGNAL(13, "Channel 7 Quadrature B"),
1190 QUAD8_QUAD_SIGNAL(14, "Channel 8 Quadrature A"),
1191 QUAD8_QUAD_SIGNAL(15, "Channel 8 Quadrature B"),
1192 QUAD8_INDEX_SIGNAL(16, "Channel 1 Index"),
1193 QUAD8_INDEX_SIGNAL(17, "Channel 2 Index"),
1194 QUAD8_INDEX_SIGNAL(18, "Channel 3 Index"),
1195 QUAD8_INDEX_SIGNAL(19, "Channel 4 Index"),
1196 QUAD8_INDEX_SIGNAL(20, "Channel 5 Index"),
1197 QUAD8_INDEX_SIGNAL(21, "Channel 6 Index"),
1198 QUAD8_INDEX_SIGNAL(22, "Channel 7 Index"),
1199 QUAD8_INDEX_SIGNAL(23, "Channel 8 Index")
1202 #define QUAD8_COUNT_SYNAPSES(_id) { \
1204 .actions_list = quad8_synapse_actions_list, \
1205 .num_actions = ARRAY_SIZE(quad8_synapse_actions_list), \
1206 .signal = quad8_signals + 2 * (_id) \
1209 .actions_list = quad8_synapse_actions_list, \
1210 .num_actions = ARRAY_SIZE(quad8_synapse_actions_list), \
1211 .signal = quad8_signals + 2 * (_id) + 1 \
1214 .actions_list = quad8_index_actions_list, \
1215 .num_actions = ARRAY_SIZE(quad8_index_actions_list), \
1216 .signal = quad8_signals + 2 * (_id) + 16 \
1220 static struct counter_synapse quad8_count_synapses
[][3] = {
1221 QUAD8_COUNT_SYNAPSES(0), QUAD8_COUNT_SYNAPSES(1),
1222 QUAD8_COUNT_SYNAPSES(2), QUAD8_COUNT_SYNAPSES(3),
1223 QUAD8_COUNT_SYNAPSES(4), QUAD8_COUNT_SYNAPSES(5),
1224 QUAD8_COUNT_SYNAPSES(6), QUAD8_COUNT_SYNAPSES(7)
1227 static const struct counter_count_ext quad8_count_ext
[] = {
1230 .read
= quad8_count_ceiling_read
,
1231 .write
= quad8_count_ceiling_write
1235 .read
= quad8_count_floor_read
1237 COUNTER_COUNT_ENUM("count_mode", &quad8_cnt_mode_enum
),
1238 COUNTER_COUNT_ENUM_AVAILABLE("count_mode", &quad8_cnt_mode_enum
),
1240 .name
= "direction",
1241 .read
= quad8_count_direction_read
1245 .read
= quad8_count_enable_read
,
1246 .write
= quad8_count_enable_write
1248 COUNTER_COUNT_ENUM("error_noise", &quad8_error_noise_enum
),
1249 COUNTER_COUNT_ENUM_AVAILABLE("error_noise", &quad8_error_noise_enum
),
1252 .read
= quad8_count_preset_read
,
1253 .write
= quad8_count_preset_write
1256 .name
= "preset_enable",
1257 .read
= quad8_count_preset_enable_read
,
1258 .write
= quad8_count_preset_enable_write
1262 #define QUAD8_COUNT(_id, _cntname) { \
1264 .name = (_cntname), \
1265 .functions_list = quad8_count_functions_list, \
1266 .num_functions = ARRAY_SIZE(quad8_count_functions_list), \
1267 .synapses = quad8_count_synapses[(_id)], \
1268 .num_synapses = 2, \
1269 .ext = quad8_count_ext, \
1270 .num_ext = ARRAY_SIZE(quad8_count_ext) \
1273 static struct counter_count quad8_counts
[] = {
1274 QUAD8_COUNT(0, "Channel 1 Count"),
1275 QUAD8_COUNT(1, "Channel 2 Count"),
1276 QUAD8_COUNT(2, "Channel 3 Count"),
1277 QUAD8_COUNT(3, "Channel 4 Count"),
1278 QUAD8_COUNT(4, "Channel 5 Count"),
1279 QUAD8_COUNT(5, "Channel 6 Count"),
1280 QUAD8_COUNT(6, "Channel 7 Count"),
1281 QUAD8_COUNT(7, "Channel 8 Count")
1284 static int quad8_probe(struct device
*dev
, unsigned int id
)
1286 struct iio_dev
*indio_dev
;
1287 struct quad8_iio
*quad8iio
;
1289 unsigned int base_offset
;
1292 if (!devm_request_region(dev
, base
[id
], QUAD8_EXTENT
, dev_name(dev
))) {
1293 dev_err(dev
, "Unable to lock port addresses (0x%X-0x%X)\n",
1294 base
[id
], base
[id
] + QUAD8_EXTENT
);
1298 /* Allocate IIO device; this also allocates driver data structure */
1299 indio_dev
= devm_iio_device_alloc(dev
, sizeof(*quad8iio
));
1303 /* Initialize IIO device */
1304 indio_dev
->info
= &quad8_info
;
1305 indio_dev
->modes
= INDIO_DIRECT_MODE
;
1306 indio_dev
->num_channels
= ARRAY_SIZE(quad8_channels
);
1307 indio_dev
->channels
= quad8_channels
;
1308 indio_dev
->name
= dev_name(dev
);
1309 indio_dev
->dev
.parent
= dev
;
1311 /* Initialize Counter device and driver data */
1312 quad8iio
= iio_priv(indio_dev
);
1313 quad8iio
->counter
.name
= dev_name(dev
);
1314 quad8iio
->counter
.parent
= dev
;
1315 quad8iio
->counter
.ops
= &quad8_ops
;
1316 quad8iio
->counter
.counts
= quad8_counts
;
1317 quad8iio
->counter
.num_counts
= ARRAY_SIZE(quad8_counts
);
1318 quad8iio
->counter
.signals
= quad8_signals
;
1319 quad8iio
->counter
.num_signals
= ARRAY_SIZE(quad8_signals
);
1320 quad8iio
->counter
.priv
= quad8iio
;
1321 quad8iio
->base
= base
[id
];
1323 /* Reset all counters and disable interrupt function */
1324 outb(QUAD8_CHAN_OP_RESET_COUNTERS
, base
[id
] + QUAD8_REG_CHAN_OP
);
1325 /* Set initial configuration for all counters */
1326 for (i
= 0; i
< QUAD8_NUM_COUNTERS
; i
++) {
1327 base_offset
= base
[id
] + 2 * i
;
1328 /* Reset Byte Pointer */
1329 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_BP
, base_offset
+ 1);
1330 /* Reset Preset Register */
1331 for (j
= 0; j
< 3; j
++)
1332 outb(0x00, base_offset
);
1333 /* Reset Borrow, Carry, Compare, and Sign flags */
1334 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_FLAGS
, base_offset
+ 1);
1335 /* Reset Error flag */
1336 outb(QUAD8_CTR_RLD
| QUAD8_RLD_RESET_E
, base_offset
+ 1);
1337 /* Binary encoding; Normal count; non-quadrature mode */
1338 outb(QUAD8_CTR_CMR
, base_offset
+ 1);
1339 /* Disable A and B inputs; preset on index; FLG1 as Carry */
1340 outb(QUAD8_CTR_IOR
, base_offset
+ 1);
1341 /* Disable index function; negative index polarity */
1342 outb(QUAD8_CTR_IDR
, base_offset
+ 1);
1344 /* Enable all counters */
1345 outb(QUAD8_CHAN_OP_ENABLE_COUNTERS
, base
[id
] + QUAD8_REG_CHAN_OP
);
1347 /* Register IIO device */
1348 err
= devm_iio_device_register(dev
, indio_dev
);
1352 /* Register Counter device */
1353 return devm_counter_register(dev
, &quad8iio
->counter
);
1356 static struct isa_driver quad8_driver
= {
1357 .probe
= quad8_probe
,
1359 .name
= "104-quad-8"
1363 module_isa_driver(quad8_driver
, num_quad8
);
1365 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
1366 MODULE_DESCRIPTION("ACCES 104-QUAD-8 IIO driver");
1367 MODULE_LICENSE("GPL v2");