diff --git a/drivers/sensor/st/lsm6dsv16x/CMakeLists.txt b/drivers/sensor/st/lsm6dsv16x/CMakeLists.txt index 5006feef19d64fa..760aa21db65d9b0 100644 --- a/drivers/sensor/st/lsm6dsv16x/CMakeLists.txt +++ b/drivers/sensor/st/lsm6dsv16x/CMakeLists.txt @@ -9,5 +9,7 @@ zephyr_library() zephyr_library_sources(lsm6dsv16x.c) zephyr_library_sources_ifdef(CONFIG_LSM6DSV16X_SENSORHUB lsm6dsv16x_shub.c) zephyr_library_sources_ifdef(CONFIG_LSM6DSV16X_TRIGGER lsm6dsv16x_trigger.c) +zephyr_library_sources_ifdef(CONFIG_SENSOR_ASYNC_API lsm6dsv16x_rtio.c lsm6dsv16x_decoder.c) +zephyr_library_sources_ifdef(CONFIG_LSM6DSV16X_STREAM lsm6dsv16x_rtio_stream.c) zephyr_library_include_directories(../stmemsc) diff --git a/drivers/sensor/st/lsm6dsv16x/Kconfig b/drivers/sensor/st/lsm6dsv16x/Kconfig index d4f4ec6ffeb92a4..c3071b389f1a191 100644 --- a/drivers/sensor/st/lsm6dsv16x/Kconfig +++ b/drivers/sensor/st/lsm6dsv16x/Kconfig @@ -12,12 +12,22 @@ menuconfig LSM6DSV16X select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSV16X),spi) select HAS_STMEMSC select USE_STDC_LSM6DSV16X + select RTIO_WORKQ if SENSOR_ASYNC_API help Enable driver for LSM6DSV16X accelerometer and gyroscope sensor. if LSM6DSV16X +config LSM6DSV16X_STREAM + bool "Use hardware FIFO to stream data" + select LSM6DSV16X_TRIGGER + default y + depends on I2C_RTIO || SPI_RTIO + depends on SENSOR_ASYNC_API + help + Use this config option to enable streaming sensor data via RTIO subsystem. + choice LSM6DSV16X_TRIGGER_MODE prompt "Trigger mode" help diff --git a/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x.c b/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x.c index cfa725bd2892016..880e456379264e9 100644 --- a/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x.c +++ b/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x.c @@ -19,6 +19,8 @@ #include #include "lsm6dsv16x.h" +#include "lsm6dsv16x_decoder.h" +#include "lsm6dsv16x_rtio.h" LOG_MODULE_REGISTER(LSM6DSV16X, CONFIG_SENSOR_LOG_LEVEL); @@ -86,6 +88,16 @@ static const uint16_t lsm6dsv16x_gyro_fs_map[] = {125, 250, 500, 1000, 2000, 0, 0, 0, 0, 0, 0, 4000}; static const uint16_t lsm6dsv16x_gyro_fs_sens[] = {1, 2, 4, 8, 16, 0, 0, 0, 0, 0, 0, 0, 32}; +int lsm6dsv16x_calc_accel_gain(uint8_t fs) +{ + return lsm6dsv16x_accel_fs_map[fs] * GAIN_UNIT_XL / 2; +} + +int lsm6dsv16x_calc_gyro_gain(uint8_t fs) +{ + return lsm6dsv16x_gyro_fs_sens[fs] * GAIN_UNIT_G; +} + static int lsm6dsv16x_gyro_range_to_fs_val(int32_t range) { size_t i; @@ -205,7 +217,7 @@ static int lsm6dsv16x_accel_range_set(const struct device *dev, int32_t range) return -EIO; } - data->acc_gain = lsm6dsv16x_accel_fs_map[fs] * GAIN_UNIT_XL / 2; + data->acc_gain = lsm6dsv16x_calc_accel_gain(fs); return 0; } @@ -295,7 +307,7 @@ static int lsm6dsv16x_gyro_range_set(const struct device *dev, int32_t range) return -EIO; } - data->gyro_gain = (lsm6dsv16x_gyro_fs_sens[fs] * GAIN_UNIT_G); + data->gyro_gain = lsm6dsv16x_calc_gyro_gain(fs); return 0; } @@ -924,6 +936,10 @@ static const struct sensor_driver_api lsm6dsv16x_driver_api = { #endif .sample_fetch = lsm6dsv16x_sample_fetch, .channel_get = lsm6dsv16x_channel_get, +#ifdef CONFIG_SENSOR_ASYNC_API + .get_decoder = lsm6dsv16x_get_decoder, + .submit = lsm6dsv16x_submit, +#endif }; static int lsm6dsv16x_init_chip(const struct device *dev) @@ -970,7 +986,7 @@ static int lsm6dsv16x_init_chip(const struct device *dev) LOG_ERR("failed to set accelerometer range %d", fs); return -EIO; } - lsm6dsv16x->acc_gain = lsm6dsv16x_accel_fs_map[fs] * GAIN_UNIT_XL / 2; + lsm6dsv16x->acc_gain = lsm6dsv16x_calc_accel_gain(fs); odr = cfg->accel_odr; LOG_DBG("accel odr is %d", odr); @@ -985,7 +1001,7 @@ static int lsm6dsv16x_init_chip(const struct device *dev) LOG_ERR("failed to set gyroscope range %d", fs); return -EIO; } - lsm6dsv16x->gyro_gain = (lsm6dsv16x_gyro_fs_sens[fs] * GAIN_UNIT_G); + lsm6dsv16x->gyro_gain = lsm6dsv16x_calc_gyro_gain(fs); odr = cfg->gyro_odr; LOG_DBG("gyro odr is %d", odr); @@ -1057,10 +1073,6 @@ static int lsm6dsv16x_init(const struct device *dev) CONFIG_SENSOR_INIT_PRIORITY, \ &lsm6dsv16x_driver_api); -/* - * Instantiation macros used when a device is on a SPI bus. - */ - #ifdef CONFIG_LSM6DSV16X_TRIGGER #define LSM6DSV16X_CFG_IRQ(inst) \ .trig_enabled = true, \ @@ -1072,19 +1084,33 @@ static int lsm6dsv16x_init(const struct device *dev) #define LSM6DSV16X_CFG_IRQ(inst) #endif /* CONFIG_LSM6DSV16X_TRIGGER */ +#define LSM6DSV16X_CONFIG_COMMON(inst) \ + .accel_odr = DT_INST_PROP(inst, accel_odr), \ + .accel_range = DT_INST_PROP(inst, accel_range), \ + .gyro_odr = DT_INST_PROP(inst, gyro_odr), \ + .gyro_range = DT_INST_PROP(inst, gyro_range), \ + IF_ENABLED(CONFIG_LSM6DSV16X_STREAM, \ + (.fifo_wtm = DT_INST_PROP(inst, fifo_watermark), \ + .accel_batch = DT_INST_PROP(inst, accel_fifo_batch_rate), \ + .gyro_batch = DT_INST_PROP(inst, gyro_fifo_batch_rate), \ + .temp_batch = DT_INST_PROP(inst, temp_fifo_batch_rate),)) \ + IF_ENABLED(UTIL_OR(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \ + DT_INST_NODE_HAS_PROP(inst, int2_gpios)), \ + (LSM6DSV16X_CFG_IRQ(inst))) + +/* + * Instantiation macros used when a device is on a SPI bus. + */ + #define LSM6DSV16X_SPI_OP (SPI_WORD_SET(8) | \ SPI_OP_MODE_MASTER | \ SPI_MODE_CPOL | \ SPI_MODE_CPHA) \ -#define LSM6DSV16X_CONFIG_COMMON(inst) \ - .accel_odr = DT_INST_PROP(inst, accel_odr), \ - .accel_range = DT_INST_PROP(inst, accel_range), \ - .gyro_odr = DT_INST_PROP(inst, gyro_odr), \ - .gyro_range = DT_INST_PROP(inst, gyro_range), \ - IF_ENABLED(UTIL_OR(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \ - DT_INST_NODE_HAS_PROP(inst, int2_gpios)), \ - (LSM6DSV16X_CFG_IRQ(inst))) +#define LSM6DSV16X_SPI_RTIO_DEFINE(inst) \ + SPI_DT_IODEV_DEFINE(lsm6dsv16x_iodev_##inst, \ + DT_DRV_INST(inst), LSM6DSV16X_SPI_OP, 0U); \ + RTIO_DEFINE(lsm6dsv16x_rtio_ctx_##inst, 4, 4); #define LSM6DSV16X_CONFIG_SPI(inst) \ { \ @@ -1097,10 +1123,25 @@ static int lsm6dsv16x_init(const struct device *dev) LSM6DSV16X_CONFIG_COMMON(inst) \ } +#define LSM6DSV16X_DEFINE_SPI(inst) \ + IF_ENABLED(CONFIG_LSM6DSV16X_STREAM, (LSM6DSV16X_SPI_RTIO_DEFINE(inst))); \ + static struct lsm6dsv16x_data lsm6dsv16x_data_##inst = { \ + IF_ENABLED(CONFIG_LSM6DSV16X_STREAM, \ + (.rtio_ctx = &lsm6dsv16x_rtio_ctx_##inst, \ + .iodev = &lsm6dsv16x_iodev_##inst, \ + .bus_type = BUS_SPI,)) \ + }; \ + static const struct lsm6dsv16x_config lsm6dsv16x_config_##inst = \ + LSM6DSV16X_CONFIG_SPI(inst); \ + /* * Instantiation macros used when a device is on an I2C bus. */ +#define LSM6DSV16X_I2C_RTIO_DEFINE(inst) \ + I2C_DT_IODEV_DEFINE(lsm6dsv16x_iodev_##inst, DT_DRV_INST(inst));\ + RTIO_DEFINE(lsm6dsv16x_rtio_ctx_##inst, 4, 4); + #define LSM6DSV16X_CONFIG_I2C(inst) \ { \ STMEMSC_CTX_I2C(&lsm6dsv16x_config_##inst.stmemsc_cfg), \ @@ -1110,17 +1151,27 @@ static int lsm6dsv16x_init(const struct device *dev) LSM6DSV16X_CONFIG_COMMON(inst) \ } + +#define LSM6DSV16X_DEFINE_I2C(inst) \ + IF_ENABLED(CONFIG_LSM6DSV16X_STREAM, (LSM6DSV16X_I2C_RTIO_DEFINE(inst))); \ + static struct lsm6dsv16x_data lsm6dsv16x_data_##inst = { \ + IF_ENABLED(CONFIG_LSM6DSV16X_STREAM, \ + (.rtio_ctx = &lsm6dsv16x_rtio_ctx_##inst, \ + .iodev = &lsm6dsv16x_iodev_##inst, \ + .bus_type = BUS_I2C,)) \ + }; \ + static const struct lsm6dsv16x_config lsm6dsv16x_config_##inst = \ + LSM6DSV16X_CONFIG_I2C(inst); \ + /* * Main instantiation macro. Use of COND_CODE_1() selects the right * bus-specific macro at preprocessor time. */ #define LSM6DSV16X_DEFINE(inst) \ - static struct lsm6dsv16x_data lsm6dsv16x_data_##inst; \ - static const struct lsm6dsv16x_config lsm6dsv16x_config_##inst = \ COND_CODE_1(DT_INST_ON_BUS(inst, spi), \ - (LSM6DSV16X_CONFIG_SPI(inst)), \ - (LSM6DSV16X_CONFIG_I2C(inst))); \ - LSM6DSV16X_DEVICE_INIT(inst) + (LSM6DSV16X_DEFINE_SPI(inst)), \ + (LSM6DSV16X_DEFINE_I2C(inst))); \ + LSM6DSV16X_DEVICE_INIT(inst) DT_INST_FOREACH_STATUS_OKAY(LSM6DSV16X_DEFINE) diff --git a/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x.h b/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x.h index 76132f743ccc09f..fa2ed7d437cc17c 100644 --- a/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x.h +++ b/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x.h @@ -35,6 +35,9 @@ /* Gyro sensor sensitivity grain is 4.375 udps/LSB */ #define GAIN_UNIT_G (4375LL) +int lsm6dsv16x_calc_accel_gain(uint8_t fs); +int lsm6dsv16x_calc_gyro_gain(uint8_t fs); + struct lsm6dsv16x_config { stmdev_ctx_t ctx; union { @@ -52,6 +55,12 @@ struct lsm6dsv16x_config { uint8_t gyro_odr; uint8_t gyro_range; uint8_t drdy_pulsed; +#ifdef CONFIG_LSM6DSV16X_STREAM + uint8_t fifo_wtm; + uint8_t accel_batch : 4; + uint8_t gyro_batch : 4; + uint8_t temp_batch : 2; +#endif #ifdef CONFIG_LSM6DSV16X_TRIGGER const struct gpio_dt_spec int1_gpio; const struct gpio_dt_spec int2_gpio; @@ -98,6 +107,20 @@ struct lsm6dsv16x_data { uint8_t gyro_freq; uint8_t gyro_fs; +#ifdef CONFIG_LSM6DSV16X_STREAM + struct rtio_iodev_sqe *streaming_sqe; + struct rtio *rtio_ctx; + struct rtio_iodev *iodev; + uint8_t fifo_status[2]; + uint16_t fifo_count; + uint8_t fifo_irq; + uint8_t accel_batch_odr : 4; + uint8_t gyro_batch_odr : 4; + uint8_t temp_batch_odr : 2; + uint8_t bus_type : 1; /* I2C is 0, SPI is 1 */ + uint8_t reserved : 5; +#endif + #ifdef CONFIG_LSM6DSV16X_TRIGGER struct gpio_dt_spec *drdy_gpio; @@ -119,6 +142,19 @@ struct lsm6dsv16x_data { #endif /* CONFIG_LSM6DSV16X_TRIGGER */ }; +#ifdef CONFIG_LSM6DSV16X_STREAM +#define BUS_I2C 0 +#define BUS_SPI 1 + +static inline uint8_t lsm6dsv16x_bus_reg(struct lsm6dsv16x_data *data, uint8_t x) +{ + return (data->bus_type == BUS_SPI) ? x | 0x80 : x; +} + +#define LSM6DSV16X_FIFO_ITEM_LEN 7 +#define LSM6DSV16X_FIFO_SIZE(x) (x * LSM6DSV16X_FIFO_ITEM_LEN) +#endif + #if defined(CONFIG_LSM6DSV16X_SENSORHUB) int lsm6dsv16x_shub_init(const struct device *dev); int lsm6dsv16x_shub_fetch_external_devs(const struct device *dev); diff --git a/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_decoder.c b/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_decoder.c new file mode 100644 index 000000000000000..6ef18613a972314 --- /dev/null +++ b/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_decoder.c @@ -0,0 +1,446 @@ +/* ST Microelectronics LSM6DSV16X 6-axis IMU sensor driver + * + * Copyright (c) 2023 Google LLC + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "lsm6dsv16x.h" +#include "lsm6dsv16x_decoder.h" +#include + +#include +LOG_MODULE_REGISTER(LSM6DSV16X_DECODER, CONFIG_SENSOR_LOG_LEVEL); + +#ifdef CONFIG_LSM6DSV16X_STREAM +static const uint32_t accel_period_ns[] = { + [LSM6DSV16X_XL_BATCHED_AT_1Hz875] = UINT32_C(1000000000000) / 1875, + [LSM6DSV16X_XL_BATCHED_AT_7Hz5] = UINT32_C(1000000000000) / 7500, + [LSM6DSV16X_XL_BATCHED_AT_15Hz] = UINT32_C(1000000000) / 15, + [LSM6DSV16X_XL_BATCHED_AT_30Hz] = UINT32_C(1000000000) / 30, + [LSM6DSV16X_XL_BATCHED_AT_60Hz] = UINT32_C(1000000000) / 60, + [LSM6DSV16X_XL_BATCHED_AT_120Hz] = UINT32_C(1000000000) / 120, + [LSM6DSV16X_XL_BATCHED_AT_240Hz] = UINT32_C(1000000000) / 240, + [LSM6DSV16X_XL_BATCHED_AT_480Hz] = UINT32_C(1000000000) / 480, + [LSM6DSV16X_XL_BATCHED_AT_960Hz] = UINT32_C(1000000000) / 960, + [LSM6DSV16X_XL_BATCHED_AT_1920Hz] = UINT32_C(1000000000) / 1920, + [LSM6DSV16X_XL_BATCHED_AT_3840Hz] = UINT32_C(1000000000) / 3840, + [LSM6DSV16X_XL_BATCHED_AT_7680Hz] = UINT32_C(1000000000) / 7680, +}; + +static const uint32_t gyro_period_ns[] = { + [LSM6DSV16X_GY_BATCHED_AT_1Hz875] = UINT32_C(1000000000000) / 1875, + [LSM6DSV16X_GY_BATCHED_AT_7Hz5] = UINT32_C(1000000000000) / 7500, + [LSM6DSV16X_GY_BATCHED_AT_15Hz] = UINT32_C(1000000000) / 15, + [LSM6DSV16X_GY_BATCHED_AT_30Hz] = UINT32_C(1000000000) / 30, + [LSM6DSV16X_GY_BATCHED_AT_60Hz] = UINT32_C(1000000000) / 60, + [LSM6DSV16X_GY_BATCHED_AT_120Hz] = UINT32_C(1000000000) / 120, + [LSM6DSV16X_GY_BATCHED_AT_240Hz] = UINT32_C(1000000000) / 240, + [LSM6DSV16X_GY_BATCHED_AT_480Hz] = UINT32_C(1000000000) / 480, + [LSM6DSV16X_GY_BATCHED_AT_960Hz] = UINT32_C(1000000000) / 960, + [LSM6DSV16X_GY_BATCHED_AT_1920Hz] = UINT32_C(1000000000) / 1920, + [LSM6DSV16X_GY_BATCHED_AT_3840Hz] = UINT32_C(1000000000) / 3840, + [LSM6DSV16X_GY_BATCHED_AT_7680Hz] = UINT32_C(1000000000) / 7680, +}; + +#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) +static const uint32_t temp_period_ns[] = { + [LSM6DSV16X_TEMP_BATCHED_AT_1Hz875] = UINT32_C(1000000000000) / 1875, + [LSM6DSV16X_TEMP_BATCHED_AT_15Hz] = UINT32_C(1000000000) / 15, + [LSM6DSV16X_TEMP_BATCHED_AT_60Hz] = UINT32_C(1000000000) / 60, +}; +#endif +#endif /* CONFIG_LSM6DSV16X_STREAM */ + +/* + * Expand micro_val (a generic micro unit) to q31_t according to its range; this is achieved + * multiplying by 2^31/2^range. Then transform it to val. + */ +#define Q31_SHIFT_MICROVAL(micro_val, range) \ + (q31_t) ((int64_t)(micro_val) * ((int64_t)1 << (31 - (range))) / 1000000LL) + +/* bit range for Accelerometer for a given fs */ +static const int8_t accel_range[] = { + [LSM6DSV16X_DT_FS_2G] = 5, + [LSM6DSV16X_DT_FS_4G] = 6, + [LSM6DSV16X_DT_FS_8G] = 7, + [LSM6DSV16X_DT_FS_16G] = 8, +}; + +/* bit range for Gyroscope for a given fs */ +static const int8_t gyro_range[] = { + [LSM6DSV16X_DT_FS_125DPS] = 2, + [LSM6DSV16X_DT_FS_250DPS] = 3, + [LSM6DSV16X_DT_FS_500DPS] = 4, + [LSM6DSV16X_DT_FS_1000DPS] = 5, + [LSM6DSV16X_DT_FS_2000DPS] = 6, + [LSM6DSV16X_DT_FS_4000DPS] = 7, +}; + +#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) +/* bit range for Temperature sensor */ +static const int8_t temp_range = 9; + +/* transform temperature LSB into micro-Celsius */ +#define SENSOR_TEMP_UCELSIUS(t_lsb) \ + (int64_t) (25000000LL + (((int64_t)(t_lsb) * 1000000LL) / 256LL)) + +#endif + +/* Calculate scaling factor to transform micro-g/LSB unit into micro-ms2/LSB */ +#define SENSOR_SCALE_UG_TO_UMS2(ug_lsb) \ + (int32_t)((ug_lsb) * SENSOR_G / 1000000LL) + +/* + * Accelerometer scaling factors table (indexed by full scale) + * GAIN_UNIT_XL is expressed in ug/LSB. + */ +static const int32_t accel_scaler[] = { + [LSM6DSV16X_DT_FS_2G] = SENSOR_SCALE_UG_TO_UMS2(GAIN_UNIT_XL), + [LSM6DSV16X_DT_FS_4G] = SENSOR_SCALE_UG_TO_UMS2(2 * GAIN_UNIT_XL), + [LSM6DSV16X_DT_FS_8G] = SENSOR_SCALE_UG_TO_UMS2(4 * GAIN_UNIT_XL), + [LSM6DSV16X_DT_FS_16G] = SENSOR_SCALE_UG_TO_UMS2(8 * GAIN_UNIT_XL), +}; + +/* Calculate scaling factor to transform micro-dps/LSB unit into micro-rads/LSB */ +#define SENSOR_SCALE_UDPS_TO_URADS(udps_lsb) \ + (int32_t)(((udps_lsb) * SENSOR_PI / 180LL) / 1000000LL) + +/* + * Accelerometer scaling factors table (indexed by full scale) + * GAIN_UNIT_G is expressed in udps/LSB. + */ +static const int32_t gyro_scaler[] = { + [LSM6DSV16X_DT_FS_125DPS] = SENSOR_SCALE_UDPS_TO_URADS(GAIN_UNIT_G), + [LSM6DSV16X_DT_FS_250DPS] = SENSOR_SCALE_UDPS_TO_URADS(2 * GAIN_UNIT_G), + [LSM6DSV16X_DT_FS_500DPS] = SENSOR_SCALE_UDPS_TO_URADS(4 * GAIN_UNIT_G), + [LSM6DSV16X_DT_FS_1000DPS] = SENSOR_SCALE_UDPS_TO_URADS(8 * GAIN_UNIT_G), + [LSM6DSV16X_DT_FS_2000DPS] = SENSOR_SCALE_UDPS_TO_URADS(16 * GAIN_UNIT_G), + [LSM6DSV16X_DT_FS_4000DPS] = SENSOR_SCALE_UDPS_TO_URADS(32 * GAIN_UNIT_G), +}; + +static int lsm6dsv16x_decoder_get_frame_count(const uint8_t *buffer, + struct sensor_chan_spec chan_spec, + uint16_t *frame_count) +{ + struct lsm6dsv16x_fifo_data *data = (struct lsm6dsv16x_fifo_data *)buffer; + const struct lsm6dsv16x_decoder_header *header = &data->header; + + if (chan_spec.chan_idx != 0) { + return -ENOTSUP; + } + + if (!header->is_fifo) { + switch (chan_spec.chan_type) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + case SENSOR_CHAN_GYRO_XYZ: + case SENSOR_CHAN_DIE_TEMP: + *frame_count = 1; + return 0; + default: + return -ENOTSUP; + } + + return 0; + } + +#ifdef CONFIG_LSM6DSV16X_STREAM + *frame_count = data->fifo_count; +#endif + return 0; +} + +#ifdef CONFIG_LSM6DSV16X_STREAM +static int lsm6dsv16x_decode_fifo(const uint8_t *buffer, struct sensor_chan_spec chan_spec, + uint32_t *fit, uint16_t max_count, void *data_out) +{ + const struct lsm6dsv16x_fifo_data *edata = (const struct lsm6dsv16x_fifo_data *)buffer; + const uint8_t *buffer_end; + const struct lsm6dsv16x_decoder_header *header = &edata->header; + int count = 0; + uint8_t fifo_tag; + uint16_t xl_count = 0, gy_count = 0; + +#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) + uint16_t temp_count = 0; +#endif + + buffer += sizeof(struct lsm6dsv16x_fifo_data); + buffer_end = buffer + LSM6DSV16X_FIFO_SIZE(edata->fifo_count); + + ((struct sensor_data_header *)data_out)->base_timestamp_ns = edata->header.timestamp; + + while (count < max_count && buffer < buffer_end) { + const uint8_t *frame_end = buffer; + uint8_t skip_frame; + + skip_frame = 0; + frame_end += LSM6DSV16X_FIFO_ITEM_LEN; + + fifo_tag = (buffer[0] >> 3); + + switch (fifo_tag) { + case LSM6DSV16X_XL_NC_TAG: { + struct sensor_three_axis_data *out = data_out; + int16_t x, y, z; + const int32_t scale = accel_scaler[header->accel_fs]; + + xl_count++; + if ((uintptr_t)buffer < *fit) { + /* This frame was already decoded, move on to the next frame */ + buffer = frame_end; + continue; + } + + if (!SENSOR_CHANNEL_IS_ACCEL(chan_spec.chan_type)) { + buffer = frame_end; + continue; + } + + out->header.base_timestamp_ns = edata->header.timestamp; + out->readings[count].timestamp_delta = + (xl_count - 1) * accel_period_ns[edata->accel_batch_odr]; + + x = *(int16_t *)&buffer[1]; + y = *(int16_t *)&buffer[3]; + z = *(int16_t *)&buffer[5]; + + out->shift = accel_range[header->accel_fs]; + + out->readings[count].x = Q31_SHIFT_MICROVAL(scale * x, out->shift); + out->readings[count].y = Q31_SHIFT_MICROVAL(scale * y, out->shift); + out->readings[count].z = Q31_SHIFT_MICROVAL(scale * z, out->shift); + break; + } + case LSM6DSV16X_GY_NC_TAG: { + struct sensor_three_axis_data *out = data_out; + int16_t x, y, z; + const int32_t scale = gyro_scaler[header->gyro_fs]; + + gy_count++; + if ((uintptr_t)buffer < *fit) { + /* This frame was already decoded, move on to the next frame */ + buffer = frame_end; + continue; + } + + if (!SENSOR_CHANNEL_IS_GYRO(chan_spec.chan_type)) { + buffer = frame_end; + continue; + } + + out->header.base_timestamp_ns = edata->header.timestamp; + out->readings[count].timestamp_delta = + (gy_count - 1) * gyro_period_ns[edata->gyro_batch_odr]; + + x = *(int16_t *)&buffer[1]; + y = *(int16_t *)&buffer[3]; + z = *(int16_t *)&buffer[5]; + + out->shift = gyro_range[header->gyro_fs]; + + out->readings[count].x = Q31_SHIFT_MICROVAL(scale * x, out->shift); + out->readings[count].y = Q31_SHIFT_MICROVAL(scale * y, out->shift); + out->readings[count].z = Q31_SHIFT_MICROVAL(scale * z, out->shift); + break; + } +#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) + case LSM6DSV16X_TEMPERATURE_TAG: { + struct sensor_q31_data *out = data_out; + int16_t t; + int64_t t_uC; + + temp_count++; + if ((uintptr_t)buffer < *fit) { + /* This frame was already decoded, move on to the next frame */ + buffer = frame_end; + continue; + } + + if (chan_spec.chan_type != SENSOR_CHAN_DIE_TEMP) { + buffer = frame_end; + continue; + } + + out->header.base_timestamp_ns = edata->header.timestamp; + out->readings[count].timestamp_delta = + (temp_count - 1) * temp_period_ns[edata->temp_batch_odr]; + + t = *(int16_t *)&buffer[1]; + t_uC = SENSOR_TEMP_UCELSIUS(t); + + out->shift = temp_range; + + out->readings[count].temperature = Q31_SHIFT_MICROVAL(t_uC, out->shift); + break; + } +#endif + default: + /* skip unhandled FIFO tag */ + buffer = frame_end; + LOG_DBG("unknown FIFO tag %02x", fifo_tag); + continue; + } + + buffer = frame_end; + *fit = (uintptr_t)frame_end; + count++; + } + + return count; +} +#endif /* CONFIG_LSM6DSV16X_STREAM */ + +static int lsm6dsv16x_decode_sample(const uint8_t *buffer, struct sensor_chan_spec chan_spec, + uint32_t *fit, uint16_t max_count, void *data_out) +{ + const struct lsm6dsv16x_rtio_data *edata = (const struct lsm6dsv16x_rtio_data *)buffer; + const struct lsm6dsv16x_decoder_header *header = &edata->header; + + if (*fit != 0) { + return 0; + } + if (max_count == 0 || chan_spec.chan_idx != 0) { + return -EINVAL; + } + + switch (chan_spec.chan_type) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: { + const int32_t scale = accel_scaler[header->accel_fs]; + + if (edata->has_accel == 0) { + return -ENODATA; + } + + struct sensor_three_axis_data *out = data_out; + + out->header.base_timestamp_ns = edata->header.timestamp; + out->header.reading_count = 1; + + out->shift = accel_range[header->accel_fs]; + + out->readings[0].x = Q31_SHIFT_MICROVAL(scale * edata->acc[0], out->shift); + out->readings[0].y = Q31_SHIFT_MICROVAL(scale * edata->acc[1], out->shift); + out->readings[0].z = Q31_SHIFT_MICROVAL(scale * edata->acc[2], out->shift); + *fit = 1; + return 1; + } + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + case SENSOR_CHAN_GYRO_XYZ: { + const int32_t scale = gyro_scaler[header->gyro_fs]; + + if (edata->has_gyro == 0) { + return -ENODATA; + } + + struct sensor_three_axis_data *out = data_out; + + out->header.base_timestamp_ns = edata->header.timestamp; + out->header.reading_count = 1; + + out->shift = gyro_range[header->gyro_fs]; + + out->readings[0].x = Q31_SHIFT_MICROVAL(scale * edata->gyro[0], out->shift); + out->readings[0].y = Q31_SHIFT_MICROVAL(scale * edata->gyro[1], out->shift); + out->readings[0].z = Q31_SHIFT_MICROVAL(scale * edata->gyro[2], out->shift); + *fit = 1; + return 1; + } +#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) + case SENSOR_CHAN_DIE_TEMP: { + int64_t t_uC; + + if (edata->has_temp == 0) { + return -ENODATA; + } + + struct sensor_q31_data *out = data_out; + + out->header.base_timestamp_ns = edata->header.timestamp; + out->header.reading_count = 1; + + out->shift = temp_range; + + /* transform temperature LSB into micro-Celsius */ + t_uC = SENSOR_TEMP_UCELSIUS(edata->temp); + + out->readings[0].temperature = Q31_SHIFT_MICROVAL(t_uC, out->shift); + *fit = 1; + return 1; + } +#endif + default: + return -EINVAL; + } +} + +static int lsm6dsv16x_decoder_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec, + uint32_t *fit, uint16_t max_count, void *data_out) +{ +#ifdef CONFIG_LSM6DSV16X_STREAM + const struct lsm6dsv16x_decoder_header *header = + (const struct lsm6dsv16x_decoder_header *)buffer; + + if (header->is_fifo) { + return lsm6dsv16x_decode_fifo(buffer, chan_spec, fit, max_count, data_out); + } +#endif + + return lsm6dsv16x_decode_sample(buffer, chan_spec, fit, max_count, data_out); +} + +static int lsm6dsv16x_decoder_get_size_info(struct sensor_chan_spec chan_spec, size_t *base_size, + size_t *frame_size) +{ + switch (chan_spec.chan_type) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + case SENSOR_CHAN_GYRO_XYZ: + *base_size = sizeof(struct sensor_three_axis_data); + *frame_size = sizeof(struct sensor_three_axis_sample_data); + return 0; + case SENSOR_CHAN_DIE_TEMP: + *base_size = sizeof(struct sensor_q31_data); + *frame_size = sizeof(struct sensor_q31_sample_data); + return 0; + default: + return -ENOTSUP; + } +} + +static bool lsm6dsv16x_decoder_has_trigger(const uint8_t *buffer, enum sensor_trigger_type trigger) +{ + return false; +} + +SENSOR_DECODER_API_DT_DEFINE() = { + .get_frame_count = lsm6dsv16x_decoder_get_frame_count, + .get_size_info = lsm6dsv16x_decoder_get_size_info, + .decode = lsm6dsv16x_decoder_decode, + .has_trigger = lsm6dsv16x_decoder_has_trigger, +}; + +int lsm6dsv16x_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder) +{ + ARG_UNUSED(dev); + *decoder = &SENSOR_DECODER_NAME(); + + return 0; +} diff --git a/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_decoder.h b/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_decoder.h new file mode 100644 index 000000000000000..1a02af51e720c17 --- /dev/null +++ b/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_decoder.h @@ -0,0 +1,54 @@ +/* ST Microelectronics LSM6DSV16X 6-axis IMU sensor driver + * + * Copyright (c) 2023 Google LLC + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_LSM6DSV16X_DECODER_H_ +#define ZEPHYR_DRIVERS_SENSOR_LSM6DSV16X_DECODER_H_ + +#include +#include + +struct lsm6dsv16x_decoder_header { + uint64_t timestamp; + uint8_t is_fifo: 1; + uint8_t gyro_fs: 4; + uint8_t accel_fs: 2; + uint8_t reserved: 1; +} __attribute__((__packed__)); + +struct lsm6dsv16x_fifo_data { + struct lsm6dsv16x_decoder_header header; + uint8_t int_status; + uint16_t gyro_odr: 4; + uint16_t accel_odr: 4; + uint16_t fifo_count: 11; + uint16_t reserved_1: 5; + uint16_t gyro_batch_odr: 4; + uint16_t accel_batch_odr: 4; + uint16_t temp_batch_odr: 4; + uint16_t reserved_2: 4; +} __attribute__((__packed__)); + +struct lsm6dsv16x_rtio_data { + struct lsm6dsv16x_decoder_header header; + struct { + uint8_t has_accel: 1; /* set if accel channel has data */ + uint8_t has_gyro: 1; /* set if gyro channel has data */ + uint8_t has_temp: 1; /* set if temp channel has data */ + uint8_t reserved: 5; + } __attribute__((__packed__)); + int16_t acc[3]; + int16_t gyro[3]; + int16_t temp; +}; + +int lsm6dsv16x_encode(const struct device *dev, const struct sensor_chan_spec *const channels, + const size_t num_channels, uint8_t *buf); + +int lsm6dsv16x_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder); + +#endif /* ZEPHYR_DRIVERS_SENSOR_LSM6DSV16X_DECODER_H_ */ diff --git a/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio.c b/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio.c new file mode 100644 index 000000000000000..c43f0c9b89853cd --- /dev/null +++ b/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio.c @@ -0,0 +1,157 @@ +/* ST Microelectronics LSM6DSV16X 6-axis IMU sensor driver + * + * Copyright (c) 2023 Google LLC + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "lsm6dsv16x.h" +#include "lsm6dsv16x_rtio.h" +#include "lsm6dsv16x_decoder.h" +#include + +#include +LOG_MODULE_REGISTER(LSM6DSV16X_RTIO, CONFIG_SENSOR_LOG_LEVEL); + +static void lsm6dsv16x_submit_sample(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +{ + const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data; + const struct sensor_chan_spec *const channels = cfg->channels; + const size_t num_channels = cfg->count; + uint32_t min_buf_len = sizeof(struct lsm6dsv16x_rtio_data); + int rc = 0; + uint8_t *buf; + uint32_t buf_len; + struct lsm6dsv16x_rtio_data *edata; + struct lsm6dsv16x_data *data = dev->data; + + const struct lsm6dsv16x_config *config = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&config->ctx; + + /* Get the buffer for the frame, it may be allocated dynamically by the rtio context */ + rc = rtio_sqe_rx_buf(iodev_sqe, min_buf_len, min_buf_len, &buf, &buf_len); + if (rc != 0) { + LOG_ERR("Failed to get a read buffer of size %u bytes", min_buf_len); + goto err; + } + + edata = (struct lsm6dsv16x_rtio_data *)buf; + + edata->has_accel = 0; + edata->has_gyro = 0; + edata->has_temp = 0; + + for (int i = 0; i < num_channels; i++) { + switch (channels[i].chan_type) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + edata->has_accel = 1; + + rc = lsm6dsv16x_acceleration_raw_get(ctx, edata->acc); + if (rc < 0) { + LOG_DBG("Failed to read accel sample"); + goto err; + } + break; + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + case SENSOR_CHAN_GYRO_XYZ: + edata->has_gyro = 1; + + rc = lsm6dsv16x_angular_rate_raw_get(ctx, edata->gyro); + if (rc < 0) { + LOG_DBG("Failed to read gyro sample"); + goto err; + } + break; +#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) + case SENSOR_CHAN_DIE_TEMP: + edata->has_temp = 1; + + rc = lsm6dsv16x_temperature_raw_get(ctx, &edata->temp); + if (rc < 0) { + LOG_DBG("Failed to read temp sample"); + goto err; + } + break; +#endif + case SENSOR_CHAN_ALL: + edata->has_accel = 1; + + rc = lsm6dsv16x_acceleration_raw_get(ctx, edata->acc); + if (rc < 0) { + LOG_DBG("Failed to read accel sample"); + goto err; + } + + edata->has_gyro = 1; + + rc = lsm6dsv16x_angular_rate_raw_get(ctx, edata->gyro); + if (rc < 0) { + LOG_DBG("Failed to read gyro sample"); + goto err; + } + +#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) + edata->has_temp = 1; + + rc = lsm6dsv16x_temperature_raw_get(ctx, &edata->temp); + if (rc < 0) { + LOG_DBG("Failed to read temp sample"); + goto err; + } +#endif + break; + default: + continue; + } + } + + edata->header.is_fifo = false; + edata->header.accel_fs = data->accel_fs; + edata->header.gyro_fs = data->gyro_fs; + edata->header.timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); + + rtio_iodev_sqe_ok(iodev_sqe, 0); + +err: + /* Check that the fetch succeeded */ + if (rc != 0) { + LOG_ERR("Failed to fetch samples"); + rtio_iodev_sqe_err(iodev_sqe, rc); + return; + } +} + +void lsm6dsv16x_submit_sync(struct rtio_iodev_sqe *iodev_sqe) +{ + const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data; + const struct device *dev = cfg->sensor; + + if (!cfg->is_streaming) { + lsm6dsv16x_submit_sample(dev, iodev_sqe); + } else if (IS_ENABLED(CONFIG_LSM6DSV16X_STREAM)) { + lsm6dsv16x_submit_stream(dev, iodev_sqe); + } else { + rtio_iodev_sqe_err(iodev_sqe, -ENOTSUP); + } +} + +void lsm6dsv16x_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +{ + struct rtio_work_req *req = rtio_work_req_alloc(); + + if (req == NULL) { + LOG_ERR("RTIO work item allocation failed. Consider to increase " + "CONFIG_RTIO_WORKQ_POOL_ITEMS."); + rtio_iodev_sqe_err(iodev_sqe, -ENOMEM); + return; + } + + rtio_work_req_submit(req, iodev_sqe, lsm6dsv16x_submit_sync); +} diff --git a/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio.h b/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio.h new file mode 100644 index 000000000000000..9aa838ddd455e67 --- /dev/null +++ b/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio.h @@ -0,0 +1,20 @@ +/* ST Microelectronics LSM6DSV16X 6-axis IMU sensor driver + * + * Copyright (c) 2023 Google LLC + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_LSM6DSV16X_RTIO_H_ +#define ZEPHYR_DRIVERS_SENSOR_LSM6DSV16X_RTIO_H_ + +#include +#include + +void lsm6dsv16x_submit(const struct device *sensor, struct rtio_iodev_sqe *iodev_sqe); + +void lsm6dsv16x_submit_stream(const struct device *sensor, struct rtio_iodev_sqe *iodev_sqe); +void lsm6dsv16x_stream_irq_handler(const struct device *dev); + +#endif /* ZEPHYR_DRIVERS_SENSOR_LSM6DSV16X_RTIO_H_ */ diff --git a/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio_stream.c b/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio_stream.c new file mode 100644 index 000000000000000..8543814a392ebb8 --- /dev/null +++ b/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio_stream.c @@ -0,0 +1,357 @@ +/* ST Microelectronics LSM6DSV16X 6-axis IMU sensor driver + * + * Copyright (c) 2023 Google LLC + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT st_lsm6dsv16x + +#include +#include +#include "lsm6dsv16x.h" +#include "lsm6dsv16x_decoder.h" +#include + +#include +LOG_MODULE_DECLARE(LSM6DSV16X_RTIO); + +static void lsm6dsv16x_config_fifo(const struct device *dev, uint8_t enable) +{ + struct lsm6dsv16x_data *lsm6dsv16x = dev->data; + const struct lsm6dsv16x_config *config = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&config->ctx; + uint8_t fifo_wtm = 0; + lsm6dsv16x_pin_int_route_t pin_int = { 0 }; + lsm6dsv16x_fifo_xl_batch_t xl_batch = LSM6DSV16X_DT_XL_NOT_BATCHED; + lsm6dsv16x_fifo_gy_batch_t gy_batch = LSM6DSV16X_DT_GY_NOT_BATCHED; + lsm6dsv16x_fifo_temp_batch_t temp_batch = LSM6DSV16X_DT_TEMP_NOT_BATCHED; + lsm6dsv16x_fifo_mode_t fifo_mode = LSM6DSV16X_BYPASS_MODE; + + /* disable FIFO as first thing */ + lsm6dsv16x_fifo_mode_set(ctx, LSM6DSV16X_BYPASS_MODE); + + pin_int.fifo_th = PROPERTY_DISABLE; + + if (enable != 0) { + pin_int.fifo_th = PROPERTY_ENABLE; + + xl_batch = config->accel_batch; + gy_batch = config->gyro_batch; + temp_batch = config->temp_batch; + + fifo_mode = LSM6DSV16X_STREAM_MODE; + fifo_wtm = config->fifo_wtm; + } + + /* + * Set FIFO watermark (number of unread sensor data TAG + 6 bytes + * stored in FIFO) to FIFO_WATERMARK samples + */ + lsm6dsv16x_fifo_watermark_set(ctx, config->fifo_wtm); + + /* Turn on/off FIFO */ + lsm6dsv16x_fifo_mode_set(ctx, fifo_mode); + + /* Set FIFO batch rates */ + lsm6dsv16x_fifo_xl_batch_set(ctx, xl_batch); + lsm6dsv16x->accel_batch_odr = xl_batch; + lsm6dsv16x_fifo_gy_batch_set(ctx, gy_batch); + lsm6dsv16x->gyro_batch_odr = gy_batch; +#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) + lsm6dsv16x_fifo_temp_batch_set(ctx, temp_batch); + lsm6dsv16x->temp_batch_odr = temp_batch; +#endif + + /* Set pin interrupt (fifo_th could be on or off) */ + if (config->drdy_pin == 1) { + lsm6dsv16x_pin_int1_route_set(ctx, &pin_int); + } else { + lsm6dsv16x_pin_int2_route_set(ctx, &pin_int); + } +} + +void lsm6dsv16x_submit_stream(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +{ + struct lsm6dsv16x_data *lsm6dsv16x = dev->data; + const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data; + uint8_t fifo_irq = 0; + + gpio_pin_interrupt_configure_dt(lsm6dsv16x->drdy_gpio, GPIO_INT_DISABLE); + + for (size_t i = 0; i < cfg->count; i++) { + if ((cfg->triggers[i].trigger == SENSOR_TRIG_FIFO_WATERMARK) || + (cfg->triggers[i].trigger == SENSOR_TRIG_FIFO_FULL)) { + fifo_irq = 1; + } + } + + /* if any change in fifo irq */ + if (fifo_irq != lsm6dsv16x->fifo_irq) { + lsm6dsv16x->fifo_irq = fifo_irq; + + /* enable/disable the FIFO */ + lsm6dsv16x_config_fifo(dev, fifo_irq); + } + + lsm6dsv16x->streaming_sqe = iodev_sqe; + + gpio_pin_interrupt_configure_dt(lsm6dsv16x->drdy_gpio, GPIO_INT_EDGE_TO_ACTIVE); +} + +static void lsm6dsv16x_complete_op_cb(struct rtio *r, const struct rtio_sqe *sqe, void *arg) +{ + const struct device *dev = arg; + struct lsm6dsv16x_data *lsm6dsv16x = dev->data; + + /* + * Mark operation completed + */ + rtio_iodev_sqe_ok(sqe->userdata, 0); + lsm6dsv16x->streaming_sqe = NULL; + gpio_pin_interrupt_configure_dt(lsm6dsv16x->drdy_gpio, GPIO_INT_EDGE_TO_ACTIVE); +} + +static void lsm6dsv16x_read_fifo_cb(struct rtio *r, const struct rtio_sqe *sqe, void *arg) +{ + const struct device *dev = arg; + struct lsm6dsv16x_data *lsm6dsv16x = dev->data; + struct gpio_dt_spec *irq_gpio = lsm6dsv16x->drdy_gpio; + struct rtio_iodev *iodev = lsm6dsv16x->iodev; + struct sensor_read_config *read_config; + uint8_t fifo_th = 0, fifo_full = 0; + uint16_t fifo_count; + + /* At this point, no sqe request is queued should be considered as a bug */ + __ASSERT_NO_MSG(lsm6dsv16x->streaming_sqe != NULL); + + read_config = (struct sensor_read_config *)lsm6dsv16x->streaming_sqe->sqe.iodev->data; + __ASSERT_NO_MSG(read_config != NULL); + __ASSERT_NO_MSG(read_config->is_streaming == true); + + /* parse the configuration in search for any configured trigger */ + struct sensor_stream_trigger *fifo_ths_cfg = NULL; + struct sensor_stream_trigger *fifo_full_cfg = NULL; + + for (int i = 0; i < read_config->count; ++i) { + if (read_config->triggers[i].trigger == SENSOR_TRIG_FIFO_WATERMARK) { + fifo_ths_cfg = &read_config->triggers[i]; + continue; + } + + if (read_config->triggers[i].trigger == SENSOR_TRIG_FIFO_FULL) { + fifo_full_cfg = &read_config->triggers[i]; + continue; + } + } + + /* fill fifo h/w status */ + fifo_th = (lsm6dsv16x->fifo_status[1] & 0x80) ? 1 : 0; + fifo_full = (lsm6dsv16x->fifo_status[1] & 0x20) ? 1 : 0; + fifo_count = (uint16_t)lsm6dsv16x->fifo_status[1] & 0x1U; + fifo_count = (fifo_count << 8) | lsm6dsv16x->fifo_status[0]; + lsm6dsv16x->fifo_count = fifo_count; + + bool has_fifo_ths_trig = fifo_ths_cfg != NULL && fifo_th == 1; + bool has_fifo_full_trig = fifo_full_cfg != NULL && fifo_full == 1; + + /* check if no theshold/full fifo interrupt or spurious interrupts */ + if (!has_fifo_ths_trig && !has_fifo_full_trig) { + /* complete operation with no error */ + rtio_iodev_sqe_ok(sqe->userdata, 0); + + lsm6dsv16x->streaming_sqe = NULL; + gpio_pin_interrupt_configure_dt(irq_gpio, GPIO_INT_EDGE_TO_ACTIVE); + return; + } + + struct rtio_cqe *cqe; + int res = 0; + + do { + cqe = rtio_cqe_consume(lsm6dsv16x->rtio_ctx); + if (cqe != NULL) { + if ((cqe->result < 0) && (res == 0)) { + LOG_ERR("Bus error: %d", cqe->result); + res = cqe->result; + } + rtio_cqe_release(lsm6dsv16x->rtio_ctx, cqe); + } + } while (cqe != NULL); + + /* Bail/cancel attempt to read sensor on any error */ + if (res != 0) { + rtio_iodev_sqe_err(lsm6dsv16x->streaming_sqe, res); + lsm6dsv16x->streaming_sqe = NULL; + return; + } + + enum sensor_stream_data_opt data_opt; + + if (has_fifo_ths_trig && !has_fifo_full_trig) { + /* Only care about fifo threshold */ + data_opt = fifo_ths_cfg->opt; + } else if (!has_fifo_ths_trig && has_fifo_full_trig) { + /* Only care about fifo full */ + data_opt = fifo_full_cfg->opt; + } else { + /* Both fifo threshold and full */ + data_opt = MIN(fifo_ths_cfg->opt, fifo_full_cfg->opt); + } + + if (data_opt == SENSOR_STREAM_DATA_NOP || data_opt == SENSOR_STREAM_DATA_DROP) { + uint8_t *buf; + uint32_t buf_len; + + /* Clear streaming_sqe since we're done with the call */ + if (rtio_sqe_rx_buf(lsm6dsv16x->streaming_sqe, sizeof(struct lsm6dsv16x_fifo_data), + sizeof(struct lsm6dsv16x_fifo_data), &buf, &buf_len) != 0) { + rtio_iodev_sqe_err(lsm6dsv16x->streaming_sqe, -ENOMEM); + lsm6dsv16x->streaming_sqe = NULL; + gpio_pin_interrupt_configure_dt(irq_gpio, GPIO_INT_EDGE_TO_ACTIVE); + return; + } + + struct lsm6dsv16x_fifo_data *rx_data = (struct lsm6dsv16x_fifo_data *)buf; + + memset(buf, 0, buf_len); + rx_data->header.is_fifo = 1; + rx_data->header.timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); + rx_data->int_status = lsm6dsv16x->fifo_status[1]; + rx_data->fifo_count = 0; + + /* complete request with ok */ + rtio_iodev_sqe_ok(lsm6dsv16x->streaming_sqe, 0); + lsm6dsv16x->streaming_sqe = NULL; + + if (data_opt == SENSOR_STREAM_DATA_DROP) { + + /* + * Flush the FIFO by setting the mode to LSM6DSV16X_BYPASS_MODE + * + * STMEMSC API equivalent code: + * + * lsm6dsv16x_fifo_mode_set(ctx, LSM6DSV16X_BYPASS_MODE); + */ + struct rtio_sqe *write_fifo_mode = rtio_sqe_acquire(lsm6dsv16x->rtio_ctx); + uint8_t lsm6dsv16x_fifo_mode_set[] = { + LSM6DSV16X_FIFO_CTRL4, + LSM6DSV16X_BYPASS_MODE, + }; + + rtio_sqe_prep_tiny_write(write_fifo_mode, iodev, + RTIO_PRIO_NORM, lsm6dsv16x_fifo_mode_set, + ARRAY_SIZE(lsm6dsv16x_fifo_mode_set), NULL); + + rtio_submit(lsm6dsv16x->rtio_ctx, 0); + } + + gpio_pin_interrupt_configure_dt(irq_gpio, GPIO_INT_EDGE_TO_ACTIVE); + return; + } + + uint8_t *buf, *read_buf; + uint32_t buf_len, buf_avail; + uint32_t req_len = LSM6DSV16X_FIFO_SIZE(fifo_count) + sizeof(struct lsm6dsv16x_fifo_data); + + if (rtio_sqe_rx_buf(lsm6dsv16x->streaming_sqe, req_len, req_len, &buf, &buf_len) != 0) { + LOG_ERR("Failed to get buffer"); + rtio_iodev_sqe_err(lsm6dsv16x->streaming_sqe, -ENOMEM); + lsm6dsv16x->streaming_sqe = NULL; + gpio_pin_interrupt_configure_dt(irq_gpio, GPIO_INT_EDGE_TO_ACTIVE); + return; + } + + struct lsm6dsv16x_fifo_data hdr = { + .header = { + .is_fifo = true, + .accel_fs = lsm6dsv16x->accel_fs, + .gyro_fs = lsm6dsv16x->gyro_fs, + .timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()), + }, + .fifo_count = fifo_count, + .accel_batch_odr = lsm6dsv16x->accel_batch_odr, + .gyro_batch_odr = lsm6dsv16x->gyro_batch_odr, +#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) + .temp_batch_odr = lsm6dsv16x->temp_batch_odr, +#endif + }; + + memcpy(buf, &hdr, sizeof(hdr)); + read_buf = buf + sizeof(hdr); + buf_avail = buf_len - sizeof(hdr); + + /* + * Prepare rtio enabled bus to read all fifo_count entries from + * LSM6DSV16X_FIFO_DATA_OUT_TAG. Then lsm6dsv16x_complete_op_cb + * callback will be invoked. + * + * STMEMSC API equivalent code: + * + * num = fifo_status.fifo_level; + * + * while (num--) { + * lsm6dsv16x_fifo_out_raw_t f_data; + * + * lsm6dsv16x_fifo_out_raw_get(&dev_ctx, &f_data); + * } + */ + struct rtio_sqe *write_fifo_dout_addr = rtio_sqe_acquire(lsm6dsv16x->rtio_ctx); + struct rtio_sqe *read_fifo_dout_reg = rtio_sqe_acquire(lsm6dsv16x->rtio_ctx); + struct rtio_sqe *complete_op = rtio_sqe_acquire(lsm6dsv16x->rtio_ctx); + uint8_t reg = lsm6dsv16x_bus_reg(lsm6dsv16x, LSM6DSV16X_FIFO_DATA_OUT_TAG); + + rtio_sqe_prep_tiny_write(write_fifo_dout_addr, iodev, RTIO_PRIO_NORM, ®, 1, NULL); + write_fifo_dout_addr->flags = RTIO_SQE_TRANSACTION; + rtio_sqe_prep_read(read_fifo_dout_reg, iodev, RTIO_PRIO_NORM, + read_buf, buf_avail, lsm6dsv16x->streaming_sqe); + read_fifo_dout_reg->flags = RTIO_SQE_CHAINED; + if (lsm6dsv16x->bus_type == BUS_I2C) { + read_fifo_dout_reg->iodev_flags |= RTIO_IODEV_I2C_STOP | RTIO_IODEV_I2C_RESTART; + } + rtio_sqe_prep_callback(complete_op, + lsm6dsv16x_complete_op_cb, (void *)dev, lsm6dsv16x->streaming_sqe); + + rtio_submit(lsm6dsv16x->rtio_ctx, 0); +} + +void lsm6dsv16x_stream_irq_handler(const struct device *dev) +{ + struct lsm6dsv16x_data *lsm6dsv16x = dev->data; + struct rtio_iodev *iodev = lsm6dsv16x->iodev; + + if (lsm6dsv16x->streaming_sqe == NULL) { + return; + } + + lsm6dsv16x->fifo_status[0] = lsm6dsv16x->fifo_status[1] = 0; + + /* + * Prepare rtio enabled bus to read LSM6DSV16X_FIFO_STATUS1 and LSM6DSV16X_FIFO_STATUS2 + * registers where FIFO threshold condition and count are reported. + * Then lsm6dsv16x_read_fifo_cb callback will be invoked. + * + * STMEMSC API equivalent code: + * + * lsm6dsv16x_fifo_status_t fifo_status; + * + * lsm6dsv16x_fifo_status_get(&dev_ctx, &fifo_status); + */ + struct rtio_sqe *write_fifo_status_addr = rtio_sqe_acquire(lsm6dsv16x->rtio_ctx); + struct rtio_sqe *read_fifo_status_reg = rtio_sqe_acquire(lsm6dsv16x->rtio_ctx); + struct rtio_sqe *check_fifo_status_reg = rtio_sqe_acquire(lsm6dsv16x->rtio_ctx); + uint8_t reg = lsm6dsv16x_bus_reg(lsm6dsv16x, LSM6DSV16X_FIFO_STATUS1); + + rtio_sqe_prep_tiny_write(write_fifo_status_addr, iodev, RTIO_PRIO_NORM, ®, 1, NULL); + write_fifo_status_addr->flags = RTIO_SQE_TRANSACTION; + rtio_sqe_prep_read(read_fifo_status_reg, iodev, RTIO_PRIO_NORM, + lsm6dsv16x->fifo_status, 2, NULL); + read_fifo_status_reg->flags = RTIO_SQE_CHAINED; + if (lsm6dsv16x->bus_type == BUS_I2C) { + read_fifo_status_reg->iodev_flags |= RTIO_IODEV_I2C_STOP | RTIO_IODEV_I2C_RESTART; + } + rtio_sqe_prep_callback(check_fifo_status_reg, + lsm6dsv16x_read_fifo_cb, (void *)dev, NULL); + rtio_submit(lsm6dsv16x->rtio_ctx, 0); +} diff --git a/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_trigger.c b/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_trigger.c index 52bd7d6c0dd0452..6738b0db2ed58d3 100644 --- a/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_trigger.c +++ b/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_trigger.c @@ -16,6 +16,7 @@ #include #include "lsm6dsv16x.h" +#include "lsm6dsv16x_rtio.h" LOG_MODULE_DECLARE(LSM6DSV16X, CONFIG_SENSOR_LOG_LEVEL); @@ -120,33 +121,49 @@ int lsm6dsv16x_trigger_set(const struct device *dev, { const struct lsm6dsv16x_config *cfg = dev->config; struct lsm6dsv16x_data *lsm6dsv16x = dev->data; + int ret = 0; if (!cfg->trig_enabled) { LOG_ERR("trigger_set op not supported"); return -ENOTSUP; } - if (trig->chan == SENSOR_CHAN_ACCEL_XYZ) { - lsm6dsv16x->handler_drdy_acc = handler; - lsm6dsv16x->trig_drdy_acc = trig; - if (handler) { - return lsm6dsv16x_enable_xl_int(dev, LSM6DSV16X_EN_BIT); - } else { - return lsm6dsv16x_enable_xl_int(dev, LSM6DSV16X_DIS_BIT); - } - } else if (trig->chan == SENSOR_CHAN_GYRO_XYZ) { - lsm6dsv16x->handler_drdy_gyr = handler; - lsm6dsv16x->trig_drdy_gyr = trig; - if (handler) { - return lsm6dsv16x_enable_g_int(dev, LSM6DSV16X_EN_BIT); - } else { - return lsm6dsv16x_enable_g_int(dev, LSM6DSV16X_DIS_BIT); + if (trig == NULL) { + LOG_ERR("no trigger"); + return -EINVAL; + } + + switch (trig->type) { + case SENSOR_TRIG_DATA_READY: + if (trig->chan == SENSOR_CHAN_ACCEL_XYZ) { + lsm6dsv16x->handler_drdy_acc = handler; + lsm6dsv16x->trig_drdy_acc = trig; + if (handler) { + lsm6dsv16x_enable_xl_int(dev, LSM6DSV16X_EN_BIT); + } else { + lsm6dsv16x_enable_xl_int(dev, LSM6DSV16X_DIS_BIT); + } + } else if (trig->chan == SENSOR_CHAN_GYRO_XYZ) { + lsm6dsv16x->handler_drdy_gyr = handler; + lsm6dsv16x->trig_drdy_gyr = trig; + if (handler) { + lsm6dsv16x_enable_g_int(dev, LSM6DSV16X_EN_BIT); + } else { + lsm6dsv16x_enable_g_int(dev, LSM6DSV16X_DIS_BIT); + } } + + break; + default: + ret = -ENOTSUP; + break; } - return -ENOTSUP; + return ret; } +#if defined(CONFIG_LSM6DSV16X_TRIGGER_OWN_THREAD) || \ + defined(CONFIG_LSM6DSV16X_TRIGGER_GLOBAL_THREAD) /** * lsm6dsv16x_handle_interrupt - handle the drdy event * read data and call handler if registered any @@ -181,6 +198,7 @@ static void lsm6dsv16x_handle_interrupt(const struct device *dev) gpio_pin_interrupt_configure_dt(lsm6dsv16x->drdy_gpio, GPIO_INT_EDGE_TO_ACTIVE); } +#endif /* CONFIG_LSM6DSV16X_TRIGGER_OWN_THREAD || CONFIG_LSM6DSV16X_TRIGGER_GLOBAL_THREAD */ static void lsm6dsv16x_gpio_callback(const struct device *dev, struct gpio_callback *cb, uint32_t pins) @@ -192,6 +210,10 @@ static void lsm6dsv16x_gpio_callback(const struct device *dev, gpio_pin_interrupt_configure_dt(lsm6dsv16x->drdy_gpio, GPIO_INT_DISABLE); + if (IS_ENABLED(CONFIG_LSM6DSV16X_STREAM)) { + lsm6dsv16x_stream_irq_handler(lsm6dsv16x->dev); + } + #if defined(CONFIG_LSM6DSV16X_TRIGGER_OWN_THREAD) k_sem_give(&lsm6dsv16x->gpio_sem); #elif defined(CONFIG_LSM6DSV16X_TRIGGER_GLOBAL_THREAD) diff --git a/dts/bindings/sensor/st,lsm6dsv16x-common.yaml b/dts/bindings/sensor/st,lsm6dsv16x-common.yaml index 84c0dce96a713be..8d8df5037109141 100644 --- a/dts/bindings/sensor/st,lsm6dsv16x-common.yaml +++ b/dts/bindings/sensor/st,lsm6dsv16x-common.yaml @@ -184,3 +184,77 @@ properties: description: | Selects the pulsed mode for data-ready interrupt when enabled, and the latched mode when disabled. + + fifo-watermark: + type: int + default: 32 + description: | + Specify the default FIFO watermark threshold. Every unit indicates a FIFO row (1 byte of TAG + + 6 bytes of data). (min 0; max 255) + A typical threshold value is 32 which is then used as default. + + accel-fifo-batch-rate: + type: int + default: 0x0 + description: | + Specify the default accelerometer FIFO batch data rate expressed in samples per second (Hz). + The values are taken in accordance to lsm6dsv16x_fifo_xl_batch_t enumerative in hal/st + module. + Default is power-up configuration. + + - 0x0 # LSM6DSV16X_DT_XL_NOT_BATCHED + - 0x1 # LSM6DSV16X_DT_XL_BATCHED_AT_1Hz875 + - 0x2 # LSM6DSV16X_DT_XL_BATCHED_AT_7Hz5 + - 0x3 # LSM6DSV16X_DT_XL_BATCHED_AT_15Hz + - 0x4 # LSM6DSV16X_DT_XL_BATCHED_AT_30Hz + - 0x5 # LSM6DSV16X_DT_XL_BATCHED_AT_60Hz + - 0x6 # LSM6DSV16X_DT_XL_BATCHED_AT_120Hz + - 0x7 # LSM6DSV16X_DT_XL_BATCHED_AT_240Hz + - 0x8 # LSM6DSV16X_DT_XL_BATCHED_AT_480Hz + - 0x9 # LSM6DSV16X_DT_XL_BATCHED_AT_960Hz + - 0xa # LSM6DSV16X_DT_XL_BATCHED_AT_1920Hz + - 0xb # LSM6DSV16X_DT_XL_BATCHED_AT_3840Hz + - 0xc # LSM6DSV16X_DT_XL_BATCHED_AT_7680Hz + + enum: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c] + + gyro-fifo-batch-rate: + type: int + default: 0x0 + description: | + Specify the default gyroscope FIFO batch data rate expressed in samples per second (Hz). + The values are taken in accordance to lsm6dsv16x_fifo_gy_batch_t enumerative in hal/st + module. + Default is power-up configuration. + + - 0x0 # LSM6DSV16X_DT_GY_NOT_BATCHED + - 0x1 # LSM6DSV16X_DT_GY_BATCHED_AT_1Hz875 + - 0x2 # LSM6DSV16X_DT_GY_BATCHED_AT_7Hz5 + - 0x3 # LSM6DSV16X_DT_GY_BATCHED_AT_15Hz + - 0x4 # LSM6DSV16X_DT_GY_BATCHED_AT_30Hz + - 0x5 # LSM6DSV16X_DT_GY_BATCHED_AT_60Hz + - 0x6 # LSM6DSV16X_DT_GY_BATCHED_AT_120Hz + - 0x7 # LSM6DSV16X_DT_GY_BATCHED_AT_240Hz + - 0x8 # LSM6DSV16X_DT_GY_BATCHED_AT_480Hz + - 0x9 # LSM6DSV16X_DT_GY_BATCHED_AT_960Hz + - 0xa # LSM6DSV16X_DT_GY_BATCHED_AT_1920Hz + - 0xb # LSM6DSV16X_DT_GY_BATCHED_AT_3840Hz + - 0xc # LSM6DSV16X_DT_GY_BATCHED_AT_7680Hz + + enum: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c] + + temp-fifo-batch-rate: + type: int + default: 0x0 + description: | + Specify the default temperature FIFO batch data rate expressed in samples per second (Hz). + The values are taken in accordance to lsm6dsv16x_fifo_temp_batch_t enumerative in hal/st + module. + Default is power-up configuration. + + - 0x0 # LSM6DSV16X_DT_TEMP_NOT_BATCHED + - 0x1 # LSM6DSV16X_DT_TEMP_BATCHED_AT_1Hz875 + - 0x2 # LSM6DSV16X_DT_TEMP_BATCHED_AT_15Hz + - 0x3 # LSM6DSV16X_DT_TEMP_BATCHED_AT_60Hz + + enum: [0x00, 0x01, 0x02, 0x03] diff --git a/include/zephyr/drivers/sensor.h b/include/zephyr/drivers/sensor.h index 1d958a4b7070495..6cd8cc708279780 100644 --- a/include/zephyr/drivers/sensor.h +++ b/include/zephyr/drivers/sensor.h @@ -941,6 +941,30 @@ struct __attribute__((__packed__)) sensor_data_generic_header { ((chan) == SENSOR_CHAN_ACCEL_XYZ || (chan) == SENSOR_CHAN_GYRO_XYZ || \ (chan) == SENSOR_CHAN_MAGN_XYZ || (chan) == SENSOR_CHAN_POS_DXYZ) +/** + * @brief checks if a given channel is an Accelerometer + * + * @param[in] chan The channel to check + * @retval true if @p chan is any of @ref SENSOR_CHAN_ACCEL_XYZ, @ref SENSOR_CHAN_ACCEL_X, or + * @ref SENSOR_CHAN_ACCEL_Y, or @ref SENSOR_CHAN_ACCEL_Z + * @retval false otherwise + */ +#define SENSOR_CHANNEL_IS_ACCEL(chan) \ + ((chan) == SENSOR_CHAN_ACCEL_XYZ || (chan) == SENSOR_CHAN_ACCEL_X || \ + (chan) == SENSOR_CHAN_ACCEL_Y || (chan) == SENSOR_CHAN_ACCEL_Z) + +/** + * @brief checks if a given channel is a Gyroscope + * + * @param[in] chan The channel to check + * @retval true if @p chan is any of @ref SENSOR_CHAN_GYRO_XYZ, @ref SENSOR_CHAN_GYRO_X, or + * @ref SENSOR_CHAN_GYRO_Y, or @ref SENSOR_CHAN_GYRO_Z + * @retval false otherwise + */ +#define SENSOR_CHANNEL_IS_GYRO(chan) \ + ((chan) == SENSOR_CHAN_GYRO_XYZ || (chan) == SENSOR_CHAN_GYRO_X || \ + (chan) == SENSOR_CHAN_GYRO_Y || (chan) == SENSOR_CHAN_GYRO_Z) + /** * @brief Get the sensor's decoder API * diff --git a/include/zephyr/dt-bindings/sensor/lsm6dsv16x.h b/include/zephyr/dt-bindings/sensor/lsm6dsv16x.h index 533dd5e3febb085..76caabbdb7f9d64 100644 --- a/include/zephyr/dt-bindings/sensor/lsm6dsv16x.h +++ b/include/zephyr/dt-bindings/sensor/lsm6dsv16x.h @@ -55,4 +55,40 @@ #define LSM6DSV16X_DT_ODR_HA02_AT_3200Hz 0x2B #define LSM6DSV16X_DT_ODR_HA02_AT_6400Hz 0x2C +/* Accelerometer batching rates */ +#define LSM6DSV16X_DT_XL_NOT_BATCHED 0x0 +#define LSM6DSV16X_DT_XL_BATCHED_AT_1Hz875 0x1 +#define LSM6DSV16X_DT_XL_BATCHED_AT_7Hz5 0x2 +#define LSM6DSV16X_DT_XL_BATCHED_AT_15Hz 0x3 +#define LSM6DSV16X_DT_XL_BATCHED_AT_30Hz 0x4 +#define LSM6DSV16X_DT_XL_BATCHED_AT_60Hz 0x5 +#define LSM6DSV16X_DT_XL_BATCHED_AT_120Hz 0x6 +#define LSM6DSV16X_DT_XL_BATCHED_AT_240Hz 0x7 +#define LSM6DSV16X_DT_XL_BATCHED_AT_480Hz 0x8 +#define LSM6DSV16X_DT_XL_BATCHED_AT_960Hz 0x9 +#define LSM6DSV16X_DT_XL_BATCHED_AT_1920Hz 0xa +#define LSM6DSV16X_DT_XL_BATCHED_AT_3840Hz 0xb +#define LSM6DSV16X_DT_XL_BATCHED_AT_7680Hz 0xc + +/* Gyroscope batching rates */ +#define LSM6DSV16X_DT_GY_NOT_BATCHED 0x0 +#define LSM6DSV16X_DT_GY_BATCHED_AT_1Hz875 0x1 +#define LSM6DSV16X_DT_GY_BATCHED_AT_7Hz5 0x2 +#define LSM6DSV16X_DT_GY_BATCHED_AT_15Hz 0x3 +#define LSM6DSV16X_DT_GY_BATCHED_AT_30Hz 0x4 +#define LSM6DSV16X_DT_GY_BATCHED_AT_60Hz 0x5 +#define LSM6DSV16X_DT_GY_BATCHED_AT_120Hz 0x6 +#define LSM6DSV16X_DT_GY_BATCHED_AT_240Hz 0x7 +#define LSM6DSV16X_DT_GY_BATCHED_AT_480Hz 0x8 +#define LSM6DSV16X_DT_GY_BATCHED_AT_960Hz 0x9 +#define LSM6DSV16X_DT_GY_BATCHED_AT_1920Hz 0xa +#define LSM6DSV16X_DT_GY_BATCHED_AT_3840Hz 0xb +#define LSM6DSV16X_DT_GY_BATCHED_AT_7680Hz 0xc + +/* Temperature sensor batching rates */ +#define LSM6DSV16X_DT_TEMP_NOT_BATCHED 0x0 +#define LSM6DSV16X_DT_TEMP_BATCHED_AT_1Hz875 0x1 +#define LSM6DSV16X_DT_TEMP_BATCHED_AT_15Hz 0x2 +#define LSM6DSV16X_DT_TEMP_BATCHED_AT_60Hz 0x3 + #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LSM6DSV16X_H_ */