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 24static unsigned int base[max_num_isa_dev(QUAD8_EXTENT)]; 25static unsigned int num_quad8; 26module_param_array(base, uint, &num_quad8, 0); 27MODULE_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 * @fck_prescaler: array of filter clock prescaler configurations 35 * @preset: array of preset values 36 * @count_mode: array of count mode configurations 37 * @quadrature_mode: array of quadrature mode configurations 38 * @quadrature_scale: array of quadrature mode scale configurations 39 * @ab_enable: array of A and B inputs enable configurations 40 * @preset_enable: array of set_to_preset_on_index attribute configurations 41 * @synchronous_mode: array of index function synchronous mode configurations 42 * @index_polarity: array of index function polarity configurations 43 * @cable_fault_enable: differential encoder cable status enable configurations 44 * @base: base port address of the IIO device 45 */ 46struct quad8_iio { 47 struct mutex lock; 48 struct counter_device counter; 49 unsigned int fck_prescaler[QUAD8_NUM_COUNTERS]; 50 unsigned int preset[QUAD8_NUM_COUNTERS]; 51 unsigned int count_mode[QUAD8_NUM_COUNTERS]; 52 unsigned int quadrature_mode[QUAD8_NUM_COUNTERS]; 53 unsigned int quadrature_scale[QUAD8_NUM_COUNTERS]; 54 unsigned int ab_enable[QUAD8_NUM_COUNTERS]; 55 unsigned int preset_enable[QUAD8_NUM_COUNTERS]; 56 unsigned int synchronous_mode[QUAD8_NUM_COUNTERS]; 57 unsigned int index_polarity[QUAD8_NUM_COUNTERS]; 58 unsigned int cable_fault_enable; 59 unsigned int base; 60}; 61 62#define QUAD8_REG_CHAN_OP 0x11 63#define QUAD8_REG_INDEX_INPUT_LEVELS 0x16 64#define QUAD8_DIFF_ENCODER_CABLE_STATUS 0x17 65/* Error flag */ 66#define QUAD8_FLAG_E BIT(4) 67/* Up/Down flag */ 68#define QUAD8_FLAG_UD BIT(5) 69/* Reset and Load Signal Decoders */ 70#define QUAD8_CTR_RLD 0x00 71/* Counter Mode Register */ 72#define QUAD8_CTR_CMR 0x20 73/* Input / Output Control Register */ 74#define QUAD8_CTR_IOR 0x40 75/* Index Control Register */ 76#define QUAD8_CTR_IDR 0x60 77/* Reset Byte Pointer (three byte data pointer) */ 78#define QUAD8_RLD_RESET_BP 0x01 79/* Reset Counter */ 80#define QUAD8_RLD_RESET_CNTR 0x02 81/* Reset Borrow Toggle, Carry Toggle, Compare Toggle, and Sign flags */ 82#define QUAD8_RLD_RESET_FLAGS 0x04 83/* Reset Error flag */ 84#define QUAD8_RLD_RESET_E 0x06 85/* Preset Register to Counter */ 86#define QUAD8_RLD_PRESET_CNTR 0x08 87/* Transfer Counter to Output Latch */ 88#define QUAD8_RLD_CNTR_OUT 0x10 89/* Transfer Preset Register LSB to FCK Prescaler */ 90#define QUAD8_RLD_PRESET_PSC 0x18 91#define QUAD8_CHAN_OP_ENABLE_COUNTERS 0x00 92#define QUAD8_CHAN_OP_RESET_COUNTERS 0x01 93#define QUAD8_CMR_QUADRATURE_X1 0x08 94#define QUAD8_CMR_QUADRATURE_X2 0x10 95#define QUAD8_CMR_QUADRATURE_X4 0x18 96 97 98static int quad8_read_raw(struct iio_dev *indio_dev, 99 struct iio_chan_spec const *chan, int *val, int *val2, long mask) 100{ 101 struct quad8_iio *const priv = iio_priv(indio_dev); 102 const int base_offset = priv->base + 2 * chan->channel; 103 int i; 104 105 switch (mask) { 106 case IIO_CHAN_INFO_RAW: 107 if (chan->type == IIO_INDEX) { 108 *val = !!(inb(priv->base + QUAD8_REG_INDEX_INPUT_LEVELS) 109 & BIT(chan->channel)); 110 return IIO_VAL_INT; 111 } 112 113 *val = 0; 114 115 mutex_lock(&priv->lock); 116 117 /* Reset Byte Pointer; transfer Counter to Output Latch */ 118 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT, 119 base_offset + 1); 120 121 for (i = 0; i < 3; i++) 122 *val |= (unsigned int)inb(base_offset) << (8 * i); 123 124 mutex_unlock(&priv->lock); 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 139static 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 mutex_lock(&priv->lock); 157 158 /* Reset Byte Pointer */ 159 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 160 161 /* Counter can only be set via Preset Register */ 162 for (i = 0; i < 3; i++) 163 outb(val >> (8 * i), base_offset); 164 165 /* Transfer Preset Register to Counter */ 166 outb(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, base_offset + 1); 167 168 /* Reset Byte Pointer */ 169 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 170 171 /* Set Preset Register back to original value */ 172 val = priv->preset[chan->channel]; 173 for (i = 0; i < 3; i++) 174 outb(val >> (8 * i), base_offset); 175 176 /* Reset Borrow, Carry, Compare, and Sign flags */ 177 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1); 178 /* Reset Error flag */ 179 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1); 180 181 mutex_unlock(&priv->lock); 182 183 return 0; 184 case IIO_CHAN_INFO_ENABLE: 185 /* only boolean values accepted */ 186 if (val < 0 || val > 1) 187 return -EINVAL; 188 189 mutex_lock(&priv->lock); 190 191 priv->ab_enable[chan->channel] = val; 192 193 ior_cfg = val | priv->preset_enable[chan->channel] << 1; 194 195 /* Load I/O control configuration */ 196 outb(QUAD8_CTR_IOR | ior_cfg, base_offset + 1); 197 198 mutex_unlock(&priv->lock); 199 200 return 0; 201 case IIO_CHAN_INFO_SCALE: 202 mutex_lock(&priv->lock); 203 204 /* Quadrature scaling only available in quadrature mode */ 205 if (!priv->quadrature_mode[chan->channel] && 206 (val2 || val != 1)) { 207 mutex_unlock(&priv->lock); 208 return -EINVAL; 209 } 210 211 /* Only three gain states (1, 0.5, 0.25) */ 212 if (val == 1 && !val2) 213 priv->quadrature_scale[chan->channel] = 0; 214 else if (!val) 215 switch (val2) { 216 case 500000: 217 priv->quadrature_scale[chan->channel] = 1; 218 break; 219 case 250000: 220 priv->quadrature_scale[chan->channel] = 2; 221 break; 222 default: 223 mutex_unlock(&priv->lock); 224 return -EINVAL; 225 } 226 else { 227 mutex_unlock(&priv->lock); 228 return -EINVAL; 229 } 230 231 mutex_unlock(&priv->lock); 232 return 0; 233 } 234 235 return -EINVAL; 236} 237 238static const struct iio_info quad8_info = { 239 .read_raw = quad8_read_raw, 240 .write_raw = quad8_write_raw 241}; 242 243static ssize_t quad8_read_preset(struct iio_dev *indio_dev, uintptr_t private, 244 const struct iio_chan_spec *chan, char *buf) 245{ 246 const struct quad8_iio *const priv = iio_priv(indio_dev); 247 248 return snprintf(buf, PAGE_SIZE, "%u\n", priv->preset[chan->channel]); 249} 250 251static ssize_t quad8_write_preset(struct iio_dev *indio_dev, uintptr_t private, 252 const struct iio_chan_spec *chan, const char *buf, size_t len) 253{ 254 struct quad8_iio *const priv = iio_priv(indio_dev); 255 const int base_offset = priv->base + 2 * chan->channel; 256 unsigned int preset; 257 int ret; 258 int i; 259 260 ret = kstrtouint(buf, 0, &preset); 261 if (ret) 262 return ret; 263 264 /* Only 24-bit values are supported */ 265 if (preset > 0xFFFFFF) 266 return -EINVAL; 267 268 mutex_lock(&priv->lock); 269 270 priv->preset[chan->channel] = preset; 271 272 /* Reset Byte Pointer */ 273 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 274 275 /* Set Preset Register */ 276 for (i = 0; i < 3; i++) 277 outb(preset >> (8 * i), base_offset); 278 279 mutex_unlock(&priv->lock); 280 281 return len; 282} 283 284static ssize_t quad8_read_set_to_preset_on_index(struct iio_dev *indio_dev, 285 uintptr_t private, const struct iio_chan_spec *chan, char *buf) 286{ 287 const struct quad8_iio *const priv = iio_priv(indio_dev); 288 289 return snprintf(buf, PAGE_SIZE, "%u\n", 290 !priv->preset_enable[chan->channel]); 291} 292 293static ssize_t quad8_write_set_to_preset_on_index(struct iio_dev *indio_dev, 294 uintptr_t private, const struct iio_chan_spec *chan, const char *buf, 295 size_t len) 296{ 297 struct quad8_iio *const priv = iio_priv(indio_dev); 298 const int base_offset = priv->base + 2 * chan->channel + 1; 299 bool preset_enable; 300 int ret; 301 unsigned int ior_cfg; 302 303 ret = kstrtobool(buf, &preset_enable); 304 if (ret) 305 return ret; 306 307 /* Preset enable is active low in Input/Output Control register */ 308 preset_enable = !preset_enable; 309 310 mutex_lock(&priv->lock); 311 312 priv->preset_enable[chan->channel] = preset_enable; 313 314 ior_cfg = priv->ab_enable[chan->channel] | 315 (unsigned int)preset_enable << 1; 316 317 /* Load I/O control configuration to Input / Output Control Register */ 318 outb(QUAD8_CTR_IOR | ior_cfg, base_offset); 319 320 mutex_unlock(&priv->lock); 321 322 return len; 323} 324 325static const char *const quad8_noise_error_states[] = { 326 "No excessive noise is present at the count inputs", 327 "Excessive noise is present at the count inputs" 328}; 329 330static int quad8_get_noise_error(struct iio_dev *indio_dev, 331 const struct iio_chan_spec *chan) 332{ 333 struct quad8_iio *const priv = iio_priv(indio_dev); 334 const int base_offset = priv->base + 2 * chan->channel + 1; 335 336 return !!(inb(base_offset) & QUAD8_FLAG_E); 337} 338 339static const struct iio_enum quad8_noise_error_enum = { 340 .items = quad8_noise_error_states, 341 .num_items = ARRAY_SIZE(quad8_noise_error_states), 342 .get = quad8_get_noise_error 343}; 344 345static const char *const quad8_count_direction_states[] = { 346 "down", 347 "up" 348}; 349 350static int quad8_get_count_direction(struct iio_dev *indio_dev, 351 const struct iio_chan_spec *chan) 352{ 353 struct quad8_iio *const priv = iio_priv(indio_dev); 354 const int base_offset = priv->base + 2 * chan->channel + 1; 355 356 return !!(inb(base_offset) & QUAD8_FLAG_UD); 357} 358 359static const struct iio_enum quad8_count_direction_enum = { 360 .items = quad8_count_direction_states, 361 .num_items = ARRAY_SIZE(quad8_count_direction_states), 362 .get = quad8_get_count_direction 363}; 364 365static const char *const quad8_count_modes[] = { 366 "normal", 367 "range limit", 368 "non-recycle", 369 "modulo-n" 370}; 371 372static int quad8_set_count_mode(struct iio_dev *indio_dev, 373 const struct iio_chan_spec *chan, unsigned int cnt_mode) 374{ 375 struct quad8_iio *const priv = iio_priv(indio_dev); 376 unsigned int mode_cfg = cnt_mode << 1; 377 const int base_offset = priv->base + 2 * chan->channel + 1; 378 379 mutex_lock(&priv->lock); 380 381 priv->count_mode[chan->channel] = cnt_mode; 382 383 /* Add quadrature mode configuration */ 384 if (priv->quadrature_mode[chan->channel]) 385 mode_cfg |= (priv->quadrature_scale[chan->channel] + 1) << 3; 386 387 /* Load mode configuration to Counter Mode Register */ 388 outb(QUAD8_CTR_CMR | mode_cfg, base_offset); 389 390 mutex_unlock(&priv->lock); 391 392 return 0; 393} 394 395static int quad8_get_count_mode(struct iio_dev *indio_dev, 396 const struct iio_chan_spec *chan) 397{ 398 const struct quad8_iio *const priv = iio_priv(indio_dev); 399 400 return priv->count_mode[chan->channel]; 401} 402 403static const struct iio_enum quad8_count_mode_enum = { 404 .items = quad8_count_modes, 405 .num_items = ARRAY_SIZE(quad8_count_modes), 406 .set = quad8_set_count_mode, 407 .get = quad8_get_count_mode 408}; 409 410static const char *const quad8_synchronous_modes[] = { 411 "non-synchronous", 412 "synchronous" 413}; 414 415static int quad8_set_synchronous_mode(struct iio_dev *indio_dev, 416 const struct iio_chan_spec *chan, unsigned int synchronous_mode) 417{ 418 struct quad8_iio *const priv = iio_priv(indio_dev); 419 const int base_offset = priv->base + 2 * chan->channel + 1; 420 unsigned int idr_cfg = synchronous_mode; 421 422 mutex_lock(&priv->lock); 423 424 idr_cfg |= priv->index_polarity[chan->channel] << 1; 425 426 /* Index function must be non-synchronous in non-quadrature mode */ 427 if (synchronous_mode && !priv->quadrature_mode[chan->channel]) { 428 mutex_unlock(&priv->lock); 429 return -EINVAL; 430 } 431 432 priv->synchronous_mode[chan->channel] = synchronous_mode; 433 434 /* Load Index Control configuration to Index Control Register */ 435 outb(QUAD8_CTR_IDR | idr_cfg, base_offset); 436 437 mutex_unlock(&priv->lock); 438 439 return 0; 440} 441 442static int quad8_get_synchronous_mode(struct iio_dev *indio_dev, 443 const struct iio_chan_spec *chan) 444{ 445 const struct quad8_iio *const priv = iio_priv(indio_dev); 446 447 return priv->synchronous_mode[chan->channel]; 448} 449 450static const struct iio_enum quad8_synchronous_mode_enum = { 451 .items = quad8_synchronous_modes, 452 .num_items = ARRAY_SIZE(quad8_synchronous_modes), 453 .set = quad8_set_synchronous_mode, 454 .get = quad8_get_synchronous_mode 455}; 456 457static const char *const quad8_quadrature_modes[] = { 458 "non-quadrature", 459 "quadrature" 460}; 461 462static int quad8_set_quadrature_mode(struct iio_dev *indio_dev, 463 const struct iio_chan_spec *chan, unsigned int quadrature_mode) 464{ 465 struct quad8_iio *const priv = iio_priv(indio_dev); 466 const int base_offset = priv->base + 2 * chan->channel + 1; 467 unsigned int mode_cfg; 468 469 mutex_lock(&priv->lock); 470 471 mode_cfg = priv->count_mode[chan->channel] << 1; 472 473 if (quadrature_mode) 474 mode_cfg |= (priv->quadrature_scale[chan->channel] + 1) << 3; 475 else { 476 /* Quadrature scaling only available in quadrature mode */ 477 priv->quadrature_scale[chan->channel] = 0; 478 479 /* Synchronous function not supported in non-quadrature mode */ 480 if (priv->synchronous_mode[chan->channel]) 481 quad8_set_synchronous_mode(indio_dev, chan, 0); 482 } 483 484 priv->quadrature_mode[chan->channel] = quadrature_mode; 485 486 /* Load mode configuration to Counter Mode Register */ 487 outb(QUAD8_CTR_CMR | mode_cfg, base_offset); 488 489 mutex_unlock(&priv->lock); 490 491 return 0; 492} 493 494static int quad8_get_quadrature_mode(struct iio_dev *indio_dev, 495 const struct iio_chan_spec *chan) 496{ 497 const struct quad8_iio *const priv = iio_priv(indio_dev); 498 499 return priv->quadrature_mode[chan->channel]; 500} 501 502static const struct iio_enum quad8_quadrature_mode_enum = { 503 .items = quad8_quadrature_modes, 504 .num_items = ARRAY_SIZE(quad8_quadrature_modes), 505 .set = quad8_set_quadrature_mode, 506 .get = quad8_get_quadrature_mode 507}; 508 509static const char *const quad8_index_polarity_modes[] = { 510 "negative", 511 "positive" 512}; 513 514static int quad8_set_index_polarity(struct iio_dev *indio_dev, 515 const struct iio_chan_spec *chan, unsigned int index_polarity) 516{ 517 struct quad8_iio *const priv = iio_priv(indio_dev); 518 const int base_offset = priv->base + 2 * chan->channel + 1; 519 unsigned int idr_cfg = index_polarity << 1; 520 521 mutex_lock(&priv->lock); 522 523 idr_cfg |= priv->synchronous_mode[chan->channel]; 524 525 priv->index_polarity[chan->channel] = index_polarity; 526 527 /* Load Index Control configuration to Index Control Register */ 528 outb(QUAD8_CTR_IDR | idr_cfg, base_offset); 529 530 mutex_unlock(&priv->lock); 531 532 return 0; 533} 534 535static int quad8_get_index_polarity(struct iio_dev *indio_dev, 536 const struct iio_chan_spec *chan) 537{ 538 const struct quad8_iio *const priv = iio_priv(indio_dev); 539 540 return priv->index_polarity[chan->channel]; 541} 542 543static const struct iio_enum quad8_index_polarity_enum = { 544 .items = quad8_index_polarity_modes, 545 .num_items = ARRAY_SIZE(quad8_index_polarity_modes), 546 .set = quad8_set_index_polarity, 547 .get = quad8_get_index_polarity 548}; 549 550static const struct iio_chan_spec_ext_info quad8_count_ext_info[] = { 551 { 552 .name = "preset", 553 .shared = IIO_SEPARATE, 554 .read = quad8_read_preset, 555 .write = quad8_write_preset 556 }, 557 { 558 .name = "set_to_preset_on_index", 559 .shared = IIO_SEPARATE, 560 .read = quad8_read_set_to_preset_on_index, 561 .write = quad8_write_set_to_preset_on_index 562 }, 563 IIO_ENUM("noise_error", IIO_SEPARATE, &quad8_noise_error_enum), 564 IIO_ENUM_AVAILABLE("noise_error", &quad8_noise_error_enum), 565 IIO_ENUM("count_direction", IIO_SEPARATE, &quad8_count_direction_enum), 566 IIO_ENUM_AVAILABLE("count_direction", &quad8_count_direction_enum), 567 IIO_ENUM("count_mode", IIO_SEPARATE, &quad8_count_mode_enum), 568 IIO_ENUM_AVAILABLE("count_mode", &quad8_count_mode_enum), 569 IIO_ENUM("quadrature_mode", IIO_SEPARATE, &quad8_quadrature_mode_enum), 570 IIO_ENUM_AVAILABLE("quadrature_mode", &quad8_quadrature_mode_enum), 571 {} 572}; 573 574static const struct iio_chan_spec_ext_info quad8_index_ext_info[] = { 575 IIO_ENUM("synchronous_mode", IIO_SEPARATE, 576 &quad8_synchronous_mode_enum), 577 IIO_ENUM_AVAILABLE("synchronous_mode", &quad8_synchronous_mode_enum), 578 IIO_ENUM("index_polarity", IIO_SEPARATE, &quad8_index_polarity_enum), 579 IIO_ENUM_AVAILABLE("index_polarity", &quad8_index_polarity_enum), 580 {} 581}; 582 583#define QUAD8_COUNT_CHAN(_chan) { \ 584 .type = IIO_COUNT, \ 585 .channel = (_chan), \ 586 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 587 BIT(IIO_CHAN_INFO_ENABLE) | BIT(IIO_CHAN_INFO_SCALE), \ 588 .ext_info = quad8_count_ext_info, \ 589 .indexed = 1 \ 590} 591 592#define QUAD8_INDEX_CHAN(_chan) { \ 593 .type = IIO_INDEX, \ 594 .channel = (_chan), \ 595 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 596 .ext_info = quad8_index_ext_info, \ 597 .indexed = 1 \ 598} 599 600static const struct iio_chan_spec quad8_channels[] = { 601 QUAD8_COUNT_CHAN(0), QUAD8_INDEX_CHAN(0), 602 QUAD8_COUNT_CHAN(1), QUAD8_INDEX_CHAN(1), 603 QUAD8_COUNT_CHAN(2), QUAD8_INDEX_CHAN(2), 604 QUAD8_COUNT_CHAN(3), QUAD8_INDEX_CHAN(3), 605 QUAD8_COUNT_CHAN(4), QUAD8_INDEX_CHAN(4), 606 QUAD8_COUNT_CHAN(5), QUAD8_INDEX_CHAN(5), 607 QUAD8_COUNT_CHAN(6), QUAD8_INDEX_CHAN(6), 608 QUAD8_COUNT_CHAN(7), QUAD8_INDEX_CHAN(7) 609}; 610 611static int quad8_signal_read(struct counter_device *counter, 612 struct counter_signal *signal, enum counter_signal_value *val) 613{ 614 const struct quad8_iio *const priv = counter->priv; 615 unsigned int state; 616 617 /* Only Index signal levels can be read */ 618 if (signal->id < 16) 619 return -EINVAL; 620 621 state = inb(priv->base + QUAD8_REG_INDEX_INPUT_LEVELS) 622 & BIT(signal->id - 16); 623 624 *val = (state) ? COUNTER_SIGNAL_HIGH : COUNTER_SIGNAL_LOW; 625 626 return 0; 627} 628 629static int quad8_count_read(struct counter_device *counter, 630 struct counter_count *count, unsigned long *val) 631{ 632 struct quad8_iio *const priv = counter->priv; 633 const int base_offset = priv->base + 2 * count->id; 634 int i; 635 636 *val = 0; 637 638 mutex_lock(&priv->lock); 639 640 /* Reset Byte Pointer; transfer Counter to Output Latch */ 641 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT, 642 base_offset + 1); 643 644 for (i = 0; i < 3; i++) 645 *val |= (unsigned long)inb(base_offset) << (8 * i); 646 647 mutex_unlock(&priv->lock); 648 649 return 0; 650} 651 652static int quad8_count_write(struct counter_device *counter, 653 struct counter_count *count, unsigned long val) 654{ 655 struct quad8_iio *const priv = counter->priv; 656 const int base_offset = priv->base + 2 * count->id; 657 int i; 658 659 /* Only 24-bit values are supported */ 660 if (val > 0xFFFFFF) 661 return -EINVAL; 662 663 mutex_lock(&priv->lock); 664 665 /* Reset Byte Pointer */ 666 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 667 668 /* Counter can only be set via Preset Register */ 669 for (i = 0; i < 3; i++) 670 outb(val >> (8 * i), base_offset); 671 672 /* Transfer Preset Register to Counter */ 673 outb(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, base_offset + 1); 674 675 /* Reset Byte Pointer */ 676 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 677 678 /* Set Preset Register back to original value */ 679 val = priv->preset[count->id]; 680 for (i = 0; i < 3; i++) 681 outb(val >> (8 * i), base_offset); 682 683 /* Reset Borrow, Carry, Compare, and Sign flags */ 684 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1); 685 /* Reset Error flag */ 686 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1); 687 688 mutex_unlock(&priv->lock); 689 690 return 0; 691} 692 693enum quad8_count_function { 694 QUAD8_COUNT_FUNCTION_PULSE_DIRECTION = 0, 695 QUAD8_COUNT_FUNCTION_QUADRATURE_X1, 696 QUAD8_COUNT_FUNCTION_QUADRATURE_X2, 697 QUAD8_COUNT_FUNCTION_QUADRATURE_X4 698}; 699 700static enum counter_count_function quad8_count_functions_list[] = { 701 [QUAD8_COUNT_FUNCTION_PULSE_DIRECTION] = COUNTER_COUNT_FUNCTION_PULSE_DIRECTION, 702 [QUAD8_COUNT_FUNCTION_QUADRATURE_X1] = COUNTER_COUNT_FUNCTION_QUADRATURE_X1_A, 703 [QUAD8_COUNT_FUNCTION_QUADRATURE_X2] = COUNTER_COUNT_FUNCTION_QUADRATURE_X2_A, 704 [QUAD8_COUNT_FUNCTION_QUADRATURE_X4] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4 705}; 706 707static int quad8_function_get(struct counter_device *counter, 708 struct counter_count *count, size_t *function) 709{ 710 struct quad8_iio *const priv = counter->priv; 711 const int id = count->id; 712 713 mutex_lock(&priv->lock); 714 715 if (priv->quadrature_mode[id]) 716 switch (priv->quadrature_scale[id]) { 717 case 0: 718 *function = QUAD8_COUNT_FUNCTION_QUADRATURE_X1; 719 break; 720 case 1: 721 *function = QUAD8_COUNT_FUNCTION_QUADRATURE_X2; 722 break; 723 case 2: 724 *function = QUAD8_COUNT_FUNCTION_QUADRATURE_X4; 725 break; 726 } 727 else 728 *function = QUAD8_COUNT_FUNCTION_PULSE_DIRECTION; 729 730 mutex_unlock(&priv->lock); 731 732 return 0; 733} 734 735static int quad8_function_set(struct counter_device *counter, 736 struct counter_count *count, size_t function) 737{ 738 struct quad8_iio *const priv = counter->priv; 739 const int id = count->id; 740 unsigned int *const quadrature_mode = priv->quadrature_mode + id; 741 unsigned int *const scale = priv->quadrature_scale + id; 742 unsigned int *const synchronous_mode = priv->synchronous_mode + id; 743 const int base_offset = priv->base + 2 * id + 1; 744 unsigned int mode_cfg; 745 unsigned int idr_cfg; 746 747 mutex_lock(&priv->lock); 748 749 mode_cfg = priv->count_mode[id] << 1; 750 idr_cfg = priv->index_polarity[id] << 1; 751 752 if (function == QUAD8_COUNT_FUNCTION_PULSE_DIRECTION) { 753 *quadrature_mode = 0; 754 755 /* Quadrature scaling only available in quadrature mode */ 756 *scale = 0; 757 758 /* Synchronous function not supported in non-quadrature mode */ 759 if (*synchronous_mode) { 760 *synchronous_mode = 0; 761 /* Disable synchronous function mode */ 762 outb(QUAD8_CTR_IDR | idr_cfg, base_offset); 763 } 764 } else { 765 *quadrature_mode = 1; 766 767 switch (function) { 768 case QUAD8_COUNT_FUNCTION_QUADRATURE_X1: 769 *scale = 0; 770 mode_cfg |= QUAD8_CMR_QUADRATURE_X1; 771 break; 772 case QUAD8_COUNT_FUNCTION_QUADRATURE_X2: 773 *scale = 1; 774 mode_cfg |= QUAD8_CMR_QUADRATURE_X2; 775 break; 776 case QUAD8_COUNT_FUNCTION_QUADRATURE_X4: 777 *scale = 2; 778 mode_cfg |= QUAD8_CMR_QUADRATURE_X4; 779 break; 780 } 781 } 782 783 /* Load mode configuration to Counter Mode Register */ 784 outb(QUAD8_CTR_CMR | mode_cfg, base_offset); 785 786 mutex_unlock(&priv->lock); 787 788 return 0; 789} 790 791static void quad8_direction_get(struct counter_device *counter, 792 struct counter_count *count, enum counter_count_direction *direction) 793{ 794 const struct quad8_iio *const priv = counter->priv; 795 unsigned int ud_flag; 796 const unsigned int flag_addr = priv->base + 2 * count->id + 1; 797 798 /* U/D flag: nonzero = up, zero = down */ 799 ud_flag = inb(flag_addr) & QUAD8_FLAG_UD; 800 801 *direction = (ud_flag) ? COUNTER_COUNT_DIRECTION_FORWARD : 802 COUNTER_COUNT_DIRECTION_BACKWARD; 803} 804 805enum quad8_synapse_action { 806 QUAD8_SYNAPSE_ACTION_NONE = 0, 807 QUAD8_SYNAPSE_ACTION_RISING_EDGE, 808 QUAD8_SYNAPSE_ACTION_FALLING_EDGE, 809 QUAD8_SYNAPSE_ACTION_BOTH_EDGES 810}; 811 812static enum counter_synapse_action quad8_index_actions_list[] = { 813 [QUAD8_SYNAPSE_ACTION_NONE] = COUNTER_SYNAPSE_ACTION_NONE, 814 [QUAD8_SYNAPSE_ACTION_RISING_EDGE] = COUNTER_SYNAPSE_ACTION_RISING_EDGE 815}; 816 817static enum counter_synapse_action quad8_synapse_actions_list[] = { 818 [QUAD8_SYNAPSE_ACTION_NONE] = COUNTER_SYNAPSE_ACTION_NONE, 819 [QUAD8_SYNAPSE_ACTION_RISING_EDGE] = COUNTER_SYNAPSE_ACTION_RISING_EDGE, 820 [QUAD8_SYNAPSE_ACTION_FALLING_EDGE] = COUNTER_SYNAPSE_ACTION_FALLING_EDGE, 821 [QUAD8_SYNAPSE_ACTION_BOTH_EDGES] = COUNTER_SYNAPSE_ACTION_BOTH_EDGES 822}; 823 824static int quad8_action_get(struct counter_device *counter, 825 struct counter_count *count, struct counter_synapse *synapse, 826 size_t *action) 827{ 828 struct quad8_iio *const priv = counter->priv; 829 int err; 830 size_t function = 0; 831 const size_t signal_a_id = count->synapses[0].signal->id; 832 enum counter_count_direction direction; 833 834 /* Handle Index signals */ 835 if (synapse->signal->id >= 16) { 836 if (priv->preset_enable[count->id]) 837 *action = QUAD8_SYNAPSE_ACTION_RISING_EDGE; 838 else 839 *action = QUAD8_SYNAPSE_ACTION_NONE; 840 841 return 0; 842 } 843 844 err = quad8_function_get(counter, count, &function); 845 if (err) 846 return err; 847 848 /* Default action mode */ 849 *action = QUAD8_SYNAPSE_ACTION_NONE; 850 851 /* Determine action mode based on current count function mode */ 852 switch (function) { 853 case QUAD8_COUNT_FUNCTION_PULSE_DIRECTION: 854 if (synapse->signal->id == signal_a_id) 855 *action = QUAD8_SYNAPSE_ACTION_RISING_EDGE; 856 break; 857 case QUAD8_COUNT_FUNCTION_QUADRATURE_X1: 858 if (synapse->signal->id == signal_a_id) { 859 quad8_direction_get(counter, count, &direction); 860 861 if (direction == COUNTER_COUNT_DIRECTION_FORWARD) 862 *action = QUAD8_SYNAPSE_ACTION_RISING_EDGE; 863 else 864 *action = QUAD8_SYNAPSE_ACTION_FALLING_EDGE; 865 } 866 break; 867 case QUAD8_COUNT_FUNCTION_QUADRATURE_X2: 868 if (synapse->signal->id == signal_a_id) 869 *action = QUAD8_SYNAPSE_ACTION_BOTH_EDGES; 870 break; 871 case QUAD8_COUNT_FUNCTION_QUADRATURE_X4: 872 *action = QUAD8_SYNAPSE_ACTION_BOTH_EDGES; 873 break; 874 } 875 876 return 0; 877} 878 879static const struct counter_ops quad8_ops = { 880 .signal_read = quad8_signal_read, 881 .count_read = quad8_count_read, 882 .count_write = quad8_count_write, 883 .function_get = quad8_function_get, 884 .function_set = quad8_function_set, 885 .action_get = quad8_action_get 886}; 887 888static int quad8_index_polarity_get(struct counter_device *counter, 889 struct counter_signal *signal, size_t *index_polarity) 890{ 891 const struct quad8_iio *const priv = counter->priv; 892 const size_t channel_id = signal->id - 16; 893 894 *index_polarity = priv->index_polarity[channel_id]; 895 896 return 0; 897} 898 899static int quad8_index_polarity_set(struct counter_device *counter, 900 struct counter_signal *signal, size_t index_polarity) 901{ 902 struct quad8_iio *const priv = counter->priv; 903 const size_t channel_id = signal->id - 16; 904 const int base_offset = priv->base + 2 * channel_id + 1; 905 unsigned int idr_cfg = index_polarity << 1; 906 907 mutex_lock(&priv->lock); 908 909 idr_cfg |= priv->synchronous_mode[channel_id]; 910 911 priv->index_polarity[channel_id] = index_polarity; 912 913 /* Load Index Control configuration to Index Control Register */ 914 outb(QUAD8_CTR_IDR | idr_cfg, base_offset); 915 916 mutex_unlock(&priv->lock); 917 918 return 0; 919} 920 921static struct counter_signal_enum_ext quad8_index_pol_enum = { 922 .items = quad8_index_polarity_modes, 923 .num_items = ARRAY_SIZE(quad8_index_polarity_modes), 924 .get = quad8_index_polarity_get, 925 .set = quad8_index_polarity_set 926}; 927 928static int quad8_synchronous_mode_get(struct counter_device *counter, 929 struct counter_signal *signal, size_t *synchronous_mode) 930{ 931 const struct quad8_iio *const priv = counter->priv; 932 const size_t channel_id = signal->id - 16; 933 934 *synchronous_mode = priv->synchronous_mode[channel_id]; 935 936 return 0; 937} 938 939static int quad8_synchronous_mode_set(struct counter_device *counter, 940 struct counter_signal *signal, size_t synchronous_mode) 941{ 942 struct quad8_iio *const priv = counter->priv; 943 const size_t channel_id = signal->id - 16; 944 const int base_offset = priv->base + 2 * channel_id + 1; 945 unsigned int idr_cfg = synchronous_mode; 946 947 mutex_lock(&priv->lock); 948 949 idr_cfg |= priv->index_polarity[channel_id] << 1; 950 951 /* Index function must be non-synchronous in non-quadrature mode */ 952 if (synchronous_mode && !priv->quadrature_mode[channel_id]) { 953 mutex_unlock(&priv->lock); 954 return -EINVAL; 955 } 956 957 priv->synchronous_mode[channel_id] = synchronous_mode; 958 959 /* Load Index Control configuration to Index Control Register */ 960 outb(QUAD8_CTR_IDR | idr_cfg, base_offset); 961 962 mutex_unlock(&priv->lock); 963 964 return 0; 965} 966 967static struct counter_signal_enum_ext quad8_syn_mode_enum = { 968 .items = quad8_synchronous_modes, 969 .num_items = ARRAY_SIZE(quad8_synchronous_modes), 970 .get = quad8_synchronous_mode_get, 971 .set = quad8_synchronous_mode_set 972}; 973 974static ssize_t quad8_count_floor_read(struct counter_device *counter, 975 struct counter_count *count, void *private, char *buf) 976{ 977 /* Only a floor of 0 is supported */ 978 return sprintf(buf, "0\n"); 979} 980 981static int quad8_count_mode_get(struct counter_device *counter, 982 struct counter_count *count, size_t *cnt_mode) 983{ 984 const struct quad8_iio *const priv = counter->priv; 985 986 /* Map 104-QUAD-8 count mode to Generic Counter count mode */ 987 switch (priv->count_mode[count->id]) { 988 case 0: 989 *cnt_mode = COUNTER_COUNT_MODE_NORMAL; 990 break; 991 case 1: 992 *cnt_mode = COUNTER_COUNT_MODE_RANGE_LIMIT; 993 break; 994 case 2: 995 *cnt_mode = COUNTER_COUNT_MODE_NON_RECYCLE; 996 break; 997 case 3: 998 *cnt_mode = COUNTER_COUNT_MODE_MODULO_N; 999 break; 1000 } 1001 1002 return 0; 1003} 1004 1005static int quad8_count_mode_set(struct counter_device *counter, 1006 struct counter_count *count, size_t cnt_mode) 1007{ 1008 struct quad8_iio *const priv = counter->priv; 1009 unsigned int mode_cfg; 1010 const int base_offset = priv->base + 2 * count->id + 1; 1011 1012 /* Map Generic Counter count mode to 104-QUAD-8 count mode */ 1013 switch (cnt_mode) { 1014 case COUNTER_COUNT_MODE_NORMAL: 1015 cnt_mode = 0; 1016 break; 1017 case COUNTER_COUNT_MODE_RANGE_LIMIT: 1018 cnt_mode = 1; 1019 break; 1020 case COUNTER_COUNT_MODE_NON_RECYCLE: 1021 cnt_mode = 2; 1022 break; 1023 case COUNTER_COUNT_MODE_MODULO_N: 1024 cnt_mode = 3; 1025 break; 1026 } 1027 1028 mutex_lock(&priv->lock); 1029 1030 priv->count_mode[count->id] = cnt_mode; 1031 1032 /* Set count mode configuration value */ 1033 mode_cfg = cnt_mode << 1; 1034 1035 /* Add quadrature mode configuration */ 1036 if (priv->quadrature_mode[count->id]) 1037 mode_cfg |= (priv->quadrature_scale[count->id] + 1) << 3; 1038 1039 /* Load mode configuration to Counter Mode Register */ 1040 outb(QUAD8_CTR_CMR | mode_cfg, base_offset); 1041 1042 mutex_unlock(&priv->lock); 1043 1044 return 0; 1045} 1046 1047static struct counter_count_enum_ext quad8_cnt_mode_enum = { 1048 .items = counter_count_mode_str, 1049 .num_items = ARRAY_SIZE(counter_count_mode_str), 1050 .get = quad8_count_mode_get, 1051 .set = quad8_count_mode_set 1052}; 1053 1054static ssize_t quad8_count_direction_read(struct counter_device *counter, 1055 struct counter_count *count, void *priv, char *buf) 1056{ 1057 enum counter_count_direction dir; 1058 1059 quad8_direction_get(counter, count, &dir); 1060 1061 return sprintf(buf, "%s\n", counter_count_direction_str[dir]); 1062} 1063 1064static ssize_t quad8_count_enable_read(struct counter_device *counter, 1065 struct counter_count *count, void *private, char *buf) 1066{ 1067 const struct quad8_iio *const priv = counter->priv; 1068 1069 return sprintf(buf, "%u\n", priv->ab_enable[count->id]); 1070} 1071 1072static ssize_t quad8_count_enable_write(struct counter_device *counter, 1073 struct counter_count *count, void *private, const char *buf, size_t len) 1074{ 1075 struct quad8_iio *const priv = counter->priv; 1076 const int base_offset = priv->base + 2 * count->id; 1077 int err; 1078 bool ab_enable; 1079 unsigned int ior_cfg; 1080 1081 err = kstrtobool(buf, &ab_enable); 1082 if (err) 1083 return err; 1084 1085 mutex_lock(&priv->lock); 1086 1087 priv->ab_enable[count->id] = ab_enable; 1088 1089 ior_cfg = ab_enable | priv->preset_enable[count->id] << 1; 1090 1091 /* Load I/O control configuration */ 1092 outb(QUAD8_CTR_IOR | ior_cfg, base_offset + 1); 1093 1094 mutex_unlock(&priv->lock); 1095 1096 return len; 1097} 1098 1099static int quad8_error_noise_get(struct counter_device *counter, 1100 struct counter_count *count, size_t *noise_error) 1101{ 1102 const struct quad8_iio *const priv = counter->priv; 1103 const int base_offset = priv->base + 2 * count->id + 1; 1104 1105 *noise_error = !!(inb(base_offset) & QUAD8_FLAG_E); 1106 1107 return 0; 1108} 1109 1110static struct counter_count_enum_ext quad8_error_noise_enum = { 1111 .items = quad8_noise_error_states, 1112 .num_items = ARRAY_SIZE(quad8_noise_error_states), 1113 .get = quad8_error_noise_get 1114}; 1115 1116static ssize_t quad8_count_preset_read(struct counter_device *counter, 1117 struct counter_count *count, void *private, char *buf) 1118{ 1119 const struct quad8_iio *const priv = counter->priv; 1120 1121 return sprintf(buf, "%u\n", priv->preset[count->id]); 1122} 1123 1124static void quad8_preset_register_set(struct quad8_iio *quad8iio, int id, 1125 unsigned int preset) 1126{ 1127 const unsigned int base_offset = quad8iio->base + 2 * id; 1128 int i; 1129 1130 quad8iio->preset[id] = preset; 1131 1132 /* Reset Byte Pointer */ 1133 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 1134 1135 /* Set Preset Register */ 1136 for (i = 0; i < 3; i++) 1137 outb(preset >> (8 * i), base_offset); 1138} 1139 1140static ssize_t quad8_count_preset_write(struct counter_device *counter, 1141 struct counter_count *count, void *private, const char *buf, size_t len) 1142{ 1143 struct quad8_iio *const priv = counter->priv; 1144 unsigned int preset; 1145 int ret; 1146 1147 ret = kstrtouint(buf, 0, &preset); 1148 if (ret) 1149 return ret; 1150 1151 /* Only 24-bit values are supported */ 1152 if (preset > 0xFFFFFF) 1153 return -EINVAL; 1154 1155 mutex_lock(&priv->lock); 1156 1157 quad8_preset_register_set(priv, count->id, preset); 1158 1159 mutex_unlock(&priv->lock); 1160 1161 return len; 1162} 1163 1164static ssize_t quad8_count_ceiling_read(struct counter_device *counter, 1165 struct counter_count *count, void *private, char *buf) 1166{ 1167 struct quad8_iio *const priv = counter->priv; 1168 1169 mutex_lock(&priv->lock); 1170 1171 /* Range Limit and Modulo-N count modes use preset value as ceiling */ 1172 switch (priv->count_mode[count->id]) { 1173 case 1: 1174 case 3: 1175 mutex_unlock(&priv->lock); 1176 return sprintf(buf, "%u\n", priv->preset[count->id]); 1177 } 1178 1179 mutex_unlock(&priv->lock); 1180 1181 /* By default 0xFFFFFF (24 bits unsigned) is maximum count */ 1182 return sprintf(buf, "16777215\n"); 1183} 1184 1185static ssize_t quad8_count_ceiling_write(struct counter_device *counter, 1186 struct counter_count *count, void *private, const char *buf, size_t len) 1187{ 1188 struct quad8_iio *const priv = counter->priv; 1189 unsigned int ceiling; 1190 int ret; 1191 1192 ret = kstrtouint(buf, 0, &ceiling); 1193 if (ret) 1194 return ret; 1195 1196 /* Only 24-bit values are supported */ 1197 if (ceiling > 0xFFFFFF) 1198 return -EINVAL; 1199 1200 mutex_lock(&priv->lock); 1201 1202 /* Range Limit and Modulo-N count modes use preset value as ceiling */ 1203 switch (priv->count_mode[count->id]) { 1204 case 1: 1205 case 3: 1206 quad8_preset_register_set(priv, count->id, ceiling); 1207 mutex_unlock(&priv->lock); 1208 return len; 1209 } 1210 1211 mutex_unlock(&priv->lock); 1212 1213 return -EINVAL; 1214} 1215 1216static ssize_t quad8_count_preset_enable_read(struct counter_device *counter, 1217 struct counter_count *count, void *private, char *buf) 1218{ 1219 const struct quad8_iio *const priv = counter->priv; 1220 1221 return sprintf(buf, "%u\n", !priv->preset_enable[count->id]); 1222} 1223 1224static ssize_t quad8_count_preset_enable_write(struct counter_device *counter, 1225 struct counter_count *count, void *private, const char *buf, size_t len) 1226{ 1227 struct quad8_iio *const priv = counter->priv; 1228 const int base_offset = priv->base + 2 * count->id + 1; 1229 bool preset_enable; 1230 int ret; 1231 unsigned int ior_cfg; 1232 1233 ret = kstrtobool(buf, &preset_enable); 1234 if (ret) 1235 return ret; 1236 1237 /* Preset enable is active low in Input/Output Control register */ 1238 preset_enable = !preset_enable; 1239 1240 mutex_lock(&priv->lock); 1241 1242 priv->preset_enable[count->id] = preset_enable; 1243 1244 ior_cfg = priv->ab_enable[count->id] | (unsigned int)preset_enable << 1; 1245 1246 /* Load I/O control configuration to Input / Output Control Register */ 1247 outb(QUAD8_CTR_IOR | ior_cfg, base_offset); 1248 1249 mutex_unlock(&priv->lock); 1250 1251 return len; 1252} 1253 1254static ssize_t quad8_signal_cable_fault_read(struct counter_device *counter, 1255 struct counter_signal *signal, 1256 void *private, char *buf) 1257{ 1258 struct quad8_iio *const priv = counter->priv; 1259 const size_t channel_id = signal->id / 2; 1260 bool disabled; 1261 unsigned int status; 1262 unsigned int fault; 1263 1264 mutex_lock(&priv->lock); 1265 1266 disabled = !(priv->cable_fault_enable & BIT(channel_id)); 1267 1268 if (disabled) { 1269 mutex_unlock(&priv->lock); 1270 return -EINVAL; 1271 } 1272 1273 /* Logic 0 = cable fault */ 1274 status = inb(priv->base + QUAD8_DIFF_ENCODER_CABLE_STATUS); 1275 1276 mutex_unlock(&priv->lock); 1277 1278 /* Mask respective channel and invert logic */ 1279 fault = !(status & BIT(channel_id)); 1280 1281 return sprintf(buf, "%u\n", fault); 1282} 1283 1284static ssize_t quad8_signal_cable_fault_enable_read( 1285 struct counter_device *counter, struct counter_signal *signal, 1286 void *private, char *buf) 1287{ 1288 const struct quad8_iio *const priv = counter->priv; 1289 const size_t channel_id = signal->id / 2; 1290 const unsigned int enb = !!(priv->cable_fault_enable & BIT(channel_id)); 1291 1292 return sprintf(buf, "%u\n", enb); 1293} 1294 1295static ssize_t quad8_signal_cable_fault_enable_write( 1296 struct counter_device *counter, struct counter_signal *signal, 1297 void *private, const char *buf, size_t len) 1298{ 1299 struct quad8_iio *const priv = counter->priv; 1300 const size_t channel_id = signal->id / 2; 1301 bool enable; 1302 int ret; 1303 unsigned int cable_fault_enable; 1304 1305 ret = kstrtobool(buf, &enable); 1306 if (ret) 1307 return ret; 1308 1309 mutex_lock(&priv->lock); 1310 1311 if (enable) 1312 priv->cable_fault_enable |= BIT(channel_id); 1313 else 1314 priv->cable_fault_enable &= ~BIT(channel_id); 1315 1316 /* Enable is active low in Differential Encoder Cable Status register */ 1317 cable_fault_enable = ~priv->cable_fault_enable; 1318 1319 outb(cable_fault_enable, priv->base + QUAD8_DIFF_ENCODER_CABLE_STATUS); 1320 1321 mutex_unlock(&priv->lock); 1322 1323 return len; 1324} 1325 1326static ssize_t quad8_signal_fck_prescaler_read(struct counter_device *counter, 1327 struct counter_signal *signal, void *private, char *buf) 1328{ 1329 const struct quad8_iio *const priv = counter->priv; 1330 const size_t channel_id = signal->id / 2; 1331 1332 return sprintf(buf, "%u\n", priv->fck_prescaler[channel_id]); 1333} 1334 1335static ssize_t quad8_signal_fck_prescaler_write(struct counter_device *counter, 1336 struct counter_signal *signal, void *private, const char *buf, 1337 size_t len) 1338{ 1339 struct quad8_iio *const priv = counter->priv; 1340 const size_t channel_id = signal->id / 2; 1341 const int base_offset = priv->base + 2 * channel_id; 1342 u8 prescaler; 1343 int ret; 1344 1345 ret = kstrtou8(buf, 0, &prescaler); 1346 if (ret) 1347 return ret; 1348 1349 mutex_lock(&priv->lock); 1350 1351 priv->fck_prescaler[channel_id] = prescaler; 1352 1353 /* Reset Byte Pointer */ 1354 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 1355 1356 /* Set filter clock factor */ 1357 outb(prescaler, base_offset); 1358 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC, 1359 base_offset + 1); 1360 1361 mutex_unlock(&priv->lock); 1362 1363 return len; 1364} 1365 1366static const struct counter_signal_ext quad8_signal_ext[] = { 1367 { 1368 .name = "cable_fault", 1369 .read = quad8_signal_cable_fault_read 1370 }, 1371 { 1372 .name = "cable_fault_enable", 1373 .read = quad8_signal_cable_fault_enable_read, 1374 .write = quad8_signal_cable_fault_enable_write 1375 }, 1376 { 1377 .name = "filter_clock_prescaler", 1378 .read = quad8_signal_fck_prescaler_read, 1379 .write = quad8_signal_fck_prescaler_write 1380 } 1381}; 1382 1383static const struct counter_signal_ext quad8_index_ext[] = { 1384 COUNTER_SIGNAL_ENUM("index_polarity", &quad8_index_pol_enum), 1385 COUNTER_SIGNAL_ENUM_AVAILABLE("index_polarity", &quad8_index_pol_enum), 1386 COUNTER_SIGNAL_ENUM("synchronous_mode", &quad8_syn_mode_enum), 1387 COUNTER_SIGNAL_ENUM_AVAILABLE("synchronous_mode", &quad8_syn_mode_enum) 1388}; 1389 1390#define QUAD8_QUAD_SIGNAL(_id, _name) { \ 1391 .id = (_id), \ 1392 .name = (_name), \ 1393 .ext = quad8_signal_ext, \ 1394 .num_ext = ARRAY_SIZE(quad8_signal_ext) \ 1395} 1396 1397#define QUAD8_INDEX_SIGNAL(_id, _name) { \ 1398 .id = (_id), \ 1399 .name = (_name), \ 1400 .ext = quad8_index_ext, \ 1401 .num_ext = ARRAY_SIZE(quad8_index_ext) \ 1402} 1403 1404static struct counter_signal quad8_signals[] = { 1405 QUAD8_QUAD_SIGNAL(0, "Channel 1 Quadrature A"), 1406 QUAD8_QUAD_SIGNAL(1, "Channel 1 Quadrature B"), 1407 QUAD8_QUAD_SIGNAL(2, "Channel 2 Quadrature A"), 1408 QUAD8_QUAD_SIGNAL(3, "Channel 2 Quadrature B"), 1409 QUAD8_QUAD_SIGNAL(4, "Channel 3 Quadrature A"), 1410 QUAD8_QUAD_SIGNAL(5, "Channel 3 Quadrature B"), 1411 QUAD8_QUAD_SIGNAL(6, "Channel 4 Quadrature A"), 1412 QUAD8_QUAD_SIGNAL(7, "Channel 4 Quadrature B"), 1413 QUAD8_QUAD_SIGNAL(8, "Channel 5 Quadrature A"), 1414 QUAD8_QUAD_SIGNAL(9, "Channel 5 Quadrature B"), 1415 QUAD8_QUAD_SIGNAL(10, "Channel 6 Quadrature A"), 1416 QUAD8_QUAD_SIGNAL(11, "Channel 6 Quadrature B"), 1417 QUAD8_QUAD_SIGNAL(12, "Channel 7 Quadrature A"), 1418 QUAD8_QUAD_SIGNAL(13, "Channel 7 Quadrature B"), 1419 QUAD8_QUAD_SIGNAL(14, "Channel 8 Quadrature A"), 1420 QUAD8_QUAD_SIGNAL(15, "Channel 8 Quadrature B"), 1421 QUAD8_INDEX_SIGNAL(16, "Channel 1 Index"), 1422 QUAD8_INDEX_SIGNAL(17, "Channel 2 Index"), 1423 QUAD8_INDEX_SIGNAL(18, "Channel 3 Index"), 1424 QUAD8_INDEX_SIGNAL(19, "Channel 4 Index"), 1425 QUAD8_INDEX_SIGNAL(20, "Channel 5 Index"), 1426 QUAD8_INDEX_SIGNAL(21, "Channel 6 Index"), 1427 QUAD8_INDEX_SIGNAL(22, "Channel 7 Index"), 1428 QUAD8_INDEX_SIGNAL(23, "Channel 8 Index") 1429}; 1430 1431#define QUAD8_COUNT_SYNAPSES(_id) { \ 1432 { \ 1433 .actions_list = quad8_synapse_actions_list, \ 1434 .num_actions = ARRAY_SIZE(quad8_synapse_actions_list), \ 1435 .signal = quad8_signals + 2 * (_id) \ 1436 }, \ 1437 { \ 1438 .actions_list = quad8_synapse_actions_list, \ 1439 .num_actions = ARRAY_SIZE(quad8_synapse_actions_list), \ 1440 .signal = quad8_signals + 2 * (_id) + 1 \ 1441 }, \ 1442 { \ 1443 .actions_list = quad8_index_actions_list, \ 1444 .num_actions = ARRAY_SIZE(quad8_index_actions_list), \ 1445 .signal = quad8_signals + 2 * (_id) + 16 \ 1446 } \ 1447} 1448 1449static struct counter_synapse quad8_count_synapses[][3] = { 1450 QUAD8_COUNT_SYNAPSES(0), QUAD8_COUNT_SYNAPSES(1), 1451 QUAD8_COUNT_SYNAPSES(2), QUAD8_COUNT_SYNAPSES(3), 1452 QUAD8_COUNT_SYNAPSES(4), QUAD8_COUNT_SYNAPSES(5), 1453 QUAD8_COUNT_SYNAPSES(6), QUAD8_COUNT_SYNAPSES(7) 1454}; 1455 1456static const struct counter_count_ext quad8_count_ext[] = { 1457 { 1458 .name = "ceiling", 1459 .read = quad8_count_ceiling_read, 1460 .write = quad8_count_ceiling_write 1461 }, 1462 { 1463 .name = "floor", 1464 .read = quad8_count_floor_read 1465 }, 1466 COUNTER_COUNT_ENUM("count_mode", &quad8_cnt_mode_enum), 1467 COUNTER_COUNT_ENUM_AVAILABLE("count_mode", &quad8_cnt_mode_enum), 1468 { 1469 .name = "direction", 1470 .read = quad8_count_direction_read 1471 }, 1472 { 1473 .name = "enable", 1474 .read = quad8_count_enable_read, 1475 .write = quad8_count_enable_write 1476 }, 1477 COUNTER_COUNT_ENUM("error_noise", &quad8_error_noise_enum), 1478 COUNTER_COUNT_ENUM_AVAILABLE("error_noise", &quad8_error_noise_enum), 1479 { 1480 .name = "preset", 1481 .read = quad8_count_preset_read, 1482 .write = quad8_count_preset_write 1483 }, 1484 { 1485 .name = "preset_enable", 1486 .read = quad8_count_preset_enable_read, 1487 .write = quad8_count_preset_enable_write 1488 } 1489}; 1490 1491#define QUAD8_COUNT(_id, _cntname) { \ 1492 .id = (_id), \ 1493 .name = (_cntname), \ 1494 .functions_list = quad8_count_functions_list, \ 1495 .num_functions = ARRAY_SIZE(quad8_count_functions_list), \ 1496 .synapses = quad8_count_synapses[(_id)], \ 1497 .num_synapses = 2, \ 1498 .ext = quad8_count_ext, \ 1499 .num_ext = ARRAY_SIZE(quad8_count_ext) \ 1500} 1501 1502static struct counter_count quad8_counts[] = { 1503 QUAD8_COUNT(0, "Channel 1 Count"), 1504 QUAD8_COUNT(1, "Channel 2 Count"), 1505 QUAD8_COUNT(2, "Channel 3 Count"), 1506 QUAD8_COUNT(3, "Channel 4 Count"), 1507 QUAD8_COUNT(4, "Channel 5 Count"), 1508 QUAD8_COUNT(5, "Channel 6 Count"), 1509 QUAD8_COUNT(6, "Channel 7 Count"), 1510 QUAD8_COUNT(7, "Channel 8 Count") 1511}; 1512 1513static int quad8_probe(struct device *dev, unsigned int id) 1514{ 1515 struct iio_dev *indio_dev; 1516 struct quad8_iio *quad8iio; 1517 int i, j; 1518 unsigned int base_offset; 1519 int err; 1520 1521 if (!devm_request_region(dev, base[id], QUAD8_EXTENT, dev_name(dev))) { 1522 dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", 1523 base[id], base[id] + QUAD8_EXTENT); 1524 return -EBUSY; 1525 } 1526 1527 /* Allocate IIO device; this also allocates driver data structure */ 1528 indio_dev = devm_iio_device_alloc(dev, sizeof(*quad8iio)); 1529 if (!indio_dev) 1530 return -ENOMEM; 1531 1532 /* Initialize IIO device */ 1533 indio_dev->info = &quad8_info; 1534 indio_dev->modes = INDIO_DIRECT_MODE; 1535 indio_dev->num_channels = ARRAY_SIZE(quad8_channels); 1536 indio_dev->channels = quad8_channels; 1537 indio_dev->name = dev_name(dev); 1538 1539 /* Initialize Counter device and driver data */ 1540 quad8iio = iio_priv(indio_dev); 1541 quad8iio->counter.name = dev_name(dev); 1542 quad8iio->counter.parent = dev; 1543 quad8iio->counter.ops = &quad8_ops; 1544 quad8iio->counter.counts = quad8_counts; 1545 quad8iio->counter.num_counts = ARRAY_SIZE(quad8_counts); 1546 quad8iio->counter.signals = quad8_signals; 1547 quad8iio->counter.num_signals = ARRAY_SIZE(quad8_signals); 1548 quad8iio->counter.priv = quad8iio; 1549 quad8iio->base = base[id]; 1550 1551 /* Initialize mutex */ 1552 mutex_init(&quad8iio->lock); 1553 1554 /* Reset all counters and disable interrupt function */ 1555 outb(QUAD8_CHAN_OP_RESET_COUNTERS, base[id] + QUAD8_REG_CHAN_OP); 1556 /* Set initial configuration for all counters */ 1557 for (i = 0; i < QUAD8_NUM_COUNTERS; i++) { 1558 base_offset = base[id] + 2 * i; 1559 /* Reset Byte Pointer */ 1560 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 1561 /* Reset filter clock factor */ 1562 outb(0, base_offset); 1563 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC, 1564 base_offset + 1); 1565 /* Reset Byte Pointer */ 1566 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 1567 /* Reset Preset Register */ 1568 for (j = 0; j < 3; j++) 1569 outb(0x00, base_offset); 1570 /* Reset Borrow, Carry, Compare, and Sign flags */ 1571 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1); 1572 /* Reset Error flag */ 1573 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1); 1574 /* Binary encoding; Normal count; non-quadrature mode */ 1575 outb(QUAD8_CTR_CMR, base_offset + 1); 1576 /* Disable A and B inputs; preset on index; FLG1 as Carry */ 1577 outb(QUAD8_CTR_IOR, base_offset + 1); 1578 /* Disable index function; negative index polarity */ 1579 outb(QUAD8_CTR_IDR, base_offset + 1); 1580 } 1581 /* Disable Differential Encoder Cable Status for all channels */ 1582 outb(0xFF, base[id] + QUAD8_DIFF_ENCODER_CABLE_STATUS); 1583 /* Enable all counters */ 1584 outb(QUAD8_CHAN_OP_ENABLE_COUNTERS, base[id] + QUAD8_REG_CHAN_OP); 1585 1586 /* Register IIO device */ 1587 err = devm_iio_device_register(dev, indio_dev); 1588 if (err) 1589 return err; 1590 1591 /* Register Counter device */ 1592 return devm_counter_register(dev, &quad8iio->counter); 1593} 1594 1595static struct isa_driver quad8_driver = { 1596 .probe = quad8_probe, 1597 .driver = { 1598 .name = "104-quad-8" 1599 } 1600}; 1601 1602module_isa_driver(quad8_driver, num_quad8); 1603 1604MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 1605MODULE_DESCRIPTION("ACCES 104-QUAD-8 IIO driver"); 1606MODULE_LICENSE("GPL v2"); 1607