diff mbox series

[v4,2/6] iio: imu: st_lsm6dsx: add motion events

Message ID 20190906121716.66194-2-sean@geanix.com (mailing list archive)
State New, archived
Headers show
Series [v4,1/6] iio: imu: st_lsm6dsx: move interrupt thread to core | expand

Commit Message

Sean Nyekjaer Sept. 6, 2019, 12:17 p.m. UTC
Add event channels that controls the creation of motion events.

Signed-off-by: Sean Nyekjaer <sean@geanix.com>
---
Changes since v3:
 * based channel struct on newer driver
 * use st_lsm6dsx_reg for relevant values

 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h      |  41 +++++
 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 157 +++++++++++++++++--
 2 files changed, 189 insertions(+), 9 deletions(-)

Comments

Lorenzo Bianconi Sept. 6, 2019, 2:02 p.m. UTC | #1
> Add event channels that controls the creation of motion events.
> 
> Signed-off-by: Sean Nyekjaer <sean@geanix.com>
> ---
> Changes since v3:
>  * based channel struct on newer driver
>  * use st_lsm6dsx_reg for relevant values
> 
>  drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h      |  41 +++++
>  drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 157 +++++++++++++++++--
>  2 files changed, 189 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
> index 5e3cd96b0059..d04473861fba 100644
> --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
> +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
> @@ -12,6 +12,7 @@
>  #define ST_LSM6DSX_H
>  
>  #include <linux/device.h>
> +#include <linux/iio/iio.h>
>  
>  #define ST_LSM6DS3_DEV_NAME	"lsm6ds3"
>  #define ST_LSM6DS3H_DEV_NAME	"lsm6ds3h"
> @@ -54,6 +55,26 @@ enum st_lsm6dsx_hw_id {
>  					 * ST_LSM6DSX_TAGGED_SAMPLE_SIZE)
>  #define ST_LSM6DSX_SHIFT_VAL(val, mask)	(((val) << __ffs(mask)) & (mask))
>  

[...]

