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