diff options
Diffstat (limited to 'drivers/counter/104-quad-8.c')
-rw-r--r-- | drivers/counter/104-quad-8.c | 136 |
1 files changed, 133 insertions, 3 deletions
diff --git a/drivers/counter/104-quad-8.c b/drivers/counter/104-quad-8.c index 17e67a84777d..9dab190c49b0 100644 --- a/drivers/counter/104-quad-8.c +++ b/drivers/counter/104-quad-8.c @@ -31,6 +31,7 @@ MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses"); /** * struct quad8_iio - IIO device private data structure * @counter: instance of the counter_device + * @fck_prescaler: array of filter clock prescaler configurations * @preset: array of preset values * @count_mode: array of count mode configurations * @quadrature_mode: array of quadrature mode configurations @@ -39,10 +40,12 @@ MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses"); * @preset_enable: array of set_to_preset_on_index attribute configurations * @synchronous_mode: array of index function synchronous mode configurations * @index_polarity: array of index function polarity configurations + * @cable_fault_enable: differential encoder cable status enable configurations * @base: base port address of the IIO device */ struct quad8_iio { struct counter_device counter; + unsigned int fck_prescaler[QUAD8_NUM_COUNTERS]; unsigned int preset[QUAD8_NUM_COUNTERS]; unsigned int count_mode[QUAD8_NUM_COUNTERS]; unsigned int quadrature_mode[QUAD8_NUM_COUNTERS]; @@ -51,11 +54,13 @@ struct quad8_iio { unsigned int preset_enable[QUAD8_NUM_COUNTERS]; unsigned int synchronous_mode[QUAD8_NUM_COUNTERS]; unsigned int index_polarity[QUAD8_NUM_COUNTERS]; + unsigned int cable_fault_enable; unsigned int base; }; #define QUAD8_REG_CHAN_OP 0x11 #define QUAD8_REG_INDEX_INPUT_LEVELS 0x16 +#define QUAD8_DIFF_ENCODER_CABLE_STATUS 0x17 /* Borrow Toggle flip-flop */ #define QUAD8_FLAG_BT BIT(0) /* Carry Toggle flip-flop */ @@ -84,6 +89,8 @@ struct quad8_iio { #define QUAD8_RLD_PRESET_CNTR 0x08 /* Transfer Counter to Output Latch */ #define QUAD8_RLD_CNTR_OUT 0x10 +/* Transfer Preset Register LSB to FCK Prescaler */ +#define QUAD8_RLD_PRESET_PSC 0x18 #define QUAD8_CHAN_OP_ENABLE_COUNTERS 0x00 #define QUAD8_CHAN_OP_RESET_COUNTERS 0x01 #define QUAD8_CMR_QUADRATURE_X1 0x08 @@ -1140,6 +1147,119 @@ static ssize_t quad8_count_preset_enable_write(struct counter_device *counter, return len; } +static ssize_t quad8_signal_cable_fault_read(struct counter_device *counter, + struct counter_signal *signal, + void *private, char *buf) +{ + const struct quad8_iio *const priv = counter->priv; + const size_t channel_id = signal->id / 2; + const bool disabled = !(priv->cable_fault_enable & BIT(channel_id)); + unsigned int status; + unsigned int fault; + + if (disabled) + return -EINVAL; + + /* Logic 0 = cable fault */ + status = inb(priv->base + QUAD8_DIFF_ENCODER_CABLE_STATUS); + + /* Mask respective channel and invert logic */ + fault = !(status & BIT(channel_id)); + + return sprintf(buf, "%u\n", fault); +} + +static ssize_t quad8_signal_cable_fault_enable_read( + struct counter_device *counter, struct counter_signal *signal, + void *private, char *buf) +{ + const struct quad8_iio *const priv = counter->priv; + const size_t channel_id = signal->id / 2; + const unsigned int enb = !!(priv->cable_fault_enable & BIT(channel_id)); + + return sprintf(buf, "%u\n", enb); +} + +static ssize_t quad8_signal_cable_fault_enable_write( + struct counter_device *counter, struct counter_signal *signal, + void *private, const char *buf, size_t len) +{ + struct quad8_iio *const priv = counter->priv; + const size_t channel_id = signal->id / 2; + bool enable; + int ret; + unsigned int cable_fault_enable; + + ret = kstrtobool(buf, &enable); + if (ret) + return ret; + + if (enable) + priv->cable_fault_enable |= BIT(channel_id); + else + priv->cable_fault_enable &= ~BIT(channel_id); + + /* Enable is active low in Differential Encoder Cable Status register */ + cable_fault_enable = ~priv->cable_fault_enable; + + outb(cable_fault_enable, priv->base + QUAD8_DIFF_ENCODER_CABLE_STATUS); + + return len; +} + +static ssize_t quad8_signal_fck_prescaler_read(struct counter_device *counter, + struct counter_signal *signal, void *private, char *buf) +{ + const struct quad8_iio *const priv = counter->priv; + const size_t channel_id = signal->id / 2; + + return sprintf(buf, "%u\n", priv->fck_prescaler[channel_id]); +} + +static ssize_t quad8_signal_fck_prescaler_write(struct counter_device *counter, + struct counter_signal *signal, void *private, const char *buf, + size_t len) +{ + struct quad8_iio *const priv = counter->priv; + const size_t channel_id = signal->id / 2; + const int base_offset = priv->base + 2 * channel_id; + u8 prescaler; + int ret; + + ret = kstrtou8(buf, 0, &prescaler); + if (ret) + return ret; + + priv->fck_prescaler[channel_id] = prescaler; + + /* Reset Byte Pointer */ + outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); + + /* Set filter clock factor */ + outb(prescaler, base_offset); + outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC, + base_offset + 1); + + return len; +} + +static const struct counter_signal_ext quad8_signal_ext[] = { + { + .name = "cable_fault", + .read = quad8_signal_cable_fault_read + }, + { + .name = "cable_fault_enable", + .read = quad8_signal_cable_fault_enable_read, + .write = quad8_signal_cable_fault_enable_write + }, + { + .name = "filter_clock_prescaler", + .read = quad8_signal_fck_prescaler_read, + .write = quad8_signal_fck_prescaler_write + } +}; + static const struct counter_signal_ext quad8_index_ext[] = { COUNTER_SIGNAL_ENUM("index_polarity", &quad8_index_pol_enum), COUNTER_SIGNAL_ENUM_AVAILABLE("index_polarity", &quad8_index_pol_enum), @@ -1147,9 +1267,11 @@ static const struct counter_signal_ext quad8_index_ext[] = { COUNTER_SIGNAL_ENUM_AVAILABLE("synchronous_mode", &quad8_syn_mode_enum) }; -#define QUAD8_QUAD_SIGNAL(_id, _name) { \ - .id = (_id), \ - .name = (_name) \ +#define QUAD8_QUAD_SIGNAL(_id, _name) { \ + .id = (_id), \ + .name = (_name), \ + .ext = quad8_signal_ext, \ + .num_ext = ARRAY_SIZE(quad8_signal_ext) \ } #define QUAD8_INDEX_SIGNAL(_id, _name) { \ @@ -1314,6 +1436,12 @@ static int quad8_probe(struct device *dev, unsigned int id) base_offset = base[id] + 2 * i; /* Reset Byte Pointer */ outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); + /* Reset filter clock factor */ + outb(0, base_offset); + outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC, + base_offset + 1); + /* Reset Byte Pointer */ + outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); /* Reset Preset Register */ for (j = 0; j < 3; j++) outb(0x00, base_offset); @@ -1328,6 +1456,8 @@ static int quad8_probe(struct device *dev, unsigned int id) /* Disable index function; negative index polarity */ outb(QUAD8_CTR_IDR, base_offset + 1); } + /* Disable Differential Encoder Cable Status for all channels */ + outb(0xFF, base[id] + QUAD8_DIFF_ENCODER_CABLE_STATUS); /* Enable all counters */ outb(QUAD8_CHAN_OP_ENABLE_COUNTERS, base[id] + QUAD8_REG_CHAN_OP); |