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