> @@ -508,6 +511,16 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
>  				.mask = GENMASK(5, 3),
>  			},
>  		},
> +		.event_settings = {
> +			.enable_reg = {
> +				.addr = 0x58,
> +				.mask = BIT(7),
> +			},
> +			.wakeup_reg = {
> +				.addr = 0x5B,
> +				.mask = GENMASK(5, 0),
> +			},
> +		},
>  	},
>  	{
>  		.wai = 0x6c,
> @@ -1072,18 +1085,21 @@ static int st_lsm6dsx_read_oneshot(struct st_lsm6dsx_sensor *sensor,
>  	int err, delay;
>  	__le16 data;
>  
> -	err = st_lsm6dsx_sensor_set_enable(sensor, true);
> -	if (err < 0)
> -		return err;
> +	if (!hw->enable_event) {

I think we do not need this since it is ok if the acc is already enable right?
Just check to not disable it

> +		err = st_lsm6dsx_sensor_set_enable(sensor, true);
> +		if (err < 0)
> +			return err;
>  
> -	delay = 1000000 / sensor->odr;
> -	usleep_range(delay, 2 * delay);
> +		delay = 1000000 / sensor->odr;
> +		usleep_range(delay, 2 * delay);
> +	}
>  
>  	err = st_lsm6dsx_read_locked(hw, addr, &data, sizeof(data));
>  	if (err < 0)
>  		return err;
>  
> -	st_lsm6dsx_sensor_set_enable(sensor, false);
> +	if (!hw->enable_event)
> +		st_lsm6dsx_sensor_set_enable(sensor, false);
>  
>  	*val = (s16)le16_to_cpu(data);
>  
> @@ -1156,6 +1172,121 @@ static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev,
>  	return err;
>  }
>  
> +int st_lsm6dsx_event_setup(struct st_lsm6dsx_hw *hw, int state)
> +{
> +	int err;
> +	u8 enable = 0;
> +
> +	enable = state ? hw->settings->event_settings.enable_reg.mask : 0;
> +
> +	err = regmap_update_bits(hw->regmap,
> +				 hw->settings->event_settings.enable_reg.addr,
> +				 hw->settings->event_settings.enable_reg.mask,
> +				 enable);
> +	if (err < 0)
> +		return err;
> +
> +	enable = state ? hw->irq_routing.mask : 0;
> +
> +	/* Enable wakeup interrupt */
> +	err = regmap_update_bits(hw->regmap, hw->irq_routing.addr,
> +				 hw->irq_routing.mask,
> +				 enable);

return regmap_update_bits(hw->regmap, hw->irq_routing.addr,
			  hw->irq_routing.mask, enable);
			  
> +
> +	return err;
> +}
> +
> +static int st_lsm6dsx_read_event(struct iio_dev *iio_dev,
> +				   const struct iio_chan_spec *chan,
> +				   enum iio_event_type type,
> +				   enum iio_event_direction dir,
> +				   enum iio_event_info info,
> +				   int *val, int *val2)
> +{
> +	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
> +	struct st_lsm6dsx_hw *hw = sensor->hw;
> +
> +	if (type != IIO_EV_TYPE_THRESH)
> +		return -EINVAL;
> +
> +	*val2 = 0;
> +	*val = hw->event_threshold;
> +
> +	return IIO_VAL_INT;
> +}
> +
> +static int st_lsm6dsx_write_event(struct iio_dev *iio_dev,
> +				    const struct iio_chan_spec *chan,
> +				    enum iio_event_type type,
> +				    enum iio_event_direction dir,
> +				    enum iio_event_info info,
> +				    int val, int val2)
> +{
> +	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
> +	struct st_lsm6dsx_hw *hw = sensor->hw;
> +	int err;
> +
> +	if (type != IIO_EV_TYPE_THRESH)
> +		return -EINVAL;
> +
> +	if (val < 0 || val > 31)
> +		return -EINVAL;
> +
> +	err = regmap_update_bits(hw->regmap,
> +				 hw->settings->event_settings.wakeup_reg.addr,
> +				 hw->settings->event_settings.wakeup_reg.mask,
> +				 val);
> +	if (err)
> +		return -EINVAL;
> +
> +	hw->event_threshold = val;
> +
> +	return 0;
> +}
> +
> +static int st_lsm6dsx_read_event_config(struct iio_dev *iio_dev,
> +					  const struct iio_chan_spec *chan,
> +					  enum iio_event_type type,
> +					  enum iio_event_direction dir)
> +{
> +	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
> +	struct st_lsm6dsx_hw *hw = sensor->hw;
> +
> +	if (type != IIO_EV_TYPE_THRESH)
> +		return -EINVAL;
> +
> +	return hw->enable_event;
> +}
> +
> +static int st_lsm6dsx_write_event_config(struct iio_dev *iio_dev,
> +					   const struct iio_chan_spec *chan,
> +					   enum iio_event_type type,
> +					   enum iio_event_direction dir,
> +					   int state)
> +{
> +	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
> +	struct st_lsm6dsx_hw *hw = sensor->hw;
> +	int err = 0;
> +
> +	if (type != IIO_EV_TYPE_THRESH)
> +		return -EINVAL;
> +
> +	if (state && hw->enable_event)
> +		return 0;

This does not make a lot of sense to me since you just check to not enable it
if it has been already done. Moreover you need to check if the particular
sensor supports this event (AFAIU just one sensor does right?)

> +
> +	err = st_lsm6dsx_event_setup(hw, state);
> +	if (err < 0)
> +		return err;
> +
> +	err = st_lsm6dsx_sensor_set_enable(sensor, state);
> +	if (err < 0)
> +		return err;
> +
> +	hw->enable_event = state;
> +
> +	return 0;
> +}
> +
>  int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val)
>  {
>  	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
> @@ -1240,6 +1371,10 @@ static const struct iio_info st_lsm6dsx_acc_info = {
>  	.attrs = &st_lsm6dsx_acc_attribute_group,
>  	.read_raw = st_lsm6dsx_read_raw,
>  	.write_raw = st_lsm6dsx_write_raw,
> +	.read_event_value = st_lsm6dsx_read_event,
> +	.write_event_value = st_lsm6dsx_write_event,
> +	.read_event_config = st_lsm6dsx_read_event_config,
> +	.write_event_config = st_lsm6dsx_write_event_config,
>  	.hwfifo_set_watermark = st_lsm6dsx_set_watermark,
>  };
>  
> @@ -1285,9 +1420,13 @@ static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg)
>  	switch (drdy_pin) {
>  	case 1:
>  		*drdy_reg = hw->settings->int1_addr;
> +		hw->irq_routing.addr = hw->settings->int1_func_addr;
> +		hw->irq_routing.mask = hw->settings->int_func_mask;
>  		break;
>  	case 2:
>  		*drdy_reg = hw->settings->int2_addr;
> +		hw->irq_routing.addr = hw->settings->int2_func_addr;
> +		hw->irq_routing.mask = hw->settings->int_func_mask;
>  		break;
>  	default:
>  		dev_err(hw->dev, "unsupported data ready pin\n");
> -- 
> 2.23.0
>
Lorenzo Bianconi Sept. 6, 2019, 2:13 p.m. UTC | #2
On Sep 06, Lorenzo Bianconi wrote:
> > Add event channels that controls the creation of motion events.
> > 
> > Signed-off-by: Sean Nyekjaer <sean@geanix.com>
> > ---
> > Changes since v3:
> >  * based channel struct on newer driver
> >  * use st_lsm6dsx_reg for relevant values
> > 
> >  drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h      |  41 +++++
> >  drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 157 +++++++++++++++++--
> >  2 files changed, 189 insertions(+), 9 deletions(-)
> > 
> > diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
> > index 5e3cd96b0059..d04473861fba 100644
> > --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
> > +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
> > @@ -12,6 +12,7 @@
> >  #define ST_LSM6DSX_H
> >  
> >  #include <linux/device.h>
> > +#include <linux/iio/iio.h>
> >  
> >  #define ST_LSM6DS3_DEV_NAME	"lsm6ds3"
> >  #define ST_LSM6DS3H_DEV_NAME	"lsm6ds3h"
> > @@ -54,6 +55,26 @@ enum st_lsm6dsx_hw_id {
> >  					 * ST_LSM6DSX_TAGGED_SAMPLE_SIZE)
> >  #define ST_LSM6DSX_SHIFT_VAL(val, mask)	(((val) << __ffs(mask)) & (mask))
> >  
> 
> [...]
> 
> > @@ -508,6 +511,16 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
> >  				.mask = GENMASK(5, 3),
> >  			},
> >  		},
> > +		.event_settings = {
> > +			.enable_reg = {
> > +				.addr = 0x58,
> > +				.mask = BIT(7),
> > +			},
> > +			.wakeup_reg = {
> > +				.addr = 0x5B,
> > +				.mask = GENMASK(5, 0),
> > +			},
> > +		},
> >  	},
> >  	{
> >  		.wai = 0x6c,
> > @@ -1072,18 +1085,21 @@ static int st_lsm6dsx_read_oneshot(struct st_lsm6dsx_sensor *sensor,
> >  	int err, delay;
> >  	__le16 data;
> >  
> > -	err = st_lsm6dsx_sensor_set_enable(sensor, true);
> > -	if (err < 0)
> > -		return err;
> > +	if (!hw->enable_event) {
> 
> I think we do not need this since it is ok if the acc is already enable right?
> Just check to not disable it
> 
> > +		err = st_lsm6dsx_sensor_set_enable(sensor, true);
> > +		if (err < 0)
> > +			return err;
> >  
> > -	delay = 1000000 / sensor->odr;
> > -	usleep_range(delay, 2 * delay);
> > +		delay = 1000000 / sensor->odr;
> > +		usleep_range(delay, 2 * delay);
> > +	}
> >  
> >  	err = st_lsm6dsx_read_locked(hw, addr, &data, sizeof(data));
> >  	if (err < 0)
> >  		return err;
> >  
> > -	st_lsm6dsx_sensor_set_enable(sensor, false);
> > +	if (!hw->enable_event)
> > +		st_lsm6dsx_sensor_set_enable(sensor, false);
> >  
> >  	*val = (s16)le16_to_cpu(data);
> >  
> > @@ -1156,6 +1172,121 @@ static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev,
> >  	return err;
> >  }
> >  
> > +int st_lsm6dsx_event_setup(struct st_lsm6dsx_hw *hw, int state)
> > +{
> > +	int err;
> > +	u8 enable = 0;

here you do something like:

	if (!hw->settings->event_settings.enable_reg.addr)
		return -ENOSUPP;

> > +
> > +	enable = state ? hw->settings->event_settings.enable_reg.mask : 0;
> > +
> > +	err = regmap_update_bits(hw->regmap,
> > +				 hw->settings->event_settings.enable_reg.addr,
> > +				 hw->settings->event_settings.enable_reg.mask,
> > +				 enable);
> > +	if (err < 0)
> > +		return err;
> > +
> > +	enable = state ? hw->irq_routing.mask : 0;
> > +
> > +	/* Enable wakeup interrupt */
> > +	err = regmap_update_bits(hw->regmap, hw->irq_routing.addr,
> > +				 hw->irq_routing.mask,
> > +				 enable);
> 
> return regmap_update_bits(hw->regmap, hw->irq_routing.addr,
> 			  hw->irq_routing.mask, enable);
> 			  
> > +
> > +	return err;
> > +}
> > +
> > +static int st_lsm6dsx_read_event(struct iio_dev *iio_dev,
> > +				   const struct iio_chan_spec *chan,
> > +				   enum iio_event_type type,
> > +				   enum iio_event_direction dir,
> > +				   enum iio_event_info info,
> > +				   int *val, int *val2)
> > +{
> > +	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
> > +	struct st_lsm6dsx_hw *hw = sensor->hw;
> > +
> > +	if (type != IIO_EV_TYPE_THRESH)
> > +		return -EINVAL;
> > +
> > +	*val2 = 0;
> > +	*val = hw->event_threshold;
> > +
> > +	return IIO_VAL_INT;
> > +}
> > +
> > +static int st_lsm6dsx_write_event(struct iio_dev *iio_dev,
> > +				    const struct iio_chan_spec *chan,
> > +				    enum iio_event_type type,
> > +				    enum iio_event_direction dir,
> > +				    enum iio_event_info info,
> > +				    int val, int val2)
> > +{
> > +	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
> > +	struct st_lsm6dsx_hw *hw = sensor->hw;
> > +	int err;
> > +
> > +	if (type != IIO_EV_TYPE_THRESH)
> > +		return -EINVAL;
> > +
> > +	if (val < 0 || val > 31)
> > +		return -EINVAL;
> > +
> > +	err = regmap_update_bits(hw->regmap,
> > +				 hw->settings->event_settings.wakeup_reg.addr,
> > +				 hw->settings->event_settings.wakeup_reg.mask,
> > +				 val);
> > +	if (err)
> > +		return -EINVAL;
> > +
> > +	hw->event_threshold = val;
> > +
> > +	return 0;
> > +}
> > +
> > +static int st_lsm6dsx_read_event_config(struct iio_dev *iio_dev,
> > +					  const struct iio_chan_spec *chan,
> > +					  enum iio_event_type type,
> > +					  enum iio_event_direction dir)
> > +{
> > +	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
> > +	struct st_lsm6dsx_hw *hw = sensor->hw;
> > +
> > +	if (type != IIO_EV_TYPE_THRESH)
> > +		return -EINVAL;
> > +
> > +	return hw->enable_event;
> > +}
> > +
> > +static int st_lsm6dsx_write_event_config(struct iio_dev *iio_dev,
> > +					   const struct iio_chan_spec *chan,
> > +					   enum iio_event_type type,
> > +					   enum iio_event_direction dir,
> > +					   int state)
> > +{
> > +	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
> > +	struct st_lsm6dsx_hw *hw = sensor->hw;
> > +	int err = 0;
> > +
> > +	if (type != IIO_EV_TYPE_THRESH)
> > +		return -EINVAL;
> > +
> > +	if (state && hw->enable_event)
> > +		return 0;
> 
> This does not make a lot of sense to me since you just check to not enable it
> if it has been already done. Moreover you need to check if the particular
> sensor supports this event (AFAIU just one sensor does right?)
> 
> > +
> > +	err = st_lsm6dsx_event_setup(hw, state);
> > +	if (err < 0)
> > +		return err;
> > +
> > +	err = st_lsm6dsx_sensor_set_enable(sensor, state);
> > +	if (err < 0)
> > +		return err;
> > +
> > +	hw->enable_event = state;
> > +
> > +	return 0;
> > +}
> > +
> >  int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val)
> >  {
> >  	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
> > @@ -1240,6 +1371,10 @@ static const struct iio_info st_lsm6dsx_acc_info = {
> >  	.attrs = &st_lsm6dsx_acc_attribute_group,
> >  	.read_raw = st_lsm6dsx_read_raw,
> >  	.write_raw = st_lsm6dsx_write_raw,
> > +	.read_event_value = st_lsm6dsx_read_event,
> > +	.write_event_value = st_lsm6dsx_write_event,
> > +	.read_event_config = st_lsm6dsx_read_event_config,
> > +	.write_event_config = st_lsm6dsx_write_event_config,
> >  	.hwfifo_set_watermark = st_lsm6dsx_set_watermark,
> >  };
> >  
> > @@ -1285,9 +1420,13 @@ static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg)
> >  	switch (drdy_pin) {
> >  	case 1:
> >  		*drdy_reg = hw->settings->int1_addr;
> > +		hw->irq_routing.addr = hw->settings->int1_func_addr;
> > +		hw->irq_routing.mask = hw->settings->int_func_mask;
> >  		break;
> >  	case 2:
> >  		*drdy_reg = hw->settings->int2_addr;
> > +		hw->irq_routing.addr = hw->settings->int2_func_addr;
> > +		hw->irq_routing.mask = hw->settings->int_func_mask;
> >  		break;
> >  	default:
> >  		dev_err(hw->dev, "unsupported data ready pin\n");
> > -- 
> > 2.23.0
> >
Sean Nyekjaer Sept. 9, 2019, 6:41 a.m. UTC | #3
On 06/09/2019 16.13, Lorenzo Bianconi wrote:
>>> +int st_lsm6dsx_event_setup(struct st_lsm6dsx_hw *hw, int state)
>>> +{
>>> +	int err;
>>> +	u8 enable = 0;
> here you do something like:
> 
> 	if (!hw->settings->event_settings.enable_reg.addr)
> 		return -ENOSUPP;
> 

Here we need to do something else the LSM6DS3 doesn't feature this 
enable register.
My best guess it's enough to enable the routing of the interrupt in the 
MD register

/Sean
diff mbox series

Patch

diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
index 5e3cd96b0059..d04473861fba 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
@@ -12,6 +12,7 @@ 
 #define ST_LSM6DSX_H
 
 #include <linux/device.h>
+#include <linux/iio/iio.h>
 
 #define ST_LSM6DS3_DEV_NAME	"lsm6ds3"
 #define ST_LSM6DS3H_DEV_NAME	"lsm6ds3h"
@@ -54,6 +55,26 @@  enum st_lsm6dsx_hw_id {
 					 * ST_LSM6DSX_TAGGED_SAMPLE_SIZE)
 #define ST_LSM6DSX_SHIFT_VAL(val, mask)	(((val) << __ffs(mask)) & (mask))
 
+#define ST_LSM6DSX_CHANNEL_ACC(chan_type, addr, mod, scan_idx)		\
+{									\
+	.type = chan_type,						\
+	.address = addr,						\
+	.modified = 1,							\
+	.channel2 = mod,						\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),			\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),		\
+	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
+	.scan_index = scan_idx,						\
+	.scan_type = {							\
+		.sign = 's',						\
+		.realbits = 16,						\
+		.storagebits = 16,					\
+		.endianness = IIO_LE,					\
+	},								\
+	.event_spec = &st_lsm6dsx_event,				\
+	.num_event_specs = 1,						\
+}
+
 #define ST_LSM6DSX_CHANNEL(chan_type, addr, mod, scan_idx)		\
 {									\
 	.type = chan_type,						\
@@ -162,6 +183,11 @@  struct st_lsm6dsx_shub_settings {
 	u8 batch_en;
 };
 
+struct st_lsm6dsx_event_settings {
+	struct st_lsm6dsx_reg enable_reg;
+	struct st_lsm6dsx_reg wakeup_reg;
+};
+
 enum st_lsm6dsx_ext_sensor_id {
 	ST_LSM6DSX_ID_MAGN,
 };
@@ -223,6 +249,9 @@  struct st_lsm6dsx_settings {
 	u8 wai;
 	u8 int1_addr;
 	u8 int2_addr;
+	u8 int1_func_addr;
+	u8 int2_func_addr;
+	u8 int_func_mask;
 	u8 reset_addr;
 	u16 max_fifo_size;
 	struct {
@@ -240,6 +269,7 @@  struct st_lsm6dsx_settings {
 	struct st_lsm6dsx_fifo_ops fifo_ops;
 	struct st_lsm6dsx_hw_ts_settings ts_settings;
 	struct st_lsm6dsx_shub_settings shub_settings;
+	struct st_lsm6dsx_event_settings event_settings;
 };
 
 enum st_lsm6dsx_sensor_id {
@@ -320,6 +350,10 @@  struct st_lsm6dsx_hw {
 	u8 ts_sip;
 	u8 sip;
 
+	u8 event_threshold;
+	bool enable_event;
+	struct st_lsm6dsx_reg irq_routing;
+
 	u8 *buff;
 
 	struct iio_dev *iio_devs[ST_LSM6DSX_ID_MAX];
@@ -327,6 +361,13 @@  struct st_lsm6dsx_hw {
 	const struct st_lsm6dsx_settings *settings;
 };
 
+static const struct iio_event_spec st_lsm6dsx_event = {
+	.type = IIO_EV_TYPE_THRESH,
+	.dir = IIO_EV_DIR_EITHER,
+	.mask_separate = BIT(IIO_EV_INFO_VALUE) |
+			 BIT(IIO_EV_INFO_ENABLE)
+};
+
 static const unsigned long st_lsm6dsx_available_scan_masks[] = {0x7, 0x0};
 extern const struct dev_pm_ops st_lsm6dsx_pm_ops;
 
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
index d0bcbbfb6297..7761ee5b1ec7 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
@@ -73,9 +73,9 @@ 
 #define ST_LSM6DSX_REG_PP_OD_MASK		BIT(4)
 
 static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = {
-	ST_LSM6DSX_CHANNEL(IIO_ACCEL, 0x28, IIO_MOD_X, 0),
-	ST_LSM6DSX_CHANNEL(IIO_ACCEL, 0x2a, IIO_MOD_Y, 1),
-	ST_LSM6DSX_CHANNEL(IIO_ACCEL, 0x2c, IIO_MOD_Z, 2),
+	ST_LSM6DSX_CHANNEL_ACC(IIO_ACCEL, 0x28, IIO_MOD_X, 0),
+	ST_LSM6DSX_CHANNEL_ACC(IIO_ACCEL, 0x2a, IIO_MOD_Y, 1),
+	ST_LSM6DSX_CHANNEL_ACC(IIO_ACCEL, 0x2c, IIO_MOD_Z, 2),
 	IIO_CHAN_SOFT_TIMESTAMP(3),
 };
 
@@ -392,6 +392,9 @@  static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
 		.wai = 0x6a,
 		.int1_addr = 0x0d,
 		.int2_addr = 0x0e,
+		.int1_func_addr = 0x5e,
+		.int2_func_addr = 0x5f,
+		.int_func_mask = BIT(5),
 		.reset_addr = 0x12,
 		.max_fifo_size = 682,
 		.id = {
@@ -508,6 +511,16 @@  static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
 				.mask = GENMASK(5, 3),
 			},
 		},
+		.event_settings = {
+			.enable_reg = {
+				.addr = 0x58,
+				.mask = BIT(7),
+			},
+			.wakeup_reg = {
+				.addr = 0x5B,
+				.mask = GENMASK(5, 0),
+			},
+		},
 	},
 	{
 		.wai = 0x6c,
@@ -1072,18 +1085,21 @@  static int st_lsm6dsx_read_oneshot(struct st_lsm6dsx_sensor *sensor,
 	int err, delay;
 	__le16 data;
 
-	err = st_lsm6dsx_sensor_set_enable(sensor, true);
-	if (err < 0)
-		return err;
+	if (!hw->enable_event) {
+		err = st_lsm6dsx_sensor_set_enable(sensor, true);
+		if (err < 0)
+			return err;
 
-	delay = 1000000 / sensor->odr;
-	usleep_range(delay, 2 * delay);
+		delay = 1000000 / sensor->odr;
+		usleep_range(delay, 2 * delay);
+	}
 
 	err = st_lsm6dsx_read_locked(hw, addr, &data, sizeof(data));
 	if (err < 0)
 		return err;
 
-	st_lsm6dsx_sensor_set_enable(sensor, false);
+	if (!hw->enable_event)
+		st_lsm6dsx_sensor_set_enable(sensor, false);
 
 	*val = (s16)le16_to_cpu(data);
 
@@ -1156,6 +1172,121 @@  static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev,
 	return err;
 }
 
+int st_lsm6dsx_event_setup(struct st_lsm6dsx_hw *hw, int state)
+{
+	int err;
+	u8 enable = 0;
+
+	enable = state ? hw->settings->event_settings.enable_reg.mask : 0;
+
+	err = regmap_update_bits(hw->regmap,
+				 hw->settings->event_settings.enable_reg.addr,
+				 hw->settings->event_settings.enable_reg.mask,
+				 enable);
+	if (err < 0)
+		return err;
+
+	enable = state ? hw->irq_routing.mask : 0;
+
+	/* Enable wakeup interrupt */
+	err = regmap_update_bits(hw->regmap, hw->irq_routing.addr,
+				 hw->irq_routing.mask,
+				 enable);
+
+	return err;
+}
+
+static int st_lsm6dsx_read_event(struct iio_dev *iio_dev,
+				   const struct iio_chan_spec *chan,
+				   enum iio_event_type type,
+				   enum iio_event_direction dir,
+				   enum iio_event_info info,
+				   int *val, int *val2)
+{
+	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
+	struct st_lsm6dsx_hw *hw = sensor->hw;
+
+	if (type != IIO_EV_TYPE_THRESH)
+		return -EINVAL;
+
+	*val2 = 0;
+	*val = hw->event_threshold;
+
+	return IIO_VAL_INT;
+}
+
+static int st_lsm6dsx_write_event(struct iio_dev *iio_dev,
+				    const struct iio_chan_spec *chan,
+				    enum iio_event_type type,
+				    enum iio_event_direction dir,
+				    enum iio_event_info info,
+				    int val, int val2)
+{
+	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
+	struct st_lsm6dsx_hw *hw = sensor->hw;
+	int err;
+
+	if (type != IIO_EV_TYPE_THRESH)
+		return -EINVAL;
+
+	if (val < 0 || val > 31)
+		return -EINVAL;
+
+	err = regmap_update_bits(hw->regmap,
+				 hw->settings->event_settings.wakeup_reg.addr,
+				 hw->settings->event_settings.wakeup_reg.mask,
+				 val);
+	if (err)
+		return -EINVAL;
+
+	hw->event_threshold = val;
+
+	return 0;
+}
+
+static int st_lsm6dsx_read_event_config(struct iio_dev *iio_dev,
+					  const struct iio_chan_spec *chan,
+					  enum iio_event_type type,
+					  enum iio_event_direction dir)
+{
+	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
+	struct st_lsm6dsx_hw *hw = sensor->hw;
+
+	if (type != IIO_EV_TYPE_THRESH)
+		return -EINVAL;
+
+	return hw->enable_event;
+}
+
+static int st_lsm6dsx_write_event_config(struct iio_dev *iio_dev,
+					   const struct iio_chan_spec *chan,
+					   enum iio_event_type type,
+					   enum iio_event_direction dir,
+					   int state)
+{
+	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
+	struct st_lsm6dsx_hw *hw = sensor->hw;
+	int err = 0;
+
+	if (type != IIO_EV_TYPE_THRESH)
+		return -EINVAL;
+
+	if (state && hw->enable_event)
+		return 0;
+
+	err = st_lsm6dsx_event_setup(hw, state);
+	if (err < 0)
+		return err;
+
+	err = st_lsm6dsx_sensor_set_enable(sensor, state);
+	if (err < 0)
+		return err;
+
+	hw->enable_event = state;
+
+	return 0;
+}
+
 int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val)
 {
 	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
@@ -1240,6 +1371,10 @@  static const struct iio_info st_lsm6dsx_acc_info = {
 	.attrs = &st_lsm6dsx_acc_attribute_group,
 	.read_raw = st_lsm6dsx_read_raw,
 	.write_raw = st_lsm6dsx_write_raw,
+	.read_event_value = st_lsm6dsx_read_event,
+	.write_event_value = st_lsm6dsx_write_event,
+	.read_event_config = st_lsm6dsx_read_event_config,
+	.write_event_config = st_lsm6dsx_write_event_config,
 	.hwfifo_set_watermark = st_lsm6dsx_set_watermark,
 };
 
@@ -1285,9 +1420,13 @@  static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg)
 	switch (drdy_pin) {
 	case 1:
 		*drdy_reg = hw->settings->int1_addr;
+		hw->irq_routing.addr = hw->settings->int1_func_addr;
+		hw->irq_routing.mask = hw->settings->int_func_mask;
 		break;
 	case 2:
 		*drdy_reg = hw->settings->int2_addr;
+		hw->irq_routing.addr = hw->settings->int2_func_addr;
+		hw->irq_routing.mask = hw->settings->int_func_mask;
 		break;
 	default:
 		dev_err(hw->dev, "unsupported data ready pin\n");