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, enum counter_signal_value *val) 566 { 567 const struct quad8_iio *const priv = counter->priv; 568 unsigned int state; 569 570 /* Only Index signal levels can be read */ 571 if (signal->id < 16) 572 return -EINVAL; 573 574 state = inb(priv->base + QUAD8_REG_INDEX_INPUT_LEVELS) 575 & BIT(signal->id - 16); 576 577 *val = (state) ? COUNTER_SIGNAL_HIGH : COUNTER_SIGNAL_LOW; 578 579 return 0; 580 } 581 582 static int quad8_count_read(struct counter_device *counter, 583 struct counter_count *count, unsigned long *val) 584 { 585 const struct quad8_iio *const priv = counter->priv; 586 const int base_offset = priv->base + 2 * count->id; 587 unsigned int flags; 588 unsigned int borrow; 589 unsigned int carry; 590 int i; 591 592 flags = inb(base_offset + 1); 593 borrow = flags & QUAD8_FLAG_BT; 594 carry = !!(flags & QUAD8_FLAG_CT); 595 596 /* Borrow XOR Carry effectively doubles count range */ 597 *val = (unsigned long)(borrow ^ carry) << 24; 598 599 /* Reset Byte Pointer; transfer Counter to Output Latch */ 600 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT, 601 base_offset + 1); 602 603 for (i = 0; i < 3; i++) 604 *val |= (unsigned long)inb(base_offset) << (8 * i); 605 606 return 0; 607 } 608 609 static int quad8_count_write(struct counter_device *counter, 610 struct counter_count *count, unsigned long val) 611 { 612 const struct quad8_iio *const priv = counter->priv; 613 const int base_offset = priv->base + 2 * count->id; 614 int i; 615 616 /* Only 24-bit values are supported */ 617 if (val > 0xFFFFFF) 618 return -EINVAL; 619 620 /* Reset Byte Pointer */ 621 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 622 623 /* Counter can only be set via Preset Register */ 624 for (i = 0; i < 3; i++) 625 outb(val >> (8 * i), base_offset); 626 627 /* Transfer Preset Register to Counter */ 628 outb(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, base_offset + 1); 629 630 /* Reset Byte Pointer */ 631 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 632 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); 637 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); 642 643 return 0; 644 } 645 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 651 }; 652 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 658 }; 659 660 static int quad8_function_get(struct counter_device *counter, 661 struct counter_count *count, size_t *function) 662 { 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]; 667 668 if (quadrature_mode) 669 switch (scale) { 670 case 0: 671 *function = QUAD8_COUNT_FUNCTION_QUADRATURE_X1; 672 break; 673 case 1: 674 *function = QUAD8_COUNT_FUNCTION_QUADRATURE_X2; 675 break; 676 case 2: 677 *function = QUAD8_COUNT_FUNCTION_QUADRATURE_X4; 678 break; 679 } 680 else 681 *function = QUAD8_COUNT_FUNCTION_PULSE_DIRECTION; 682 683 return 0; 684 } 685 686 static int quad8_function_set(struct counter_device *counter, 687 struct counter_count *count, size_t function) 688 { 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; 697 698 if (function == QUAD8_COUNT_FUNCTION_PULSE_DIRECTION) { 699 *quadrature_mode = 0; 700 701 /* Quadrature scaling only available in quadrature mode */ 702 *scale = 0; 703 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); 709 } 710 } else { 711 *quadrature_mode = 1; 712 713 switch (function) { 714 case QUAD8_COUNT_FUNCTION_QUADRATURE_X1: 715 *scale = 0; 716 mode_cfg |= QUAD8_CMR_QUADRATURE_X1; 717 break; 718 case QUAD8_COUNT_FUNCTION_QUADRATURE_X2: 719 *scale = 1; 720 mode_cfg |= QUAD8_CMR_QUADRATURE_X2; 721 break; 722 case QUAD8_COUNT_FUNCTION_QUADRATURE_X4: 723 *scale = 2; 724 mode_cfg |= QUAD8_CMR_QUADRATURE_X4; 725 break; 726 } 727 } 728 729 /* Load mode configuration to Counter Mode Register */ 730 outb(QUAD8_CTR_CMR | mode_cfg, base_offset); 731 732 return 0; 733 } 734 735 static void quad8_direction_get(struct counter_device *counter, 736 struct counter_count *count, enum counter_count_direction *direction) 737 { 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; 741 742 /* U/D flag: nonzero = up, zero = down */ 743 ud_flag = inb(flag_addr) & QUAD8_FLAG_UD; 744 745 *direction = (ud_flag) ? COUNTER_COUNT_DIRECTION_FORWARD : 746 COUNTER_COUNT_DIRECTION_BACKWARD; 747 } 748 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 754 }; 755 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 759 }; 760 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 766 }; 767 768 static int quad8_action_get(struct counter_device *counter, 769 struct counter_count *count, struct counter_synapse *synapse, 770 size_t *action) 771 { 772 struct quad8_iio *const priv = counter->priv; 773 int err; 774 size_t function = 0; 775 const size_t signal_a_id = count->synapses[0].signal->id; 776 enum counter_count_direction direction; 777 778 /* Handle Index signals */ 779 if (synapse->signal->id >= 16) { 780 if (priv->preset_enable[count->id]) 781 *action = QUAD8_SYNAPSE_ACTION_RISING_EDGE; 782 else 783 *action = QUAD8_SYNAPSE_ACTION_NONE; 784 785 return 0; 786 } 787 788 err = quad8_function_get(counter, count, &function); 789 if (err) 790 return err; 791 792 /* Default action mode */ 793 *action = QUAD8_SYNAPSE_ACTION_NONE; 794 795 /* Determine action mode based on current count function mode */ 796 switch (function) { 797 case QUAD8_COUNT_FUNCTION_PULSE_DIRECTION: 798 if (synapse->signal->id == signal_a_id) 799 *action = QUAD8_SYNAPSE_ACTION_RISING_EDGE; 800 break; 801 case QUAD8_COUNT_FUNCTION_QUADRATURE_X1: 802 if (synapse->signal->id == signal_a_id) { 803 quad8_direction_get(counter, count, &direction); 804 805 if (direction == COUNTER_COUNT_DIRECTION_FORWARD) 806 *action = QUAD8_SYNAPSE_ACTION_RISING_EDGE; 807 else 808 *action = QUAD8_SYNAPSE_ACTION_FALLING_EDGE; 809 } 810 break; 811 case QUAD8_COUNT_FUNCTION_QUADRATURE_X2: 812 if (synapse->signal->id == signal_a_id) 813 *action = QUAD8_SYNAPSE_ACTION_BOTH_EDGES; 814 break; 815 case QUAD8_COUNT_FUNCTION_QUADRATURE_X4: 816 *action = QUAD8_SYNAPSE_ACTION_BOTH_EDGES; 817 break; 818 } 819 820 return 0; 821 } 822 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 830 }; 831 832 static int quad8_index_polarity_get(struct counter_device *counter, 833 struct counter_signal *signal, size_t *index_polarity) 834 { 835 const struct quad8_iio *const priv = counter->priv; 836 const size_t channel_id = signal->id - 16; 837 838 *index_polarity = priv->index_polarity[channel_id]; 839 840 return 0; 841 } 842 843 static int quad8_index_polarity_set(struct counter_device *counter, 844 struct counter_signal *signal, size_t index_polarity) 845 { 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] | 849 index_polarity << 1; 850 const int base_offset = priv->base + 2 * channel_id + 1; 851 852 priv->index_polarity[channel_id] = index_polarity; 853 854 /* Load Index Control configuration to Index Control Register */ 855 outb(QUAD8_CTR_IDR | idr_cfg, base_offset); 856 857 return 0; 858 } 859 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 865 }; 866 867 static int quad8_synchronous_mode_get(struct counter_device *counter, 868 struct counter_signal *signal, size_t *synchronous_mode) 869 { 870 const struct quad8_iio *const priv = counter->priv; 871 const size_t channel_id = signal->id - 16; 872 873 *synchronous_mode = priv->synchronous_mode[channel_id]; 874 875 return 0; 876 } 877 878 static int quad8_synchronous_mode_set(struct counter_device *counter, 879 struct counter_signal *signal, size_t synchronous_mode) 880 { 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; 886 887 /* Index function must be non-synchronous in non-quadrature mode */ 888 if (synchronous_mode && !priv->quadrature_mode[channel_id]) 889 return -EINVAL; 890 891 priv->synchronous_mode[channel_id] = synchronous_mode; 892 893 /* Load Index Control configuration to Index Control Register */ 894 outb(QUAD8_CTR_IDR | idr_cfg, base_offset); 895 896 return 0; 897 } 898 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 904 }; 905 906 static ssize_t quad8_count_floor_read(struct counter_device *counter, 907 struct counter_count *count, void *private, char *buf) 908 { 909 /* Only a floor of 0 is supported */ 910 return sprintf(buf, "0\n"); 911 } 912 913 static int quad8_count_mode_get(struct counter_device *counter, 914 struct counter_count *count, size_t *cnt_mode) 915 { 916 const struct quad8_iio *const priv = counter->priv; 917 918 /* Map 104-QUAD-8 count mode to Generic Counter count mode */ 919 switch (priv->count_mode[count->id]) { 920 case 0: 921 *cnt_mode = COUNTER_COUNT_MODE_NORMAL; 922 break; 923 case 1: 924 *cnt_mode = COUNTER_COUNT_MODE_RANGE_LIMIT; 925 break; 926 case 2: 927 *cnt_mode = COUNTER_COUNT_MODE_NON_RECYCLE; 928 break; 929 case 3: 930 *cnt_mode = COUNTER_COUNT_MODE_MODULO_N; 931 break; 932 } 933 934 return 0; 935 } 936 937 static int quad8_count_mode_set(struct counter_device *counter, 938 struct counter_count *count, size_t cnt_mode) 939 { 940 struct quad8_iio *const priv = counter->priv; 941 unsigned int mode_cfg; 942 const int base_offset = priv->base + 2 * count->id + 1; 943 944 /* Map Generic Counter count mode to 104-QUAD-8 count mode */ 945 switch (cnt_mode) { 946 case COUNTER_COUNT_MODE_NORMAL: 947 cnt_mode = 0; 948 break; 949 case COUNTER_COUNT_MODE_RANGE_LIMIT: 950 cnt_mode = 1; 951 break; 952 case COUNTER_COUNT_MODE_NON_RECYCLE: 953 cnt_mode = 2; 954 break; 955 case COUNTER_COUNT_MODE_MODULO_N: 956 cnt_mode = 3; 957 break; 958 } 959 960 priv->count_mode[count->id] = cnt_mode; 961 962 /* Set count mode configuration value */ 963 mode_cfg = cnt_mode << 1; 964 965 /* Add quadrature mode configuration */ 966 if (priv->quadrature_mode[count->id]) 967 mode_cfg |= (priv->quadrature_scale[count->id] + 1) << 3; 968 969 /* Load mode configuration to Counter Mode Register */ 970 outb(QUAD8_CTR_CMR | mode_cfg, base_offset); 971 972 return 0; 973 } 974 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 980 }; 981 982 static ssize_t quad8_count_direction_read(struct counter_device *counter, 983 struct counter_count *count, void *priv, char *buf) 984 { 985 enum counter_count_direction dir; 986 987 quad8_direction_get(counter, count, &dir); 988 989 return sprintf(buf, "%s\n", counter_count_direction_str[dir]); 990 } 991 992 static ssize_t quad8_count_enable_read(struct counter_device *counter, 993 struct counter_count *count, void *private, char *buf) 994 { 995 const struct quad8_iio *const priv = counter->priv; 996 997 return sprintf(buf, "%u\n", priv->ab_enable[count->id]); 998 } 999 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) 1002 { 1003 struct quad8_iio *const priv = counter->priv; 1004 const int base_offset = priv->base + 2 * count->id; 1005 int err; 1006 bool ab_enable; 1007 unsigned int ior_cfg; 1008 1009 err = kstrtobool(buf, &ab_enable); 1010 if (err) 1011 return err; 1012 1013 priv->ab_enable[count->id] = ab_enable; 1014 1015 ior_cfg = ab_enable | priv->preset_enable[count->id] << 1; 1016 1017 /* Load I/O control configuration */ 1018 outb(QUAD8_CTR_IOR | ior_cfg, base_offset + 1); 1019 1020 return len; 1021 } 1022 1023 static int quad8_error_noise_get(struct counter_device *counter, 1024 struct counter_count *count, size_t *noise_error) 1025 { 1026 const struct quad8_iio *const priv = counter->priv; 1027 const int base_offset = priv->base + 2 * count->id + 1; 1028 1029 *noise_error = !!(inb(base_offset) & QUAD8_FLAG_E); 1030 1031 return 0; 1032 } 1033 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 1038 }; 1039 1040 static ssize_t quad8_count_preset_read(struct counter_device *counter, 1041 struct counter_count *count, void *private, char *buf) 1042 { 1043 const struct quad8_iio *const priv = counter->priv; 1044 1045 return sprintf(buf, "%u\n", priv->preset[count->id]); 1046 } 1047 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) 1050 { 1051 struct quad8_iio *const priv = counter->priv; 1052 const int base_offset = priv->base + 2 * count->id; 1053 unsigned int preset; 1054 int ret; 1055 int i; 1056 1057 ret = kstrtouint(buf, 0, &preset); 1058 if (ret) 1059 return ret; 1060 1061 /* Only 24-bit values are supported */ 1062 if (preset > 0xFFFFFF) 1063 return -EINVAL; 1064 1065 priv->preset[count->id] = preset; 1066 1067 /* Reset Byte Pointer */ 1068 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 1069 1070 /* Set Preset Register */ 1071 for (i = 0; i < 3; i++) 1072 outb(preset >> (8 * i), base_offset); 1073 1074 return len; 1075 } 1076 1077 static ssize_t quad8_count_ceiling_read(struct counter_device *counter, 1078 struct counter_count *count, void *private, char *buf) 1079 { 1080 const struct quad8_iio *const priv = counter->priv; 1081 1082 /* Range Limit and Modulo-N count modes use preset value as ceiling */ 1083 switch (priv->count_mode[count->id]) { 1084 case 1: 1085 case 3: 1086 return quad8_count_preset_read(counter, count, private, buf); 1087 } 1088 1089 /* By default 0x1FFFFFF (25 bits unsigned) is maximum count */ 1090 return sprintf(buf, "33554431\n"); 1091 } 1092 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) 1095 { 1096 struct quad8_iio *const priv = counter->priv; 1097 1098 /* Range Limit and Modulo-N count modes use preset value as ceiling */ 1099 switch (priv->count_mode[count->id]) { 1100 case 1: 1101 case 3: 1102 return quad8_count_preset_write(counter, count, private, buf, 1103 len); 1104 } 1105 1106 return len; 1107 } 1108 1109 static ssize_t quad8_count_preset_enable_read(struct counter_device *counter, 1110 struct counter_count *count, void *private, char *buf) 1111 { 1112 const struct quad8_iio *const priv = counter->priv; 1113 1114 return sprintf(buf, "%u\n", !priv->preset_enable[count->id]); 1115 } 1116 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) 1119 { 1120 struct quad8_iio *const priv = counter->priv; 1121 const int base_offset = priv->base + 2 * count->id + 1; 1122 bool preset_enable; 1123 int ret; 1124 unsigned int ior_cfg; 1125 1126 ret = kstrtobool(buf, &preset_enable); 1127 if (ret) 1128 return ret; 1129 1130 /* Preset enable is active low in Input/Output Control register */ 1131 preset_enable = !preset_enable; 1132 1133 priv->preset_enable[count->id] = preset_enable; 1134 1135 ior_cfg = priv->ab_enable[count->id] | (unsigned int)preset_enable << 1; 1136 1137 /* Load I/O control configuration to Input / Output Control Register */ 1138 outb(QUAD8_CTR_IOR | ior_cfg, base_offset); 1139 1140 return len; 1141 } 1142 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) 1148 }; 1149 1150 #define QUAD8_QUAD_SIGNAL(_id, _name) { \ 1151 .id = (_id), \ 1152 .name = (_name) \ 1153 } 1154 1155 #define QUAD8_INDEX_SIGNAL(_id, _name) { \ 1156 .id = (_id), \ 1157 .name = (_name), \ 1158 .ext = quad8_index_ext, \ 1159 .num_ext = ARRAY_SIZE(quad8_index_ext) \ 1160 } 1161 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") 1187 }; 1188 1189 #define QUAD8_COUNT_SYNAPSES(_id) { \ 1190 { \ 1191 .actions_list = quad8_synapse_actions_list, \ 1192 .num_actions = ARRAY_SIZE(quad8_synapse_actions_list), \ 1193 .signal = quad8_signals + 2 * (_id) \ 1194 }, \ 1195 { \ 1196 .actions_list = quad8_synapse_actions_list, \ 1197 .num_actions = ARRAY_SIZE(quad8_synapse_actions_list), \ 1198 .signal = quad8_signals + 2 * (_id) + 1 \ 1199 }, \ 1200 { \ 1201 .actions_list = quad8_index_actions_list, \ 1202 .num_actions = ARRAY_SIZE(quad8_index_actions_list), \ 1203 .signal = quad8_signals + 2 * (_id) + 16 \ 1204 } \ 1205 } 1206 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) 1212 }; 1213 1214 static const struct counter_count_ext quad8_count_ext[] = { 1215 { 1216 .name = "ceiling", 1217 .read = quad8_count_ceiling_read, 1218 .write = quad8_count_ceiling_write 1219 }, 1220 { 1221 .name = "floor", 1222 .read = quad8_count_floor_read 1223 }, 1224 COUNTER_COUNT_ENUM("count_mode", &quad8_cnt_mode_enum), 1225 COUNTER_COUNT_ENUM_AVAILABLE("count_mode", &quad8_cnt_mode_enum), 1226 { 1227 .name = "direction", 1228 .read = quad8_count_direction_read 1229 }, 1230 { 1231 .name = "enable", 1232 .read = quad8_count_enable_read, 1233 .write = quad8_count_enable_write 1234 }, 1235 COUNTER_COUNT_ENUM("error_noise", &quad8_error_noise_enum), 1236 COUNTER_COUNT_ENUM_AVAILABLE("error_noise", &quad8_error_noise_enum), 1237 { 1238 .name = "preset", 1239 .read = quad8_count_preset_read, 1240 .write = quad8_count_preset_write 1241 }, 1242 { 1243 .name = "preset_enable", 1244 .read = quad8_count_preset_enable_read, 1245 .write = quad8_count_preset_enable_write 1246 } 1247 }; 1248 1249 #define QUAD8_COUNT(_id, _cntname) { \ 1250 .id = (_id), \ 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) \ 1258 } 1259 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") 1269 }; 1270 1271 static int quad8_probe(struct device *dev, unsigned int id) 1272 { 1273 struct iio_dev *indio_dev; 1274 struct quad8_iio *quad8iio; 1275 int i, j; 1276 unsigned int base_offset; 1277 int err; 1278 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); 1282 return -EBUSY; 1283 } 1284 1285 /* Allocate IIO device; this also allocates driver data structure */ 1286 indio_dev = devm_iio_device_alloc(dev, sizeof(*quad8iio)); 1287 if (!indio_dev) 1288 return -ENOMEM; 1289 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; 1297 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]; 1309 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); 1330 } 1331 /* Enable all counters */ 1332 outb(QUAD8_CHAN_OP_ENABLE_COUNTERS, base[id] + QUAD8_REG_CHAN_OP); 1333 1334 /* Register IIO device */ 1335 err = devm_iio_device_register(dev, indio_dev); 1336 if (err) 1337 return err; 1338 1339 /* Register Counter device */ 1340 return devm_counter_register(dev, &quad8iio->counter); 1341 } 1342 1343 static struct isa_driver quad8_driver = { 1344 .probe = quad8_probe, 1345 .driver = { 1346 .name = "104-quad-8" 1347 } 1348 }; 1349 1350 module_isa_driver(quad8_driver, num_quad8); 1351 1352 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 1353 MODULE_DESCRIPTION("ACCES 104-QUAD-8 IIO driver"); 1354 MODULE_LICENSE("GPL v2"); 1355