From 0e6f6871a1591f4bb0971809c45bc91a991f1967 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 14 Apr 2016 10:45:21 +0200 Subject: iio: st_sensors: support open drain mode 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 Cc: Denis Ciocca Acked-by: Rob Herring Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron --- drivers/iio/common/st_sensors/st_sensors_core.c | 20 ++++++++++++++++++++ drivers/iio/common/st_sensors/st_sensors_trigger.c | 13 +++++++++++++ 2 files changed, 33 insertions(+) (limited to 'drivers/iio/common/st_sensors') diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index f5a2d44..dffe006 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -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; diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c index 6a8c983..da72279 100644 --- a/drivers/iio/common/st_sensors/st_sensors_trigger.c +++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c @@ -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, -- cgit v1.1