1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Counter driver for the ACCES 104-QUAD-8 4 * Copyright (C) 2016 William Breathitt Gray 5 * 6 * This driver supports the ACCES 104-QUAD-8 and ACCES 104-QUAD-4. 7 */ 8 #include <linux/bitops.h> 9 #include <linux/counter.h> 10 #include <linux/device.h> 11 #include <linux/errno.h> 12 #include <linux/iio/iio.h> 13 #include <linux/iio/types.h> 14 #include <linux/io.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> 21 22 #define QUAD8_EXTENT 32 23 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"); 28 29 #define QUAD8_NUM_COUNTERS 8 30 31 /** 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 43 */ 44 struct quad8_iio { 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]; 54 unsigned int base; 55 }; 56 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) 63 /* Error flag */ 64 #define QUAD8_FLAG_E BIT(4) 65 /* Up/Down flag */ 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 77 /* Reset Counter */ 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 92 93 94 static int quad8_read_raw(struct iio_dev *indio_dev, 95 struct iio_chan_spec const *chan, int *val, int *val2, long mask) 96 { 97 struct quad8_iio *const priv = iio_priv(indio_dev); 98 const int base_offset = priv->base + 2 * chan->channel; 99 unsigned int flags; 100 unsigned int borrow; 101 unsigned int carry; 102 int i; 103 104 switch (mask) { 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)); 109 return IIO_VAL_INT; 110 } 111 112 flags = inb(base_offset + 1); 113 borrow = flags & QUAD8_FLAG_BT; 114 carry = !!(flags & QUAD8_FLAG_CT); 115 116 /* Borrow XOR Carry effectively doubles count range */ 117 *val = (borrow ^ carry) << 24; 118 119 /* Reset Byte Pointer; transfer Counter to Output Latch */ 120 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT, 121 base_offset + 1); 122 123 for (i = 0; i < 3; i++) 124 *val |= (unsigned int)inb(base_offset) << (8 * i); 125 126 return IIO_VAL_INT; 127 case IIO_CHAN_INFO_ENABLE: 128 *val = priv->ab_enable[chan->channel]; 129 return IIO_VAL_INT; 130 case IIO_CHAN_INFO_SCALE: 131 *val = 1; 132 *val2 = priv->quadrature_scale[chan->channel]; 133 return IIO_VAL_FRACTIONAL_LOG2; 134 } 135 136 return -EINVAL; 137 } 138 139 static int quad8_write_raw(struct iio_dev *indio_dev, 140 struct iio_chan_spec const *chan, int val, int val2, long mask) 141 { 142 struct quad8_iio *const priv = iio_priv(indio_dev); 143 const int base_offset = priv->base + 2 * chan->channel; 144 int i; 145 unsigned int ior_cfg; 146 147 switch (mask) { 148 case IIO_CHAN_INFO_RAW: 149 if (chan->type == IIO_INDEX) 150 return -EINVAL; 151 152 /* Only 24-bit values are supported */ 153 if ((unsigned int)val > 0xFFFFFF) 154 return -EINVAL; 155 156 /* Reset Byte Pointer */ 157 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 158 159 /* Counter can only be set via Preset Register */ 160 for (i = 0; i < 3; i++) 161 outb(val >> (8 * i), base_offset); 162 163 /* Transfer Preset Register to Counter */ 164 outb(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, base_offset + 1); 165 166 /* Reset Byte Pointer */ 167 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 168 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); 173 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); 178 179 return 0; 180 case IIO_CHAN_INFO_ENABLE: 181 /* only boolean values accepted */ 182 if (val < 0 || val > 1) 183 return -EINVAL; 184 185 priv->ab_enable[chan->channel] = val; 186 187 ior_cfg = val | priv->preset_enable[chan->channel] << 1; 188 189 /* Load I/O control configuration */ 190 outb(QUAD8_CTR_IOR | ior_cfg, base_offset + 1); 191 192 return 0; 193 case IIO_CHAN_INFO_SCALE: 194 /* Quadrature scaling only available in quadrature mode */ 195 if (!priv->quadrature_mode[chan->channel] && (val2 || val != 1)) 196 return -EINVAL; 197 198 /* Only three gain states (1, 0.5, 0.25) */ 199 if (val == 1 && !val2) 200 priv->quadrature_scale[chan->channel] = 0; 201 else if (!val) 202 switch (val2) { 203 case 500000: 204 priv->quadrature_scale[chan->channel] = 1; 205 break; 206 case 250000: 207 priv->quadrature_scale[chan->channel] = 2; 208 break; 209 default: 210 return -EINVAL; 211 } 212 else 213 return -EINVAL; 214 215 return 0; 216 } 217 218 return -EINVAL; 219 } 220 221 static const struct iio_info quad8_info = { 222 .read_raw = quad8_read_raw, 223 .write_raw = quad8_write_raw 224 }; 225 226 static ssize_t quad8_read_preset(struct iio_dev *indio_dev, uintptr_t private, 227 const struct iio_chan_spec *chan, char *buf) 228 { 229 const struct quad8_iio *const priv = iio_priv(indio_dev); 230 231 return snprintf(buf, PAGE_SIZE, "%u\n", priv->preset[chan->channel]); 232 } 233 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) 236 { 237 struct quad8_iio *const priv = iio_priv(indio_dev); 238 const int base_offset = priv->base + 2 * chan->channel; 239 unsigned int preset; 240 int ret; 241 int i; 242 243 ret = kstrtouint(buf, 0, &preset); 244 if (ret) 245 return ret; 246 247 /* Only 24-bit values are supported */ 248 if (preset > 0xFFFFFF) 249 return -EINVAL; 250 251 priv->preset[chan->channel] = preset; 252 253 /* Reset Byte Pointer */ 254 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 255 256 /* Set Preset Register */ 257 for (i = 0; i < 3; i++) 258 outb(preset >> (8 * i), base_offset); 259 260 return len; 261 } 262 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) 265 { 266 const struct quad8_iio *const priv = iio_priv(indio_dev); 267 268 return snprintf(buf, PAGE_SIZE, "%u\n", 269 !priv->preset_enable[chan->channel]); 270 } 271 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, 274 size_t len) 275 { 276 struct quad8_iio *const priv = iio_priv(indio_dev); 277 const int base_offset = priv->base + 2 * chan->channel + 1; 278 bool preset_enable; 279 int ret; 280 unsigned int ior_cfg; 281 282 ret = kstrtobool(buf, &preset_enable); 283 if (ret) 284 return ret; 285 286 /* Preset enable is active low in Input/Output Control register */ 287 preset_enable = !preset_enable; 288 289 priv->preset_enable[chan->channel] = preset_enable; 290 291 ior_cfg = priv->ab_enable[chan->channel] | 292 (unsigned int)preset_enable << 1; 293 294 /* Load I/O control configuration to Input / Output Control Register */ 295 outb(QUAD8_CTR_IOR | ior_cfg, base_offset); 296 297 return len; 298 } 299 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" 303 }; 304 305 static int quad8_get_noise_error(struct iio_dev *indio_dev, 306 const struct iio_chan_spec *chan) 307 { 308 struct quad8_iio *const priv = iio_priv(indio_dev); 309 const int base_offset = priv->base + 2 * chan->channel + 1; 310 311 return !!(inb(base_offset) & QUAD8_FLAG_E); 312 } 313 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 318 }; 319 320 static const char *const quad8_count_direction_states[] = { 321 "down", 322 "up" 323 }; 324 325 static int quad8_get_count_direction(struct iio_dev *indio_dev, 326 const struct iio_chan_spec *chan) 327 { 328 struct quad8_iio *const priv = iio_priv(indio_dev); 329 const int base_offset = priv->base + 2 * chan->channel + 1; 330 331 return !!(inb(base_offset) & QUAD8_FLAG_UD); 332 } 333 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 338 }; 339 340 static const char *const quad8_count_modes[] = { 341 "normal", 342 "range limit", 343 "non-recycle", 344 "modulo-n" 345 }; 346 347 static int quad8_set_count_mode(struct iio_dev *indio_dev, 348 const struct iio_chan_spec *chan, unsigned int cnt_mode) 349 { 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; 353 354 priv->count_mode[chan->channel] = cnt_mode; 355 356 /* Add quadrature mode configuration */ 357 if (priv->quadrature_mode[chan->channel]) 358 mode_cfg |= (priv->quadrature_scale[chan->channel] + 1) << 3; 359 360 /* Load mode configuration to Counter Mode Register */ 361 outb(QUAD8_CTR_CMR | mode_cfg, base_offset); 362 363 return 0; 364 } 365 366 static int quad8_get_count_mode(struct iio_dev *indio_dev, 367 const struct iio_chan_spec *chan) 368 { 369 const struct quad8_iio *const priv = iio_priv(indio_dev); 370 371 return priv->count_mode[chan->channel]; 372 } 373 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 379 }; 380 381 static const char *const quad8_synchronous_modes[] = { 382 "non-synchronous", 383 "synchronous" 384 }; 385 386 static int quad8_set_synchronous_mode(struct iio_dev *indio_dev, 387 const struct iio_chan_spec *chan, unsigned int synchronous_mode) 388 { 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; 393 394 /* Index function must be non-synchronous in non-quadrature mode */ 395 if (synchronous_mode && !priv->quadrature_mode[chan->channel]) 396 return -EINVAL; 397 398 priv->synchronous_mode[chan->channel] = synchronous_mode; 399 400 /* Load Index Control configuration to Index Control Register */ 401 outb(QUAD8_CTR_IDR | idr_cfg, base_offset); 402 403 return 0; 404 } 405 406 static int quad8_get_synchronous_mode(struct iio_dev *indio_dev, 407 const struct iio_chan_spec *chan) 408 { 409 const struct quad8_iio *const priv = iio_priv(indio_dev); 410 411 return priv->synchronous_mode[chan->channel]; 412 } 413 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 419 }; 420 421 static const char *const quad8_quadrature_modes[] = { 422 "non-quadrature", 423 "quadrature" 424 }; 425 426 static int quad8_set_quadrature_mode(struct iio_dev *indio_dev, 427 const struct iio_chan_spec *chan, unsigned int quadrature_mode) 428 { 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; 432 433 if (quadrature_mode) 434 mode_cfg |= (priv->quadrature_scale[chan->channel] + 1) << 3; 435 else { 436 /* Quadrature scaling only available in quadrature mode */ 437 priv->quadrature_scale[chan->channel] = 0; 438 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); 442 } 443 444 priv->quadrature_mode[chan->channel] = quadrature_mode; 445 446 /* Load mode configuration to Counter Mode Register */ 447 outb(QUAD8_CTR_CMR | mode_cfg, base_offset); 448 449 return 0; 450 } 451 452 static int quad8_get_quadrature_mode(struct iio_dev *indio_dev, 453 const struct iio_chan_spec *chan) 454 { 455 const struct quad8_iio *const priv = iio_priv(indio_dev); 456 457 return priv->quadrature_mode[chan->channel]; 458 } 459 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 465 }; 466 467 static const char *const quad8_index_polarity_modes[] = { 468 "negative", 469 "positive" 470 }; 471 472 static int quad8_set_index_polarity(struct iio_dev *indio_dev, 473 const struct iio_chan_spec *chan, unsigned int index_polarity) 474 { 475 struct quad8_iio *const priv = iio_priv(indio_dev); 476 const unsigned int idr_cfg = priv->synchronous_mode[chan->channel] | 477 index_polarity << 1; 478 const int base_offset = priv->base + 2 * chan->channel + 1; 479 480 priv->index_polarity[chan->channel] = index_polarity; 481 482 /* Load Index Control configuration to Index Control Register */ 483 outb(QUAD8_CTR_IDR | idr_cfg, base_offset); 484 485 return 0; 486 } 487 488 static int quad8_get_index_polarity(struct iio_dev *indio_dev, 489 const struct iio_chan_spec *chan) 490 { 491 const struct quad8_iio *const priv = iio_priv(indio_dev); 492 493 return priv->index_polarity[chan->channel]; 494 } 495 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 501 }; 502 503 static const struct iio_chan_spec_ext_info quad8_count_ext_info[] = { 504 { 505 .name = "preset", 506 .shared = IIO_SEPARATE, 507 .read = quad8_read_preset, 508 .write = quad8_write_preset 509 }, 510 { 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 515 }, 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), 524 {} 525 }; 526 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), 533 {} 534 }; 535 536 #define QUAD8_COUNT_CHAN(_chan) { \ 537 .type = IIO_COUNT, \ 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, \ 542 .indexed = 1 \ 543 } 544 545 #define QUAD8_INDEX_CHAN(_chan) { \ 546 .type = IIO_INDEX, \ 547 .channel = (_chan), \ 548 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 549 .ext_info = quad8_index_ext_info, \ 550 .indexed = 1 \ 551 } 552 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) 562 }; 563 564 static int quad8_signal_read(struct counter_device *counter, 565 struct counter_signal *signal, struct counter_signal_read_value *val) 566 { 567 const struct quad8_iio *const priv = counter->priv; 568 unsigned int state; 569 enum counter_signal_level level; 570 571 /* Only Index signal levels can be read */ 572 if (signal->id < 16) 573 return -EINVAL; 574 575 state = inb(priv->base + QUAD8_REG_INDEX_INPUT_LEVELS) 576 & BIT(signal->id - 16); 577 578 level = (state) ? COUNTER_SIGNAL_LEVEL_HIGH : COUNTER_SIGNAL_LEVEL_LOW; 579 580 counter_signal_read_value_set(val, COUNTER_SIGNAL_LEVEL, &level); 581 582 return 0; 583 } 584 585 static int quad8_count_read(struct counter_device *counter, 586 struct counter_count *count, struct counter_count_read_value *val) 587 { 588 const struct quad8_iio *const priv = counter->priv; 589 const int base_offset = priv->base + 2 * count->id; 590 unsigned int flags; 591 unsigned int borrow; 592 unsigned int carry; 593 unsigned long position; 594 int i; 595 596 flags = inb(base_offset + 1); 597 borrow = flags & QUAD8_FLAG_BT; 598 carry = !!(flags & QUAD8_FLAG_CT); 599 600 /* Borrow XOR Carry effectively doubles count range */ 601 position = (unsigned long)(borrow ^ carry) << 24; 602 603 /* Reset Byte Pointer; transfer Counter to Output Latch */ 604 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT, 605 base_offset + 1); 606 607 for (i = 0; i < 3; i++) 608 position |= (unsigned long)inb(base_offset) << (8 * i); 609 610 counter_count_read_value_set(val, COUNTER_COUNT_POSITION, &position); 611 612 return 0; 613 } 614 615 static int quad8_count_write(struct counter_device *counter, 616 struct counter_count *count, struct counter_count_write_value *val) 617 { 618 const struct quad8_iio *const priv = counter->priv; 619 const int base_offset = priv->base + 2 * count->id; 620 int err; 621 unsigned long position; 622 int i; 623 624 err = counter_count_write_value_get(&position, COUNTER_COUNT_POSITION, 625 val); 626 if (err) 627 return err; 628 629 /* Only 24-bit values are supported */ 630 if (position > 0xFFFFFF) 631 return -EINVAL; 632 633 /* Reset Byte Pointer */ 634 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 635 636 /* Counter can only be set via Preset Register */ 637 for (i = 0; i < 3; i++) 638 outb(position >> (8 * i), base_offset); 639 640 /* Transfer Preset Register to Counter */ 641 outb(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, base_offset + 1); 642 643 /* Reset Byte Pointer */ 644 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 645 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); 650 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); 655 656 return 0; 657 } 658 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 664 }; 665 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 671 }; 672 673 static int quad8_function_get(struct counter_device *counter, 674 struct counter_count *count, size_t *function) 675 { 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]; 680 681 if (quadrature_mode) 682 switch (scale) { 683 case 0: 684 *function = QUAD8_COUNT_FUNCTION_QUADRATURE_X1; 685 break; 686 case 1: 687 *function = QUAD8_COUNT_FUNCTION_QUADRATURE_X2; 688 break; 689 case 2: 690 *function = QUAD8_COUNT_FUNCTION_QUADRATURE_X4; 691 break; 692 } 693 else 694 *function = QUAD8_COUNT_FUNCTION_PULSE_DIRECTION; 695 696 return 0; 697 } 698 699 static int quad8_function_set(struct counter_device *counter, 700 struct counter_count *count, size_t function) 701 { 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; 710 711 if (function == QUAD8_COUNT_FUNCTION_PULSE_DIRECTION) { 712 *quadrature_mode = 0; 713 714 /* Quadrature scaling only available in quadrature mode */ 715 *scale = 0; 716 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); 722 } 723 } else { 724 *quadrature_mode = 1; 725 726 switch (function) { 727 case QUAD8_COUNT_FUNCTION_QUADRATURE_X1: 728 *scale = 0; 729 mode_cfg |= QUAD8_CMR_QUADRATURE_X1; 730 break; 731 case QUAD8_COUNT_FUNCTION_QUADRATURE_X2: 732 *scale = 1; 733 mode_cfg |= QUAD8_CMR_QUADRATURE_X2; 734 break; 735 case QUAD8_COUNT_FUNCTION_QUADRATURE_X4: 736 *scale = 2; 737 mode_cfg |= QUAD8_CMR_QUADRATURE_X4; 738 break; 739 } 740 } 741 742 /* Load mode configuration to Counter Mode Register */ 743 outb(QUAD8_CTR_CMR | mode_cfg, base_offset); 744 745 return 0; 746 } 747 748 static void quad8_direction_get(struct counter_device *counter, 749 struct counter_count *count, enum counter_count_direction *direction) 750 { 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; 754 755 /* U/D flag: nonzero = up, zero = down */ 756 ud_flag = inb(flag_addr) & QUAD8_FLAG_UD; 757 758 *direction = (ud_flag) ? COUNTER_COUNT_DIRECTION_FORWARD : 759 COUNTER_COUNT_DIRECTION_BACKWARD; 760 } 761 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 767 }; 768 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 772 }; 773 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 779 }; 780 781 static int quad8_action_get(struct counter_device *counter, 782 struct counter_count *count, struct counter_synapse *synapse, 783 size_t *action) 784 { 785 struct quad8_iio *const priv = counter->priv; 786 int err; 787 size_t function = 0; 788 const size_t signal_a_id = count->synapses[0].signal->id; 789 enum counter_count_direction direction; 790 791 /* Handle Index signals */ 792 if (synapse->signal->id >= 16) { 793 if (priv->preset_enable[count->id]) 794 *action = QUAD8_SYNAPSE_ACTION_RISING_EDGE; 795 else 796 *action = QUAD8_SYNAPSE_ACTION_NONE; 797 798 return 0; 799 } 800 801 err = quad8_function_get(counter, count, &function); 802 if (err) 803 return err; 804 805 /* Default action mode */ 806 *action = QUAD8_SYNAPSE_ACTION_NONE; 807 808 /* Determine action mode based on current count function mode */ 809 switch (function) { 810 case QUAD8_COUNT_FUNCTION_PULSE_DIRECTION: 811 if (synapse->signal->id == signal_a_id) 812 *action = QUAD8_SYNAPSE_ACTION_RISING_EDGE; 813 break; 814 case QUAD8_COUNT_FUNCTION_QUADRATURE_X1: 815 if (synapse->signal->id == signal_a_id) { 816 quad8_direction_get(counter, count, &direction); 817 818 if (direction == COUNTER_COUNT_DIRECTION_FORWARD) 819 *action = QUAD8_SYNAPSE_ACTION_RISING_EDGE; 820 else 821 *action = QUAD8_SYNAPSE_ACTION_FALLING_EDGE; 822 } 823 break; 824 case QUAD8_COUNT_FUNCTION_QUADRATURE_X2: 825 if (synapse->signal->id == signal_a_id) 826 *action = QUAD8_SYNAPSE_ACTION_BOTH_EDGES; 827 break; 828 case QUAD8_COUNT_FUNCTION_QUADRATURE_X4: 829 *action = QUAD8_SYNAPSE_ACTION_BOTH_EDGES; 830 break; 831 } 832 833 return 0; 834 } 835 836 static 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 843 }; 844 845 static int quad8_index_polarity_get(struct counter_device *counter, 846 struct counter_signal *signal, size_t *index_polarity) 847 { 848 const struct quad8_iio *const priv = counter->priv; 849 const size_t channel_id = signal->id - 16; 850 851 *index_polarity = priv->index_polarity[channel_id]; 852 853 return 0; 854 } 855 856 static int quad8_index_polarity_set(struct counter_device *counter, 857 struct counter_signal *signal, size_t index_polarity) 858 { 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] | 862 index_polarity << 1; 863 const int base_offset = priv->base + 2 * channel_id + 1; 864 865 priv->index_polarity[channel_id] = index_polarity; 866 867 /* Load Index Control configuration to Index Control Register */ 868 outb(QUAD8_CTR_IDR | idr_cfg, base_offset); 869 870 return 0; 871 } 872 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 878 }; 879 880 static int quad8_synchronous_mode_get(struct counter_device *counter, 881 struct counter_signal *signal, size_t *synchronous_mode) 882 { 883 const struct quad8_iio *const priv = counter->priv; 884 const size_t channel_id = signal->id - 16; 885 886 *synchronous_mode = priv->synchronous_mode[channel_id]; 887 888 return 0; 889 } 890 891 static int quad8_synchronous_mode_set(struct counter_device *counter, 892 struct counter_signal *signal, size_t synchronous_mode) 893 { 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; 899 900 /* Index function must be non-synchronous in non-quadrature mode */ 901 if (synchronous_mode && !priv->quadrature_mode[channel_id]) 902 return -EINVAL; 903 904 priv->synchronous_mode[channel_id] = synchronous_mode; 905 906 /* Load Index Control configuration to Index Control Register */ 907 outb(QUAD8_CTR_IDR | idr_cfg, base_offset); 908 909 return 0; 910 } 911 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 917 }; 918 919 static ssize_t quad8_count_floor_read(struct counter_device *counter, 920 struct counter_count *count, void *private, char *buf) 921 { 922 /* Only a floor of 0 is supported */ 923 return sprintf(buf, "0\n"); 924 } 925 926 static int quad8_count_mode_get(struct counter_device *counter, 927 struct counter_count *count, size_t *cnt_mode) 928 { 929 const struct quad8_iio *const priv = counter->priv; 930 931 /* Map 104-QUAD-8 count mode to Generic Counter count mode */ 932 switch (priv->count_mode[count->id]) { 933 case 0: 934 *cnt_mode = COUNTER_COUNT_MODE_NORMAL; 935 break; 936 case 1: 937 *cnt_mode = COUNTER_COUNT_MODE_RANGE_LIMIT; 938 break; 939 case 2: 940 *cnt_mode = COUNTER_COUNT_MODE_NON_RECYCLE; 941 break; 942 case 3: 943 *cnt_mode = COUNTER_COUNT_MODE_MODULO_N; 944 break; 945 } 946 947 return 0; 948 } 949 950 static int quad8_count_mode_set(struct counter_device *counter, 951 struct counter_count *count, size_t cnt_mode) 952 { 953 struct quad8_iio *const priv = counter->priv; 954 unsigned int mode_cfg; 955 const int base_offset = priv->base + 2 * count->id + 1; 956 957 /* Map Generic Counter count mode to 104-QUAD-8 count mode */ 958 switch (cnt_mode) { 959 case COUNTER_COUNT_MODE_NORMAL: 960 cnt_mode = 0; 961 break; 962 case COUNTER_COUNT_MODE_RANGE_LIMIT: 963 cnt_mode = 1; 964 break; 965 case COUNTER_COUNT_MODE_NON_RECYCLE: 966 cnt_mode = 2; 967 break; 968 case COUNTER_COUNT_MODE_MODULO_N: 969 cnt_mode = 3; 970 break; 971 } 972 973 priv->count_mode[count->id] = cnt_mode; 974 975 /* Set count mode configuration value */ 976 mode_cfg = cnt_mode << 1; 977 978 /* Add quadrature mode configuration */ 979 if (priv->quadrature_mode[count->id]) 980 mode_cfg |= (priv->quadrature_scale[count->id] + 1) << 3; 981 982 /* Load mode configuration to Counter Mode Register */ 983 outb(QUAD8_CTR_CMR | mode_cfg, base_offset); 984 985 return 0; 986 } 987 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 993 }; 994 995 static ssize_t quad8_count_direction_read(struct counter_device *counter, 996 struct counter_count *count, void *priv, char *buf) 997 { 998 enum counter_count_direction dir; 999 1000 quad8_direction_get(counter, count, &dir); 1001 1002 return sprintf(buf, "%s\n", counter_count_direction_str[dir]); 1003 } 1004 1005 static ssize_t quad8_count_enable_read(struct counter_device *counter, 1006 struct counter_count *count, void *private, char *buf) 1007 { 1008 const struct quad8_iio *const priv = counter->priv; 1009 1010 return sprintf(buf, "%u\n", priv->ab_enable[count->id]); 1011 } 1012 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) 1015 { 1016 struct quad8_iio *const priv = counter->priv; 1017 const int base_offset = priv->base + 2 * count->id; 1018 int err; 1019 bool ab_enable; 1020 unsigned int ior_cfg; 1021 1022 err = kstrtobool(buf, &ab_enable); 1023 if (err) 1024 return err; 1025 1026 priv->ab_enable[count->id] = ab_enable; 1027 1028 ior_cfg = ab_enable | priv->preset_enable[count->id] << 1; 1029 1030 /* Load I/O control configuration */ 1031 outb(QUAD8_CTR_IOR | ior_cfg, base_offset + 1); 1032 1033 return len; 1034 } 1035 1036 static int quad8_error_noise_get(struct counter_device *counter, 1037 struct counter_count *count, size_t *noise_error) 1038 { 1039 const struct quad8_iio *const priv = counter->priv; 1040 const int base_offset = priv->base + 2 * count->id + 1; 1041 1042 *noise_error = !!(inb(base_offset) & QUAD8_FLAG_E); 1043 1044 return 0; 1045 } 1046 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 1051 }; 1052 1053 static ssize_t quad8_count_preset_read(struct counter_device *counter, 1054 struct counter_count *count, void *private, char *buf) 1055 { 1056 const struct quad8_iio *const priv = counter->priv; 1057 1058 return sprintf(buf, "%u\n", priv->preset[count->id]); 1059 } 1060 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) 1063 { 1064 struct quad8_iio *const priv = counter->priv; 1065 const int base_offset = priv->base + 2 * count->id; 1066 unsigned int preset; 1067 int ret; 1068 int i; 1069 1070 ret = kstrtouint(buf, 0, &preset); 1071 if (ret) 1072 return ret; 1073 1074 /* Only 24-bit values are supported */ 1075 if (preset > 0xFFFFFF) 1076 return -EINVAL; 1077 1078 priv->preset[count->id] = preset; 1079 1080 /* Reset Byte Pointer */ 1081 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 1082 1083 /* Set Preset Register */ 1084 for (i = 0; i < 3; i++) 1085 outb(preset >> (8 * i), base_offset); 1086 1087 return len; 1088 } 1089 1090 static ssize_t quad8_count_ceiling_read(struct counter_device *counter, 1091 struct counter_count *count, void *private, char *buf) 1092 { 1093 const struct quad8_iio *const priv = counter->priv; 1094 1095 /* Range Limit and Modulo-N count modes use preset value as ceiling */ 1096 switch (priv->count_mode[count->id]) { 1097 case 1: 1098 case 3: 1099 return quad8_count_preset_read(counter, count, private, buf); 1100 } 1101 1102 /* By default 0x1FFFFFF (25 bits unsigned) is maximum count */ 1103 return sprintf(buf, "33554431\n"); 1104 } 1105 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) 1108 { 1109 struct quad8_iio *const priv = counter->priv; 1110 1111 /* Range Limit and Modulo-N count modes use preset value as ceiling */ 1112 switch (priv->count_mode[count->id]) { 1113 case 1: 1114 case 3: 1115 return quad8_count_preset_write(counter, count, private, buf, 1116 len); 1117 } 1118 1119 return len; 1120 } 1121 1122 static ssize_t quad8_count_preset_enable_read(struct counter_device *counter, 1123 struct counter_count *count, void *private, char *buf) 1124 { 1125 const struct quad8_iio *const priv = counter->priv; 1126 1127 return sprintf(buf, "%u\n", !priv->preset_enable[count->id]); 1128 } 1129 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) 1132 { 1133 struct quad8_iio *const priv = counter->priv; 1134 const int base_offset = priv->base + 2 * count->id + 1; 1135 bool preset_enable; 1136 int ret; 1137 unsigned int ior_cfg; 1138 1139 ret = kstrtobool(buf, &preset_enable); 1140 if (ret) 1141 return ret; 1142 1143 /* Preset enable is active low in Input/Output Control register */ 1144 preset_enable = !preset_enable; 1145 1146 priv->preset_enable[count->id] = preset_enable; 1147 1148 ior_cfg = priv->ab_enable[count->id] | (unsigned int)preset_enable << 1; 1149 1150 /* Load I/O control configuration to Input / Output Control Register */ 1151 outb(QUAD8_CTR_IOR | ior_cfg, base_offset); 1152 1153 return len; 1154 } 1155 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) 1161 }; 1162 1163 #define QUAD8_QUAD_SIGNAL(_id, _name) { \ 1164 .id = (_id), \ 1165 .name = (_name) \ 1166 } 1167 1168 #define QUAD8_INDEX_SIGNAL(_id, _name) { \ 1169 .id = (_id), \ 1170 .name = (_name), \ 1171 .ext = quad8_index_ext, \ 1172 .num_ext = ARRAY_SIZE(quad8_index_ext) \ 1173 } 1174 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") 1200 }; 1201 1202 #define QUAD8_COUNT_SYNAPSES(_id) { \ 1203 { \ 1204 .actions_list = quad8_synapse_actions_list, \ 1205 .num_actions = ARRAY_SIZE(quad8_synapse_actions_list), \ 1206 .signal = quad8_signals + 2 * (_id) \ 1207 }, \ 1208 { \ 1209 .actions_list = quad8_synapse_actions_list, \ 1210 .num_actions = ARRAY_SIZE(quad8_synapse_actions_list), \ 1211 .signal = quad8_signals + 2 * (_id) + 1 \ 1212 }, \ 1213 { \ 1214 .actions_list = quad8_index_actions_list, \ 1215 .num_actions = ARRAY_SIZE(quad8_index_actions_list), \ 1216 .signal = quad8_signals + 2 * (_id) + 16 \ 1217 } \ 1218 } 1219 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) 1225 }; 1226 1227 static const struct counter_count_ext quad8_count_ext[] = { 1228 { 1229 .name = "ceiling", 1230 .read = quad8_count_ceiling_read, 1231 .write = quad8_count_ceiling_write 1232 }, 1233 { 1234 .name = "floor", 1235 .read = quad8_count_floor_read 1236 }, 1237 COUNTER_COUNT_ENUM("count_mode", &quad8_cnt_mode_enum), 1238 COUNTER_COUNT_ENUM_AVAILABLE("count_mode", &quad8_cnt_mode_enum), 1239 { 1240 .name = "direction", 1241 .read = quad8_count_direction_read 1242 }, 1243 { 1244 .name = "enable", 1245 .read = quad8_count_enable_read, 1246 .write = quad8_count_enable_write 1247 }, 1248 COUNTER_COUNT_ENUM("error_noise", &quad8_error_noise_enum), 1249 COUNTER_COUNT_ENUM_AVAILABLE("error_noise", &quad8_error_noise_enum), 1250 { 1251 .name = "preset", 1252 .read = quad8_count_preset_read, 1253 .write = quad8_count_preset_write 1254 }, 1255 { 1256 .name = "preset_enable", 1257 .read = quad8_count_preset_enable_read, 1258 .write = quad8_count_preset_enable_write 1259 } 1260 }; 1261 1262 #define QUAD8_COUNT(_id, _cntname) { \ 1263 .id = (_id), \ 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) \ 1271 } 1272 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") 1282 }; 1283 1284 static int quad8_probe(struct device *dev, unsigned int id) 1285 { 1286 struct iio_dev *indio_dev; 1287 struct quad8_iio *quad8iio; 1288 int i, j; 1289 unsigned int base_offset; 1290 int err; 1291 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); 1295 return -EBUSY; 1296 } 1297 1298 /* Allocate IIO device; this also allocates driver data structure */ 1299 indio_dev = devm_iio_device_alloc(dev, sizeof(*quad8iio)); 1300 if (!indio_dev) 1301 return -ENOMEM; 1302 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; 1310 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]; 1322 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); 1343 } 1344 /* Enable all counters */ 1345 outb(QUAD8_CHAN_OP_ENABLE_COUNTERS, base[id] + QUAD8_REG_CHAN_OP); 1346 1347 /* Register IIO device */ 1348 err = devm_iio_device_register(dev, indio_dev); 1349 if (err) 1350 return err; 1351 1352 /* Register Counter device */ 1353 return devm_counter_register(dev, &quad8iio->counter); 1354 } 1355 1356 static struct isa_driver quad8_driver = { 1357 .probe = quad8_probe, 1358 .driver = { 1359 .name = "104-quad-8" 1360 } 1361 }; 1362 1363 module_isa_driver(quad8_driver, num_quad8); 1364 1365 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 1366 MODULE_DESCRIPTION("ACCES 104-QUAD-8 IIO driver"); 1367 MODULE_LICENSE("GPL v2"); 1368