From 9db02d32b8eedb4441f79cb2a1696344060c1b78 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 11 Sep 2019 08:50:03 +0200 Subject: iio: imu: st_lsm6dsx: enable LIR for sensor events Enable Latched interrupt by default for sensor events Signed-off-by: Lorenzo Bianconi Tested-by: Sean Nyekjaer Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 35 ++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 2d3495560136..a208da865efe 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -237,6 +237,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .mask = GENMASK(5, 3), }, }, + .lir = { + .addr = 0x58, + .mask = BIT(0), + }, .fifo_ops = { .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_fifo, @@ -349,6 +353,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .mask = GENMASK(5, 3), }, }, + .lir = { + .addr = 0x58, + .mask = BIT(0), + }, .fifo_ops = { .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_fifo, @@ -470,6 +478,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .mask = GENMASK(5, 3), }, }, + .lir = { + .addr = 0x58, + .mask = BIT(0), + }, .fifo_ops = { .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_fifo, @@ -585,6 +597,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .mask = GENMASK(7, 4), }, }, + .lir = { + .addr = 0x56, + .mask = BIT(0), + }, .fifo_ops = { .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_tagged_fifo, @@ -715,6 +731,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .mask = GENMASK(7, 4), }, }, + .lir = { + .addr = 0x56, + .mask = BIT(0), + }, .fifo_ops = { .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_tagged_fifo, @@ -822,6 +842,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .mask = GENMASK(7, 4), }, }, + .lir = { + .addr = 0x56, + .mask = BIT(0), + }, .fifo_ops = { .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_tagged_fifo, @@ -1416,6 +1440,17 @@ static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw) if (err < 0) return err; + /* enable Latched interrupts for device events */ + if (hw->settings->lir.addr) { + unsigned int data; + + data = ST_LSM6DSX_SHIFT_VAL(1, hw->settings->lir.mask); + err = regmap_update_bits(hw->regmap, hw->settings->lir.addr, + hw->settings->lir.mask, data); + if (err < 0) + return err; + } + err = st_lsm6dsx_init_shub(hw); if (err < 0) return err; -- cgit v1.2.3-59-g8ed1b From 22ea565110731e48d9434d029df4f62c94df0a89 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 11 Sep 2019 08:50:04 +0200 Subject: iio: imu: st_lsm6dsx: enable clear on read for latched interrupts Enable clear on read feature for latched interrupts. This bit allows immediately clearing the latched interrupts of an event detection upon the read of the corresponding status register. It must be set to 1 together with LIR. This feature is available just on LSM6DS0/LSM6DSR/ASM330LHH Signed-off-by: Lorenzo Bianconi Tested-by: Sean Nyekjaer Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 2 ++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index cb5316488f31..21d14072d1c6 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -216,6 +216,7 @@ struct st_lsm6dsx_ext_dev_settings { * @decimator: List of decimator register info (addr + mask). * @batch: List of FIFO batching register info (addr + mask). * @lir: Latched interrupt register info (addr + mask). + * @clear_on_read: Clear on read register info (addr + mask). * @fifo_ops: Sensor hw FIFO parameters. * @ts_settings: Hw timer related settings. * @shub_settings: i2c controller related settings. @@ -239,6 +240,7 @@ struct st_lsm6dsx_settings { struct st_lsm6dsx_reg decimator[ST_LSM6DSX_MAX_ID]; struct st_lsm6dsx_reg batch[ST_LSM6DSX_MAX_ID]; struct st_lsm6dsx_reg lir; + struct st_lsm6dsx_reg clear_on_read; struct st_lsm6dsx_fifo_ops fifo_ops; struct st_lsm6dsx_hw_ts_settings ts_settings; struct st_lsm6dsx_shub_settings shub_settings; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index a208da865efe..b65a6ca775e0 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -601,6 +601,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x56, .mask = BIT(0), }, + .clear_on_read = { + .addr = 0x56, + .mask = BIT(6), + }, .fifo_ops = { .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_tagged_fifo, @@ -735,6 +739,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x56, .mask = BIT(0), }, + .clear_on_read = { + .addr = 0x56, + .mask = BIT(6), + }, .fifo_ops = { .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_tagged_fifo, @@ -846,6 +854,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x56, .mask = BIT(0), }, + .clear_on_read = { + .addr = 0x56, + .mask = BIT(6), + }, .fifo_ops = { .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_tagged_fifo, @@ -1449,6 +1461,18 @@ static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw) hw->settings->lir.mask, data); if (err < 0) return err; + + /* enable clear on read for latched interrupts */ + if (hw->settings->clear_on_read.addr) { + data = ST_LSM6DSX_SHIFT_VAL(1, + hw->settings->clear_on_read.mask); + err = regmap_update_bits(hw->regmap, + hw->settings->clear_on_read.addr, + hw->settings->clear_on_read.mask, + data); + if (err < 0) + return err; + } } err = st_lsm6dsx_init_shub(hw); -- cgit v1.2.3-59-g8ed1b From 6ee6a368ac0ad48dd5c5eca0e02739ac932a5b21 Mon Sep 17 00:00:00 2001 From: Sean Nyekjaer Date: Mon, 16 Sep 2019 15:56:26 +0200 Subject: iio: imu: st_lsm6dsx: move interrupt thread to core This prepares the interrupt to be used for other stuff than fifo reading + event readings. Signed-off-by: Sean Nyekjaer Acked-by: Lorenzo Bianconi Reviewed-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c | 78 +---------------------- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 88 ++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 77 deletions(-) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index b0f3da1976e4..ef579650fd52 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -30,8 +30,6 @@ * Denis Ciocca */ #include -#include -#include #include #include #include @@ -42,10 +40,6 @@ #include "st_lsm6dsx.h" -#define ST_LSM6DSX_REG_HLACTIVE_ADDR 0x12 -#define ST_LSM6DSX_REG_HLACTIVE_MASK BIT(5) -#define ST_LSM6DSX_REG_PP_OD_ADDR 0x12 -#define ST_LSM6DSX_REG_PP_OD_MASK BIT(4) #define ST_LSM6DSX_REG_FIFO_MODE_ADDR 0x0a #define ST_LSM6DSX_FIFO_MODE_MASK GENMASK(2, 0) #define ST_LSM6DSX_FIFO_ODR_MASK GENMASK(6, 3) @@ -654,25 +648,6 @@ out: return err; } -static irqreturn_t st_lsm6dsx_handler_irq(int irq, void *private) -{ - struct st_lsm6dsx_hw *hw = private; - - return hw->sip > 0 ? IRQ_WAKE_THREAD : IRQ_NONE; -} - -static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private) -{ - struct st_lsm6dsx_hw *hw = private; - int count; - - mutex_lock(&hw->fifo_lock); - count = hw->settings->fifo_ops.read_fifo(hw); - mutex_unlock(&hw->fifo_lock); - - return count ? IRQ_HANDLED : IRQ_NONE; -} - static int st_lsm6dsx_buffer_preenable(struct iio_dev *iio_dev) { struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); @@ -702,59 +677,8 @@ static const struct iio_buffer_setup_ops st_lsm6dsx_buffer_ops = { int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw) { - struct device_node *np = hw->dev->of_node; - struct st_sensors_platform_data *pdata; struct iio_buffer *buffer; - unsigned long irq_type; - bool irq_active_low; - int i, err; - - irq_type = irqd_get_trigger_type(irq_get_irq_data(hw->irq)); - - switch (irq_type) { - case IRQF_TRIGGER_HIGH: - case IRQF_TRIGGER_RISING: - irq_active_low = false; - break; - case IRQF_TRIGGER_LOW: - case IRQF_TRIGGER_FALLING: - irq_active_low = true; - break; - default: - dev_info(hw->dev, "mode %lx unsupported\n", irq_type); - return -EINVAL; - } - - err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_HLACTIVE_ADDR, - ST_LSM6DSX_REG_HLACTIVE_MASK, - FIELD_PREP(ST_LSM6DSX_REG_HLACTIVE_MASK, - irq_active_low)); - if (err < 0) - return err; - - pdata = (struct st_sensors_platform_data *)hw->dev->platform_data; - if ((np && of_property_read_bool(np, "drive-open-drain")) || - (pdata && pdata->open_drain)) { - err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_PP_OD_ADDR, - ST_LSM6DSX_REG_PP_OD_MASK, - FIELD_PREP(ST_LSM6DSX_REG_PP_OD_MASK, - 1)); - if (err < 0) - return err; - - irq_type |= IRQF_SHARED; - } - - err = devm_request_threaded_irq(hw->dev, hw->irq, - st_lsm6dsx_handler_irq, - st_lsm6dsx_handler_thread, - irq_type | IRQF_ONESHOT, - "lsm6dsx", hw); - if (err) { - dev_err(hw->dev, "failed to request trigger irq %d\n", - hw->irq); - return err; - } + int i; for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { if (!hw->iio_devs[i]) diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index b65a6ca775e0..ef838206b30f 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -50,6 +50,8 @@ #include #include #include +#include +#include #include #include #include @@ -65,6 +67,11 @@ #define ST_LSM6DSX_REG_BDU_ADDR 0x12 #define ST_LSM6DSX_REG_BDU_MASK BIT(6) +#define ST_LSM6DSX_REG_HLACTIVE_ADDR 0x12 +#define ST_LSM6DSX_REG_HLACTIVE_MASK BIT(5) +#define ST_LSM6DSX_REG_PP_OD_ADDR 0x12 +#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), @@ -1525,6 +1532,83 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw, return iio_dev; } +static irqreturn_t st_lsm6dsx_handler_irq(int irq, void *private) +{ + struct st_lsm6dsx_hw *hw = private; + + return hw->sip > 0 ? IRQ_WAKE_THREAD : IRQ_NONE; +} + +static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private) +{ + struct st_lsm6dsx_hw *hw = private; + int count; + + mutex_lock(&hw->fifo_lock); + count = hw->settings->fifo_ops.read_fifo(hw); + mutex_unlock(&hw->fifo_lock); + + return count ? IRQ_HANDLED : IRQ_NONE; +} + +static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw) +{ + struct st_sensors_platform_data *pdata; + struct device_node *np = hw->dev->of_node; + unsigned long irq_type; + bool irq_active_low; + int err; + + irq_type = irqd_get_trigger_type(irq_get_irq_data(hw->irq)); + + switch (irq_type) { + case IRQF_TRIGGER_HIGH: + case IRQF_TRIGGER_RISING: + irq_active_low = false; + break; + case IRQF_TRIGGER_LOW: + case IRQF_TRIGGER_FALLING: + irq_active_low = true; + break; + default: + dev_info(hw->dev, "mode %lx unsupported\n", irq_type); + return -EINVAL; + } + + err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_HLACTIVE_ADDR, + ST_LSM6DSX_REG_HLACTIVE_MASK, + FIELD_PREP(ST_LSM6DSX_REG_HLACTIVE_MASK, + irq_active_low)); + if (err < 0) + return err; + + pdata = (struct st_sensors_platform_data *)hw->dev->platform_data; + if ((np && of_property_read_bool(np, "drive-open-drain")) || + (pdata && pdata->open_drain)) { + err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_PP_OD_ADDR, + ST_LSM6DSX_REG_PP_OD_MASK, + FIELD_PREP(ST_LSM6DSX_REG_PP_OD_MASK, + 1)); + if (err < 0) + return err; + + irq_type |= IRQF_SHARED; + } + + err = devm_request_threaded_irq(hw->dev, hw->irq, + st_lsm6dsx_handler_irq, + st_lsm6dsx_handler_thread, + irq_type | IRQF_ONESHOT, + "lsm6dsx", hw); + if (err) { + dev_err(hw->dev, "failed to request trigger irq %d\n", + hw->irq); + return err; + } + + return 0; +} + int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, struct regmap *regmap) { @@ -1573,6 +1657,10 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, } if (hw->irq > 0) { + err = st_lsm6dsx_irq_setup(hw); + if (err < 0) + return err; + err = st_lsm6dsx_fifo_setup(hw); if (err < 0) return err; -- cgit v1.2.3-59-g8ed1b From b5969abfa8b8ed43ebd93479d394f664bd4a5a87 Mon Sep 17 00:00:00 2001 From: Sean Nyekjaer Date: Mon, 16 Sep 2019 15:56:27 +0200 Subject: iio: imu: st_lsm6dsx: add motion events Add event channels that controls the creation of motion events. Tested on ISM330DLC Signed-off-by: Sean Nyekjaer Reviewed-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 41 ++++++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 191 ++++++++++++++++++++++++++- 2 files changed, 228 insertions(+), 4 deletions(-) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 21d14072d1c6..6b0ba48394eb 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)) +#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, }; @@ -225,6 +251,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 { @@ -244,6 +273,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 { @@ -324,6 +354,10 @@ struct st_lsm6dsx_hw { u8 ts_sip; u8 sip; + u8 event_threshold; + u8 enable_event; + struct st_lsm6dsx_reg irq_routing; + u8 *buff; struct iio_dev *iio_devs[ST_LSM6DSX_ID_MAX]; @@ -331,6 +365,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 ef838206b30f..806935c8f033 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), }; @@ -168,6 +168,9 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .wai = 0x69, .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 = 1365, .id = { @@ -279,11 +282,20 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .mask = GENMASK(5, 3), }, }, + .event_settings = { + .wakeup_reg = { + .addr = 0x5B, + .mask = GENMASK(5, 0), + }, + }, }, { .wai = 0x69, .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 = { @@ -395,11 +407,20 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .mask = GENMASK(5, 3), }, }, + .event_settings = { + .wakeup_reg = { + .addr = 0x5B, + .mask = GENMASK(5, 0), + }, + }, }, { .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 = { @@ -520,6 +541,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, @@ -666,6 +697,9 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .wai = 0x6b, .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 = 512, .id = { @@ -773,11 +807,24 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .mask = GENMASK(7, 6), }, }, + .event_settings = { + .enable_reg = { + .addr = 0x58, + .mask = BIT(7), + }, + .wakeup_reg = { + .addr = 0x5B, + .mask = GENMASK(5, 0), + }, + }, }, { .wai = 0x6b, .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 = 512, .id = { @@ -913,6 +960,16 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .slv0_addr = 0x15, .dw_slv0_addr = 0x21, .batch_en = BIT(3), + }, + .event_settings = { + .enable_reg = { + .addr = 0x58, + .mask = BIT(7), + }, + .wakeup_reg = { + .addr = 0x5B, + .mask = GENMASK(5, 0), + }, } }, }; @@ -1119,7 +1176,8 @@ static int st_lsm6dsx_read_oneshot(struct st_lsm6dsx_sensor *sensor, 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); @@ -1192,6 +1250,123 @@ static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev, return err; } +static int st_lsm6dsx_event_setup(struct st_lsm6dsx_hw *hw, int state) +{ + int err; + u8 enable = 0; + + if (!hw->settings->int1_func_addr) + return -ENOTSUPP; + + 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 */ + return regmap_update_bits(hw->regmap, hw->irq_routing.addr, + hw->irq_routing.mask, + enable); +} + +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; + + /* do not enable events if they are already enabled */ + 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); @@ -1276,6 +1451,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, }; @@ -1321,9 +1500,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"); -- cgit v1.2.3-59-g8ed1b From 4c997dfa692d8bdc9f2906057d17f1c61d5dcda2 Mon Sep 17 00:00:00 2001 From: Sean Nyekjaer Date: Mon, 16 Sep 2019 15:56:28 +0200 Subject: iio: imu: st_lsm6dsx: add wakeup-source option This add ways for the SoC to wake from accelerometer wake events. In the suspend function we skip disabling the sensor if wakeup-source and events are activated. Signed-off-by: Sean Nyekjaer Reviewed-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 806935c8f033..dcac1314e769 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -1858,6 +1858,9 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, return err; } + if (dev->of_node && of_property_read_bool(dev->of_node, "wakeup-source")) + device_init_wakeup(dev, true); + return 0; } EXPORT_SYMBOL(st_lsm6dsx_probe); @@ -1876,6 +1879,13 @@ static int __maybe_unused st_lsm6dsx_suspend(struct device *dev) if (!(hw->enable_mask & BIT(sensor->id))) continue; + if (device_may_wakeup(dev) && + sensor->id == ST_LSM6DSX_ID_ACC && hw->enable_event) { + /* Enable wake from IRQ */ + enable_irq_wake(hw->irq); + continue; + } + if (sensor->id == ST_LSM6DSX_ID_EXT0 || sensor->id == ST_LSM6DSX_ID_EXT1 || sensor->id == ST_LSM6DSX_ID_EXT2) @@ -1905,6 +1915,10 @@ static int __maybe_unused st_lsm6dsx_resume(struct device *dev) continue; sensor = iio_priv(hw->iio_devs[i]); + if (device_may_wakeup(dev) && + sensor->id == ST_LSM6DSX_ID_ACC && hw->enable_event) + disable_irq_wake(hw->irq); + if (!(hw->suspend_mask & BIT(sensor->id))) continue; -- cgit v1.2.3-59-g8ed1b From a3aa17d4badf17c9cbe785f3c842c1b62f5b527d Mon Sep 17 00:00:00 2001 From: Sean Nyekjaer Date: Mon, 16 Sep 2019 15:56:29 +0200 Subject: iio: imu: st_lsm6dsx: always enter interrupt thread The interrupt source can come from multiple sources, fifo and wake interrupts. Enter interrupt thread to check which interrupt that has fired. Signed-off-by: Sean Nyekjaer Reviewed-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index dcac1314e769..26acc852982d 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -1715,13 +1715,6 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw, return iio_dev; } -static irqreturn_t st_lsm6dsx_handler_irq(int irq, void *private) -{ - struct st_lsm6dsx_hw *hw = private; - - return hw->sip > 0 ? IRQ_WAKE_THREAD : IRQ_NONE; -} - static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private) { struct st_lsm6dsx_hw *hw = private; @@ -1779,7 +1772,7 @@ static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw) } err = devm_request_threaded_irq(hw->dev, hw->irq, - st_lsm6dsx_handler_irq, + NULL, st_lsm6dsx_handler_thread, irq_type | IRQF_ONESHOT, "lsm6dsx", hw); -- cgit v1.2.3-59-g8ed1b From 1aabad1fb5e98aa5a7449e0d288b4886aca3ebda Mon Sep 17 00:00:00 2001 From: Sean Nyekjaer Date: Mon, 16 Sep 2019 15:56:30 +0200 Subject: iio: imu: st_lsm6dsx: add motion report function and call from interrupt Report iio motion events to iio subsystem and filter motion events. Wakeup will still be on all channels as it's not possible to do the filtering in hw. Signed-off-by: Sean Nyekjaer Reviewed-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 5 ++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 97 ++++++++++++++++++++++++++-- 2 files changed, 98 insertions(+), 4 deletions(-) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 6b0ba48394eb..fd02d0e184f3 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -186,6 +186,11 @@ struct st_lsm6dsx_shub_settings { struct st_lsm6dsx_event_settings { struct st_lsm6dsx_reg enable_reg; struct st_lsm6dsx_reg wakeup_reg; + u8 wakeup_src_reg; + u8 wakeup_src_status_mask; + u8 wakeup_src_z_mask; + u8 wakeup_src_y_mask; + u8 wakeup_src_x_mask; }; enum st_lsm6dsx_ext_sensor_id { diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 26acc852982d..8a813ddba19c 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -287,6 +288,11 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x5B, .mask = GENMASK(5, 0), }, + .wakeup_src_reg = 0x1b, + .wakeup_src_status_mask = BIT(3), + .wakeup_src_z_mask = BIT(0), + .wakeup_src_y_mask = BIT(1), + .wakeup_src_x_mask = BIT(2), }, }, { @@ -412,6 +418,11 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x5B, .mask = GENMASK(5, 0), }, + .wakeup_src_reg = 0x1b, + .wakeup_src_status_mask = BIT(3), + .wakeup_src_z_mask = BIT(0), + .wakeup_src_y_mask = BIT(1), + .wakeup_src_x_mask = BIT(2), }, }, { @@ -550,6 +561,11 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x5B, .mask = GENMASK(5, 0), }, + .wakeup_src_reg = 0x1b, + .wakeup_src_status_mask = BIT(3), + .wakeup_src_z_mask = BIT(0), + .wakeup_src_y_mask = BIT(1), + .wakeup_src_x_mask = BIT(2), }, }, { @@ -816,6 +832,11 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x5B, .mask = GENMASK(5, 0), }, + .wakeup_src_reg = 0x1b, + .wakeup_src_status_mask = BIT(3), + .wakeup_src_z_mask = BIT(0), + .wakeup_src_y_mask = BIT(1), + .wakeup_src_x_mask = BIT(2), }, }, { @@ -970,6 +991,11 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x5B, .mask = GENMASK(5, 0), }, + .wakeup_src_reg = 0x1b, + .wakeup_src_status_mask = BIT(3), + .wakeup_src_z_mask = BIT(0), + .wakeup_src_y_mask = BIT(1), + .wakeup_src_x_mask = BIT(2), } }, }; @@ -1334,7 +1360,7 @@ static int st_lsm6dsx_read_event_config(struct iio_dev *iio_dev, if (type != IIO_EV_TYPE_THRESH) return -EINVAL; - return hw->enable_event; + return !!(hw->enable_event & BIT(chan->channel2)); } static int st_lsm6dsx_write_event_config(struct iio_dev *iio_dev, @@ -1345,13 +1371,28 @@ static int st_lsm6dsx_write_event_config(struct iio_dev *iio_dev, { struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); struct st_lsm6dsx_hw *hw = sensor->hw; + u8 enable_event; int err = 0; if (type != IIO_EV_TYPE_THRESH) return -EINVAL; - /* do not enable events if they are already enabled */ - if (state && hw->enable_event) + if (state) { + enable_event = hw->enable_event | BIT(chan->channel2); + + /* do not enable events if they are already enabled */ + if (hw->enable_event) + goto out; + } else { + enable_event = hw->enable_event & ~BIT(chan->channel2); + + /* only turn off sensor if no events is enabled */ + if (enable_event) + goto out; + } + + /* stop here if no changes have been made */ + if (hw->enable_event == enable_event) return 0; err = st_lsm6dsx_event_setup(hw, state); @@ -1362,7 +1403,8 @@ static int st_lsm6dsx_write_event_config(struct iio_dev *iio_dev, if (err < 0) return err; - hw->enable_event = state; +out: + hw->enable_event = enable_event; return 0; } @@ -1715,10 +1757,57 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw, return iio_dev; } +static void st_lsm6dsx_report_motion_event(struct st_lsm6dsx_hw *hw, int data) +{ + s64 timestamp = iio_get_time_ns(hw->iio_devs[ST_LSM6DSX_ID_ACC]); + + if ((data & hw->settings->event_settings.wakeup_src_z_mask) && + (hw->enable_event & BIT(IIO_MOD_Z))) + iio_push_event(hw->iio_devs[ST_LSM6DSX_ID_ACC], + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_Z, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + timestamp); + + if ((data & hw->settings->event_settings.wakeup_src_y_mask) && + (hw->enable_event & BIT(IIO_MOD_Y))) + iio_push_event(hw->iio_devs[ST_LSM6DSX_ID_ACC], + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_Y, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + timestamp); + + if ((data & hw->settings->event_settings.wakeup_src_x_mask) && + (hw->enable_event & BIT(IIO_MOD_X))) + iio_push_event(hw->iio_devs[ST_LSM6DSX_ID_ACC], + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_X, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + timestamp); +} + static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private) { struct st_lsm6dsx_hw *hw = private; int count; + int data, err; + + if (hw->enable_event) { + err = regmap_read(hw->regmap, + hw->settings->event_settings.wakeup_src_reg, + &data); + if (err < 0) + return IRQ_NONE; + + if (data & hw->settings->event_settings.wakeup_src_status_mask) + st_lsm6dsx_report_motion_event(hw, data); + } mutex_lock(&hw->fifo_lock); count = hw->settings->fifo_ops.read_fifo(hw); -- cgit v1.2.3-59-g8ed1b From 615bd3785b5abf17e50c7940d4f0ce418b65176a Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 6 Oct 2019 15:21:55 +0200 Subject: iio: imu: st_lsm6dsx: use st_lsm6dsx_read_locked in st_lsm6dsx_report_motion_event Rely on st_lsm6dsx_read_locked in st_lsm6dsx_report_motion_event since it can run concurrently with sensor hub configuration. Move event related code in st_lsm6dsx_report_motion_event Fixes: 1aabad1fb5e9 ("iio: imu: st_lsm6dsx: add motion report function and call from interrupt") Signed-off-by: Lorenzo Bianconi Tested-by: Sean Nyekjaer Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 34 ++++++++++++++++------------ 1 file changed, 20 insertions(+), 14 deletions(-) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index de0049c75eeb..5dfb92d83afc 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -1767,10 +1767,23 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw, return iio_dev; } -static void st_lsm6dsx_report_motion_event(struct st_lsm6dsx_hw *hw, int data) +static bool +st_lsm6dsx_report_motion_event(struct st_lsm6dsx_hw *hw) { - s64 timestamp = iio_get_time_ns(hw->iio_devs[ST_LSM6DSX_ID_ACC]); + const struct st_lsm6dsx_event_settings *event_settings; + int err, data; + s64 timestamp; + if (!hw->enable_event) + return false; + + event_settings = &hw->settings->event_settings; + err = st_lsm6dsx_read_locked(hw, event_settings->wakeup_src_reg, + &data, sizeof(data)); + if (err < 0) + return false; + + timestamp = iio_get_time_ns(hw->iio_devs[ST_LSM6DSX_ID_ACC]); if ((data & hw->settings->event_settings.wakeup_src_z_mask) && (hw->enable_event & BIT(IIO_MOD_Z))) iio_push_event(hw->iio_devs[ST_LSM6DSX_ID_ACC], @@ -1800,30 +1813,23 @@ static void st_lsm6dsx_report_motion_event(struct st_lsm6dsx_hw *hw, int data) IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER), timestamp); + + return data & event_settings->wakeup_src_status_mask; } static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private) { struct st_lsm6dsx_hw *hw = private; + bool event; int count; - int data, err; - - if (hw->enable_event) { - err = regmap_read(hw->regmap, - hw->settings->event_settings.wakeup_src_reg, - &data); - if (err < 0) - return IRQ_NONE; - if (data & hw->settings->event_settings.wakeup_src_status_mask) - st_lsm6dsx_report_motion_event(hw, data); - } + event = st_lsm6dsx_report_motion_event(hw); mutex_lock(&hw->fifo_lock); count = hw->settings->fifo_ops.read_fifo(hw); mutex_unlock(&hw->fifo_lock); - return count ? IRQ_HANDLED : IRQ_NONE; + return count || event ? IRQ_HANDLED : IRQ_NONE; } static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw) -- cgit v1.2.3-59-g8ed1b From a912ee4c91542e3746742611a656de1129f919b6 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 6 Oct 2019 15:21:56 +0200 Subject: iio: imu: st_lsm6dsx: add sanity check for read_fifo pointer Check read_fifo pointer before using it since we can't assume it is always set adding new sensors. This patch fixes the following crash: irq 277: nobody cared (try booting with the "irqpoll" option) CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.3.0-rc5-00322-g792b824-dirty #7 Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree) [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (dump_stack+0xd8/0x10c) [] (dump_stack) from [] (__report_bad_irq+0x24/0xc0) [] (__report_bad_irq) from [] (note_interrupt+0x27c/0x2dc) [] (note_interrupt) from [] (handle_irq_event_percpu+0x54/0x7c) [] (handle_irq_event_percpu) from [] (handle_irq_event+0x38/0x5c) [] (handle_irq_event) from [] (handle_level_irq+0xc8/0x154) [] (handle_level_irq) from [] (generic_handle_irq+0x20/0x34) [] (generic_handle_irq) from [] (mxc_gpio_irq_handler+0xc4/0xf8) [] (mxc_gpio_irq_handler) from [] (mx3_gpio_irq_handler+0x64/0xb8) [] (mx3_gpio_irq_handler) from [] (generic_handle_irq+0x20/0x34) [] (generic_handle_irq) from [] (__handle_domain_irq+0x64/0xe0) [] (__handle_domain_irq) from [] (gic_handle_irq+0x4c/0xa0) [] (gic_handle_irq) from [] (__irq_svc+0x70/0x98) Exception stack(0xc1301f10 to 0xc1301f58 1f00: 00000001 00000006 00000000 c130c340 1f20: c1300000 c1308928 00000001 c1308960 00000000 c12b9db0 c1308908 00000000 1f40: 00000000 c1301f60 c0182010 c0109508 20000013 ffffffff [] (__irq_svc) from [] (arch_cpu_idle+0x20/0x3c) [] (arch_cpu_idle) from [] (do_idle+0x1bc/0x2bc) [] (do_idle) from [] (cpu_startup_entry+0x18/0x1c) [] (cpu_startup_entry) from [] (start_kernel+0x440/0x504) [] (start_kernel) from [<00000000>] (0x0) handlers: [<62052c0d>] st_lsm6dsx_handler_irq threaded [] st_lsm6dsx_handler_thread Fixes: 52f4b1f19679 ("iio: imu: st_lsm6dsx: add support for accel/gyro unit of lsm9ds1") Tested-by: Bobby Jones Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c | 3 +++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 3 +++ 2 files changed, 6 insertions(+) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index ef579650fd52..cabd4bfeab17 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -586,6 +586,9 @@ int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw) { int err; + if (!hw->settings->fifo_ops.read_fifo) + return -ENOTSUPP; + mutex_lock(&hw->fifo_lock); hw->settings->fifo_ops.read_fifo(hw); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 5dfb92d83afc..5928d29dd589 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -1825,6 +1825,9 @@ static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private) event = st_lsm6dsx_report_motion_event(hw); + if (!hw->settings->fifo_ops.read_fifo) + return event ? IRQ_HANDLED : IRQ_NONE; + mutex_lock(&hw->fifo_lock); count = hw->settings->fifo_ops.read_fifo(hw); mutex_unlock(&hw->fifo_lock); -- cgit v1.2.3-59-g8ed1b From 7e9061030dd60562fc4346efd84d2186ee65111b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 6 Oct 2019 15:21:57 +0200 Subject: iio: imu: st_lsm6dsx: move irq related definitions in irq_config Group irq related definition in irq_config structure in st_lsm6dsx_settings. This is a preliminary patch to move OpenDrain/Active low registers in st_lsm6dsx_settings. Signed-off-by: Lorenzo Bianconi Tested-by: Sean Nyekjaer Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 22 +-- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 265 +++++++++++++++++---------- 2 files changed, 179 insertions(+), 108 deletions(-) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index e5e782f756e4..2784e3d97a7d 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -238,29 +238,21 @@ struct st_lsm6dsx_ext_dev_settings { /** * struct st_lsm6dsx_settings - ST IMU sensor settings * @wai: Sensor WhoAmI default value. - * @int1_addr: Control Register address for INT1 - * @int2_addr: Control Register address for INT2 * @reset_addr: register address for reset/reboot * @max_fifo_size: Sensor max fifo length in FIFO words. * @id: List of hw id/device name supported by the driver configuration. * @channels: IIO channels supported by the device. + * @irq_config: interrupts related registers. * @odr_table: Hw sensors odr table (Hz + val). * @fs_table: Hw sensors gain table (gain + val). * @decimator: List of decimator register info (addr + mask). * @batch: List of FIFO batching register info (addr + mask). - * @lir: Latched interrupt register info (addr + mask). - * @clear_on_read: Clear on read register info (addr + mask). * @fifo_ops: Sensor hw FIFO parameters. * @ts_settings: Hw timer related settings. * @shub_settings: i2c controller related settings. */ 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 { @@ -271,12 +263,18 @@ struct st_lsm6dsx_settings { const struct iio_chan_spec *chan; int len; } channels[2]; + struct { + struct st_lsm6dsx_reg irq1; + struct st_lsm6dsx_reg irq2; + struct st_lsm6dsx_reg irq1_func; + struct st_lsm6dsx_reg irq2_func; + struct st_lsm6dsx_reg lir; + struct st_lsm6dsx_reg clear_on_read; + } irq_config; struct st_lsm6dsx_odr_table_entry odr_table[2]; struct st_lsm6dsx_fs_table_entry fs_table[2]; struct st_lsm6dsx_reg decimator[ST_LSM6DSX_MAX_ID]; struct st_lsm6dsx_reg batch[ST_LSM6DSX_MAX_ID]; - struct st_lsm6dsx_reg lir; - struct st_lsm6dsx_reg clear_on_read; struct st_lsm6dsx_fifo_ops fifo_ops; struct st_lsm6dsx_hw_ts_settings ts_settings; struct st_lsm6dsx_shub_settings shub_settings; @@ -361,9 +359,9 @@ struct st_lsm6dsx_hw { u8 ts_sip; u8 sip; + const struct st_lsm6dsx_reg *irq_routing; u8 event_threshold; u8 enable_event; - struct st_lsm6dsx_reg irq_routing; u8 *buff; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 5928d29dd589..402895954065 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -61,7 +61,6 @@ #include "st_lsm6dsx.h" -#define ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK BIT(3) #define ST_LSM6DSX_REG_WHOAMI_ADDR 0x0f #define ST_LSM6DSX_REG_RESET_MASK BIT(0) #define ST_LSM6DSX_REG_BOOT_MASK BIT(7) @@ -97,8 +96,6 @@ static const struct iio_chan_spec st_lsm6ds0_gyro_channels[] = { static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { { .wai = 0x68, - .int1_addr = 0x0c, - .int2_addr = 0x0d, .reset_addr = 0x22, .max_fifo_size = 32, .id = { @@ -166,14 +163,19 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .fs_len = 3, }, }, + .irq_config = { + .irq1 = { + .addr = 0x0c, + .mask = BIT(3), + }, + .irq2 = { + .addr = 0x0d, + .mask = BIT(3), + }, + }, }, { .wai = 0x69, - .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 = 1365, .id = { @@ -242,6 +244,28 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .fs_len = 4, }, }, + .irq_config = { + .irq1 = { + .addr = 0x0d, + .mask = BIT(3), + }, + .irq2 = { + .addr = 0x0e, + .mask = BIT(3), + }, + .lir = { + .addr = 0x58, + .mask = BIT(0), + }, + .irq1_func = { + .addr = 0x5e, + .mask = BIT(5), + }, + .irq2_func = { + .addr = 0x5f, + .mask = BIT(5), + }, + }, .decimator = { [ST_LSM6DSX_ID_ACC] = { .addr = 0x08, @@ -252,10 +276,6 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .mask = GENMASK(5, 3), }, }, - .lir = { - .addr = 0x58, - .mask = BIT(0), - }, .fifo_ops = { .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_fifo, @@ -301,11 +321,6 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, { .wai = 0x69, - .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 = { @@ -374,6 +389,28 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .fs_len = 4, }, }, + .irq_config = { + .irq1 = { + .addr = 0x0d, + .mask = BIT(3), + }, + .irq2 = { + .addr = 0x0e, + .mask = BIT(3), + }, + .lir = { + .addr = 0x58, + .mask = BIT(0), + }, + .irq1_func = { + .addr = 0x5e, + .mask = BIT(5), + }, + .irq2_func = { + .addr = 0x5f, + .mask = BIT(5), + }, + }, .decimator = { [ST_LSM6DSX_ID_ACC] = { .addr = 0x08, @@ -384,10 +421,6 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .mask = GENMASK(5, 3), }, }, - .lir = { - .addr = 0x58, - .mask = BIT(0), - }, .fifo_ops = { .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_fifo, @@ -433,11 +466,6 @@ 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 = { @@ -515,6 +543,28 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .fs_len = 4, }, }, + .irq_config = { + .irq1 = { + .addr = 0x0d, + .mask = BIT(3), + }, + .irq2 = { + .addr = 0x0e, + .mask = BIT(3), + }, + .lir = { + .addr = 0x58, + .mask = BIT(0), + }, + .irq1_func = { + .addr = 0x5e, + .mask = BIT(5), + }, + .irq2_func = { + .addr = 0x5f, + .mask = BIT(5), + }, + }, .decimator = { [ST_LSM6DSX_ID_ACC] = { .addr = 0x08, @@ -525,10 +575,6 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .mask = GENMASK(5, 3), }, }, - .lir = { - .addr = 0x58, - .mask = BIT(0), - }, .fifo_ops = { .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_fifo, @@ -578,8 +624,6 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, { .wai = 0x6c, - .int1_addr = 0x0d, - .int2_addr = 0x0e, .reset_addr = 0x12, .max_fifo_size = 512, .id = { @@ -651,6 +695,24 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .fs_len = 4, }, }, + .irq_config = { + .irq1 = { + .addr = 0x0d, + .mask = BIT(3), + }, + .irq2 = { + .addr = 0x0e, + .mask = BIT(3), + }, + .lir = { + .addr = 0x56, + .mask = BIT(0), + }, + .clear_on_read = { + .addr = 0x56, + .mask = BIT(6), + }, + }, .batch = { [ST_LSM6DSX_ID_ACC] = { .addr = 0x09, @@ -661,14 +723,6 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .mask = GENMASK(7, 4), }, }, - .lir = { - .addr = 0x56, - .mask = BIT(0), - }, - .clear_on_read = { - .addr = 0x56, - .mask = BIT(6), - }, .fifo_ops = { .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_tagged_fifo, @@ -721,11 +775,6 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, { .wai = 0x6b, - .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 = 512, .id = { @@ -794,6 +843,32 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .fs_len = 4, }, }, + .irq_config = { + .irq1 = { + .addr = 0x0d, + .mask = BIT(3), + }, + .irq2 = { + .addr = 0x0e, + .mask = BIT(3), + }, + .lir = { + .addr = 0x56, + .mask = BIT(0), + }, + .clear_on_read = { + .addr = 0x56, + .mask = BIT(6), + }, + .irq1_func = { + .addr = 0x5e, + .mask = BIT(5), + }, + .irq2_func = { + .addr = 0x5f, + .mask = BIT(5), + }, + }, .batch = { [ST_LSM6DSX_ID_ACC] = { .addr = 0x09, @@ -804,14 +879,6 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .mask = GENMASK(7, 4), }, }, - .lir = { - .addr = 0x56, - .mask = BIT(0), - }, - .clear_on_read = { - .addr = 0x56, - .mask = BIT(6), - }, .fifo_ops = { .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_tagged_fifo, @@ -853,11 +920,6 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, { .wai = 0x6b, - .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 = 512, .id = { @@ -929,6 +991,32 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .fs_len = 4, }, }, + .irq_config = { + .irq1 = { + .addr = 0x0d, + .mask = BIT(3), + }, + .irq2 = { + .addr = 0x0e, + .mask = BIT(3), + }, + .lir = { + .addr = 0x56, + .mask = BIT(0), + }, + .clear_on_read = { + .addr = 0x56, + .mask = BIT(6), + }, + .irq1_func = { + .addr = 0x5e, + .mask = BIT(5), + }, + .irq2_func = { + .addr = 0x5f, + .mask = BIT(5), + }, + }, .batch = { [ST_LSM6DSX_ID_ACC] = { .addr = 0x09, @@ -939,14 +1027,6 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .mask = GENMASK(7, 4), }, }, - .lir = { - .addr = 0x56, - .mask = BIT(0), - }, - .clear_on_read = { - .addr = 0x56, - .mask = BIT(6), - }, .fifo_ops = { .update_fifo = st_lsm6dsx_update_fifo, .read_fifo = st_lsm6dsx_read_tagged_fifo, @@ -1296,7 +1376,7 @@ static int st_lsm6dsx_event_setup(struct st_lsm6dsx_hw *hw, int state) int err; u8 enable = 0; - if (!hw->settings->int1_func_addr) + if (!hw->settings->irq_config.irq1_func.addr) return -ENOTSUPP; enable = state ? hw->settings->event_settings.enable_reg.mask : 0; @@ -1308,12 +1388,11 @@ static int st_lsm6dsx_event_setup(struct st_lsm6dsx_hw *hw, int state) if (err < 0) return err; - enable = state ? hw->irq_routing.mask : 0; + enable = state ? hw->irq_routing->mask : 0; /* Enable wakeup interrupt */ - return 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); } static int st_lsm6dsx_read_event(struct iio_dev *iio_dev, @@ -1537,7 +1616,9 @@ static int st_lsm6dsx_of_get_drdy_pin(struct st_lsm6dsx_hw *hw, int *drdy_pin) return of_property_read_u32(np, "st,drdy-int-pin", drdy_pin); } -static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg) +static int +st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, + const struct st_lsm6dsx_reg **drdy_reg) { int err = 0, drdy_pin; @@ -1551,14 +1632,12 @@ 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; + hw->irq_routing = &hw->settings->irq_config.irq1_func; + *drdy_reg = &hw->settings->irq_config.irq1; 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; + hw->irq_routing = &hw->settings->irq_config.irq2_func; + *drdy_reg = &hw->settings->irq_config.irq2; break; default: dev_err(hw->dev, "unsupported data ready pin\n"); @@ -1654,7 +1733,7 @@ static int st_lsm6dsx_init_hw_timer(struct st_lsm6dsx_hw *hw) static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw) { - u8 drdy_int_reg; + const struct st_lsm6dsx_reg *reg; int err; /* device sw reset */ @@ -1683,35 +1762,29 @@ static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw) return err; /* enable FIFO watermak interrupt */ - err = st_lsm6dsx_get_drdy_reg(hw, &drdy_int_reg); + err = st_lsm6dsx_get_drdy_reg(hw, ®); if (err < 0) return err; - err = regmap_update_bits(hw->regmap, drdy_int_reg, - ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK, - FIELD_PREP(ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK, - 1)); + err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, + ST_LSM6DSX_SHIFT_VAL(1, reg->mask)); if (err < 0) return err; /* enable Latched interrupts for device events */ - if (hw->settings->lir.addr) { - unsigned int data; - - data = ST_LSM6DSX_SHIFT_VAL(1, hw->settings->lir.mask); - err = regmap_update_bits(hw->regmap, hw->settings->lir.addr, - hw->settings->lir.mask, data); + if (hw->settings->irq_config.lir.addr) { + reg = &hw->settings->irq_config.lir; + err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, + ST_LSM6DSX_SHIFT_VAL(1, reg->mask)); if (err < 0) return err; /* enable clear on read for latched interrupts */ - if (hw->settings->clear_on_read.addr) { - data = ST_LSM6DSX_SHIFT_VAL(1, - hw->settings->clear_on_read.mask); + if (hw->settings->irq_config.clear_on_read.addr) { + reg = &hw->settings->irq_config.clear_on_read; err = regmap_update_bits(hw->regmap, - hw->settings->clear_on_read.addr, - hw->settings->clear_on_read.mask, - data); + reg->addr, reg->mask, + ST_LSM6DSX_SHIFT_VAL(1, reg->mask)); if (err < 0) return err; } -- cgit v1.2.3-59-g8ed1b From 31fe8d4e0fd559880bcb54c02d939e228ba18080 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 6 Oct 2019 15:21:58 +0200 Subject: iio: imu: st_lsm6dsx: do not access active-low/open-drain regs if not supported Move active low and open drain register definitions in hw_settings register map since not all supported sensors (e.g lsm9ds1) rely on the same definitions Fixes: 52f4b1f19679 ("iio: imu: st_lsm6dsx: add support for accel/gyro unit of lsm9ds1") Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 2 + drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 79 +++++++++++++++++++++++----- 2 files changed, 67 insertions(+), 14 deletions(-) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 2784e3d97a7d..2fb92f765226 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -270,6 +270,8 @@ struct st_lsm6dsx_settings { struct st_lsm6dsx_reg irq2_func; struct st_lsm6dsx_reg lir; struct st_lsm6dsx_reg clear_on_read; + struct st_lsm6dsx_reg hla; + struct st_lsm6dsx_reg od; } irq_config; struct st_lsm6dsx_odr_table_entry odr_table[2]; struct st_lsm6dsx_fs_table_entry fs_table[2]; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 402895954065..1f29dd24dcae 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -67,11 +67,6 @@ #define ST_LSM6DSX_REG_BDU_ADDR 0x12 #define ST_LSM6DSX_REG_BDU_MASK BIT(6) -#define ST_LSM6DSX_REG_HLACTIVE_ADDR 0x12 -#define ST_LSM6DSX_REG_HLACTIVE_MASK BIT(5) -#define ST_LSM6DSX_REG_PP_OD_ADDR 0x12 -#define ST_LSM6DSX_REG_PP_OD_MASK BIT(4) - static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = { ST_LSM6DSX_CHANNEL_ACC(IIO_ACCEL, 0x28, IIO_MOD_X, 0), ST_LSM6DSX_CHANNEL_ACC(IIO_ACCEL, 0x2a, IIO_MOD_Y, 1), @@ -172,6 +167,14 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x0d, .mask = BIT(3), }, + .hla = { + .addr = 0x22, + .mask = BIT(5), + }, + .od = { + .addr = 0x22, + .mask = BIT(4), + }, }, }, { @@ -265,6 +268,14 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x5f, .mask = BIT(5), }, + .hla = { + .addr = 0x12, + .mask = BIT(5), + }, + .od = { + .addr = 0x12, + .mask = BIT(4), + }, }, .decimator = { [ST_LSM6DSX_ID_ACC] = { @@ -410,6 +421,14 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x5f, .mask = BIT(5), }, + .hla = { + .addr = 0x12, + .mask = BIT(5), + }, + .od = { + .addr = 0x12, + .mask = BIT(4), + }, }, .decimator = { [ST_LSM6DSX_ID_ACC] = { @@ -564,6 +583,14 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x5f, .mask = BIT(5), }, + .hla = { + .addr = 0x12, + .mask = BIT(5), + }, + .od = { + .addr = 0x12, + .mask = BIT(4), + }, }, .decimator = { [ST_LSM6DSX_ID_ACC] = { @@ -712,6 +739,14 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x56, .mask = BIT(6), }, + .hla = { + .addr = 0x12, + .mask = BIT(5), + }, + .od = { + .addr = 0x12, + .mask = BIT(4), + }, }, .batch = { [ST_LSM6DSX_ID_ACC] = { @@ -868,6 +903,14 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x5f, .mask = BIT(5), }, + .hla = { + .addr = 0x12, + .mask = BIT(5), + }, + .od = { + .addr = 0x12, + .mask = BIT(4), + }, }, .batch = { [ST_LSM6DSX_ID_ACC] = { @@ -1016,6 +1059,14 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x5f, .mask = BIT(5), }, + .hla = { + .addr = 0x12, + .mask = BIT(5), + }, + .od = { + .addr = 0x12, + .mask = BIT(4), + }, }, .batch = { [ST_LSM6DSX_ID_ACC] = { @@ -1910,8 +1961,9 @@ static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private) static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw) { - struct st_sensors_platform_data *pdata; struct device_node *np = hw->dev->of_node; + struct st_sensors_platform_data *pdata; + const struct st_lsm6dsx_reg *reg; unsigned long irq_type; bool irq_active_low; int err; @@ -1932,20 +1984,19 @@ static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw) return -EINVAL; } - err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_HLACTIVE_ADDR, - ST_LSM6DSX_REG_HLACTIVE_MASK, - FIELD_PREP(ST_LSM6DSX_REG_HLACTIVE_MASK, - irq_active_low)); + reg = &hw->settings->irq_config.hla; + err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, + ST_LSM6DSX_SHIFT_VAL(irq_active_low, + reg->mask)); if (err < 0) return err; pdata = (struct st_sensors_platform_data *)hw->dev->platform_data; if ((np && of_property_read_bool(np, "drive-open-drain")) || (pdata && pdata->open_drain)) { - err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_PP_OD_ADDR, - ST_LSM6DSX_REG_PP_OD_MASK, - FIELD_PREP(ST_LSM6DSX_REG_PP_OD_MASK, - 1)); + reg = &hw->settings->irq_config.od; + err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, + ST_LSM6DSX_SHIFT_VAL(1, reg->mask)); if (err < 0) return err; -- cgit v1.2.3-59-g8ed1b From 66b662a1760e4c21af6f3aaf8dd575363c174473 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 6 Oct 2019 15:21:59 +0200 Subject: iio: imu: st_lsm6dsx: move bdu/boot and reset register info in hw_settings Move bdu, boot and reset register definitions in hw_settings register map since not all supported sensors (e.g lsm9ds1) rely on the same definitions Fixes: 52f4b1f19679 ("iio: imu: st_lsm6dsx: add support for accel/gyro unit of lsm9ds1") Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 8 +- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 113 ++++++++++++++++++++++----- 2 files changed, 99 insertions(+), 22 deletions(-) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 2fb92f765226..7dbce8b971ef 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -238,7 +238,9 @@ struct st_lsm6dsx_ext_dev_settings { /** * struct st_lsm6dsx_settings - ST IMU sensor settings * @wai: Sensor WhoAmI default value. - * @reset_addr: register address for reset/reboot + * @reset: register address for reset. + * @boot: register address for boot. + * @bdu: register address for Block Data Update. * @max_fifo_size: Sensor max fifo length in FIFO words. * @id: List of hw id/device name supported by the driver configuration. * @channels: IIO channels supported by the device. @@ -253,7 +255,9 @@ struct st_lsm6dsx_ext_dev_settings { */ struct st_lsm6dsx_settings { u8 wai; - u8 reset_addr; + struct st_lsm6dsx_reg reset; + struct st_lsm6dsx_reg boot; + struct st_lsm6dsx_reg bdu; u16 max_fifo_size; struct { enum st_lsm6dsx_hw_id hw_id; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 1f29dd24dcae..854489e024ad 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -62,10 +62,6 @@ #include "st_lsm6dsx.h" #define ST_LSM6DSX_REG_WHOAMI_ADDR 0x0f -#define ST_LSM6DSX_REG_RESET_MASK BIT(0) -#define ST_LSM6DSX_REG_BOOT_MASK BIT(7) -#define ST_LSM6DSX_REG_BDU_ADDR 0x12 -#define ST_LSM6DSX_REG_BDU_MASK BIT(6) static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = { ST_LSM6DSX_CHANNEL_ACC(IIO_ACCEL, 0x28, IIO_MOD_X, 0), @@ -91,7 +87,18 @@ static const struct iio_chan_spec st_lsm6ds0_gyro_channels[] = { static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { { .wai = 0x68, - .reset_addr = 0x22, + .reset = { + .addr = 0x22, + .mask = BIT(0), + }, + .boot = { + .addr = 0x22, + .mask = BIT(7), + }, + .bdu = { + .addr = 0x22, + .mask = BIT(6), + }, .max_fifo_size = 32, .id = { { @@ -179,7 +186,18 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, { .wai = 0x69, - .reset_addr = 0x12, + .reset = { + .addr = 0x12, + .mask = BIT(0), + }, + .boot = { + .addr = 0x12, + .mask = BIT(7), + }, + .bdu = { + .addr = 0x12, + .mask = BIT(6), + }, .max_fifo_size = 1365, .id = { { @@ -332,7 +350,18 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, { .wai = 0x69, - .reset_addr = 0x12, + .reset = { + .addr = 0x12, + .mask = BIT(0), + }, + .boot = { + .addr = 0x12, + .mask = BIT(7), + }, + .bdu = { + .addr = 0x12, + .mask = BIT(6), + }, .max_fifo_size = 682, .id = { { @@ -485,7 +514,18 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, { .wai = 0x6a, - .reset_addr = 0x12, + .reset = { + .addr = 0x12, + .mask = BIT(0), + }, + .boot = { + .addr = 0x12, + .mask = BIT(7), + }, + .bdu = { + .addr = 0x12, + .mask = BIT(6), + }, .max_fifo_size = 682, .id = { { @@ -651,7 +691,18 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, { .wai = 0x6c, - .reset_addr = 0x12, + .reset = { + .addr = 0x12, + .mask = BIT(0), + }, + .boot = { + .addr = 0x12, + .mask = BIT(7), + }, + .bdu = { + .addr = 0x12, + .mask = BIT(6), + }, .max_fifo_size = 512, .id = { { @@ -810,7 +861,18 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, { .wai = 0x6b, - .reset_addr = 0x12, + .reset = { + .addr = 0x12, + .mask = BIT(0), + }, + .boot = { + .addr = 0x12, + .mask = BIT(7), + }, + .bdu = { + .addr = 0x12, + .mask = BIT(6), + }, .max_fifo_size = 512, .id = { { @@ -963,7 +1025,18 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, { .wai = 0x6b, - .reset_addr = 0x12, + .reset = { + .addr = 0x12, + .mask = BIT(0), + }, + .boot = { + .addr = 0x12, + .mask = BIT(7), + }, + .bdu = { + .addr = 0x12, + .mask = BIT(6), + }, .max_fifo_size = 512, .id = { { @@ -1788,27 +1861,27 @@ static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw) int err; /* device sw reset */ - err = regmap_update_bits(hw->regmap, hw->settings->reset_addr, - ST_LSM6DSX_REG_RESET_MASK, - FIELD_PREP(ST_LSM6DSX_REG_RESET_MASK, 1)); + reg = &hw->settings->reset; + err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, + ST_LSM6DSX_SHIFT_VAL(1, reg->mask)); if (err < 0) return err; msleep(50); /* reload trimming parameter */ - err = regmap_update_bits(hw->regmap, hw->settings->reset_addr, - ST_LSM6DSX_REG_BOOT_MASK, - FIELD_PREP(ST_LSM6DSX_REG_BOOT_MASK, 1)); + reg = &hw->settings->boot; + err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, + ST_LSM6DSX_SHIFT_VAL(1, reg->mask)); if (err < 0) return err; msleep(50); /* enable Block Data Update */ - err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_BDU_ADDR, - ST_LSM6DSX_REG_BDU_MASK, - FIELD_PREP(ST_LSM6DSX_REG_BDU_MASK, 1)); + reg = &hw->settings->bdu; + err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, + ST_LSM6DSX_SHIFT_VAL(1, reg->mask)); if (err < 0) return err; -- cgit v1.2.3-59-g8ed1b From 84b2e7c319b8e9707c9c62eeeaf9cf937ef36cbd Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 6 Oct 2019 15:22:00 +0200 Subject: iio: imu: st_lsm6dsx: always check enable_reg in st_lsm6dsx_event_setup Check if enable_reg of event_settings data structure is defined before writing on it Fixes: b5969abfa8b8 ("iio: imu: st_lsm6dsx: add motion events") Signed-off-by: Lorenzo Bianconi Tested-by: Sean Nyekjaer Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 854489e024ad..e697436d27a1 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -1497,26 +1497,25 @@ static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev, static int st_lsm6dsx_event_setup(struct st_lsm6dsx_hw *hw, int state) { + const struct st_lsm6dsx_reg *reg; int err; - u8 enable = 0; if (!hw->settings->irq_config.irq1_func.addr) return -ENOTSUPP; - 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; + reg = &hw->settings->event_settings.enable_reg; + if (reg->addr) { + err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, + ST_LSM6DSX_SHIFT_VAL(state, reg->mask)); + if (err < 0) + return err; + } /* Enable wakeup interrupt */ return regmap_update_bits(hw->regmap, hw->irq_routing->addr, - hw->irq_routing->mask, enable); + hw->irq_routing->mask, + ST_LSM6DSX_SHIFT_VAL(state, + hw->irq_routing->mask)); } static int st_lsm6dsx_read_event(struct iio_dev *iio_dev, -- cgit v1.2.3-59-g8ed1b From 04ca37d5ade99aaf49b662da8142926c981d154f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 6 Oct 2019 15:22:01 +0200 Subject: iio: imu: st_lsm6dsx: rely on st_lsm6dsx_update_bits_locked configuring events Rely on st_lsm6dsx_update_bits_locked in st_lsm6dsx_write_event and st_lsm6dsx_event_setup routines since they can run concurrently with sensor hub configuration Fixes: b5969abfa8b8 ("iio: imu: st_lsm6dsx: add motion events") Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index e697436d27a1..a6d5a9ea7806 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -1498,6 +1498,7 @@ static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev, static int st_lsm6dsx_event_setup(struct st_lsm6dsx_hw *hw, int state) { const struct st_lsm6dsx_reg *reg; + unsigned int data; int err; if (!hw->settings->irq_config.irq1_func.addr) @@ -1505,17 +1506,17 @@ static int st_lsm6dsx_event_setup(struct st_lsm6dsx_hw *hw, int state) reg = &hw->settings->event_settings.enable_reg; if (reg->addr) { - err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, - ST_LSM6DSX_SHIFT_VAL(state, reg->mask)); + data = ST_LSM6DSX_SHIFT_VAL(state, reg->mask); + err = st_lsm6dsx_update_bits_locked(hw, reg->addr, + reg->mask, data); if (err < 0) return err; } /* Enable wakeup interrupt */ - return regmap_update_bits(hw->regmap, hw->irq_routing->addr, - hw->irq_routing->mask, - ST_LSM6DSX_SHIFT_VAL(state, - hw->irq_routing->mask)); + data = ST_LSM6DSX_SHIFT_VAL(state, hw->irq_routing->mask); + return st_lsm6dsx_update_bits_locked(hw, hw->irq_routing->addr, + hw->irq_routing->mask, data); } static int st_lsm6dsx_read_event(struct iio_dev *iio_dev, @@ -1546,6 +1547,8 @@ static int st_lsm6dsx_write_event(struct iio_dev *iio_dev, { struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); struct st_lsm6dsx_hw *hw = sensor->hw; + const struct st_lsm6dsx_reg *reg; + unsigned int data; int err; if (type != IIO_EV_TYPE_THRESH) @@ -1554,11 +1557,11 @@ static int st_lsm6dsx_write_event(struct iio_dev *iio_dev, 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) + reg = &hw->settings->event_settings.wakeup_reg; + data = ST_LSM6DSX_SHIFT_VAL(val, reg->mask); + err = st_lsm6dsx_update_bits_locked(hw, reg->addr, + reg->mask, data); + if (err < 0) return -EINVAL; hw->event_threshold = val; -- cgit v1.2.3-59-g8ed1b From d278d4479402d9cd653bfa5714399410f4196445 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 6 Oct 2019 15:22:02 +0200 Subject: iio: imu: st_lsm6dsx: grab conf mutex in st_lsm6dsx_write_event_config Always grub conf mutex in st_lsm6dsx_write_event_config since it can run concurrently with FIFO configuration Fixes: b5969abfa8b8 ("iio: imu: st_lsm6dsx: add motion events") Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index a6d5a9ea7806..0d5054a5105e 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -1619,7 +1619,9 @@ static int st_lsm6dsx_write_event_config(struct iio_dev *iio_dev, if (err < 0) return err; + mutex_lock(&hw->conf_lock); err = st_lsm6dsx_sensor_set_enable(sensor, state); + mutex_unlock(&hw->conf_lock); if (err < 0) return err; -- cgit v1.2.3-59-g8ed1b From b307f495468b455d3f85f8715e5b7cd83937a76a Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 6 Oct 2019 15:22:03 +0200 Subject: iio: imu: st_lsm6dsx: fix checkpatch warning Fix following checkpatch warnings: CHECK: Alignment should match open parenthesis +static int st_lsm6dsx_read_event(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, CHECK: Alignment should match open parenthesis +static int st_lsm6dsx_write_event(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, CHECK: Alignment should match open parenthesis +static int st_lsm6dsx_read_event_config(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, CHECK: Alignment should match open parenthesis +static int st_lsm6dsx_write_event_config(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, WARNING: line over 80 characters + if (dev->of_node && of_property_read_bool(dev->of_node, "wakeup-source")) Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 35 +++++++++++++++------------- 1 file changed, 19 insertions(+), 16 deletions(-) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 0d5054a5105e..c0df2615ed74 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -1538,12 +1538,13 @@ static int st_lsm6dsx_read_event(struct iio_dev *iio_dev, 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) +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; @@ -1569,10 +1570,11 @@ static int st_lsm6dsx_write_event(struct iio_dev *iio_dev, 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) +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; @@ -1583,11 +1585,11 @@ static int st_lsm6dsx_read_event_config(struct iio_dev *iio_dev, return !!(hw->enable_event & BIT(chan->channel2)); } -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) +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; @@ -2160,7 +2162,8 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, return err; } - if (dev->of_node && of_property_read_bool(dev->of_node, "wakeup-source")) + if (dev->of_node && + of_property_read_bool(dev->of_node, "wakeup-source")) device_init_wakeup(dev, true); return 0; -- cgit v1.2.3-59-g8ed1b From b7a73b33bb39575848df66c4bff09cd281652882 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 6 Oct 2019 15:22:04 +0200 Subject: iio: imu: st_lsm6dsx: add wakeup_source in st_sensors_platform_data Add the possibility to enable/disable wakeup source through st_sensors_platform_data and not only through device tree Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 6 ++++-- include/linux/platform_data/st_sensors_pdata.h | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index c0df2615ed74..5be372d5f407 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -2099,7 +2099,9 @@ static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw) int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, struct regmap *regmap) { + struct st_sensors_platform_data *pdata = dev->platform_data; const struct st_lsm6dsx_shub_settings *hub_settings; + struct device_node *np = dev->of_node; struct st_lsm6dsx_hw *hw; const char *name = NULL; int i, err; @@ -2162,8 +2164,8 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, return err; } - if (dev->of_node && - of_property_read_bool(dev->of_node, "wakeup-source")) + if ((np && of_property_read_bool(np, "wakeup-source")) || + (pdata && pdata->wakeup_source)) device_init_wakeup(dev, true); return 0; diff --git a/include/linux/platform_data/st_sensors_pdata.h b/include/linux/platform_data/st_sensors_pdata.h index 30929c22227d..e40b28ca892e 100644 --- a/include/linux/platform_data/st_sensors_pdata.h +++ b/include/linux/platform_data/st_sensors_pdata.h @@ -18,12 +18,14 @@ * @open_drain: set the interrupt line to be open drain if possible. * @spi_3wire: enable spi-3wire mode. * @pullups: enable/disable i2c controller pullup resistors. + * @wakeup_source: enable/disable device as wakeup generator. */ struct st_sensors_platform_data { u8 drdy_int_pin; bool open_drain; bool spi_3wire; bool pullups; + bool wakeup_source; }; #endif /* ST_SENSORS_PDATA_H */ -- cgit v1.2.3-59-g8ed1b From 3ea39d61eea6af614fe166814c9e5cb8cff0e8c3 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 6 Oct 2019 15:22:07 +0200 Subject: iio: imu: st_lsm6dsx: enable wake-up event for LSM6DSO Add missing wake-up register info for LSM6DSO/LSM6DSOX sensor Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 5be372d5f407..8f70a645f65c 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -790,6 +790,14 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x56, .mask = BIT(6), }, + .irq1_func = { + .addr = 0x5e, + .mask = BIT(5), + }, + .irq2_func = { + .addr = 0x5f, + .mask = BIT(5), + }, .hla = { .addr = 0x12, .mask = BIT(5), @@ -857,7 +865,22 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .slv0_addr = 0x15, .dw_slv0_addr = 0x21, .batch_en = BIT(3), - } + }, + .event_settings = { + .enable_reg = { + .addr = 0x58, + .mask = BIT(7), + }, + .wakeup_reg = { + .addr = 0x5b, + .mask = GENMASK(5, 0), + }, + .wakeup_src_reg = 0x1b, + .wakeup_src_status_mask = BIT(3), + .wakeup_src_z_mask = BIT(0), + .wakeup_src_y_mask = BIT(1), + .wakeup_src_x_mask = BIT(2), + }, }, { .wai = 0x6b, -- cgit v1.2.3-59-g8ed1b From 960506ed2c69a87a2004556624c8f702391b2e43 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 8 Oct 2019 14:05:02 +0200 Subject: iio: imu: st_lsm6dsx: enable drdy-mask if available Enable drdy mask if available in order to mark invalid samples during sensor bootstrap phase Tested-by: Mario Tesi Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 2 ++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c | 6 ++++++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 21 +++++++++++++++++++++ 3 files changed, 29 insertions(+) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 858b4e96e846..b766c2218f4b 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -245,6 +245,7 @@ struct st_lsm6dsx_ext_dev_settings { * @id: List of hw id/device name supported by the driver configuration. * @channels: IIO channels supported by the device. * @irq_config: interrupts related registers. + * @drdy_mask: register info for data-ready mask (addr + mask). * @odr_table: Hw sensors odr table (Hz + val). * @fs_table: Hw sensors gain table (gain + val). * @decimator: List of decimator register info (addr + mask). @@ -277,6 +278,7 @@ struct st_lsm6dsx_settings { struct st_lsm6dsx_reg hla; struct st_lsm6dsx_reg od; } irq_config; + struct st_lsm6dsx_reg drdy_mask; struct st_lsm6dsx_odr_table_entry odr_table[2]; struct st_lsm6dsx_fs_table_entry fs_table[2]; struct st_lsm6dsx_reg decimator[ST_LSM6DSX_MAX_ID]; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index cabd4bfeab17..1f6873441aa0 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -450,13 +450,19 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw) return read_len; } +#define ST_LSM6DSX_INVALID_SAMPLE 0x7ffd static int st_lsm6dsx_push_tagged_data(struct st_lsm6dsx_hw *hw, u8 tag, u8 *data, s64 ts) { + s16 val = le16_to_cpu(*(__le16 *)data); struct st_lsm6dsx_sensor *sensor; struct iio_dev *iio_dev; + /* invalid sample during bootstrap phase */ + if (val >= ST_LSM6DSX_INVALID_SAMPLE) + return -EINVAL; + /* * EXT_TAG are managed in FIFO fashion so ST_LSM6DSX_EXT0_TAG * corresponds to the first enabled channel, ST_LSM6DSX_EXT1_TAG diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 8f70a645f65c..4f2a787f63f4 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -723,6 +723,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .len = ARRAY_SIZE(st_lsm6dsx_gyro_channels), }, }, + .drdy_mask = { + .addr = 0x13, + .mask = BIT(3), + }, .odr_table = { [ST_LSM6DSX_ID_ACC] = { .reg = { @@ -913,6 +917,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .len = ARRAY_SIZE(st_lsm6dsx_gyro_channels), }, }, + .drdy_mask = { + .addr = 0x13, + .mask = BIT(3), + }, .odr_table = { [ST_LSM6DSX_ID_ACC] = { .reg = { @@ -1080,6 +1088,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .len = ARRAY_SIZE(st_lsm6dsx_gyro_channels), }, }, + .drdy_mask = { + .addr = 0x13, + .mask = BIT(3), + }, .odr_table = { [ST_LSM6DSX_ID_ACC] = { .reg = { @@ -1943,6 +1955,15 @@ static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw) } } + /* enable drdy-mas if available */ + if (hw->settings->drdy_mask.addr) { + reg = &hw->settings->drdy_mask; + err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, + ST_LSM6DSX_SHIFT_VAL(1, reg->mask)); + if (err < 0) + return err; + } + err = st_lsm6dsx_init_shub(hw); if (err < 0) return err; -- cgit v1.2.3-59-g8ed1b From cb3b6b8e1bc0456d15a40a4bc3f95ad214340fed Mon Sep 17 00:00:00 2001 From: Mario Tesi Date: Mon, 7 Oct 2019 15:56:26 +0200 Subject: iio: imu: st_lsm6dsx: add odr calibration feature On LSM6DSO/LSM6DSR/LSM6DSOX/ASM330LHH and ISH330DHCX devices it is possible to trim the hardware timestamp resolution through the FREQ_FINE[7:0] bits of the INTERNAL_FREQ_FINE register, which contains the difference in percentage of the effective ODR (and timestamp rate) with respect to the typical value. The formula for calculating the effective ODR reported in the application notes has been linearized to the first order to simplify the calculation (pls. see note on source code). This change may be useful in the outcome of CTS tests regarding the SingleSensorTests and the SensorTest#testSensorTimeStamps for high ODRs Signed-off-by: Mario Tesi Acked-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 4 ++++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c | 5 ++--- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 23 +++++++++++++++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index b766c2218f4b..3dfd21f5d2a4 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -153,12 +153,14 @@ struct st_lsm6dsx_fifo_ops { * @hr_timer: Hw timer resolution register info (addr + mask). * @fifo_en: Hw timer FIFO enable register info (addr + mask). * @decimator: Hw timer FIFO decimator register info (addr + mask). + * @freq_fine: Difference in % of ODR with respect to the typical. */ struct st_lsm6dsx_hw_ts_settings { struct st_lsm6dsx_reg timer_en; struct st_lsm6dsx_reg hr_timer; struct st_lsm6dsx_reg fifo_en; struct st_lsm6dsx_reg decimator; + u8 freq_fine; }; /** @@ -346,6 +348,7 @@ struct st_lsm6dsx_sensor { * @fifo_mode: FIFO operating mode supported by the device. * @suspend_mask: Suspended sensor bitmask. * @enable_mask: Enabled sensor bitmask. + * @ts_gain: Hw timestamp rate after internal calibration. * @ts_sip: Total number of timestamp samples in a given pattern. * @sip: Total number of samples (acc/gyro/ts) in a given pattern. * @buff: Device read buffer. @@ -367,6 +370,7 @@ struct st_lsm6dsx_hw { enum st_lsm6dsx_fifo_mode fifo_mode; u8 suspend_mask; u8 enable_mask; + s64 ts_gain; u8 ts_sip; u8 sip; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index 1f6873441aa0..ffeb2596b97b 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -50,7 +50,6 @@ #define ST_LSM6DSX_MAX_FIFO_ODR_VAL 0x08 -#define ST_LSM6DSX_TS_SENSITIVITY 25000UL /* 25us */ #define ST_LSM6DSX_TS_RESET_VAL 0xaa struct st_lsm6dsx_decimator_entry { @@ -423,7 +422,7 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw) */ if (!reset_ts && ts >= 0xff0000) reset_ts = true; - ts *= ST_LSM6DSX_TS_SENSITIVITY; + ts *= hw->ts_gain; offset += ST_LSM6DSX_SAMPLE_SIZE; } @@ -572,7 +571,7 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw) */ if (!reset_ts && ts >= 0xffff0000) reset_ts = true; - ts *= ST_LSM6DSX_TS_SENSITIVITY; + ts *= hw->ts_gain; } else { st_lsm6dsx_push_tagged_data(hw, tag, iio_buff, ts); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 4f2a787f63f4..b0f525066237 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -63,6 +63,8 @@ #define ST_LSM6DSX_REG_WHOAMI_ADDR 0x0f +#define ST_LSM6DSX_TS_SENSITIVITY 25000UL /* 25us */ + static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = { ST_LSM6DSX_CHANNEL_ACC(IIO_ACCEL, 0x28, IIO_MOD_X, 0), ST_LSM6DSX_CHANNEL_ACC(IIO_ACCEL, 0x2a, IIO_MOD_Y, 1), @@ -843,6 +845,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x0a, .mask = GENMASK(7, 6), }, + .freq_fine = 0x63, }, .shub_settings = { .page_mux = { @@ -1037,6 +1040,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x0a, .mask = GENMASK(7, 6), }, + .freq_fine = 0x63, }, .event_settings = { .enable_reg = { @@ -1208,6 +1212,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x0a, .mask = GENMASK(7, 6), }, + .freq_fine = 0x63, }, .shub_settings = { .page_mux = { @@ -1893,6 +1898,24 @@ static int st_lsm6dsx_init_hw_timer(struct st_lsm6dsx_hw *hw) if (err < 0) return err; } + + /* calibrate timestamp sensitivity */ + hw->ts_gain = ST_LSM6DSX_TS_SENSITIVITY; + if (ts_settings->freq_fine) { + err = regmap_read(hw->regmap, ts_settings->freq_fine, &val); + if (err < 0) + return err; + + /* + * linearize the AN5192 formula: + * 1 / (1 + x) ~= 1 - x (Taylor’s Series) + * ttrim[s] = 1 / (40000 * (1 + 0.0015 * val)) + * ttrim[ns] ~= 25000 - 37.5 * val + * ttrim[ns] ~= 25000 - (37500 * val) / 1000 + */ + hw->ts_gain -= ((s8)val * 37500) / 1000; + } + return 0; } -- cgit v1.2.3-59-g8ed1b From 1b3751017e09f0857bc38f9b1be08dce38f3d92c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 7 Oct 2019 11:12:13 +0200 Subject: iio: imu: st_lsm6dsx: fix gyro gain definitions for LSM9DS1 Fix typos in gyro gain definitions for LSM9DS1 sensor Fixes: 52f4b1f19679 ("iio: imu: st_lsm6dsx: add support for accel/gyro unit of lsm9ds1") Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index b0f525066237..35b74311e0c6 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -161,9 +161,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x10, .mask = GENMASK(4, 3), }, - .fs_avl[0] = { IIO_DEGREE_TO_RAD(245), 0x0 }, - .fs_avl[1] = { IIO_DEGREE_TO_RAD(500), 0x1 }, - .fs_avl[2] = { IIO_DEGREE_TO_RAD(2000), 0x3 }, + + .fs_avl[0] = { IIO_DEGREE_TO_RAD(8750), 0x0 }, + .fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 }, + .fs_avl[2] = { IIO_DEGREE_TO_RAD(70000), 0x3 }, .fs_len = 3, }, }, -- cgit v1.2.3-59-g8ed1b From fa060a3d9cebfefc87158ceab1f550355f5e4e0b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 7 Oct 2019 11:43:37 +0200 Subject: iio: imu: st_lsm6dsx: add support to LSM6DS0 Add support to STM LSM6DS0 6-axis (acc + gyro) Mems sensor Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/Kconfig | 2 +- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 2 ++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 5 ++++- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c | 5 +++++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c | 5 +++++ 5 files changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig index 77aa0e77212d..b425a356d99e 100644 --- a/drivers/iio/imu/st_lsm6dsx/Kconfig +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig @@ -12,7 +12,7 @@ config IIO_ST_LSM6DSX Say yes here to build support for STMicroelectronics LSM6DSx imu sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm, ism330dlc, lsm6dso, lsm6dsox, asm330lhh, lsm6dsr, lsm6ds3tr-c, - ism330dhcx and the accelerometer/gyroscope of lsm9ds1. + ism330dhcx, lsm6ds0 and the accelerometer/gyroscope of lsm9ds1. To compile this driver as a module, choose M here: the module will be called st_lsm6dsx. diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 3dfd21f5d2a4..f660359ccb4d 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -26,6 +26,7 @@ #define ST_LSM6DS3TRC_DEV_NAME "lsm6ds3tr-c" #define ST_ISM330DHCX_DEV_NAME "ism330dhcx" #define ST_LSM9DS1_DEV_NAME "lsm9ds1-imu" +#define ST_LSM6DS0_DEV_NAME "lsm6ds0" enum st_lsm6dsx_hw_id { ST_LSM6DS3_ID, @@ -40,6 +41,7 @@ enum st_lsm6dsx_hw_id { ST_LSM6DS3TRC_ID, ST_ISM330DHCX_ID, ST_LSM9DS1_ID, + ST_LSM6DS0_ID, ST_LSM6DSX_MAX_ID, }; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 35b74311e0c6..f9c83aa2c9b7 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -32,7 +32,7 @@ * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 * - FIFO size: 3KB * - * - LSM9DS1: + * - LSM9DS1/LSM6DS0: * - Accelerometer supported ODR [Hz]: 10, 50, 119, 238, 476, 952 * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 * - Gyroscope supported ODR [Hz]: 15, 60, 119, 238, 476, 952 @@ -106,6 +106,9 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { { .hw_id = ST_LSM9DS1_ID, .name = ST_LSM9DS1_DEV_NAME, + }, { + .hw_id = ST_LSM6DS0_ID, + .name = ST_LSM6DS0_DEV_NAME, }, }, .channels = { diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c index f52511059545..e57744affbd0 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c @@ -87,6 +87,10 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = { .compatible = "st,lsm9ds1-imu", .data = (void *)ST_LSM9DS1_ID, }, + { + .compatible = "st,lsm6ds0", + .data = (void *)ST_LSM6DS0_ID, + }, {}, }; MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match); @@ -104,6 +108,7 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = { { ST_LSM6DS3TRC_DEV_NAME, ST_LSM6DS3TRC_ID }, { ST_ISM330DHCX_DEV_NAME, ST_ISM330DHCX_ID }, { ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID }, + { ST_LSM6DS0_DEV_NAME, ST_LSM6DS0_ID }, {}, }; MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c index 344b28dddebb..933d4f9f6a4a 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c @@ -87,6 +87,10 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = { .compatible = "st,lsm9ds1-imu", .data = (void *)ST_LSM9DS1_ID, }, + { + .compatible = "st,lsm6ds0", + .data = (void *)ST_LSM6DS0_ID, + }, {}, }; MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match); @@ -104,6 +108,7 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = { { ST_LSM6DS3TRC_DEV_NAME, ST_LSM6DS3TRC_ID }, { ST_ISM330DHCX_DEV_NAME, ST_ISM330DHCX_ID }, { ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID }, + { ST_LSM6DS0_DEV_NAME, ST_LSM6DS0_ID }, {}, }; MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table); -- cgit v1.2.3-59-g8ed1b From cf9c71b38befbe02d910d0c4e128abaaf69d6e27 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 24 Oct 2019 17:42:33 +0200 Subject: iio: imu: st_lsm6dsx: add support to LSM6DSRX Add support to STM LSM6DSRX 6-axis (acc + gyro) Mems sensor https://www.st.com/resource/en/datasheet/lsm6dsrx.pdf Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/Kconfig | 3 ++- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 2 ++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c | 8 ++++---- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 3 +++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c | 5 +++++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c | 5 +++++ 6 files changed, 21 insertions(+), 5 deletions(-) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig index b425a356d99e..28f59d09208a 100644 --- a/drivers/iio/imu/st_lsm6dsx/Kconfig +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig @@ -12,7 +12,8 @@ config IIO_ST_LSM6DSX Say yes here to build support for STMicroelectronics LSM6DSx imu sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm, ism330dlc, lsm6dso, lsm6dsox, asm330lhh, lsm6dsr, lsm6ds3tr-c, - ism330dhcx, lsm6ds0 and the accelerometer/gyroscope of lsm9ds1. + ism330dhcx, lsm6dsrx, lsm6ds0 and the accelerometer/gyroscope + of lsm9ds1. To compile this driver as a module, choose M here: the module will be called st_lsm6dsx. diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index f660359ccb4d..37e499fe6bcf 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -27,6 +27,7 @@ #define ST_ISM330DHCX_DEV_NAME "ism330dhcx" #define ST_LSM9DS1_DEV_NAME "lsm9ds1-imu" #define ST_LSM6DS0_DEV_NAME "lsm6ds0" +#define ST_LSM6DSRX_DEV_NAME "lsm6dsrx" enum st_lsm6dsx_hw_id { ST_LSM6DS3_ID, @@ -42,6 +43,7 @@ enum st_lsm6dsx_hw_id { ST_ISM330DHCX_ID, ST_LSM9DS1_ID, ST_LSM6DS0_ID, + ST_LSM6DSRX_ID, ST_LSM6DSX_MAX_ID, }; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index ffeb2596b97b..31cd90d2c60e 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -14,10 +14,10 @@ * (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated depending on the * value of the decimation factor and ODR set for each FIFO data set. * - * LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR/ISM330DHCX: The FIFO buffer can be - * configured to store data from gyroscope and accelerometer. Each sample - * is queued with a tag (1B) indicating data source (gyroscope, accelerometer, - * hw timer). + * LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR/LSM6DSRX/ISM330DHCX: + * The FIFO buffer can be configured to store data from gyroscope and + * accelerometer. Each sample is queued with a tag (1B) indicating data + * source (gyroscope, accelerometer, hw timer). * * FIFO supported modes: * - BYPASS: FIFO disabled diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index f9c83aa2c9b7..1f28a7733fc0 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -1084,6 +1084,9 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, { .hw_id = ST_ISM330DHCX_ID, .name = ST_ISM330DHCX_DEV_NAME, + }, { + .hw_id = ST_LSM6DSRX_ID, + .name = ST_LSM6DSRX_DEV_NAME, }, }, .channels = { diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c index e57744affbd0..cd47ec1fedcb 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c @@ -91,6 +91,10 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = { .compatible = "st,lsm6ds0", .data = (void *)ST_LSM6DS0_ID, }, + { + .compatible = "st,lsm6dsrx", + .data = (void *)ST_LSM6DSRX_ID, + }, {}, }; MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match); @@ -109,6 +113,7 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = { { ST_ISM330DHCX_DEV_NAME, ST_ISM330DHCX_ID }, { ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID }, { ST_LSM6DS0_DEV_NAME, ST_LSM6DS0_ID }, + { ST_LSM6DSRX_DEV_NAME, ST_LSM6DSRX_ID }, {}, }; MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c index 933d4f9f6a4a..67ff36eac247 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c @@ -91,6 +91,10 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = { .compatible = "st,lsm6ds0", .data = (void *)ST_LSM6DS0_ID, }, + { + .compatible = "st,lsm6dsrx", + .data = (void *)ST_LSM6DSRX_ID, + }, {}, }; MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match); @@ -109,6 +113,7 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = { { ST_ISM330DHCX_DEV_NAME, ST_ISM330DHCX_ID }, { ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID }, { ST_LSM6DS0_DEV_NAME, ST_LSM6DS0_ID }, + { ST_LSM6DSRX_DEV_NAME, ST_LSM6DSRX_ID }, {}, }; MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table); -- cgit v1.2.3-59-g8ed1b From 59af4e206365d38fe78a94852f1f9c28f4f92c9d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 3 Nov 2019 20:47:17 +0100 Subject: iio: imu: st_lsm6dsx: explicitly define odr table size Introduce odr_len in st_lsm6dsx_odr_table_entry data structure in order to explicitly define odr table size and support devices with different odr table map Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 2 ++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 27 +++++++++++++++++++++------ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c | 12 ++++++------ 3 files changed, 29 insertions(+), 12 deletions(-) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 37e499fe6bcf..9ffc8e06f73d 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -113,7 +113,9 @@ struct st_lsm6dsx_odr { #define ST_LSM6DSX_ODR_LIST_SIZE 6 struct st_lsm6dsx_odr_table_entry { struct st_lsm6dsx_reg reg; + struct st_lsm6dsx_odr odr_avl[ST_LSM6DSX_ODR_LIST_SIZE]; + int odr_len; }; struct st_lsm6dsx_fs { diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 1f28a7733fc0..a3333c215339 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -133,6 +133,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 238, 0x04 }, .odr_avl[4] = { 476, 0x05 }, .odr_avl[5] = { 952, 0x06 }, + .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { .reg = { @@ -145,6 +146,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 238, 0x04 }, .odr_avl[4] = { 476, 0x05 }, .odr_avl[5] = { 952, 0x06 }, + .odr_len = 6, }, }, .fs_table = { @@ -233,6 +235,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 104, 0x04 }, .odr_avl[4] = { 208, 0x05 }, .odr_avl[5] = { 416, 0x06 }, + .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { .reg = { @@ -245,6 +248,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 104, 0x04 }, .odr_avl[4] = { 208, 0x05 }, .odr_avl[5] = { 416, 0x06 }, + .odr_len = 6, }, }, .fs_table = { @@ -397,6 +401,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 104, 0x04 }, .odr_avl[4] = { 208, 0x05 }, .odr_avl[5] = { 416, 0x06 }, + .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { .reg = { @@ -409,6 +414,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 104, 0x04 }, .odr_avl[4] = { 208, 0x05 }, .odr_avl[5] = { 416, 0x06 }, + .odr_len = 6, }, }, .fs_table = { @@ -570,6 +576,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 104, 0x04 }, .odr_avl[4] = { 208, 0x05 }, .odr_avl[5] = { 416, 0x06 }, + .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { .reg = { @@ -582,6 +589,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 104, 0x04 }, .odr_avl[4] = { 208, 0x05 }, .odr_avl[5] = { 416, 0x06 }, + .odr_len = 6, }, }, .fs_table = { @@ -745,6 +753,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 104, 0x04 }, .odr_avl[4] = { 208, 0x05 }, .odr_avl[5] = { 416, 0x06 }, + .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { .reg = { @@ -757,6 +766,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 104, 0x04 }, .odr_avl[4] = { 208, 0x05 }, .odr_avl[5] = { 416, 0x06 }, + .odr_len = 6, }, }, .fs_table = { @@ -940,6 +950,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 104, 0x04 }, .odr_avl[4] = { 208, 0x05 }, .odr_avl[5] = { 416, 0x06 }, + .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { .reg = { @@ -952,6 +963,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 104, 0x04 }, .odr_avl[4] = { 208, 0x05 }, .odr_avl[5] = { 416, 0x06 }, + .odr_len = 6, }, }, .fs_table = { @@ -1115,6 +1127,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 104, 0x04 }, .odr_avl[4] = { 208, 0x05 }, .odr_avl[5] = { 416, 0x06 }, + .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { .reg = { @@ -1127,6 +1140,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .odr_avl[3] = { 104, 0x04 }, .odr_avl[4] = { 208, 0x05 }, .odr_avl[5] = { 416, 0x06 }, + .odr_len = 6, }, }, .fs_table = { @@ -1350,15 +1364,16 @@ int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val) int i; odr_table = &sensor->hw->settings->odr_table[sensor->id]; - for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) + for (i = 0; i < odr_table->odr_len; i++) { /* * ext devices can run at different odr respect to * accel sensor */ if (odr_table->odr_avl[i].hz >= odr) break; + } - if (i == ST_LSM6DSX_ODR_LIST_SIZE) + if (i == odr_table->odr_len) return -EINVAL; *val = odr_table->odr_avl[i].val; @@ -1709,13 +1724,13 @@ st_lsm6dsx_sysfs_sampling_frequency_avail(struct device *dev, char *buf) { struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev)); - enum st_lsm6dsx_sensor_id id = sensor->id; - struct st_lsm6dsx_hw *hw = sensor->hw; + const struct st_lsm6dsx_odr_table_entry *odr_table; int i, len = 0; - for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) + odr_table = &sensor->hw->settings->odr_table[sensor->id]; + for (i = 0; i < odr_table->odr_len; i++) len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", - hw->settings->odr_table[id].odr_avl[i].hz); + odr_table->odr_avl[i].hz); buf[len - 1] = '\n'; return len; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c index ea472cf6db7b..e029cc05a17f 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c @@ -55,6 +55,7 @@ static const struct st_lsm6dsx_ext_dev_settings st_lsm6dsx_ext_dev_table[] = { .odr_avl[1] = { 20, 0x1 }, .odr_avl[2] = { 50, 0x2 }, .odr_avl[3] = { 100, 0x3 }, + .odr_len = 4, }, .fs_table = { .fs_avl[0] = { @@ -323,11 +324,12 @@ st_lsm6dsx_shub_get_odr_val(struct st_lsm6dsx_sensor *sensor, int i; settings = sensor->ext_info.settings; - for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) + for (i = 0; i < settings->odr_table.odr_len; i++) { if (settings->odr_table.odr_avl[i].hz == odr) break; + } - if (i == ST_LSM6DSX_ODR_LIST_SIZE) + if (i == settings->odr_table.odr_len) return -EINVAL; *val = settings->odr_table.odr_avl[i].val; @@ -537,12 +539,10 @@ st_lsm6dsx_shub_sampling_freq_avail(struct device *dev, int i, len = 0; settings = sensor->ext_info.settings; - for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) { + for (i = 0; i < settings->odr_table.odr_len; i++) { u16 val = settings->odr_table.odr_avl[i].hz; - if (val > 0) - len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", - val); + len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", val); } buf[len - 1] = '\n'; -- cgit v1.2.3-59-g8ed1b From fc3f6ad7f5dc6c899fbda0255865737bac88c2e0 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 27 Oct 2019 19:02:30 +0100 Subject: iio: imu: st_lsm6dsx: fix ODR check in st_lsm6dsx_write_raw Since st_lsm6dsx i2c master controller relies on accel device as trigger and slave devices can run at different ODRs we must select an accel_odr >= slave_odr. Report real accel ODR in st_lsm6dsx_check_odr() in order to properly set sensor frequency in st_lsm6dsx_write_raw and avoid to report unsupported frequency Fixes: 6ffb55e5009ff ("iio: imu: st_lsm6dsx: introduce ST_LSM6DSX_ID_EXT sensor ids") Signed-off-by: Lorenzo Bianconi Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index a3333c215339..2f9396745bc8 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -1377,8 +1377,7 @@ int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val) return -EINVAL; *val = odr_table->odr_avl[i].val; - - return 0; + return odr_table->odr_avl[i].hz; } static u16 st_lsm6dsx_check_odr_dependency(struct st_lsm6dsx_hw *hw, u16 odr, @@ -1542,8 +1541,10 @@ static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev, case IIO_CHAN_INFO_SAMP_FREQ: { u8 data; - err = st_lsm6dsx_check_odr(sensor, val, &data); - if (!err) + val = st_lsm6dsx_check_odr(sensor, val, &data); + if (val < 0) + err = val; + else sensor->odr = val; break; } -- cgit v1.2.3-59-g8ed1b From f8710f0357bc36c740782c95f34ea847c75b7498 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 3 Nov 2019 20:47:18 +0100 Subject: iio: imu: st_lsm6dsx: express odr in mHZ Express available frequencies in mHZ in order to support even rational ODRs. This patch is need to fix an Android CTS failure Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 6 +- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c | 9 +- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 203 +++++++++++++------------ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c | 35 +++-- 4 files changed, 131 insertions(+), 122 deletions(-) (limited to 'drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 9ffc8e06f73d..c605b153be41 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -106,7 +106,7 @@ struct st_lsm6dsx_sensor; struct st_lsm6dsx_hw; struct st_lsm6dsx_odr { - u16 hz; + u32 milli_hz; u8 val; }; @@ -330,7 +330,7 @@ struct st_lsm6dsx_sensor { struct st_lsm6dsx_hw *hw; u32 gain; - u16 odr; + u32 odr; u16 watermark; u8 sip; @@ -415,7 +415,7 @@ int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw, enum st_lsm6dsx_fifo_mode fifo_mode); int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw); int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw); -int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val); +int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u32 odr, u8 *val); int st_lsm6dsx_shub_probe(struct st_lsm6dsx_hw *hw, const char *name); int st_lsm6dsx_shub_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable); int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index 31cd90d2c60e..d416990ae309 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -91,7 +91,7 @@ static int st_lsm6dsx_get_decimator_val(u8 val) } static void st_lsm6dsx_get_max_min_odr(struct st_lsm6dsx_hw *hw, - u16 *max_odr, u16 *min_odr) + u32 *max_odr, u32 *min_odr) { struct st_lsm6dsx_sensor *sensor; int i; @@ -106,16 +106,17 @@ static void st_lsm6dsx_get_max_min_odr(struct st_lsm6dsx_hw *hw, if (!(hw->enable_mask & BIT(sensor->id))) continue; - *max_odr = max_t(u16, *max_odr, sensor->odr); - *min_odr = min_t(u16, *min_odr, sensor->odr); + *max_odr = max_t(u32, *max_odr, sensor->odr); + *min_odr = min_t(u32, *min_odr, sensor->odr); } } static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw) { - u16 max_odr, min_odr, sip = 0, ts_sip = 0; const struct st_lsm6dsx_reg *ts_dec_reg; struct st_lsm6dsx_sensor *sensor; + u16 sip = 0, ts_sip = 0; + u32 max_odr, min_odr; int err = 0, i; u8 data; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 2f9396745bc8..11b2c7bc8041 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -127,12 +127,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x20, .mask = GENMASK(7, 5), }, - .odr_avl[0] = { 10, 0x01 }, - .odr_avl[1] = { 50, 0x02 }, - .odr_avl[2] = { 119, 0x03 }, - .odr_avl[3] = { 238, 0x04 }, - .odr_avl[4] = { 476, 0x05 }, - .odr_avl[5] = { 952, 0x06 }, + .odr_avl[0] = { 10000, 0x01 }, + .odr_avl[1] = { 50000, 0x02 }, + .odr_avl[2] = { 119000, 0x03 }, + .odr_avl[3] = { 238000, 0x04 }, + .odr_avl[4] = { 476000, 0x05 }, + .odr_avl[5] = { 952000, 0x06 }, .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { @@ -140,12 +140,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x10, .mask = GENMASK(7, 5), }, - .odr_avl[0] = { 15, 0x01 }, - .odr_avl[1] = { 60, 0x02 }, - .odr_avl[2] = { 119, 0x03 }, - .odr_avl[3] = { 238, 0x04 }, - .odr_avl[4] = { 476, 0x05 }, - .odr_avl[5] = { 952, 0x06 }, + .odr_avl[0] = { 14900, 0x01 }, + .odr_avl[1] = { 59500, 0x02 }, + .odr_avl[2] = { 119000, 0x03 }, + .odr_avl[3] = { 238000, 0x04 }, + .odr_avl[4] = { 476000, 0x05 }, + .odr_avl[5] = { 952000, 0x06 }, .odr_len = 6, }, }, @@ -229,12 +229,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x10, .mask = GENMASK(7, 4), }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { @@ -242,12 +242,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x11, .mask = GENMASK(7, 4), }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, .odr_len = 6, }, }, @@ -395,12 +395,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x10, .mask = GENMASK(7, 4), }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { @@ -408,12 +408,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x11, .mask = GENMASK(7, 4), }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, .odr_len = 6, }, }, @@ -570,12 +570,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x10, .mask = GENMASK(7, 4), }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { @@ -583,12 +583,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x11, .mask = GENMASK(7, 4), }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, .odr_len = 6, }, }, @@ -747,12 +747,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x10, .mask = GENMASK(7, 4), }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { @@ -760,12 +760,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x11, .mask = GENMASK(7, 4), }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, .odr_len = 6, }, }, @@ -944,12 +944,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x10, .mask = GENMASK(7, 4), }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { @@ -957,12 +957,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x11, .mask = GENMASK(7, 4), }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, .odr_len = 6, }, }, @@ -1121,12 +1121,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x10, .mask = GENMASK(7, 4), }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, .odr_len = 6, }, [ST_LSM6DSX_ID_GYRO] = { @@ -1134,12 +1134,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x11, .mask = GENMASK(7, 4), }, - .odr_avl[0] = { 13, 0x01 }, - .odr_avl[1] = { 26, 0x02 }, - .odr_avl[2] = { 52, 0x03 }, - .odr_avl[3] = { 104, 0x04 }, - .odr_avl[4] = { 208, 0x05 }, - .odr_avl[5] = { 416, 0x06 }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, .odr_len = 6, }, }, @@ -1358,7 +1358,7 @@ static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor, return 0; } -int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val) +int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u32 odr, u8 *val) { const struct st_lsm6dsx_odr_table_entry *odr_table; int i; @@ -1369,7 +1369,7 @@ int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val) * ext devices can run at different odr respect to * accel sensor */ - if (odr_table->odr_avl[i].hz >= odr) + if (odr_table->odr_avl[i].milli_hz >= odr) break; } @@ -1377,17 +1377,18 @@ int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val) return -EINVAL; *val = odr_table->odr_avl[i].val; - return odr_table->odr_avl[i].hz; + return odr_table->odr_avl[i].milli_hz; } -static u16 st_lsm6dsx_check_odr_dependency(struct st_lsm6dsx_hw *hw, u16 odr, - enum st_lsm6dsx_sensor_id id) +static int +st_lsm6dsx_check_odr_dependency(struct st_lsm6dsx_hw *hw, u32 odr, + enum st_lsm6dsx_sensor_id id) { struct st_lsm6dsx_sensor *ref = iio_priv(hw->iio_devs[id]); if (odr > 0) { if (hw->enable_mask & BIT(id)) - return max_t(u16, ref->odr, odr); + return max_t(u32, ref->odr, odr); else return odr; } else { @@ -1395,7 +1396,8 @@ static u16 st_lsm6dsx_check_odr_dependency(struct st_lsm6dsx_hw *hw, u16 odr, } } -static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 req_odr) +static int +st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u32 req_odr) { struct st_lsm6dsx_sensor *ref_sensor = sensor; struct st_lsm6dsx_hw *hw = sensor->hw; @@ -1409,7 +1411,7 @@ static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 req_odr) case ST_LSM6DSX_ID_EXT1: case ST_LSM6DSX_ID_EXT2: case ST_LSM6DSX_ID_ACC: { - u16 odr; + u32 odr; int i; /* @@ -1449,7 +1451,7 @@ int st_lsm6dsx_sensor_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable) { struct st_lsm6dsx_hw *hw = sensor->hw; - u16 odr = enable ? sensor->odr : 0; + u32 odr = enable ? sensor->odr : 0; int err; err = st_lsm6dsx_set_odr(sensor, odr); @@ -1475,7 +1477,7 @@ static int st_lsm6dsx_read_oneshot(struct st_lsm6dsx_sensor *sensor, if (err < 0) return err; - delay = 1000000 / sensor->odr; + delay = 1000000000 / sensor->odr; usleep_range(delay, 2 * delay); err = st_lsm6dsx_read_locked(hw, addr, &data, sizeof(data)); @@ -1507,8 +1509,9 @@ static int st_lsm6dsx_read_raw(struct iio_dev *iio_dev, iio_device_release_direct_mode(iio_dev); break; case IIO_CHAN_INFO_SAMP_FREQ: - *val = sensor->odr; - ret = IIO_VAL_INT; + *val = sensor->odr / 1000; + *val2 = (sensor->odr % 1000) * 1000; + ret = IIO_VAL_INT_PLUS_MICRO; break; case IIO_CHAN_INFO_SCALE: *val = 0; @@ -1541,6 +1544,7 @@ static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev, case IIO_CHAN_INFO_SAMP_FREQ: { u8 data; + val = val * 1000 + val2 / 1000; val = st_lsm6dsx_check_odr(sensor, val, &data); if (val < 0) err = val; @@ -1730,8 +1734,9 @@ st_lsm6dsx_sysfs_sampling_frequency_avail(struct device *dev, odr_table = &sensor->hw->settings->odr_table[sensor->id]; for (i = 0; i < odr_table->odr_len; i++) - len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", - odr_table->odr_avl[i].hz); + len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%03d ", + odr_table->odr_avl[i].milli_hz / 1000, + odr_table->odr_avl[i].milli_hz % 1000); buf[len - 1] = '\n'; return len; @@ -2037,7 +2042,7 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw, sensor = iio_priv(iio_dev); sensor->id = id; sensor->hw = hw; - sensor->odr = hw->settings->odr_table[id].odr_avl[0].hz; + sensor->odr = hw->settings->odr_table[id].odr_avl[0].milli_hz; sensor->gain = hw->settings->fs_table[id].fs_avl[0].gain; sensor->watermark = 1; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c index e029cc05a17f..fa5d1001a46c 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c @@ -51,10 +51,10 @@ static const struct st_lsm6dsx_ext_dev_settings st_lsm6dsx_ext_dev_table[] = { .addr = 0x60, .mask = GENMASK(3, 2), }, - .odr_avl[0] = { 10, 0x0 }, - .odr_avl[1] = { 20, 0x1 }, - .odr_avl[2] = { 50, 0x2 }, - .odr_avl[3] = { 100, 0x3 }, + .odr_avl[0] = { 10000, 0x0 }, + .odr_avl[1] = { 20000, 0x1 }, + .odr_avl[2] = { 50000, 0x2 }, + .odr_avl[3] = { 100000, 0x3 }, .odr_len = 4, }, .fs_table = { @@ -94,11 +94,11 @@ static const struct st_lsm6dsx_ext_dev_settings st_lsm6dsx_ext_dev_table[] = { static void st_lsm6dsx_shub_wait_complete(struct st_lsm6dsx_hw *hw) { struct st_lsm6dsx_sensor *sensor; - u16 odr; + u32 odr; sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]); - odr = (hw->enable_mask & BIT(ST_LSM6DSX_ID_ACC)) ? sensor->odr : 13; - msleep((2000U / odr) + 1); + odr = (hw->enable_mask & BIT(ST_LSM6DSX_ID_ACC)) ? sensor->odr : 12500; + msleep((2000000U / odr) + 1); } /** @@ -318,14 +318,14 @@ st_lsm6dsx_shub_write_with_mask(struct st_lsm6dsx_sensor *sensor, static int st_lsm6dsx_shub_get_odr_val(struct st_lsm6dsx_sensor *sensor, - u16 odr, u16 *val) + u32 odr, u16 *val) { const struct st_lsm6dsx_ext_dev_settings *settings; int i; settings = sensor->ext_info.settings; for (i = 0; i < settings->odr_table.odr_len; i++) { - if (settings->odr_table.odr_avl[i].hz == odr) + if (settings->odr_table.odr_avl[i].milli_hz == odr) break; } @@ -337,7 +337,7 @@ st_lsm6dsx_shub_get_odr_val(struct st_lsm6dsx_sensor *sensor, } static int -st_lsm6dsx_shub_set_odr(struct st_lsm6dsx_sensor *sensor, u16 odr) +st_lsm6dsx_shub_set_odr(struct st_lsm6dsx_sensor *sensor, u32 odr) { const struct st_lsm6dsx_ext_dev_settings *settings; u16 val; @@ -442,7 +442,7 @@ st_lsm6dsx_shub_read_oneshot(struct st_lsm6dsx_sensor *sensor, if (err < 0) return err; - delay = 1000000 / sensor->odr; + delay = 1000000000 / sensor->odr; usleep_range(delay, 2 * delay); len = min_t(int, sizeof(data), ch->scan_type.realbits >> 3); @@ -482,8 +482,9 @@ st_lsm6dsx_shub_read_raw(struct iio_dev *iio_dev, iio_device_release_direct_mode(iio_dev); break; case IIO_CHAN_INFO_SAMP_FREQ: - *val = sensor->odr; - ret = IIO_VAL_INT; + *val = sensor->odr / 1000; + *val2 = (sensor->odr % 1000) * 1000; + ret = IIO_VAL_INT_PLUS_MICRO; break; case IIO_CHAN_INFO_SCALE: *val = 0; @@ -514,6 +515,7 @@ st_lsm6dsx_shub_write_raw(struct iio_dev *iio_dev, case IIO_CHAN_INFO_SAMP_FREQ: { u16 data; + val = val * 1000 + val2 / 1000; err = st_lsm6dsx_shub_get_odr_val(sensor, val, &data); if (!err) sensor->odr = val; @@ -540,9 +542,10 @@ st_lsm6dsx_shub_sampling_freq_avail(struct device *dev, settings = sensor->ext_info.settings; for (i = 0; i < settings->odr_table.odr_len; i++) { - u16 val = settings->odr_table.odr_avl[i].hz; + u32 val = settings->odr_table.odr_avl[i].milli_hz; - len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", val); + len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%03d ", + val / 1000, val % 1000); } buf[len - 1] = '\n'; @@ -607,7 +610,7 @@ st_lsm6dsx_shub_alloc_iiodev(struct st_lsm6dsx_hw *hw, sensor = iio_priv(iio_dev); sensor->id = id; sensor->hw = hw; - sensor->odr = info->odr_table.odr_avl[0].hz; + sensor->odr = info->odr_table.odr_avl[0].milli_hz; sensor->gain = info->fs_table.fs_avl[0].gain; sensor->ext_info.settings = info; sensor->ext_info.addr = i2c_addr; -- cgit v1.2.3-59-g8ed1b