iio: st_sensors: support open drain mode
authorLinus Walleij <linus.walleij@linaro.org>
Thu, 14 Apr 2016 08:45:21 +0000 (10:45 +0200)
committerJonathan Cameron <jic23@kernel.org>
Tue, 19 Apr 2016 18:58:13 +0000 (19:58 +0100)
Some types of ST Sensors can be connected to the same IRQ line
as other peripherals using open drain. Add a device tree binding
and a sensor data property to flip the right bit in the interrupt
control register to enable open drain mode on the INT line.

If the line is set to be open drain, also tag on IRQF_SHARED
to the IRQ flags when requesting the interrupt, as the whole
point of using open drain interrupt lines is to share them with
more than one peripheral (wire-or).

Cc: devicetree@vger.kernel.org
Cc: Giuseppe Barba <giuseppe.barba@st.com>
Cc: Denis Ciocca <denis.ciocca@st.com>
Acked-by: Rob Herring <rob@kernel.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Documentation/devicetree/bindings/iio/st-sensors.txt
drivers/iio/accel/st_accel_core.c
drivers/iio/common/st_sensors/st_sensors_core.c
drivers/iio/common/st_sensors/st_sensors_trigger.c
drivers/iio/pressure/st_pressure_core.c
include/linux/iio/common/st_sensors.h
include/linux/platform_data/st_sensors_pdata.h

index 71b7bdff21cdffca970da409b0ba4747573c0e40..637e283f4a8b5a81a9b0585a13d967a3ea7fb32c 100644 (file)
@@ -16,6 +16,10 @@ Optional properties:
 - st,drdy-int-pin: the pin on the package that will be used to signal
   "data ready" (valid values: 1 or 2). This property is not configurable
   on all sensors.
+- drive-open-drain: the interrupt/data ready line will be configured
+  as open drain, which is useful if several sensors share the same
+  interrupt line. (This binding is taken from pinctrl/pinctrl-bindings.txt)
+  This is a boolean property.
 
 Sensors may also have applicable pin control settings, those use the
 standard bindings from pinctrl/pinctrl-bindings.txt.
index 9fb6d35fce5b493e56bda4c7efff0b1e319d8366..dc73f2d85e6d102ef719557e4db2b08c68901ab5 100644 (file)
@@ -99,6 +99,8 @@
 #define ST_ACCEL_2_DRDY_IRQ_INT2_MASK          0x10
 #define ST_ACCEL_2_IHL_IRQ_ADDR                        0x22
 #define ST_ACCEL_2_IHL_IRQ_MASK                        0x80
+#define ST_ACCEL_2_OD_IRQ_ADDR                 0x22
+#define ST_ACCEL_2_OD_IRQ_MASK                 0x40
 #define ST_ACCEL_2_MULTIREAD_BIT               true
 
 /* CUSTOM VALUES FOR SENSOR 3 */
 #define ST_ACCEL_5_DRDY_IRQ_INT2_MASK          0x20
 #define ST_ACCEL_5_IHL_IRQ_ADDR                        0x22
 #define ST_ACCEL_5_IHL_IRQ_MASK                        0x80
+#define ST_ACCEL_5_OD_IRQ_ADDR                 0x22
+#define ST_ACCEL_5_OD_IRQ_MASK                 0x40
 #define ST_ACCEL_5_IG1_EN_ADDR                 0x21
 #define ST_ACCEL_5_IG1_EN_MASK                 0x08
 #define ST_ACCEL_5_MULTIREAD_BIT               false
@@ -398,6 +402,8 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
                        .mask_int2 = ST_ACCEL_2_DRDY_IRQ_INT2_MASK,
                        .addr_ihl = ST_ACCEL_2_IHL_IRQ_ADDR,
                        .mask_ihl = ST_ACCEL_2_IHL_IRQ_MASK,
+                       .addr_od = ST_ACCEL_2_OD_IRQ_ADDR,
+                       .mask_od = ST_ACCEL_2_OD_IRQ_MASK,
                        .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
                },
                .multi_read_bit = ST_ACCEL_2_MULTIREAD_BIT,
