> Add event channels that controls the creation of motion events. > > Signed-off-by: Sean Nyekjaer > --- > 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 > +#include > > #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 >