Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <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>

authored by

Linus Walleij and committed by
Jonathan Cameron
0e6f6871 97865fe4

+61
+4
Documentation/devicetree/bindings/iio/st-sensors.txt
··· 16 16 - st,drdy-int-pin: the pin on the package that will be used to signal 17 17 "data ready" (valid values: 1 or 2). This property is not configurable 18 18 on all sensors. 19 + - drive-open-drain: the interrupt/data ready line will be configured 20 + as open drain, which is useful if several sensors share the same 21 + interrupt line. (This binding is taken from pinctrl/pinctrl-bindings.txt) 22 + This is a boolean property. 19 23 20 24 Sensors may also have applicable pin control settings, those use the 21 25 standard bindings from pinctrl/pinctrl-bindings.txt.
+8
drivers/iio/accel/st_accel_core.c
··· 99 99 #define ST_ACCEL_2_DRDY_IRQ_INT2_MASK 0x10 100 100 #define ST_ACCEL_2_IHL_IRQ_ADDR 0x22 101 101 #define ST_ACCEL_2_IHL_IRQ_MASK 0x80 102 + #define ST_ACCEL_2_OD_IRQ_ADDR 0x22 103 + #define ST_ACCEL_2_OD_IRQ_MASK 0x40 102 104 #define ST_ACCEL_2_MULTIREAD_BIT true 103 105 104 106 /* CUSTOM VALUES FOR SENSOR 3 */ ··· 182 180 #define ST_ACCEL_5_DRDY_IRQ_INT2_MASK 0x20 183 181 #define ST_ACCEL_5_IHL_IRQ_ADDR 0x22 184 182 #define ST_ACCEL_5_IHL_IRQ_MASK 0x80 183 + #define ST_ACCEL_5_OD_IRQ_ADDR 0x22 184 + #define ST_ACCEL_5_OD_IRQ_MASK 0x40 185 185 #define ST_ACCEL_5_IG1_EN_ADDR 0x21 186 186 #define ST_ACCEL_5_IG1_EN_MASK 0x08 187 187 #define ST_ACCEL_5_MULTIREAD_BIT false ··· 402 398 .mask_int2 = ST_ACCEL_2_DRDY_IRQ_INT2_MASK, 403 399 .addr_ihl = ST_ACCEL_2_IHL_IRQ_ADDR, 404 400 .mask_ihl = ST_ACCEL_2_IHL_IRQ_MASK, 401 + .addr_od = ST_ACCEL_2_OD_IRQ_ADDR, 402 + .mask_od = ST_ACCEL_2_OD_IRQ_MASK, 405 403 .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, 406 404 }, 407 405 .multi_read_bit = ST_ACCEL_2_MULTIREAD_BIT, ··· 593 587 .mask_int2 = ST_ACCEL_5_DRDY_IRQ_INT2_MASK, 594 588 .addr_ihl = ST_ACCEL_5_IHL_IRQ_ADDR, 595 589 .mask_ihl = ST_ACCEL_5_IHL_IRQ_MASK, 590 + .addr_od = ST_ACCEL_5_OD_IRQ_ADDR, 591 + .mask_od = ST_ACCEL_5_OD_IRQ_MASK, 596 592 .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, 597 593 }, 598 594 .multi_read_bit = ST_ACCEL_5_MULTIREAD_BIT,
+20
drivers/iio/common/st_sensors/st_sensors_core.c
··· 301 301 return -EINVAL; 302 302 } 303 303 304 + if (pdata->open_drain) { 305 + if (!sdata->sensor_settings->drdy_irq.addr_od) 306 + dev_err(&indio_dev->dev, 307 + "open drain requested but unsupported.\n"); 308 + else 309 + sdata->int_pin_open_drain = true; 310 + } 311 + 304 312 return 0; 305 313 } 306 314 ··· 328 320 pdata->drdy_int_pin = (u8) val; 329 321 else 330 322 pdata->drdy_int_pin = defdata ? defdata->drdy_int_pin : 0; 323 + 324 + pdata->open_drain = of_property_read_bool(np, "drive-open-drain"); 331 325 332 326 return pdata; 333 327 } ··· 380 370 err = st_sensors_write_data_with_mask(indio_dev, 381 371 sdata->sensor_settings->bdu.addr, 382 372 sdata->sensor_settings->bdu.mask, true); 373 + if (err < 0) 374 + return err; 375 + } 376 + 377 + if (sdata->int_pin_open_drain) { 378 + dev_info(&indio_dev->dev, 379 + "set interrupt line to open drain mode\n"); 380 + err = st_sensors_write_data_with_mask(indio_dev, 381 + sdata->sensor_settings->drdy_irq.addr_od, 382 + sdata->sensor_settings->drdy_irq.mask_od, 1); 383 383 if (err < 0) 384 384 return err; 385 385 }
+13
drivers/iio/common/st_sensors/st_sensors_trigger.c
··· 64 64 "rising edge\n", irq_trig); 65 65 irq_trig = IRQF_TRIGGER_RISING; 66 66 } 67 + 68 + /* 69 + * If the interrupt pin is Open Drain, by definition this 70 + * means that the interrupt line may be shared with other 71 + * peripherals. But to do this we also need to have a status 72 + * register and mask to figure out if this sensor was firing 73 + * the IRQ or not, so we can tell the interrupt handle that 74 + * it was "our" interrupt. 75 + */ 76 + if (sdata->int_pin_open_drain && 77 + sdata->sensor_settings->drdy_irq.addr_stat_drdy) 78 + irq_trig |= IRQF_SHARED; 79 + 67 80 err = request_threaded_irq(irq, 68 81 iio_trigger_generic_data_rdy_poll, 69 82 NULL,
+8
drivers/iio/pressure/st_pressure_core.c
··· 64 64 #define ST_PRESS_LPS331AP_DRDY_IRQ_INT2_MASK 0x20 65 65 #define ST_PRESS_LPS331AP_IHL_IRQ_ADDR 0x22 66 66 #define ST_PRESS_LPS331AP_IHL_IRQ_MASK 0x80 67 + #define ST_PRESS_LPS331AP_OD_IRQ_ADDR 0x22 68 + #define ST_PRESS_LPS331AP_OD_IRQ_MASK 0x40 67 69 #define ST_PRESS_LPS331AP_MULTIREAD_BIT true 68 70 #define ST_PRESS_LPS331AP_TEMP_OFFSET 42500 69 71 ··· 106 104 #define ST_PRESS_LPS25H_DRDY_IRQ_INT2_MASK 0x10 107 105 #define ST_PRESS_LPS25H_IHL_IRQ_ADDR 0x22 108 106 #define ST_PRESS_LPS25H_IHL_IRQ_MASK 0x80 107 + #define ST_PRESS_LPS25H_OD_IRQ_ADDR 0x22 108 + #define ST_PRESS_LPS25H_OD_IRQ_MASK 0x40 109 109 #define ST_PRESS_LPS25H_MULTIREAD_BIT true 110 110 #define ST_PRESS_LPS25H_TEMP_OFFSET 42500 111 111 #define ST_PRESS_LPS25H_OUT_XL_ADDR 0x28 ··· 230 226 .mask_int2 = ST_PRESS_LPS331AP_DRDY_IRQ_INT2_MASK, 231 227 .addr_ihl = ST_PRESS_LPS331AP_IHL_IRQ_ADDR, 232 228 .mask_ihl = ST_PRESS_LPS331AP_IHL_IRQ_MASK, 229 + .addr_od = ST_PRESS_LPS331AP_OD_IRQ_ADDR, 230 + .mask_od = ST_PRESS_LPS331AP_OD_IRQ_MASK, 233 231 .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, 234 232 }, 235 233 .multi_read_bit = ST_PRESS_LPS331AP_MULTIREAD_BIT, ··· 319 313 .mask_int2 = ST_PRESS_LPS25H_DRDY_IRQ_INT2_MASK, 320 314 .addr_ihl = ST_PRESS_LPS25H_IHL_IRQ_ADDR, 321 315 .mask_ihl = ST_PRESS_LPS25H_IHL_IRQ_MASK, 316 + .addr_od = ST_PRESS_LPS25H_OD_IRQ_ADDR, 317 + .mask_od = ST_PRESS_LPS25H_OD_IRQ_MASK, 322 318 .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, 323 319 }, 324 320 .multi_read_bit = ST_PRESS_LPS25H_MULTIREAD_BIT,
+6
include/linux/iio/common/st_sensors.h
··· 122 122 * @mask_int2: mask to enable/disable IRQ on INT2 pin. 123 123 * @addr_ihl: address to enable/disable active low on the INT lines. 124 124 * @mask_ihl: mask to enable/disable active low on the INT lines. 125 + * @addr_od: address to enable/disable Open Drain on the INT lines. 126 + * @mask_od: mask to enable/disable Open Drain on the INT lines. 125 127 * @addr_stat_drdy: address to read status of DRDY (data ready) interrupt 126 128 * struct ig1 - represents the Interrupt Generator 1 of sensors. 127 129 * @en_addr: address of the enable ig1 register. ··· 135 133 u8 mask_int2; 136 134 u8 addr_ihl; 137 135 u8 mask_ihl; 136 + u8 addr_od; 137 + u8 mask_od; 138 138 u8 addr_stat_drdy; 139 139 struct { 140 140 u8 en_addr; ··· 219 215 * @odr: Output data rate of the sensor [Hz]. 220 216 * num_data_channels: Number of data channels used in buffer. 221 217 * @drdy_int_pin: Redirect DRDY on pin 1 (1) or pin 2 (2). 218 + * @int_pin_open_drain: Set the interrupt/DRDY to open drain. 222 219 * @get_irq_data_ready: Function to get the IRQ used for data ready signal. 223 220 * @tf: Transfer function structure used by I/O operations. 224 221 * @tb: Transfer buffers and mutex used by I/O operations. ··· 241 236 unsigned int num_data_channels; 242 237 243 238 u8 drdy_int_pin; 239 + bool int_pin_open_drain; 244 240 245 241 unsigned int (*get_irq_data_ready) (struct iio_dev *indio_dev); 246 242
+2
include/linux/platform_data/st_sensors_pdata.h
··· 16 16 * @drdy_int_pin: Redirect DRDY on pin 1 (1) or pin 2 (2). 17 17 * Available only for accelerometer and pressure sensors. 18 18 * Accelerometer DRDY on LSM330 available only on pin 1 (see datasheet). 19 + * @open_drain: set the interrupt line to be open drain if possible. 19 20 */ 20 21 struct st_sensors_platform_data { 21 22 u8 drdy_int_pin; 23 + bool open_drain; 22 24 }; 23 25 24 26 #endif /* ST_SENSORS_PDATA_H */