drivers:iio:stm:accel:st_lis2dw12: Add multiple interrupt management
The sensor family whose founder is lis2dw12 includes the possibility to internally detect some gestures such as TAP, double TAP, wake up, etc. These events are notified to the system processor via a dedicated interrupt pin which in the previous version of the driver could not be dissociated from the accelerometer sensor interrupt pin. With this new version of the driver it is now possible to define a dedicated interrupt for the management of embedded events distinct from the accelerometer sensor interrupt. Signed-off-by: Mario Tesi <mario.tesi@st.com> Change-Id: Iac61300266582d01c0505605189c874abd1f6eb0 Reviewed-on: https://gerrit.st.com/c/linuxandroidopen/stm-ldd-iio/+/339390 Reviewed-by: Matteo DAMENO <matteo.dameno@st.com> Tested-by: CITOOLS <MDG-smet-aci-reviews@list.st.com>
This commit is contained in:
parent
6c3aaf9420
commit
ad8e9c9c06
@ -17,9 +17,15 @@ Required properties for the spi bindings:
|
||||
Optional properties for all bus drivers:
|
||||
- st,drdy-int-pin: the pin on the package that will be used to signal
|
||||
"data ready" (valid values: 1 or 2, default: 1).
|
||||
The interrupt pin used by embedded events is hardwired to 1
|
||||
by hardware design.
|
||||
|
||||
- interrupts: interrupt mapping for IRQ. It should be configured with
|
||||
flags IRQ_TYPE_LEVEL_HIGH.
|
||||
- interrupts: interrupt mapping for IRQs. It is recommended to configure
|
||||
them with flags IRQ_TYPE_LEVEL_HIGH. It is possible to
|
||||
configure an interrupt array of two elements where the first
|
||||
one is related to the accelerometer sensor data interrupt
|
||||
while the second represents the embedded events detection
|
||||
interrupt.
|
||||
|
||||
Refer to interrupt-controller/interrupts.txt for generic
|
||||
interrupt client node bindings.
|
||||
@ -31,6 +37,6 @@ lis2dw12-accel@0 {
|
||||
reg = <0x0>;
|
||||
spi-max-frequency = <1000000>;
|
||||
interrupt-parent = <&gpio0>;
|
||||
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>, <2 IRQ_TYPE_LEVEL_HIGH>;
|
||||
st,drdy-int-pin = <1>;
|
||||
};
|
||||
|
@ -66,6 +66,9 @@ struct st_lis2dw12_sensor {
|
||||
struct st_lis2dw12_hw {
|
||||
struct device *dev;
|
||||
int irq;
|
||||
int irq_emb;
|
||||
int irq_pin;
|
||||
u8 irq_reg;
|
||||
|
||||
struct mutex fifo_lock;
|
||||
struct mutex lock;
|
||||
@ -103,4 +106,3 @@ int st_lis2dw12_sensor_set_enable(struct st_lis2dw12_sensor *sensor,
|
||||
bool enable);
|
||||
|
||||
#endif /* ST_LIS2DW12_H */
|
||||
|
||||
|
@ -37,6 +37,12 @@
|
||||
#define ST_LIS2DW12_TAP_EVT_MASK GENMASK(2, 0)
|
||||
#define ST_LIS2DW12_FIFO_SAMPLES_DIFF_MASK GENMASK(5, 0)
|
||||
|
||||
#define ST_LIS2DW12_ALL_INT_SRC_ADDR 0x3b
|
||||
#define ST_LIS2DW12_ALL_INT_SRC_FF_MASK BIT(0)
|
||||
#define ST_LIS2DW12_ALL_INT_SRC_WU_MASK BIT(1)
|
||||
#define ST_LIS2DW12_ALL_INT_SRC_TAP_MASK BIT(2)
|
||||
#define ST_LIS2DW12_ALL_INT_SRC_TAP_TAP_MASK BIT(3)
|
||||
|
||||
static inline s64 st_lis2dw12_get_timestamp(struct st_lis2dw12_hw *hw)
|
||||
{
|
||||
return iio_get_time_ns(hw->iio_devs[ST_LIS2DW12_ID_ACC]);
|
||||
@ -203,6 +209,81 @@ ssize_t st_lis2dw12_flush_fifo(struct device *dev,
|
||||
return err < 0 ? err : size;
|
||||
}
|
||||
|
||||
static irqreturn_t st_lis2dw12_emb_event(struct st_lis2dw12_hw *hw)
|
||||
{
|
||||
u8 status;
|
||||
s64 code;
|
||||
int err;
|
||||
|
||||
err = hw->tf->read(hw->dev, ST_LIS2DW12_ALL_INT_SRC_ADDR,
|
||||
sizeof(status), &status);
|
||||
if (err < 0)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
if (((status & ST_LIS2DW12_ALL_INT_SRC_TAP_MASK) &&
|
||||
(hw->enable_mask & BIT(ST_LIS2DW12_ID_TAP))) ||
|
||||
((status & ST_LIS2DW12_ALL_INT_SRC_TAP_TAP_MASK) &&
|
||||
(hw->enable_mask & BIT(ST_LIS2DW12_ID_TAP_TAP)))) {
|
||||
struct iio_dev *iio_dev;
|
||||
enum iio_chan_type type;
|
||||
u8 source;
|
||||
|
||||
err = hw->tf->read(hw->dev, ST_LIS2DW12_TAP_SRC_ADDR,
|
||||
sizeof(source), &source);
|
||||
if (err < 0)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
/*
|
||||
* consider can have Tap and Double Tap events
|
||||
* contemporarely
|
||||
*/
|
||||
if (source & ST_LIS2DW12_DTAP_SRC_MASK) {
|
||||
iio_dev = hw->iio_devs[ST_LIS2DW12_ID_TAP_TAP];
|
||||
type = STM_IIO_TAP_TAP;
|
||||
code = IIO_UNMOD_EVENT_CODE(type, -1,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_RISING);
|
||||
iio_push_event(iio_dev, code, hw->ts_irq);
|
||||
}
|
||||
|
||||
if (source & ST_LIS2DW12_STAP_SRC_MASK) {
|
||||
iio_dev = hw->iio_devs[ST_LIS2DW12_ID_TAP];
|
||||
type = STM_IIO_TAP;
|
||||
code = IIO_UNMOD_EVENT_CODE(type, -1,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_RISING);
|
||||
iio_push_event(iio_dev, code, hw->ts_irq);
|
||||
}
|
||||
}
|
||||
|
||||
if (status & ST_LIS2DW12_ALL_INT_SRC_WU_MASK) {
|
||||
u8 wu_src;
|
||||
|
||||
err = hw->tf->read(hw->dev, ST_LIS2DW12_WU_SRC_ADDR,
|
||||
sizeof(wu_src), &wu_src);
|
||||
if (err < 0)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
code = IIO_UNMOD_EVENT_CODE(STM_IIO_TAP_TAP, -1,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_RISING);
|
||||
iio_push_event(hw->iio_devs[ST_LIS2DW12_ID_WU],
|
||||
STM_IIO_GESTURE, hw->ts_irq);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t st_lis2dw12_handler_irq_emb(int irq, void *private)
|
||||
{
|
||||
struct st_lis2dw12_hw *hw = private;
|
||||
s64 ts;
|
||||
|
||||
ts = st_lis2dw12_get_timestamp(hw);
|
||||
hw->ts_irq = ts;
|
||||
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
static irqreturn_t st_lis2dw12_handler_irq(int irq, void *private)
|
||||
{
|
||||
@ -221,11 +302,10 @@ static irqreturn_t st_lis2dw12_handler_thread(int irq, void *private)
|
||||
{
|
||||
struct st_lis2dw12_hw *hw = private;
|
||||
u8 status;
|
||||
s64 code;
|
||||
int err;
|
||||
|
||||
err = hw->tf->read(hw->dev, ST_LIS2DW12_STATUS_ADDR, sizeof(status),
|
||||
&status);
|
||||
err = hw->tf->read(hw->dev, ST_LIS2DW12_STATUS_ADDR,
|
||||
sizeof(status), &status);
|
||||
if (err < 0)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
@ -235,57 +315,16 @@ static irqreturn_t st_lis2dw12_handler_thread(int irq, void *private)
|
||||
mutex_unlock(&hw->fifo_lock);
|
||||
}
|
||||
|
||||
if (((status & ST_LIS2DW12_STATUS_TAP_MASK) &&
|
||||
(hw->enable_mask & BIT(ST_LIS2DW12_ID_TAP))) ||
|
||||
((status & ST_LIS2DW12_STATUS_TAP_TAP_MASK) &&
|
||||
(hw->enable_mask & BIT(ST_LIS2DW12_ID_TAP_TAP)))) {
|
||||
struct iio_dev *iio_dev;
|
||||
enum iio_chan_type type;
|
||||
u8 source;
|
||||
if (hw->irq_emb > 0)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
err = hw->tf->read(hw->dev, ST_LIS2DW12_TAP_SRC_ADDR,
|
||||
sizeof(source), &source);
|
||||
if (err < 0)
|
||||
return IRQ_HANDLED;
|
||||
return st_lis2dw12_emb_event(hw);
|
||||
}
|
||||
|
||||
/* Consider can have Tap and Double Tap events contemporarely */
|
||||
if (source & ST_LIS2DW12_DTAP_SRC_MASK) {
|
||||
iio_dev = hw->iio_devs[ST_LIS2DW12_ID_TAP_TAP];
|
||||
type = STM_IIO_TAP_TAP;
|
||||
code = IIO_UNMOD_EVENT_CODE(type, -1,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_RISING);
|
||||
iio_push_event(iio_dev, code,
|
||||
st_lis2dw12_get_timestamp(hw));
|
||||
}
|
||||
|
||||
if (source & ST_LIS2DW12_STAP_SRC_MASK) {
|
||||
iio_dev = hw->iio_devs[ST_LIS2DW12_ID_TAP];
|
||||
type = STM_IIO_TAP;
|
||||
code = IIO_UNMOD_EVENT_CODE(type, -1,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_RISING);
|
||||
iio_push_event(iio_dev, code,
|
||||
st_lis2dw12_get_timestamp(hw));
|
||||
}
|
||||
}
|
||||
|
||||
if (status & ST_LIS2DW12_STATUS_WU_MASK) {
|
||||
u8 wu_src;
|
||||
|
||||
err = hw->tf->read(hw->dev, ST_LIS2DW12_WU_SRC_ADDR,
|
||||
sizeof(wu_src), &wu_src);
|
||||
if (err < 0)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
code = IIO_UNMOD_EVENT_CODE(STM_IIO_TAP_TAP, -1,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_RISING);
|
||||
iio_push_event(hw->iio_devs[ST_LIS2DW12_ID_WU], STM_IIO_GESTURE,
|
||||
st_lis2dw12_get_timestamp(hw));
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
static irqreturn_t st_lis2dw12_handler_thread_emb(int irq,
|
||||
void *private)
|
||||
{
|
||||
return st_lis2dw12_emb_event((struct st_lis2dw12_hw *)private);
|
||||
}
|
||||
|
||||
int st_lis2dw12_fifo_setup(struct st_lis2dw12_hw *hw)
|
||||
@ -307,6 +346,19 @@ int st_lis2dw12_fifo_setup(struct st_lis2dw12_hw *hw)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (hw->irq_emb > 0) {
|
||||
ret = devm_request_threaded_irq(hw->dev, hw->irq_emb,
|
||||
st_lis2dw12_handler_irq_emb,
|
||||
st_lis2dw12_handler_thread_emb,
|
||||
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
|
||||
"st_lis2dw12", hw);
|
||||
if (ret) {
|
||||
dev_err(hw->dev, "failed to request trigger irq %d\n",
|
||||
hw->irq_emb);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
#if KERNEL_VERSION(5, 19, 0) <= LINUX_VERSION_CODE
|
||||
ret = devm_iio_kfifo_buffer_setup(hw->dev, iio_dev,
|
||||
&st_lis2dw12_acc_buffer_setup_ops);
|
||||
@ -330,4 +382,3 @@ int st_lis2dw12_fifo_setup(struct st_lis2dw12_hw *hw)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <linux/platform_data/st_sensors_pdata.h>
|
||||
@ -289,7 +290,7 @@ static u16 st_lis2dw12_check_odr_dependency(struct st_lis2dw12_hw *hw, u16 odr,
|
||||
|
||||
if (enable) {
|
||||
if (hw->enable_mask & BIT(ref_id))
|
||||
ret = (ref->odr < odr) ? odr : ref->odr;
|
||||
ret = max_t(u32, ref->odr, odr);
|
||||
else
|
||||
ret = odr;
|
||||
} else {
|
||||
@ -302,6 +303,7 @@ static u16 st_lis2dw12_check_odr_dependency(struct st_lis2dw12_hw *hw, u16 odr,
|
||||
static int st_lis2dw12_set_odr(struct st_lis2dw12_sensor *sensor, u16 req_odr)
|
||||
{
|
||||
struct st_lis2dw12_hw *hw = sensor->hw;
|
||||
u16 upd_odr = req_odr;
|
||||
u8 mode, val, i;
|
||||
int err, odr;
|
||||
|
||||
@ -309,13 +311,12 @@ static int st_lis2dw12_set_odr(struct st_lis2dw12_sensor *sensor, u16 req_odr)
|
||||
if (i == sensor->id)
|
||||
continue;
|
||||
|
||||
odr = st_lis2dw12_check_odr_dependency(hw, req_odr, i);
|
||||
if (odr != req_odr)
|
||||
/* devince already configured */
|
||||
return 0;
|
||||
odr = st_lis2dw12_check_odr_dependency(hw, upd_odr, i);
|
||||
if (odr > upd_odr)
|
||||
upd_odr = odr;
|
||||
}
|
||||
|
||||
err = st_lis2dw12_get_odr_idx(req_odr, &i);
|
||||
err = st_lis2dw12_get_odr_idx(upd_odr, &i);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
@ -350,35 +351,62 @@ static int st_lis2dw12_check_whoami(struct st_lis2dw12_hw *hw)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int st_lis2dw12_of_get_drdy_pin(struct st_lis2dw12_hw *hw,
|
||||
int *drdy_pin)
|
||||
static int st_lis2dw12_of_get_drdy_pin(struct st_lis2dw12_hw *hw)
|
||||
{
|
||||
struct device_node *np = hw->dev->of_node;
|
||||
int err;
|
||||
|
||||
if (!np)
|
||||
return -EINVAL;
|
||||
|
||||
return of_property_read_u32(np, "st,drdy-int-pin", drdy_pin);
|
||||
err = of_property_read_u32(np, "st,drdy-int-pin", &hw->irq_pin);
|
||||
if (err != 0)
|
||||
return -EINVAL;
|
||||
|
||||
hw->irq = of_irq_get(np, 0);
|
||||
if (hw->irq < 0)
|
||||
return hw->irq;
|
||||
|
||||
if (hw->irq_pin == 1) {
|
||||
/* in case same pin only one irq is requested */
|
||||
hw->irq_emb = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* embedded feature when irq is on int 2 require a new dedicated
|
||||
* irq line
|
||||
*/
|
||||
hw->irq_emb = of_irq_get(np, 1);
|
||||
if (hw->irq_emb < 0) {
|
||||
dev_err(hw->dev,
|
||||
"embedded feature require a irq line\n");
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int st_lis2dw12_get_drdy_pin(struct st_lis2dw12_hw *hw, u8 *drdy_reg)
|
||||
static int st_lis2dw12_get_drdy_pin(struct st_lis2dw12_hw *hw)
|
||||
{
|
||||
int err = 0, drdy_pin;
|
||||
int err = 0;
|
||||
|
||||
if (st_lis2dw12_of_get_drdy_pin(hw, &drdy_pin) < 0) {
|
||||
if (st_lis2dw12_of_get_drdy_pin(hw) < 0) {
|
||||
struct st_sensors_platform_data *pdata;
|
||||
struct device *dev = hw->dev;
|
||||
|
||||
pdata = (struct st_sensors_platform_data *)dev->platform_data;
|
||||
drdy_pin = pdata ? pdata->drdy_int_pin : 1;
|
||||
hw->irq_pin = pdata ? pdata->drdy_int_pin : 1;
|
||||
}
|
||||
|
||||
switch (drdy_pin) {
|
||||
switch (hw->irq_pin) {
|
||||
case 1:
|
||||
*drdy_reg = ST_LIS2DW12_CTRL4_INT1_CTRL_ADDR;
|
||||
hw->irq_reg = ST_LIS2DW12_CTRL4_INT1_CTRL_ADDR;
|
||||
break;
|
||||
case 2:
|
||||
*drdy_reg = ST_LIS2DW12_CTRL5_INT2_CTRL_ADDR;
|
||||
hw->irq_reg = ST_LIS2DW12_CTRL5_INT2_CTRL_ADDR;
|
||||
break;
|
||||
default:
|
||||
dev_err(hw->dev, "unsupported interrupt pin\n");
|
||||
@ -391,7 +419,6 @@ static int st_lis2dw12_get_drdy_pin(struct st_lis2dw12_hw *hw, u8 *drdy_reg)
|
||||
|
||||
static int st_lis2dw12_init_hw(struct st_lis2dw12_hw *hw)
|
||||
{
|
||||
u8 drdy_reg;
|
||||
int err;
|
||||
|
||||
/* soft reset the device */
|
||||
@ -463,12 +490,18 @@ static int st_lis2dw12_init_hw(struct st_lis2dw12_hw *hw)
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* configure interrupt pin */
|
||||
err = st_lis2dw12_get_drdy_pin(hw, &drdy_reg);
|
||||
/* enable latched mode */
|
||||
err = st_lis2dw12_write_with_mask(hw, ST_LIS2DW12_CTRL3_ADDR,
|
||||
ST_LIS2DW12_LIR_MASK, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return st_lis2dw12_write_with_mask(hw, drdy_reg,
|
||||
/* configure interrupt pin */
|
||||
err = st_lis2dw12_get_drdy_pin(hw);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return st_lis2dw12_write_with_mask(hw, hw->irq_reg,
|
||||
ST_LIS2DW12_FTH_INT_MASK, 1);
|
||||
}
|
||||
|
||||
@ -962,7 +995,7 @@ static struct iio_dev *st_lis2dw12_alloc_iiodev(struct st_lis2dw12_hw *hw,
|
||||
iio_dev->available_scan_masks =
|
||||
st_lis2dw12_event_avail_scan_masks;
|
||||
|
||||
sensor->odr = st_lis2dw12_odr_table[7].hz;
|
||||
sensor->odr = st_lis2dw12_odr_table[5].hz;
|
||||
break;
|
||||
case ST_LIS2DW12_ID_TAP_TAP:
|
||||
iio_dev->channels = st_lis2dw12_tap_tap_channels;
|
||||
@ -973,7 +1006,7 @@ static struct iio_dev *st_lis2dw12_alloc_iiodev(struct st_lis2dw12_hw *hw,
|
||||
iio_dev->available_scan_masks =
|
||||
st_lis2dw12_event_avail_scan_masks;
|
||||
|
||||
sensor->odr = st_lis2dw12_odr_table[7].hz;
|
||||
sensor->odr = st_lis2dw12_odr_table[6].hz;
|
||||
break;
|
||||
case ST_LIS2DW12_ID_TAP:
|
||||
iio_dev->channels = st_lis2dw12_tap_channels;
|
||||
@ -983,7 +1016,7 @@ static struct iio_dev *st_lis2dw12_alloc_iiodev(struct st_lis2dw12_hw *hw,
|
||||
iio_dev->available_scan_masks =
|
||||
st_lis2dw12_event_avail_scan_masks;
|
||||
|
||||
sensor->odr = st_lis2dw12_odr_table[7].hz;
|
||||
sensor->odr = st_lis2dw12_odr_table[6].hz;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user