From 5e8a47c253fecdbfbdb993cbb7f388ccb57cfe89 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Thu, 7 Nov 2024 09:47:59 +0100 Subject: [PATCH] sensors: lsm6dsv16x: add RTIO async and fifo stream Add RTIO async and RTIO stream functionalities that enables, among all the other things, the sensor data streaming from FIFO. RTIO stream is using both SENSOR_TRIG_FIFO_WATERMARK and SENSOR_TRIG_FIFO_FULL triggers. The decoder currently only supports following FIFO tags: - LSM6DSV16X_XL_NC_TAG - LSM6DSV16X_GY_NC_TAG - LSM6DSV16X_TEMP_NC_TAG Following FIFO parameters has to be defined in device tree to correctly stream sensor data: - fifo-watermark (defaults to 32) - accel-fifo-batch-rate (defaults to LSM6DSV16X_DT_XL_NOT_BATCHED) - gyro-fifo-batch-rate (defaults to LSM6DSV16X_DT_GY_NOT_BATCHED) - temp-fifo-batch-rate (defaults to LSM6DSV16X_DT_TEMP_NOT_BATCHED) Signed-off-by: Armando Visconti --- drivers/sensor/st/lsm6dsv16x/CMakeLists.txt | 2 + drivers/sensor/st/lsm6dsv16x/Kconfig | 10 + drivers/sensor/st/lsm6dsv16x/lsm6dsv16x.c | 93 +++- drivers/sensor/st/lsm6dsv16x/lsm6dsv16x.h | 36 ++ .../sensor/st/lsm6dsv16x/lsm6dsv16x_decoder.c | 446 ++++++++++++++++++ .../sensor/st/lsm6dsv16x/lsm6dsv16x_decoder.h | 54 +++ .../sensor/st/lsm6dsv16x/lsm6dsv16x_rtio.c | 157 ++++++ .../sensor/st/lsm6dsv16x/lsm6dsv16x_rtio.h | 20 + .../st/lsm6dsv16x/lsm6dsv16x_rtio_stream.c | 357 ++++++++++++++ .../sensor/st/lsm6dsv16x/lsm6dsv16x_trigger.c | 54 ++- dts/bindings/sensor/st,lsm6dsv16x-common.yaml | 74 +++ include/zephyr/drivers/sensor.h | 24 + .../zephyr/dt-bindings/sensor/lsm6dsv16x.h | 36 ++ 13 files changed, 1326 insertions(+), 37 deletions(-) create mode 100644 drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_decoder.c create mode 100644 drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_decoder.h create mode 100644 drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio.c create mode 100644 drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio.h create mode 100644 drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio_stream.c 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_ */