@@ -587,6 +593,8 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
                        .mask_int2 = ST_ACCEL_5_DRDY_IRQ_INT2_MASK,
                        .addr_ihl = ST_ACCEL_5_IHL_IRQ_ADDR,
                        .mask_ihl = ST_ACCEL_5_IHL_IRQ_MASK,
+                       .addr_od = ST_ACCEL_5_OD_IRQ_ADDR,
+                       .mask_od = ST_ACCEL_5_OD_IRQ_MASK,
                        .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
                },
                .multi_read_bit = ST_ACCEL_5_MULTIREAD_BIT,
index f5a2d445d0c0b619292ab379c739c3a20cb17f13..dffe006921694840c24356f44bd400299e33b8f3 100644 (file)
@@ -301,6 +301,14 @@ static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
                return -EINVAL;
        }
 
+       if (pdata->open_drain) {
+               if (!sdata->sensor_settings->drdy_irq.addr_od)
+                       dev_err(&indio_dev->dev,
+                               "open drain requested but unsupported.\n");
+               else
+                       sdata->int_pin_open_drain = true;
+       }
+
        return 0;
 }
 
@@ -321,6 +329,8 @@ static struct st_sensors_platform_data *st_sensors_of_probe(struct device *dev,
        else
                pdata->drdy_int_pin = defdata ? defdata->drdy_int_pin : 0;
 
+       pdata->open_drain = of_property_read_bool(np, "drive-open-drain");
+
        return pdata;
 }
 #else
@@ -374,6 +384,16 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev,
                        return err;
        }
 
+       if (sdata->int_pin_open_drain) {
+               dev_info(&indio_dev->dev,
+                        "set interrupt line to open drain mode\n");
+               err = st_sensors_write_data_with_mask(indio_dev,
+                               sdata->sensor_settings->drdy_irq.addr_od,
+                               sdata->sensor_settings->drdy_irq.mask_od, 1);
+               if (err < 0)
+                       return err;
+       }
+
        err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
 
        return err;
index 6a8c983279457d62ad0349988f92dc5ed12069a3..da72279fcf99cbd6eac0f48c8965837566a8cdc1 100644 (file)
@@ -64,6 +64,19 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
                        "rising edge\n", irq_trig);
                irq_trig = IRQF_TRIGGER_RISING;
        }
+
+       /*
+        * If the interrupt pin is Open Drain, by definition this
+        * means that the interrupt line may be shared with other
+        * peripherals. But to do this we also need to have a status
+        * register and mask to figure out if this sensor was firing
+        * the IRQ or not, so we can tell the interrupt handle that
+        * it was "our" interrupt.
+        */
+       if (sdata->int_pin_open_drain &&
+           sdata->sensor_settings->drdy_irq.addr_stat_drdy)
+               irq_trig |= IRQF_SHARED;
+
        err = request_threaded_irq(irq,
                        iio_trigger_generic_data_rdy_poll,
                        NULL,
index 1cd37eaa4a57b0445cd75204f9fc98543a6d2219..9e9b72a8f18f78fe7d7084710b4854604b7fb0b8 100644 (file)
@@ -64,6 +64,8 @@
 #define ST_PRESS_LPS331AP_DRDY_IRQ_INT2_MASK   0x20
 #define ST_PRESS_LPS331AP_IHL_IRQ_ADDR         0x22
 #define ST_PRESS_LPS331AP_IHL_IRQ_MASK         0x80
+#define ST_PRESS_LPS331AP_OD_IRQ_ADDR          0x22
+#define ST_PRESS_LPS331AP_OD_IRQ_MASK          0x40
 #define ST_PRESS_LPS331AP_MULTIREAD_BIT                true
 #define ST_PRESS_LPS331AP_TEMP_OFFSET          42500
 
 #define ST_PRESS_LPS25H_DRDY_IRQ_INT2_MASK     0x10
 #define ST_PRESS_LPS25H_IHL_IRQ_ADDR           0x22
 #define ST_PRESS_LPS25H_IHL_IRQ_MASK           0x80
+#define ST_PRESS_LPS25H_OD_IRQ_ADDR            0x22
+#define ST_PRESS_LPS25H_OD_IRQ_MASK            0x40
 #define ST_PRESS_LPS25H_MULTIREAD_BIT          true
 #define ST_PRESS_LPS25H_TEMP_OFFSET            42500
 #define ST_PRESS_LPS25H_OUT_XL_ADDR            0x28
@@ -226,6 +230,8 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
                        .mask_int2 = ST_PRESS_LPS331AP_DRDY_IRQ_INT2_MASK,
                        .addr_ihl = ST_PRESS_LPS331AP_IHL_IRQ_ADDR,
                        .mask_ihl = ST_PRESS_LPS331AP_IHL_IRQ_MASK,
+                       .addr_od = ST_PRESS_LPS331AP_OD_IRQ_ADDR,
+                       .mask_od = ST_PRESS_LPS331AP_OD_IRQ_MASK,
                        .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
                },
                .multi_read_bit = ST_PRESS_LPS331AP_MULTIREAD_BIT,
