root/drivers/counter/104-quad-8.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. quad8_read_raw
  2. quad8_write_raw
  3. quad8_read_preset
  4. quad8_write_preset
  5. quad8_read_set_to_preset_on_index
  6. quad8_write_set_to_preset_on_index
  7. quad8_get_noise_error
  8. quad8_get_count_direction
  9. quad8_set_count_mode
  10. quad8_get_count_mode
  11. quad8_set_synchronous_mode
  12. quad8_get_synchronous_mode
  13. quad8_set_quadrature_mode
  14. quad8_get_quadrature_mode
  15. quad8_set_index_polarity
  16. quad8_get_index_polarity
  17. quad8_signal_read
  18. quad8_count_read
  19. quad8_count_write
  20. quad8_function_get
  21. quad8_function_set
  22. quad8_direction_get
  23. quad8_action_get
  24. quad8_index_polarity_get
  25. quad8_index_polarity_set
  26. quad8_synchronous_mode_get
  27. quad8_synchronous_mode_set
  28. quad8_count_floor_read
  29. quad8_count_mode_get
  30. quad8_count_mode_set
  31. quad8_count_direction_read
  32. quad8_count_enable_read
  33. quad8_count_enable_write
  34. quad8_error_noise_get
  35. quad8_count_preset_read
  36. quad8_preset_register_set
  37. quad8_count_preset_write
  38. quad8_count_ceiling_read
  39. quad8_count_ceiling_write
  40. quad8_count_preset_enable_read
  41. quad8_count_preset_enable_write
  42. quad8_probe

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

/* [<][>][^][v][top][bottom][index][help] */