counter: 104-quad-8: Support Differential Encoder Cable Status
authorWilliam Breathitt Gray <vilhelm.gray@gmail.com>
Sun, 1 Mar 2020 22:07:19 +0000 (17:07 -0500)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Sun, 8 Mar 2020 17:28:53 +0000 (17:28 +0000)
The ACCES 104-QUAD-8 series provides status information about the
connection state of the differential encoder cable inputs. This patch
implements support to expose such information from these devices.

Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Documentation/ABI/testing/sysfs-bus-counter-104-quad-8
drivers/counter/104-quad-8.c

index 3c905d3..eac3218 100644 (file)
@@ -1,3 +1,21 @@
+What:          /sys/bus/counter/devices/counterX/signalY/cable_fault
+KernelVersion: 5.7
+Contact:       linux-iio@vger.kernel.org
+Description:
+               Read-only attribute that indicates whether a differential
+               encoder cable fault (not connected or loose wires) is detected
+               for the respective channel of Signal Y. Valid attribute values
+               are boolean. Detection must first be enabled via the
+               corresponding cable_fault_enable attribute.
+
+What:          /sys/bus/counter/devices/counterX/signalY/cable_fault_enable
+KernelVersion: 5.7
+Contact:       linux-iio@vger.kernel.org
+Description:
+               Whether detection of differential encoder cable faults for the
+               respective channel of Signal Y is enabled. Valid attribute
+               values are boolean.
+
 What:          /sys/bus/counter/devices/counterX/signalY/filter_clock_prescaler
 KernelVersion: 5.7
 Contact:       linux-iio@vger.kernel.org
index 0cfc813..9dab190 100644 (file)
@@ -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,6 +40,7 @@ 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 {
@@ -52,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 */
@@ -1143,6 +1147,66 @@ 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)
 {
@@ -1181,6 +1245,15 @@ static ssize_t quad8_signal_fck_prescaler_write(struct counter_device *counter,
 
 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
@@ -1383,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);