@@ -313,6 +319,8 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
                        .mask_int2 = ST_PRESS_LPS25H_DRDY_IRQ_INT2_MASK,
                        .addr_ihl = ST_PRESS_LPS25H_IHL_IRQ_ADDR,
                        .mask_ihl = ST_PRESS_LPS25H_IHL_IRQ_MASK,
+                       .addr_od = ST_PRESS_LPS25H_OD_IRQ_ADDR,
+                       .mask_od = ST_PRESS_LPS25H_OD_IRQ_MASK,
                        .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
                },
                .multi_read_bit = ST_PRESS_LPS25H_MULTIREAD_BIT,
index d8da075bfda09e14332e5416c2d82258a7d9e5c2..d029ffac0d691ab51065cd960ab53a926e9bbf39 100644 (file)
@@ -122,6 +122,8 @@ struct st_sensor_bdu {
  * @mask_int2: mask to enable/disable IRQ on INT2 pin.
  * @addr_ihl: address to enable/disable active low on the INT lines.
  * @mask_ihl: mask to enable/disable active low on the INT lines.
+ * @addr_od: address to enable/disable Open Drain on the INT lines.
+ * @mask_od: mask to enable/disable Open Drain on the INT lines.
  * @addr_stat_drdy: address to read status of DRDY (data ready) interrupt
  * struct ig1 - represents the Interrupt Generator 1 of sensors.
  * @en_addr: address of the enable ig1 register.
@@ -133,6 +135,8 @@ struct st_sensor_data_ready_irq {
        u8 mask_int2;
        u8 addr_ihl;
        u8 mask_ihl;
+       u8 addr_od;
+       u8 mask_od;
        u8 addr_stat_drdy;
        struct {
                u8 en_addr;
@@ -215,6 +219,7 @@ struct st_sensor_settings {
  * @odr: Output data rate of the sensor [Hz].
  * num_data_channels: Number of data channels used in buffer.
  * @drdy_int_pin: Redirect DRDY on pin 1 (1) or pin 2 (2).
+ * @int_pin_open_drain: Set the interrupt/DRDY to open drain.
  * @get_irq_data_ready: Function to get the IRQ used for data ready signal.
  * @tf: Transfer function structure used by I/O operations.
  * @tb: Transfer buffers and mutex used by I/O operations.
@@ -236,6 +241,7 @@ struct st_sensor_data {
        unsigned int num_data_channels;
 
        u8 drdy_int_pin;
+       bool int_pin_open_drain;
 
        unsigned int (*get_irq_data_ready) (struct iio_dev *indio_dev);
 
index 753839187ba0c35aee37ce5d81dc4228919be3a1..79b0e4cdb8141a10e73affb9a837d5bcc5f00a2a 100644 (file)
  * @drdy_int_pin: Redirect DRDY on pin 1 (1) or pin 2 (2).
  *     Available only for accelerometer and pressure sensors.
  *     Accelerometer DRDY on LSM330 available only on pin 1 (see datasheet).
+ * @open_drain: set the interrupt line to be open drain if possible.
  */
 struct st_sensors_platform_data {
        u8 drdy_int_pin;
+       bool open_drain;
 };
 
 #endif /* ST_SENSORS_PDATA_H */