diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index d67a20e1cad..c3e5bc55eb3 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -68,6 +68,7 @@ add_subdirectory_ifdef(CONFIG_LSM6DS0 lsm6ds0) add_subdirectory_ifdef(CONFIG_LSM6DSL lsm6dsl) add_subdirectory_ifdef(CONFIG_LSM6DSO lsm6dso) add_subdirectory_ifdef(CONFIG_LSM6DSO16IS lsm6dso16is) +add_subdirectory_ifdef(CONFIG_LSM6DSV16X lsm6dsv16x) add_subdirectory_ifdef(CONFIG_LSM9DS0_GYRO lsm9ds0_gyro) add_subdirectory_ifdef(CONFIG_LSM9DS0_MFD lsm9ds0_mfd) add_subdirectory_ifdef(CONFIG_MAX17055 max17055) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index 9e1e42c7bfd..ce71c66dab6 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -177,6 +177,8 @@ source "drivers/sensor/lsm6dso/Kconfig" source "drivers/sensor/lsm6dso16is/Kconfig" +source "drivers/sensor/lsm6dsv16x/Kconfig" + source "drivers/sensor/lsm9ds0_gyro/Kconfig" source "drivers/sensor/lsm9ds0_mfd/Kconfig" diff --git a/drivers/sensor/lsm6dsv16x/CMakeLists.txt b/drivers/sensor/lsm6dsv16x/CMakeLists.txt new file mode 100644 index 00000000000..5006feef19d --- /dev/null +++ b/drivers/sensor/lsm6dsv16x/CMakeLists.txt @@ -0,0 +1,13 @@ +# ST Microelectronics LSM6DSV16X 6-axis IMU sensor driver +# +# Copyright (c) 2023 STMicroelectronics +# +# SPDX-License-Identifier: Apache-2.0 +# +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_include_directories(../stmemsc) diff --git a/drivers/sensor/lsm6dsv16x/Kconfig b/drivers/sensor/lsm6dsv16x/Kconfig new file mode 100644 index 00000000000..eb894ac2e99 --- /dev/null +++ b/drivers/sensor/lsm6dsv16x/Kconfig @@ -0,0 +1,94 @@ +# ST Microelectronics LSM6DSV16X 6-axis IMU sensor driver + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +menuconfig LSM6DSV16X + bool "LSM6DSV16X I2C/SPI accelerometer and gyroscope Chip" + default y + depends on DT_HAS_ST_LSM6DSV16X_ENABLED + select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSV16X),i2c) + select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSV16X),spi) + select HAS_STMEMSC + select USE_STDC_LSM6DSV16X + help + Enable driver for LSM6DSV16X accelerometer and gyroscope + sensor. + +if LSM6DSV16X + +choice LSM6DSV16X_TRIGGER_MODE + prompt "Trigger mode" + help + Specify the type of triggering to be used by the driver. + +config LSM6DSV16X_TRIGGER_NONE + bool "No trigger" + +config LSM6DSV16X_TRIGGER_GLOBAL_THREAD + bool "Use global thread" + depends on GPIO + select LSM6DSV16X_TRIGGER + +config LSM6DSV16X_TRIGGER_OWN_THREAD + bool "Use own thread" + depends on GPIO + select LSM6DSV16X_TRIGGER + +endchoice + +config LSM6DSV16X_TRIGGER + bool + +if LSM6DSV16X_TRIGGER + +config LSM6DSV16X_THREAD_PRIORITY + int "Thread priority" + depends on LSM6DSV16X_TRIGGER_OWN_THREAD + default 10 + help + Priority of thread used by the driver to handle interrupts. + +config LSM6DSV16X_THREAD_STACK_SIZE + int "Thread stack size" + depends on LSM6DSV16X_TRIGGER_OWN_THREAD + default 1024 + help + Stack size of thread used by the driver to handle interrupts. + +endif # LSM6DSV16X_TRIGGER + +config LSM6DSV16X_ENABLE_TEMP + bool "Temperature" + help + Enable/disable temperature + +config LSM6DSV16X_SENSORHUB + bool "I2C sensorhub feature" + help + Enable/disable internal sensorhub. You can enable + a maximum of two external sensors (if more than two are enabled + the system would enumerate only the first two found) + +if LSM6DSV16X_SENSORHUB + +config LSM6DSV16X_EXT_LIS2MDL + bool "LIS2MDL as external sensor" + default y + +config LSM6DSV16X_EXT_LPS22HH + bool "LPS22HH as external sensor" + +config LSM6DSV16X_EXT_HTS221 + bool "HTS221 as external sensor" + +config LSM6DSV16X_EXT_LPS22HB + bool "LPS22HB as external sensor" + +config LSM6DSV16X_EXT_LPS22DF + bool "LPS22DF as external sensor" + default y + +endif # LSM6DSV16X_SENSORHUB + +endif # LSM6DSV16X diff --git a/drivers/sensor/lsm6dsv16x/lsm6dsv16x.c b/drivers/sensor/lsm6dsv16x/lsm6dsv16x.c new file mode 100644 index 00000000000..b2bed66b47d --- /dev/null +++ b/drivers/sensor/lsm6dsv16x/lsm6dsv16x.c @@ -0,0 +1,981 @@ +/* ST Microelectronics LSM6DSV16X 6-axis IMU sensor driver + * + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lsm6dsv16x.pdf + */ + +#define DT_DRV_COMPAT st_lsm6dsv16x + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lsm6dsv16x.h" + +LOG_MODULE_REGISTER(LSM6DSV16X, CONFIG_SENSOR_LOG_LEVEL); + +/* + * values taken from lsm6dsv16x_data_rate_t in hal/st module. The mode/accuracy + * should be selected through accel-odr property in DT + */ +static const float lsm6dsv16x_odr_map[3][13] = { + /* High Accuracy off */ + {0.0f, 1.875f, 7.5f, 15.0f, 30.0f, 60.0f, + 120.0f, 240.0f, 480.0f, 960.0f, 1920.0f, + 3840.0f, 7680.0f}, + + /* High Accuracy 1 */ + {0.0f, 1.875f, 7.5f, 15.625f, 31.25f, 62.5f, + 125.0f, 250.0f, 500.0f, 1000.0f, 2000.0f, + 4000.0f, 8000.0f}, + + /* High Accuracy 2 */ + {0.0f, 1.875f, 7.5f, 12.5f, 25.0f, 50.0f, + 100.0f, 200.0f, 400.0f, 800.0f, 1600.0f, + 3200.0f, 6400.0f}, + }; + +static int lsm6dsv16x_freq_to_odr_val(const struct device *dev, uint16_t freq) +{ + const struct lsm6dsv16x_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lsm6dsv16x_data_rate_t odr; + int8_t mode; + size_t i; + + if (lsm6dsv16x_xl_data_rate_get(ctx, &odr) < 0) { + return -EINVAL; + } + + mode = (odr >> 4) & 0xf; + + for (i = 0; i < ARRAY_SIZE(lsm6dsv16x_odr_map[mode]); i++) { + if (freq <= lsm6dsv16x_odr_map[mode][i]) { + LOG_DBG("mode: %d - odr: %d", mode, i); + return i; + } + } + + return -EINVAL; +} + +static const uint16_t lsm6dsv16x_accel_fs_map[] = {2, 4, 8, 16}; + +static int lsm6dsv16x_accel_range_to_fs_val(int32_t range) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(lsm6dsv16x_accel_fs_map); i++) { + if (range == lsm6dsv16x_accel_fs_map[i]) { + return i; + } + } + + return -EINVAL; +} + +static const uint16_t lsm6dsv16x_gyro_fs_map[] = {250, 125, 500, 0, 1000, 0, 2000}; +static const uint16_t lsm6dsv16x_gyro_fs_sens[] = {2, 1, 4, 0, 8, 0, 16}; + +static int lsm6dsv16x_gyro_range_to_fs_val(int32_t range) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(lsm6dsv16x_gyro_fs_map); i++) { + if (range == lsm6dsv16x_gyro_fs_map[i]) { + return i; + } + } + + return -EINVAL; +} + +static int lsm6dsv16x_accel_set_fs_raw(const struct device *dev, uint8_t fs) +{ + const struct lsm6dsv16x_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lsm6dsv16x_data *data = dev->data; + lsm6dsv16x_xl_full_scale_t val; + + switch (fs) { + case 0: + val = LSM6DSV16X_2g; + break; + case 1: + val = LSM6DSV16X_4g; + break; + case 2: + val = LSM6DSV16X_8g; + break; + case 3: + val = LSM6DSV16X_16g; + break; + default: + return -EIO; + } + + if (lsm6dsv16x_xl_full_scale_set(ctx, val) < 0) { + return -EIO; + } + + data->accel_fs = fs; + + return 0; +} + +static int lsm6dsv16x_accel_set_odr_raw(const struct device *dev, uint8_t odr) +{ + const struct lsm6dsv16x_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lsm6dsv16x_data *data = dev->data; + + if (lsm6dsv16x_xl_data_rate_set(ctx, odr) < 0) { + return -EIO; + } + + data->accel_freq = odr; + + return 0; +} + +static int lsm6dsv16x_gyro_set_fs_raw(const struct device *dev, uint8_t fs) +{ + const struct lsm6dsv16x_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + + if (lsm6dsv16x_gy_full_scale_set(ctx, fs) < 0) { + return -EIO; + } + + return 0; +} + +static int lsm6dsv16x_gyro_set_odr_raw(const struct device *dev, uint8_t odr) +{ + const struct lsm6dsv16x_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + + if (lsm6dsv16x_gy_data_rate_set(ctx, odr) < 0) { + return -EIO; + } + + return 0; +} + +static int lsm6dsv16x_accel_odr_set(const struct device *dev, uint16_t freq) +{ + int odr; + + odr = lsm6dsv16x_freq_to_odr_val(dev, freq); + if (odr < 0) { + return odr; + } + + if (lsm6dsv16x_accel_set_odr_raw(dev, odr) < 0) { + LOG_DBG("failed to set accelerometer sampling rate"); + return -EIO; + } + + return 0; +} + +static int lsm6dsv16x_accel_range_set(const struct device *dev, int32_t range) +{ + int fs; + struct lsm6dsv16x_data *data = dev->data; + + fs = lsm6dsv16x_accel_range_to_fs_val(range); + if (fs < 0) { + return fs; + } + + if (lsm6dsv16x_accel_set_fs_raw(dev, fs) < 0) { + LOG_DBG("failed to set accelerometer full-scale"); + return -EIO; + } + + data->acc_gain = lsm6dsv16x_accel_fs_map[fs] * GAIN_UNIT_XL / 2; + return 0; +} + +static int lsm6dsv16x_accel_config(const struct device *dev, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + const struct lsm6dsv16x_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lsm6dsv16x_xl_mode_t mode; + + switch (attr) { + case SENSOR_ATTR_FULL_SCALE: + return lsm6dsv16x_accel_range_set(dev, sensor_ms2_to_g(val)); + case SENSOR_ATTR_SAMPLING_FREQUENCY: + return lsm6dsv16x_accel_odr_set(dev, val->val1); + case SENSOR_ATTR_CONFIGURATION: + switch (val->val1) { + case 0: /* High Performance */ + mode = LSM6DSV16X_XL_HIGH_PERFORMANCE_MD; + break; + case 1: /* High Accuracy */ + mode = LSM6DSV16X_XL_HIGH_ACCURACY_ODR_MD; + break; + case 3: /* ODR triggered */ + mode = LSM6DSV16X_XL_ODR_TRIGGERED_MD; + break; + case 4: /* Low Power 2 */ + mode = LSM6DSV16X_XL_LOW_POWER_2_AVG_MD; + break; + case 5: /* Low Power 4 */ + mode = LSM6DSV16X_XL_LOW_POWER_4_AVG_MD; + break; + case 6: /* Low Power 8 */ + mode = LSM6DSV16X_XL_LOW_POWER_8_AVG_MD; + break; + case 7: /* Normal */ + mode = LSM6DSV16X_XL_NORMAL_MD; + break; + default: + return -EIO; + } + + return lsm6dsv16x_xl_mode_set(ctx, mode); + default: + LOG_DBG("Accel attribute not supported."); + return -ENOTSUP; + } + + return 0; +} + +static int lsm6dsv16x_gyro_odr_set(const struct device *dev, uint16_t freq) +{ + int odr; + + if (freq < 8) { + return -EIO; + } + + odr = lsm6dsv16x_freq_to_odr_val(dev, freq); + if (odr < 0) { + return odr; + } + + if (lsm6dsv16x_gyro_set_odr_raw(dev, odr) < 0) { + LOG_DBG("failed to set gyroscope sampling rate"); + return -EIO; + } + + return 0; +} + +static int lsm6dsv16x_gyro_range_set(const struct device *dev, int32_t range) +{ + int fs; + struct lsm6dsv16x_data *data = dev->data; + + fs = lsm6dsv16x_gyro_range_to_fs_val(range); + if (fs < 0) { + return fs; + } + + if (lsm6dsv16x_gyro_set_fs_raw(dev, fs) < 0) { + LOG_DBG("failed to set gyroscope full-scale"); + return -EIO; + } + + data->gyro_gain = (lsm6dsv16x_gyro_fs_sens[fs] * GAIN_UNIT_G); + return 0; +} + +static int lsm6dsv16x_gyro_config(const struct device *dev, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + const struct lsm6dsv16x_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lsm6dsv16x_gy_mode_t mode; + + switch (attr) { + case SENSOR_ATTR_FULL_SCALE: + return lsm6dsv16x_gyro_range_set(dev, sensor_rad_to_degrees(val)); + case SENSOR_ATTR_SAMPLING_FREQUENCY: + return lsm6dsv16x_gyro_odr_set(dev, val->val1); + case SENSOR_ATTR_CONFIGURATION: + switch (val->val1) { + case 0: /* High Performance */ + mode = LSM6DSV16X_GY_HIGH_PERFORMANCE_MD; + break; + case 1: /* High Accuracy */ + mode = LSM6DSV16X_GY_HIGH_ACCURACY_ODR_MD; + break; + case 4: /* Sleep */ + mode = LSM6DSV16X_GY_SLEEP_MD; + break; + case 5: /* Low Power */ + mode = LSM6DSV16X_GY_LOW_POWER_MD; + break; + default: + return -EIO; + } + + return lsm6dsv16x_gy_mode_set(ctx, mode); + default: + LOG_DBG("Gyro attribute not supported."); + return -ENOTSUP; + } + + return 0; +} + +static int lsm6dsv16x_attr_set(const struct device *dev, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ +#if defined(CONFIG_LSM6DSV16X_SENSORHUB) + struct lsm6dsv16x_data *data = dev->data; +#endif /* CONFIG_LSM6DSV16X_SENSORHUB */ + + switch (chan) { + case SENSOR_CHAN_ACCEL_XYZ: + return lsm6dsv16x_accel_config(dev, chan, attr, val); + case SENSOR_CHAN_GYRO_XYZ: + return lsm6dsv16x_gyro_config(dev, chan, attr, val); +#if defined(CONFIG_LSM6DSV16X_SENSORHUB) + case SENSOR_CHAN_MAGN_XYZ: + case SENSOR_CHAN_PRESS: + case SENSOR_CHAN_HUMIDITY: + if (!data->shub_inited) { + LOG_ERR("shub not inited."); + return -ENOTSUP; + } + + return lsm6dsv16x_shub_config(dev, chan, attr, val); +#endif /* CONFIG_LSM6DSV16X_SENSORHUB */ + default: + LOG_WRN("attr_set() not supported on this channel."); + return -ENOTSUP; + } + + return 0; +} + +static int lsm6dsv16x_sample_fetch_accel(const struct device *dev) +{ + const struct lsm6dsv16x_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lsm6dsv16x_data *data = dev->data; + + if (lsm6dsv16x_acceleration_raw_get(ctx, data->acc) < 0) { + LOG_DBG("Failed to read sample"); + return -EIO; + } + + return 0; +} + +static int lsm6dsv16x_sample_fetch_gyro(const struct device *dev) +{ + const struct lsm6dsv16x_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lsm6dsv16x_data *data = dev->data; + + if (lsm6dsv16x_angular_rate_raw_get(ctx, data->gyro) < 0) { + LOG_DBG("Failed to read sample"); + return -EIO; + } + + return 0; +} + +#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) +static int lsm6dsv16x_sample_fetch_temp(const struct device *dev) +{ + const struct lsm6dsv16x_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lsm6dsv16x_data *data = dev->data; + + if (lsm6dsv16x_temperature_raw_get(ctx, &data->temp_sample) < 0) { + LOG_DBG("Failed to read sample"); + return -EIO; + } + + return 0; +} +#endif + +#if defined(CONFIG_LSM6DSV16X_SENSORHUB) +static int lsm6dsv16x_sample_fetch_shub(const struct device *dev) +{ + if (lsm6dsv16x_shub_fetch_external_devs(dev) < 0) { + LOG_DBG("failed to read ext shub devices"); + return -EIO; + } + + return 0; +} +#endif /* CONFIG_LSM6DSV16X_SENSORHUB */ + +static int lsm6dsv16x_sample_fetch(const struct device *dev, + enum sensor_channel chan) +{ +#if defined(CONFIG_LSM6DSV16X_SENSORHUB) + struct lsm6dsv16x_data *data = dev->data; +#endif /* CONFIG_LSM6DSV16X_SENSORHUB */ + + switch (chan) { + case SENSOR_CHAN_ACCEL_XYZ: + lsm6dsv16x_sample_fetch_accel(dev); + break; + case SENSOR_CHAN_GYRO_XYZ: + lsm6dsv16x_sample_fetch_gyro(dev); + break; +#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) + case SENSOR_CHAN_DIE_TEMP: + lsm6dsv16x_sample_fetch_temp(dev); + break; +#endif + case SENSOR_CHAN_ALL: + lsm6dsv16x_sample_fetch_accel(dev); + lsm6dsv16x_sample_fetch_gyro(dev); +#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) + lsm6dsv16x_sample_fetch_temp(dev); +#endif +#if defined(CONFIG_LSM6DSV16X_SENSORHUB) + if (data->shub_inited) { + lsm6dsv16x_sample_fetch_shub(dev); + } +#endif + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static inline void lsm6dsv16x_accel_convert(struct sensor_value *val, int raw_val, + uint32_t sensitivity) +{ + int64_t dval; + + /* Sensitivity is exposed in ug/LSB */ + /* Convert to m/s^2 */ + dval = (int64_t)(raw_val) * sensitivity * SENSOR_G_DOUBLE; + val->val1 = (int32_t)(dval / 1000000); + val->val2 = (int32_t)(dval % 1000000); + +} + +static inline int lsm6dsv16x_accel_get_channel(enum sensor_channel chan, + struct sensor_value *val, + struct lsm6dsv16x_data *data, + uint32_t sensitivity) +{ + uint8_t i; + + switch (chan) { + case SENSOR_CHAN_ACCEL_X: + lsm6dsv16x_accel_convert(val, data->acc[0], sensitivity); + break; + case SENSOR_CHAN_ACCEL_Y: + lsm6dsv16x_accel_convert(val, data->acc[1], sensitivity); + break; + case SENSOR_CHAN_ACCEL_Z: + lsm6dsv16x_accel_convert(val, data->acc[2], sensitivity); + break; + case SENSOR_CHAN_ACCEL_XYZ: + for (i = 0; i < 3; i++) { + lsm6dsv16x_accel_convert(val++, data->acc[i], sensitivity); + } + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static int lsm6dsv16x_accel_channel_get(enum sensor_channel chan, + struct sensor_value *val, + struct lsm6dsv16x_data *data) +{ + return lsm6dsv16x_accel_get_channel(chan, val, data, data->acc_gain); +} + +static inline void lsm6dsv16x_gyro_convert(struct sensor_value *val, int raw_val, + uint32_t sensitivity) +{ + int64_t dval; + + /* Sensitivity is exposed in udps/LSB */ + /* Convert to rad/s */ + dval = (int64_t)(raw_val) * sensitivity * SENSOR_DEG2RAD_DOUBLE; + val->val1 = (int32_t)(dval / 1000000); + val->val2 = (int32_t)(dval % 1000000); +} + +static inline int lsm6dsv16x_gyro_get_channel(enum sensor_channel chan, + struct sensor_value *val, + struct lsm6dsv16x_data *data, + uint32_t sensitivity) +{ + uint8_t i; + + switch (chan) { + case SENSOR_CHAN_GYRO_X: + lsm6dsv16x_gyro_convert(val, data->gyro[0], sensitivity); + break; + case SENSOR_CHAN_GYRO_Y: + lsm6dsv16x_gyro_convert(val, data->gyro[1], sensitivity); + break; + case SENSOR_CHAN_GYRO_Z: + lsm6dsv16x_gyro_convert(val, data->gyro[2], sensitivity); + break; + case SENSOR_CHAN_GYRO_XYZ: + for (i = 0; i < 3; i++) { + lsm6dsv16x_gyro_convert(val++, data->gyro[i], sensitivity); + } + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static int lsm6dsv16x_gyro_channel_get(enum sensor_channel chan, + struct sensor_value *val, + struct lsm6dsv16x_data *data) +{ + return lsm6dsv16x_gyro_get_channel(chan, val, data, data->gyro_gain); +} + +#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) +static void lsm6dsv16x_gyro_channel_get_temp(struct sensor_value *val, + struct lsm6dsv16x_data *data) +{ + int32_t micro_c; + + /* convert units to micro Celsius. Raw temperature samples are + * expressed in 256 LSB/deg_C units. And LSB output is 0 at 25 C. + */ + micro_c = (data->temp_sample * 1000000) / 256; + + val->val1 = micro_c / 1000000 + 25; + val->val2 = micro_c % 1000000; +} +#endif + +#if defined(CONFIG_LSM6DSV16X_SENSORHUB) +static inline void lsm6dsv16x_magn_convert(struct sensor_value *val, int raw_val, + uint16_t sensitivity) +{ + double dval; + + /* Sensitivity is exposed in mgauss/LSB */ + dval = (double)(raw_val * sensitivity); + val->val1 = (int32_t)dval / 1000000; + val->val2 = (int32_t)dval % 1000000; +} + +static inline int lsm6dsv16x_magn_get_channel(enum sensor_channel chan, + struct sensor_value *val, + struct lsm6dsv16x_data *data) +{ + int16_t sample[3]; + int idx; + + idx = lsm6dsv16x_shub_get_idx(data->dev, SENSOR_CHAN_MAGN_XYZ); + if (idx < 0) { + LOG_DBG("external magn not supported"); + return -ENOTSUP; + } + + + sample[0] = sys_le16_to_cpu((int16_t)(data->ext_data[idx][0] | + (data->ext_data[idx][1] << 8))); + sample[1] = sys_le16_to_cpu((int16_t)(data->ext_data[idx][2] | + (data->ext_data[idx][3] << 8))); + sample[2] = sys_le16_to_cpu((int16_t)(data->ext_data[idx][4] | + (data->ext_data[idx][5] << 8))); + + switch (chan) { + case SENSOR_CHAN_MAGN_X: + lsm6dsv16x_magn_convert(val, sample[0], data->magn_gain); + break; + case SENSOR_CHAN_MAGN_Y: + lsm6dsv16x_magn_convert(val, sample[1], data->magn_gain); + break; + case SENSOR_CHAN_MAGN_Z: + lsm6dsv16x_magn_convert(val, sample[2], data->magn_gain); + break; + case SENSOR_CHAN_MAGN_XYZ: + lsm6dsv16x_magn_convert(val, sample[0], data->magn_gain); + lsm6dsv16x_magn_convert(val + 1, sample[1], data->magn_gain); + lsm6dsv16x_magn_convert(val + 2, sample[2], data->magn_gain); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static inline void lsm6dsv16x_hum_convert(struct sensor_value *val, + struct lsm6dsv16x_data *data) +{ + float rh; + int16_t raw_val; + struct hts221_data *ht = &data->hts221; + int idx; + + idx = lsm6dsv16x_shub_get_idx(data->dev, SENSOR_CHAN_HUMIDITY); + if (idx < 0) { + LOG_DBG("external press/temp not supported"); + return; + } + + raw_val = sys_le16_to_cpu((int16_t)(data->ext_data[idx][0] | + (data->ext_data[idx][1] << 8))); + + /* find relative humidty by linear interpolation */ + rh = (ht->y1 - ht->y0) * raw_val + ht->x1 * ht->y0 - ht->x0 * ht->y1; + rh /= (ht->x1 - ht->x0); + + /* convert humidity to integer and fractional part */ + val->val1 = rh; + val->val2 = rh * 1000000; +} + +static inline void lsm6dsv16x_press_convert(struct sensor_value *val, + struct lsm6dsv16x_data *data) +{ + int32_t raw_val; + int idx; + + idx = lsm6dsv16x_shub_get_idx(data->dev, SENSOR_CHAN_PRESS); + if (idx < 0) { + LOG_DBG("external press/temp not supported"); + return; + } + + raw_val = sys_le32_to_cpu((int32_t)(data->ext_data[idx][0] | + (data->ext_data[idx][1] << 8) | + (data->ext_data[idx][2] << 16))); + + /* Pressure sensitivity is 4096 LSB/hPa */ + /* Convert raw_val to val in kPa */ + val->val1 = (raw_val >> 12) / 10; + val->val2 = (raw_val >> 12) % 10 * 100000 + + (((int32_t)((raw_val) & 0x0FFF) * 100000L) >> 12); +} + +static inline void lsm6dsv16x_temp_convert(struct sensor_value *val, + struct lsm6dsv16x_data *data) +{ + int16_t raw_val; + int idx; + + idx = lsm6dsv16x_shub_get_idx(data->dev, SENSOR_CHAN_PRESS); + if (idx < 0) { + LOG_DBG("external press/temp not supported"); + return; + } + + raw_val = sys_le16_to_cpu((int16_t)(data->ext_data[idx][3] | + (data->ext_data[idx][4] << 8))); + + /* Temperature sensitivity is 100 LSB/deg C */ + val->val1 = raw_val / 100; + val->val2 = (int32_t)raw_val % 100 * (10000); +} +#endif + +static int lsm6dsv16x_channel_get(const struct device *dev, + enum sensor_channel chan, + struct sensor_value *val) +{ + struct lsm6dsv16x_data *data = dev->data; + + switch (chan) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + lsm6dsv16x_accel_channel_get(chan, val, data); + break; + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + case SENSOR_CHAN_GYRO_XYZ: + lsm6dsv16x_gyro_channel_get(chan, val, data); + break; +#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) + case SENSOR_CHAN_DIE_TEMP: + lsm6dsv16x_gyro_channel_get_temp(val, data); + break; +#endif +#if defined(CONFIG_LSM6DSV16X_SENSORHUB) + case SENSOR_CHAN_MAGN_X: + case SENSOR_CHAN_MAGN_Y: + case SENSOR_CHAN_MAGN_Z: + case SENSOR_CHAN_MAGN_XYZ: + if (!data->shub_inited) { + LOG_ERR("attr_set() shub not inited."); + return -ENOTSUP; + } + + lsm6dsv16x_magn_get_channel(chan, val, data); + break; + + case SENSOR_CHAN_HUMIDITY: + if (!data->shub_inited) { + LOG_ERR("attr_set() shub not inited."); + return -ENOTSUP; + } + + lsm6dsv16x_hum_convert(val, data); + break; + + case SENSOR_CHAN_PRESS: + if (!data->shub_inited) { + LOG_ERR("attr_set() shub not inited."); + return -ENOTSUP; + } + + lsm6dsv16x_press_convert(val, data); + break; + + case SENSOR_CHAN_AMBIENT_TEMP: + if (!data->shub_inited) { + LOG_ERR("attr_set() shub not inited."); + return -ENOTSUP; + } + + lsm6dsv16x_temp_convert(val, data); + break; +#endif + default: + return -ENOTSUP; + } + + return 0; +} + +static const struct sensor_driver_api lsm6dsv16x_driver_api = { + .attr_set = lsm6dsv16x_attr_set, +#if CONFIG_LSM6DSV16X_TRIGGER + .trigger_set = lsm6dsv16x_trigger_set, +#endif + .sample_fetch = lsm6dsv16x_sample_fetch, + .channel_get = lsm6dsv16x_channel_get, +}; + +static int lsm6dsv16x_init_chip(const struct device *dev) +{ + const struct lsm6dsv16x_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lsm6dsv16x_data *lsm6dsv16x = dev->data; + uint8_t chip_id; + uint8_t odr, fs; + + /* All registers except 0x01 are different between banks, including the WHO_AM_I + * register and the register used for a SW reset. If the lsm6dsv16x wasn't on the user + * bank when it reset, then both the chip id check and the sw reset will fail unless we + * set the bank now. + */ + if (lsm6dsv16x_mem_bank_set(ctx, LSM6DSV16X_MAIN_MEM_BANK) < 0) { + LOG_DBG("Failed to set user bank"); + return -EIO; + } + + if (lsm6dsv16x_device_id_get(ctx, &chip_id) < 0) { + LOG_DBG("Failed reading chip id"); + return -EIO; + } + + LOG_INF("chip id 0x%x", chip_id); + + if (chip_id != LSM6DSV16X_ID) { + LOG_DBG("Invalid chip id 0x%x", chip_id); + return -EIO; + } + + /* reset device (sw_por) */ + if (lsm6dsv16x_reset_set(ctx, LSM6DSV16X_GLOBAL_RST) < 0) { + return -EIO; + } + + /* wait 30ms as reported in AN5763 */ + k_sleep(K_MSEC(30)); + + fs = cfg->accel_range; + LOG_DBG("accel range is %d", fs); + if (lsm6dsv16x_accel_set_fs_raw(dev, fs) < 0) { + LOG_ERR("failed to set accelerometer range %d", fs); + return -EIO; + } + lsm6dsv16x->acc_gain = lsm6dsv16x_accel_fs_map[fs] * GAIN_UNIT_XL / 2; + + odr = cfg->accel_odr; + LOG_DBG("accel odr is %d", odr); + if (lsm6dsv16x_accel_set_odr_raw(dev, odr) < 0) { + LOG_ERR("failed to set accelerometer odr %d", odr); + return -EIO; + } + + fs = cfg->gyro_range; + LOG_DBG("gyro range is %d", fs); + if (lsm6dsv16x_gyro_set_fs_raw(dev, fs) < 0) { + LOG_ERR("failed to set gyroscope range %d", fs); + return -EIO; + } + lsm6dsv16x->gyro_gain = (lsm6dsv16x_gyro_fs_sens[fs] * GAIN_UNIT_G); + + odr = cfg->gyro_odr; + LOG_DBG("gyro odr is %d", odr); + lsm6dsv16x->gyro_freq = odr; + if (lsm6dsv16x_gyro_set_odr_raw(dev, odr) < 0) { + LOG_ERR("failed to set gyroscope odr %d", odr); + return -EIO; + } + + if (lsm6dsv16x_block_data_update_set(ctx, 1) < 0) { + LOG_DBG("failed to set BDU mode"); + return -EIO; + } + + return 0; +} + +static int lsm6dsv16x_init(const struct device *dev) +{ +#ifdef CONFIG_LSM6DSV16X_TRIGGER + const struct lsm6dsv16x_config *cfg = dev->config; +#endif + struct lsm6dsv16x_data *data = dev->data; + + LOG_INF("Initialize device %s", dev->name); + data->dev = dev; + + if (lsm6dsv16x_init_chip(dev) < 0) { + LOG_DBG("failed to initialize chip"); + return -EIO; + } + +#ifdef CONFIG_LSM6DSV16X_TRIGGER + if (cfg->trig_enabled) { + if (lsm6dsv16x_init_interrupt(dev) < 0) { + LOG_ERR("Failed to initialize interrupt."); + return -EIO; + } + } +#endif + +#ifdef CONFIG_LSM6DSV16X_SENSORHUB + data->shub_inited = true; + if (lsm6dsv16x_shub_init(dev) < 0) { + LOG_INF("shub: no external chips found"); + data->shub_inited = false; + } +#endif + + return 0; +} + +#if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0 +#warning "LSM6DSV16X driver enabled without any devices" +#endif + +/* + * Device creation macro, shared by LSM6DSV16X_DEFINE_SPI() and + * LSM6DSV16X_DEFINE_I2C(). + */ + +#define LSM6DSV16X_DEVICE_INIT(inst) \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, \ + lsm6dsv16x_init, \ + NULL, \ + &lsm6dsv16x_data_##inst, \ + &lsm6dsv16x_config_##inst, \ + POST_KERNEL, \ + 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, \ + .gpio_drdy = GPIO_DT_SPEC_INST_GET(inst, irq_gpios), \ + .drdy_pin = DT_INST_PROP(inst, drdy_pin) +#else +#define LSM6DSV16X_CFG_IRQ(inst) +#endif /* CONFIG_LSM6DSV16X_TRIGGER */ + +#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), \ + .drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed), \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, irq_gpios), \ + (LSM6DSV16X_CFG_IRQ(inst)), ()) + +#define LSM6DSV16X_CONFIG_SPI(inst) \ + { \ + STMEMSC_CTX_SPI(&lsm6dsv16x_config_##inst.stmemsc_cfg), \ + .stmemsc_cfg = { \ + .spi = SPI_DT_SPEC_INST_GET(inst, \ + LSM6DSV16X_SPI_OP, \ + 0), \ + }, \ + LSM6DSV16X_CONFIG_COMMON(inst) \ + } + +/* + * Instantiation macros used when a device is on an I2C bus. + */ + +#define LSM6DSV16X_CONFIG_I2C(inst) \ + { \ + STMEMSC_CTX_I2C(&lsm6dsv16x_config_##inst.stmemsc_cfg), \ + .stmemsc_cfg = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + }, \ + LSM6DSV16X_CONFIG_COMMON(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) + +DT_INST_FOREACH_STATUS_OKAY(LSM6DSV16X_DEFINE) diff --git a/drivers/sensor/lsm6dsv16x/lsm6dsv16x.h b/drivers/sensor/lsm6dsv16x/lsm6dsv16x.h new file mode 100644 index 00000000000..92a5e4cdcba --- /dev/null +++ b/drivers/sensor/lsm6dsv16x/lsm6dsv16x.h @@ -0,0 +1,140 @@ +/* ST Microelectronics LSM6DSV16X 6-axis IMU sensor driver + * + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lsm6dsv16x.pdf + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_LSM6DSV16X_LSM6DSV16X_H_ +#define ZEPHYR_DRIVERS_SENSOR_LSM6DSV16X_LSM6DSV16X_H_ + +#include +#include +#include +#include +#include +#include "lsm6dsv16x_reg.h" + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) +#include +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) +#include +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */ + +#define LSM6DSV16X_EN_BIT 0x01 +#define LSM6DSV16X_DIS_BIT 0x00 + +/* Accel sensor sensitivity grain is 61 ug/LSB */ +#define GAIN_UNIT_XL (61LL) + +/* Gyro sensor sensitivity grain is 4.375 udps/LSB */ +#define GAIN_UNIT_G (4375LL) + +#define SENSOR_PI_DOUBLE (SENSOR_PI / 1000000.0) +#define SENSOR_DEG2RAD_DOUBLE (SENSOR_PI_DOUBLE / 180) +#define SENSOR_G_DOUBLE (SENSOR_G / 1000000.0) + +struct lsm6dsv16x_config { + stmdev_ctx_t ctx; + union { +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) + const struct i2c_dt_spec i2c; +#endif +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) + const struct spi_dt_spec spi; +#endif + } stmemsc_cfg; + uint8_t accel_pm; + uint8_t accel_odr; + uint8_t accel_range; + uint8_t gyro_pm; + uint8_t gyro_odr; + uint8_t gyro_range; + uint8_t drdy_pulsed; +#ifdef CONFIG_LSM6DSV16X_TRIGGER + const struct gpio_dt_spec gpio_drdy; + uint8_t drdy_pin; + bool trig_enabled; +#endif /* CONFIG_LSM6DSV16X_TRIGGER */ +}; + +union samples { + uint8_t raw[6]; + struct { + int16_t axis[3]; + }; +} __aligned(2); + +#define LSM6DSV16X_SHUB_MAX_NUM_TARGETS 3 + +struct lsm6dsv16x_data { + const struct device *dev; + int16_t acc[3]; + uint32_t acc_gain; + int16_t gyro[3]; + uint32_t gyro_gain; +#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) + int16_t temp_sample; +#endif +#if defined(CONFIG_LSM6DSV16X_SENSORHUB) + uint8_t ext_data[LSM6DSV16X_SHUB_MAX_NUM_TARGETS][6]; + uint16_t magn_gain; + + struct hts221_data { + int16_t x0; + int16_t x1; + int16_t y0; + int16_t y1; + } hts221; + bool shub_inited; + uint8_t num_ext_dev; + uint8_t shub_ext[LSM6DSV16X_SHUB_MAX_NUM_TARGETS]; +#endif /* CONFIG_LSM6DSV16X_SENSORHUB */ + + uint8_t accel_freq; + uint8_t accel_fs; + uint8_t gyro_freq; + uint8_t gyro_fs; + +#ifdef CONFIG_LSM6DSV16X_TRIGGER + struct gpio_callback gpio_cb; + sensor_trigger_handler_t handler_drdy_acc; + const struct sensor_trigger *trig_drdy_acc; + sensor_trigger_handler_t handler_drdy_gyr; + const struct sensor_trigger *trig_drdy_gyr; + sensor_trigger_handler_t handler_drdy_temp; + const struct sensor_trigger *trig_drdy_temp; + +#if defined(CONFIG_LSM6DSV16X_TRIGGER_OWN_THREAD) + K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LSM6DSV16X_THREAD_STACK_SIZE); + struct k_thread thread; + struct k_sem gpio_sem; +#elif defined(CONFIG_LSM6DSV16X_TRIGGER_GLOBAL_THREAD) + struct k_work work; +#endif +#endif /* CONFIG_LSM6DSV16X_TRIGGER */ +}; + +#if defined(CONFIG_LSM6DSV16X_SENSORHUB) +int lsm6dsv16x_shub_init(const struct device *dev); +int lsm6dsv16x_shub_fetch_external_devs(const struct device *dev); +int lsm6dsv16x_shub_get_idx(const struct device *dev, enum sensor_channel type); +int lsm6dsv16x_shub_config(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val); +#endif /* CONFIG_LSM6DSV16X_SENSORHUB */ + +#ifdef CONFIG_LSM6DSV16X_TRIGGER +int lsm6dsv16x_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); + +int lsm6dsv16x_init_interrupt(const struct device *dev); +#endif + +#endif /* ZEPHYR_DRIVERS_SENSOR_LSM6DSV16X_LSM6DSV16X_H_ */ diff --git a/drivers/sensor/lsm6dsv16x/lsm6dsv16x_shub.c b/drivers/sensor/lsm6dsv16x/lsm6dsv16x_shub.c new file mode 100644 index 00000000000..5114d270a03 --- /dev/null +++ b/drivers/sensor/lsm6dsv16x/lsm6dsv16x_shub.c @@ -0,0 +1,848 @@ +/* ST Microelectronics LSM6DSV16X 6-axis IMU sensor driver + * + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lsm6dsv16x.pdf + */ + +#define DT_DRV_COMPAT st_lsm6dsv16x + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lsm6dsv16x.h" + +LOG_MODULE_DECLARE(LSM6DSV16X, CONFIG_SENSOR_LOG_LEVEL); + +static int lsm6dsv16x_shub_write_target_reg(const struct device *dev, + uint8_t trgt_addr, uint8_t trgt_reg, + uint8_t *value, uint16_t len); +static int lsm6dsv16x_shub_read_target_reg(const struct device *dev, + uint8_t trgt_addr, uint8_t trgt_reg, + uint8_t *value, uint16_t len); +static void lsm6dsv16x_shub_enable(const struct device *dev, uint8_t enable); + + +/* ST HAL skips this register, only supports it via the slower lsm6dsv16x_sh_status_get() */ +static int32_t lsm6dsv16x_sh_status_mainpage_get(stmdev_ctx_t *ctx, + lsm6dsv16x_status_master_t *val) +{ + return lsm6dsv16x_read_reg(ctx, LSM6DSV16X_STATUS_MASTER_MAINPAGE, (uint8_t *)val, 1); +} + +/* + * LIS2MDL magn device specific part + */ +#ifdef CONFIG_LSM6DSV16X_EXT_LIS2MDL + +#define LIS2MDL_CFG_REG_A 0x60 +#define LIS2MDL_CFG_REG_B 0x61 +#define LIS2MDL_CFG_REG_C 0x62 +#define LIS2MDL_STATUS_REG 0x67 + +#define LIS2MDL_SW_RESET 0x20 +#define LIS2MDL_ODR_10HZ 0x00 +#define LIS2MDL_ODR_100HZ 0x0C +#define LIS2MDL_OFF_CANC 0x02 +#define LIS2MDL_SENSITIVITY 1500 + +static int lsm6dsv16x_lis2mdl_init(const struct device *dev, uint8_t i2c_addr) +{ + struct lsm6dsv16x_data *data = dev->data; + uint8_t mag_cfg[2]; + + data->magn_gain = LIS2MDL_SENSITIVITY; + + /* sw reset device */ + mag_cfg[0] = LIS2MDL_SW_RESET; + lsm6dsv16x_shub_write_target_reg(dev, i2c_addr, + LIS2MDL_CFG_REG_A, mag_cfg, 1); + + k_sleep(K_MSEC(10)); /* turn-on time in ms */ + + /* configure mag */ + mag_cfg[0] = LIS2MDL_ODR_10HZ; + mag_cfg[1] = LIS2MDL_OFF_CANC; + lsm6dsv16x_shub_write_target_reg(dev, i2c_addr, + LIS2MDL_CFG_REG_A, mag_cfg, 2); + + return 0; +} + +static const uint16_t lis2mdl_map[] = {10, 20, 50, 100}; + +static int lsm6dsv16x_lis2mdl_odr_set(const struct device *dev, + uint8_t i2c_addr, uint16_t freq) +{ + uint8_t odr, cfg; + + for (odr = 0; odr < ARRAY_SIZE(lis2mdl_map); odr++) { + if (freq <= lis2mdl_map[odr]) { + break; + } + } + + if (odr == ARRAY_SIZE(lis2mdl_map)) { + LOG_DBG("shub: LIS2MDL freq val %d not supported.", freq); + return -ENOTSUP; + } + + cfg = (odr << 2); + lsm6dsv16x_shub_write_target_reg(dev, i2c_addr, + LIS2MDL_CFG_REG_A, &cfg, 1); + + lsm6dsv16x_shub_enable(dev, 1); + return 0; +} + +static int lsm6dsv16x_lis2mdl_conf(const struct device *dev, uint8_t i2c_addr, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + switch (attr) { + case SENSOR_ATTR_SAMPLING_FREQUENCY: + return lsm6dsv16x_lis2mdl_odr_set(dev, i2c_addr, val->val1); + default: + LOG_DBG("shub: LIS2MDL attribute not supported."); + return -ENOTSUP; + } + + return 0; +} +#endif /* CONFIG_LSM6DSV16X_EXT_LIS2MDL */ + +/* + * HTS221 humidity device specific part + */ +#ifdef CONFIG_LSM6DSV16X_EXT_HTS221 + +#define HTS221_AUTOINCREMENT BIT(7) + +#define HTS221_REG_CTRL1 0x20 +#define HTS221_ODR_1HZ 0x01 +#define HTS221_BDU 0x04 +#define HTS221_PD 0x80 + +#define HTS221_REG_CONV_START 0x30 + +static int lsm6dsv16x_hts221_read_conv_data(const struct device *dev, + uint8_t i2c_addr) +{ + struct lsm6dsv16x_data *data = dev->data; + uint8_t buf[16], i; + struct hts221_data *ht = &data->hts221; + + for (i = 0; i < sizeof(buf); i += 7) { + unsigned char len = MIN(7, sizeof(buf) - i); + + if (lsm6dsv16x_shub_read_target_reg(dev, i2c_addr, + (HTS221_REG_CONV_START + i) | + HTS221_AUTOINCREMENT, + &buf[i], len) < 0) { + LOG_DBG("shub: failed to read hts221 conv data"); + return -EIO; + } + } + + ht->y0 = buf[0] / 2; + ht->y1 = buf[1] / 2; + ht->x0 = sys_le16_to_cpu(buf[6] | (buf[7] << 8)); + ht->x1 = sys_le16_to_cpu(buf[10] | (buf[11] << 8)); + + return 0; +} + +static int lsm6dsv16x_hts221_init(const struct device *dev, uint8_t i2c_addr) +{ + uint8_t hum_cfg; + + /* configure ODR and BDU */ + hum_cfg = HTS221_ODR_1HZ | HTS221_BDU | HTS221_PD; + lsm6dsv16x_shub_write_target_reg(dev, i2c_addr, + HTS221_REG_CTRL1, &hum_cfg, 1); + + return lsm6dsv16x_hts221_read_conv_data(dev, i2c_addr); +} + +static const uint16_t hts221_map[] = {0, 1, 7, 12}; + +static int lsm6dsv16x_hts221_odr_set(const struct device *dev, + uint8_t i2c_addr, uint16_t freq) +{ + uint8_t odr, cfg; + + for (odr = 0; odr < ARRAY_SIZE(hts221_map); odr++) { + if (freq <= hts221_map[odr]) { + break; + } + } + + if (odr == ARRAY_SIZE(hts221_map)) { + LOG_DBG("shub: HTS221 freq val %d not supported.", freq); + return -ENOTSUP; + } + + cfg = odr | HTS221_BDU | HTS221_PD; + lsm6dsv16x_shub_write_target_reg(dev, i2c_addr, + HTS221_REG_CTRL1, &cfg, 1); + + lsm6dsv16x_shub_enable(dev, 1); + return 0; +} + +static int lsm6dsv16x_hts221_conf(const struct device *dev, uint8_t i2c_addr, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + switch (attr) { + case SENSOR_ATTR_SAMPLING_FREQUENCY: + return lsm6dsv16x_hts221_odr_set(dev, i2c_addr, val->val1); + default: + LOG_DBG("shub: HTS221 attribute not supported."); + return -ENOTSUP; + } + + return 0; +} +#endif /* CONFIG_LSM6DSV16X_EXT_HTS221 */ + +/* + * LPS22HB baro/temp device specific part + */ +#ifdef CONFIG_LSM6DSV16X_EXT_LPS22HB + +#define LPS22HB_CTRL_REG1 0x10 +#define LPS22HB_CTRL_REG2 0x11 + +#define LPS22HB_SW_RESET 0x04 +#define LPS22HB_ODR_10HZ 0x20 +#define LPS22HB_LPF_EN 0x08 +#define LPS22HB_BDU_EN 0x02 + +static int lsm6dsv16x_lps22hb_init(const struct device *dev, uint8_t i2c_addr) +{ + uint8_t baro_cfg[2]; + + /* sw reset device */ + baro_cfg[0] = LPS22HB_SW_RESET; + lsm6dsv16x_shub_write_target_reg(dev, i2c_addr, + LPS22HB_CTRL_REG2, baro_cfg, 1); + + k_sleep(K_MSEC(1)); /* turn-on time in ms */ + + /* configure device */ + baro_cfg[0] = LPS22HB_ODR_10HZ | LPS22HB_LPF_EN | LPS22HB_BDU_EN; + lsm6dsv16x_shub_write_target_reg(dev, i2c_addr, + LPS22HB_CTRL_REG1, baro_cfg, 1); + + return 0; +} +#endif /* CONFIG_LSM6DSV16X_EXT_LPS22HB */ + +/* + * LPS22HH baro/temp device specific part + */ +#ifdef CONFIG_LSM6DSV16X_EXT_LPS22HH + +#define LPS22HH_CTRL_REG1 0x10 +#define LPS22HH_CTRL_REG2 0x11 + +#define LPS22HH_SW_RESET 0x04 +#define LPS22HH_IF_ADD_INC 0x10 +#define LPS22HH_ODR_10HZ 0x20 +#define LPS22HH_LPF_EN 0x08 +#define LPS22HH_BDU_EN 0x02 + +static int lsm6dsv16x_lps22hh_init(const struct device *dev, uint8_t i2c_addr) +{ + uint8_t baro_cfg[2]; + + /* sw reset device */ + baro_cfg[0] = LPS22HH_SW_RESET; + lsm6dsv16x_shub_write_target_reg(dev, i2c_addr, + LPS22HH_CTRL_REG2, baro_cfg, 1); + + k_sleep(K_MSEC(100)); /* turn-on time in ms */ + + /* configure device */ + baro_cfg[0] = LPS22HH_IF_ADD_INC; + lsm6dsv16x_shub_write_target_reg(dev, i2c_addr, + LPS22HH_CTRL_REG2, baro_cfg, 1); + + baro_cfg[0] = LPS22HH_ODR_10HZ | LPS22HH_LPF_EN | LPS22HH_BDU_EN; + lsm6dsv16x_shub_write_target_reg(dev, i2c_addr, + LPS22HH_CTRL_REG1, baro_cfg, 1); + + return 0; +} + +static const uint16_t lps22hh_map[] = {0, 1, 10, 25, 50, 75, 100, 200}; + +static int lsm6dsv16x_lps22hh_odr_set(const struct device *dev, + uint8_t i2c_addr, uint16_t freq) +{ + uint8_t odr, cfg; + + for (odr = 0; odr < ARRAY_SIZE(lps22hh_map); odr++) { + if (freq <= lps22hh_map[odr]) { + break; + } + } + + if (odr == ARRAY_SIZE(lps22hh_map)) { + LOG_DBG("shub: LPS22HH freq val %d not supported.", freq); + return -ENOTSUP; + } + + cfg = (odr << 4) | LPS22HH_LPF_EN | LPS22HH_BDU_EN; + lsm6dsv16x_shub_write_target_reg(dev, i2c_addr, + LPS22HH_CTRL_REG1, &cfg, 1); + + lsm6dsv16x_shub_enable(dev, 1); + return 0; +} + +static int lsm6dsv16x_lps22hh_conf(const struct device *dev, uint8_t i2c_addr, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + switch (attr) { + case SENSOR_ATTR_SAMPLING_FREQUENCY: + return lsm6dsv16x_lps22hh_odr_set(dev, i2c_addr, val->val1); + default: + LOG_DBG("shub: LPS22HH attribute not supported."); + return -ENOTSUP; + } + + return 0; +} +#endif /* CONFIG_LSM6DSV16X_EXT_LPS22HH */ + +/* + * LPS22DF baro/temp device specific part + */ +#ifdef CONFIG_LSM6DSV16X_EXT_LPS22DF + +#define LPS22DF_CTRL_REG1 0x10 +#define LPS22DF_CTRL_REG2 0x11 + +#define LPS22DF_SW_RESET 0x04 +#define LPS22DF_BDU_EN 0x08 +#define LPS22DF_EN_LPFP 0x10 +#define LPS22DF_ODR_10HZ 0x18 +#define LPS22DF_AVG_16 0x02 + +static int lsm6dsv16x_lps22df_init(const struct device *dev, uint8_t i2c_addr) +{ + uint8_t baro_cfg[2]; + + /* sw reset device */ + baro_cfg[0] = LPS22DF_SW_RESET; + lsm6dsv16x_shub_write_target_reg(dev, i2c_addr, + LPS22DF_CTRL_REG2, baro_cfg, 1); + + k_busy_wait(50); /* turn-on time in us */ + + /* configure device */ + baro_cfg[0] = LPS22DF_BDU_EN | LPS22DF_EN_LPFP; + lsm6dsv16x_shub_write_target_reg(dev, i2c_addr, + LPS22DF_CTRL_REG2, baro_cfg, 1); + + baro_cfg[0] = LPS22DF_ODR_10HZ | LPS22DF_AVG_16; + lsm6dsv16x_shub_write_target_reg(dev, i2c_addr, + LPS22DF_CTRL_REG1, baro_cfg, 1); + + return 0; +} + +static const uint16_t lps22df_map[] = {0, 1, 4, 10, 25, 50, 75, 100, 200}; + +static int lsm6dsv16x_lps22df_odr_set(const struct device *dev, + uint8_t i2c_addr, uint16_t freq) +{ + uint8_t odr, cfg; + + for (odr = 0; odr < ARRAY_SIZE(lps22df_map); odr++) { + if (freq <= lps22df_map[odr]) { + break; + } + } + + if (odr == ARRAY_SIZE(lps22df_map)) { + LOG_DBG("shub: LPS22DF freq val %d not supported.", freq); + return -ENOTSUP; + } + + cfg = (odr << 3) | LPS22DF_AVG_16; + lsm6dsv16x_shub_write_target_reg(dev, i2c_addr, + LPS22DF_CTRL_REG1, &cfg, 1); + + lsm6dsv16x_shub_enable(dev, 1); + return 0; +} + +static int lsm6dsv16x_lps22df_conf(const struct device *dev, uint8_t i2c_addr, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + switch (attr) { + case SENSOR_ATTR_SAMPLING_FREQUENCY: + return lsm6dsv16x_lps22df_odr_set(dev, i2c_addr, val->val1); + default: + LOG_DBG("shub: LPS22DF attribute not supported."); + return -ENOTSUP; + } + + return 0; +} +#endif /* CONFIG_LSM6DSV16X_EXT_LPS22DF */ + +/* List of supported external sensors */ +static struct lsm6dsv16x_shub_slist { + enum sensor_channel type; + uint8_t i2c_addr[2]; + uint8_t ext_i2c_addr; + uint8_t wai_addr; + uint8_t wai_val; + uint8_t out_data_addr; + uint8_t out_data_len; + uint8_t sh_out_reg; + int (*dev_init)(const struct device *dev, uint8_t i2c_addr); + int (*dev_conf)(const struct device *dev, uint8_t i2c_addr, + enum sensor_channel chan, enum sensor_attribute attr, + const struct sensor_value *val); +} lsm6dsv16x_shub_slist[] = { +#ifdef CONFIG_LSM6DSV16X_EXT_LIS2MDL + { + /* LIS2MDL */ + .type = SENSOR_CHAN_MAGN_XYZ, + .i2c_addr = { 0x1E }, + .wai_addr = 0x4F, + .wai_val = 0x40, + .out_data_addr = 0x68, + .out_data_len = 0x06, + .dev_init = (lsm6dsv16x_lis2mdl_init), + .dev_conf = (lsm6dsv16x_lis2mdl_conf), + }, +#endif /* CONFIG_LSM6DSV16X_EXT_LIS2MDL */ + +#ifdef CONFIG_LSM6DSV16X_EXT_HTS221 + { + /* HTS221 */ + .type = SENSOR_CHAN_HUMIDITY, + .i2c_addr = { 0x5F }, + .wai_addr = 0x0F, + .wai_val = 0xBC, + .out_data_addr = 0x28 | HTS221_AUTOINCREMENT, + .out_data_len = 0x02, + .dev_init = (lsm6dsv16x_hts221_init), + .dev_conf = (lsm6dsv16x_hts221_conf), + }, +#endif /* CONFIG_LSM6DSV16X_EXT_HTS221 */ + +#ifdef CONFIG_LSM6DSV16X_EXT_LPS22HB + { + /* LPS22HB */ + .type = SENSOR_CHAN_PRESS, + .i2c_addr = { 0x5C, 0x5D }, + .wai_addr = 0x0F, + .wai_val = 0xB1, + .out_data_addr = 0x28, + .out_data_len = 0x05, + .dev_init = (lsm6dsv16x_lps22hb_init), + }, +#endif /* CONFIG_LSM6DSV16X_EXT_LPS22HB */ + +#ifdef CONFIG_LSM6DSV16X_EXT_LPS22HH + { + /* LPS22HH */ + .type = SENSOR_CHAN_PRESS, + .i2c_addr = { 0x5C, 0x5D }, + .wai_addr = 0x0F, + .wai_val = 0xB3, + .out_data_addr = 0x28, + .out_data_len = 0x05, + .dev_init = (lsm6dsv16x_lps22hh_init), + .dev_conf = (lsm6dsv16x_lps22hh_conf), + }, +#endif /* CONFIG_LSM6DSV16X_EXT_LPS22HH */ + +#ifdef CONFIG_LSM6DSV16X_EXT_LPS22DF + { + /* LPS22DF */ + .type = SENSOR_CHAN_PRESS, + .i2c_addr = { 0x5C, 0x5D }, + .wai_addr = 0x0F, + .wai_val = 0xB4, + .out_data_addr = 0x28, + .out_data_len = 0x05, + .dev_init = (lsm6dsv16x_lps22df_init), + .dev_conf = (lsm6dsv16x_lps22df_conf), + }, +#endif /* CONFIG_LSM6DSV16X_EXT_LPS22DF */ +}; + +static int lsm6dsv16x_shub_wait_completed(stmdev_ctx_t *ctx) +{ + lsm6dsv16x_status_master_t status; + int tries = 200; /* Should be max ~160 ms, from 2 cycles at slowest ODR 12.5 Hz */ + + do { + if (!--tries) { + LOG_DBG("shub: Timeout waiting for operation to complete"); + return -ETIMEDOUT; + } + k_msleep(1); + lsm6dsv16x_sh_status_mainpage_get(ctx, &status); + } while (status.sens_hub_endop == 0); + + return 1; +} + +static void lsm6dsv16x_shub_enable(const struct device *dev, uint8_t enable) +{ + const struct lsm6dsv16x_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lsm6dsv16x_data *data = dev->data; + + /* Enable Accel @26hz */ + if (!data->accel_freq) { + uint8_t odr = (enable) ? 2 : 0; + + if (lsm6dsv16x_xl_data_rate_set(ctx, odr) < 0) { + LOG_DBG("shub: failed to set XL sampling rate"); + return; + } + } + + if (enable) { + lsm6dsv16x_status_master_t status; + + /* Clear any pending status flags */ + lsm6dsv16x_sh_status_mainpage_get(ctx, &status); + } + + if (lsm6dsv16x_sh_master_set(ctx, enable) < 0) { + LOG_DBG("shub: failed to set master on"); + lsm6dsv16x_mem_bank_set(ctx, LSM6DSV16X_MAIN_MEM_BANK); + return; + } + + if (!enable) { + /* wait 300us (necessary per AN5763 ยง7.2.1) */ + k_busy_wait(300); + } +} + +/* must be called with master on */ +static int lsm6dsv16x_shub_check_slv0_nack(stmdev_ctx_t *ctx) +{ + lsm6dsv16x_all_sources_t status; + + if (lsm6dsv16x_all_sources_get(ctx, &status) < 0) { + LOG_DBG("shub: error reading embedded reg"); + return -EIO; + } + + if (status.sh_slave0_nack) { + LOG_DBG("shub: TRGT 0 nacked"); + return -EIO; + } + + return 0; +} + +/* + * use TRGT 0 for generic read to target device + */ +static int lsm6dsv16x_shub_read_target_reg(const struct device *dev, + uint8_t trgt_addr, uint8_t trgt_reg, + uint8_t *value, uint16_t len) +{ + const struct lsm6dsv16x_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lsm6dsv16x_sh_cfg_read_t trgt_cfg; + + trgt_cfg.slv_add = trgt_addr; + trgt_cfg.slv_subadd = trgt_reg; + trgt_cfg.slv_len = len; + + lsm6dsv16x_sh_slv0_cfg_read(ctx, &trgt_cfg); + + /* turn SH on, wait for shub i2c read to finish */ + lsm6dsv16x_shub_enable(dev, 1); + lsm6dsv16x_shub_wait_completed(ctx); + + /* read data from external target */ + if (lsm6dsv16x_sh_read_data_raw_get(ctx, (lsm6dsv16x_emb_sh_read_t *)value, len) < 0) { + LOG_DBG("shub: error reading sensor data"); + return -EIO; + } + + if (lsm6dsv16x_shub_check_slv0_nack(ctx) < 0) { + lsm6dsv16x_shub_enable(dev, 0); + return -EIO; + } + + lsm6dsv16x_shub_enable(dev, 0); + return 0; +} + +/* + * use TRGT 0 to configure target device + */ +static int lsm6dsv16x_shub_write_target_reg(const struct device *dev, + uint8_t trgt_addr, uint8_t trgt_reg, + uint8_t *value, uint16_t len) +{ + const struct lsm6dsv16x_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lsm6dsv16x_sh_cfg_write_t trgt_cfg; + uint8_t cnt = 0U; + + lsm6dsv16x_shub_enable(dev, 0); + + while (cnt < len) { + trgt_cfg.slv0_add = trgt_addr; + trgt_cfg.slv0_subadd = trgt_reg + cnt; + trgt_cfg.slv0_data = value[cnt]; + + lsm6dsv16x_sh_cfg_write(ctx, &trgt_cfg); + + /* turn SH on, wait for shub i2c write to finish */ + lsm6dsv16x_shub_enable(dev, 1); + lsm6dsv16x_shub_wait_completed(ctx); + + if (lsm6dsv16x_shub_check_slv0_nack(ctx) < 0) { + lsm6dsv16x_shub_enable(dev, 0); + return -EIO; + } + + lsm6dsv16x_shub_enable(dev, 0); + + cnt++; + } + + /* Put TRGT 0 in IDLE mode */ + trgt_cfg.slv0_add = 0x7; + trgt_cfg.slv0_subadd = 0x0; + trgt_cfg.slv0_data = 0x0; + lsm6dsv16x_sh_cfg_write(ctx, &trgt_cfg); + + return 0; +} + +/* + * TARGETs configurations: + * + * - TARGET 0: used for configuring all target devices + * - TARGET 1: used as data read channel for external target device #1 + * - TARGET 2: used as data read channel for external target device #2 + * - TARGET 3: used for generic reads while data channel is enabled + */ +static int lsm6dsv16x_shub_set_data_channel(const struct device *dev) +{ + struct lsm6dsv16x_data *data = dev->data; + const struct lsm6dsv16x_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + uint8_t n; + struct lsm6dsv16x_shub_slist *sp; + lsm6dsv16x_sh_cfg_read_t trgt_cfg; + + int32_t (*sh_chan_cfg[LSM6DSV16X_SHUB_MAX_NUM_TARGETS]) + (stmdev_ctx_t *ctx, lsm6dsv16x_sh_cfg_read_t *val) = { + lsm6dsv16x_sh_slv1_cfg_read, + lsm6dsv16x_sh_slv2_cfg_read, + lsm6dsv16x_sh_slv3_cfg_read, + }; + + /* Configure shub data channels to access external targets */ + for (n = 0; n < data->num_ext_dev; n++) { + sp = &lsm6dsv16x_shub_slist[data->shub_ext[n]]; + + trgt_cfg.slv_add = sp->ext_i2c_addr; + trgt_cfg.slv_subadd = sp->out_data_addr; + trgt_cfg.slv_len = sp->out_data_len; + + if (sh_chan_cfg[n](ctx, &trgt_cfg) < 0) { + LOG_DBG("shub: error configuring shub for ext targets"); + return -EIO; + } + } + + /* Configure the master */ + lsm6dsv16x_sh_slave_connected_t aux = LSM6DSV16X_SLV_0_1_2; + + if (lsm6dsv16x_sh_slave_connected_set(ctx, aux) < 0) { + LOG_DBG("shub: error setting aux sensors"); + return -EIO; + } + + + /* turn SH on, no need to wait for 1st shub i2c read, if any, to complete */ + lsm6dsv16x_shub_enable(dev, 1); + + return 0; +} + +int lsm6dsv16x_shub_get_idx(const struct device *dev, enum sensor_channel type) +{ + uint8_t n; + struct lsm6dsv16x_data *data = dev->data; + struct lsm6dsv16x_shub_slist *sp; + + for (n = 0; n < data->num_ext_dev; n++) { + sp = &lsm6dsv16x_shub_slist[data->shub_ext[n]]; + + if (sp->type == type) { + return n; + } + } + + LOG_ERR("shub: dev %s type %d not supported", dev->name, type); + return -ENOTSUP; +} + +int lsm6dsv16x_shub_fetch_external_devs(const struct device *dev) +{ + uint8_t n; + const struct lsm6dsv16x_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lsm6dsv16x_data *data = dev->data; + struct lsm6dsv16x_shub_slist *sp; + + /* read data from external target */ + lsm6dsv16x_mem_bank_set(ctx, LSM6DSV16X_SENSOR_HUB_MEM_BANK); + + for (n = 0; n < data->num_ext_dev; n++) { + sp = &lsm6dsv16x_shub_slist[data->shub_ext[n]]; + + if (lsm6dsv16x_read_reg(ctx, sp->sh_out_reg, + data->ext_data[n], sp->out_data_len) < 0) { + LOG_DBG("shub: failed to read sample"); + lsm6dsv16x_mem_bank_set(ctx, LSM6DSV16X_MAIN_MEM_BANK); + return -EIO; + } + } + + lsm6dsv16x_mem_bank_set(ctx, LSM6DSV16X_MAIN_MEM_BANK); + + return 0; +} + +int lsm6dsv16x_shub_config(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + struct lsm6dsv16x_data *data = dev->data; + struct lsm6dsv16x_shub_slist *sp = NULL; + uint8_t n; + + for (n = 0; n < data->num_ext_dev; n++) { + sp = &lsm6dsv16x_shub_slist[data->shub_ext[n]]; + + if (sp->type == chan) { + break; + } + } + + if (n == data->num_ext_dev) { + LOG_DBG("shub: %s chan %d not supported", dev->name, chan); + return -ENOTSUP; + } + + if (sp == NULL || sp->dev_conf == NULL) { + LOG_DBG("shub: chan not configurable"); + return -ENOTSUP; + } + + return sp->dev_conf(dev, sp->ext_i2c_addr, chan, attr, val); +} + +int lsm6dsv16x_shub_init(const struct device *dev) +{ + struct lsm6dsv16x_data *data = dev->data; + const struct lsm6dsv16x_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + uint8_t i, n = 0, regn; + uint8_t chip_id; + struct lsm6dsv16x_shub_slist *sp; + + LOG_INF("shub: start sensorhub for %s", dev->name); + + /* + * This must be set or lsm6dsv16x_shub_write_target_reg() will + * repeatedly write the same regi + */ + if (lsm6dsv16x_sh_write_mode_set(ctx, LSM6DSV16X_ONLY_FIRST_CYCLE) < 0) { + LOG_DBG("shub: error setting write once"); + return -EIO; + } + + for (n = 0; n < ARRAY_SIZE(lsm6dsv16x_shub_slist); n++) { + if (data->num_ext_dev >= LSM6DSV16X_SHUB_MAX_NUM_TARGETS) { + break; + } + + chip_id = 0; + sp = &lsm6dsv16x_shub_slist[n]; + + /* + * The external sensor may have different I2C address. + * So, try them one by one until we read the correct + * chip ID. + */ + for (i = 0U; i < ARRAY_SIZE(sp->i2c_addr); i++) { + if (lsm6dsv16x_shub_read_target_reg(dev, + sp->i2c_addr[i], + sp->wai_addr, + &chip_id, 1) < 0) { + LOG_DBG("shub: failed reading chip id"); + continue; + } + if (chip_id == sp->wai_val) { + break; + } + } + + if (i >= ARRAY_SIZE(sp->i2c_addr)) { + LOG_DBG("shub: invalid chip id 0x%x", chip_id); + continue; + } + LOG_INF("shub: Ext Device Chip Id: %02x", chip_id); + sp->ext_i2c_addr = sp->i2c_addr[i]; + + data->shub_ext[data->num_ext_dev++] = n; + } + + LOG_DBG("shub: dev %s - num_ext_dev %d", dev->name, data->num_ext_dev); + if (data->num_ext_dev == 0) { + LOG_ERR("shub: no target devices found"); + return -EINVAL; + } + + /* init external devices */ + for (n = 0, regn = 0; n < data->num_ext_dev; n++) { + sp = &lsm6dsv16x_shub_slist[data->shub_ext[n]]; + sp->sh_out_reg = LSM6DSV16X_SENSOR_HUB_1 + regn; + regn += sp->out_data_len; + sp->dev_init(dev, sp->ext_i2c_addr); + } + + lsm6dsv16x_shub_set_data_channel(dev); + + return 0; +} diff --git a/drivers/sensor/lsm6dsv16x/lsm6dsv16x_trigger.c b/drivers/sensor/lsm6dsv16x/lsm6dsv16x_trigger.c new file mode 100644 index 00000000000..14e6c9f157c --- /dev/null +++ b/drivers/sensor/lsm6dsv16x/lsm6dsv16x_trigger.c @@ -0,0 +1,333 @@ +/* ST Microelectronics LSM6DSV16X 6-axis IMU sensor driver + * + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lsm6dsv16x.pdf + */ + +#define DT_DRV_COMPAT st_lsm6dsv16x + +#include +#include +#include +#include + +#include "lsm6dsv16x.h" + +LOG_MODULE_DECLARE(LSM6DSV16X, CONFIG_SENSOR_LOG_LEVEL); + +#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) +/** + * lsm6dsv16x_enable_t_int - TEMP enable selected int pin to generate interrupt + */ +static int lsm6dsv16x_enable_t_int(const struct device *dev, int enable) +{ + const struct lsm6dsv16x_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lsm6dsv16x_pin_int_route_t val; + int ret; + + if (enable) { + int16_t buf; + + /* dummy read: re-trigger interrupt */ + lsm6dsv16x_temperature_raw_get(ctx, &buf); + } + + /* set interrupt (TEMP DRDY interrupt is only on INT2) */ + if (cfg->drdy_pin == 1) { + return -EIO; + } + + ret = lsm6dsv16x_pin_int2_route_get(ctx, &val); + if (ret < 0) { + LOG_ERR("pint_int2_route_get error"); + return ret; + } + + val.drdy_temp = 1; + + return lsm6dsv16x_pin_int2_route_set(ctx, &val); +} +#endif + +/** + * lsm6dsv16x_enable_xl_int - XL enable selected int pin to generate interrupt + */ +static int lsm6dsv16x_enable_xl_int(const struct device *dev, int enable) +{ + const struct lsm6dsv16x_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + int ret; + + if (enable) { + int16_t buf[3]; + + /* dummy read: re-trigger interrupt */ + lsm6dsv16x_acceleration_raw_get(ctx, buf); + } + + /* set interrupt */ + if (cfg->drdy_pin == 1) { + lsm6dsv16x_pin_int_route_t val; + + ret = lsm6dsv16x_pin_int1_route_get(ctx, &val); + if (ret < 0) { + LOG_ERR("pint_int1_route_get error"); + return ret; + } + + val.drdy_xl = 1; + + ret = lsm6dsv16x_pin_int1_route_set(ctx, &val); + } else { + lsm6dsv16x_pin_int_route_t val; + + ret = lsm6dsv16x_pin_int2_route_get(ctx, &val); + if (ret < 0) { + LOG_ERR("pint_int2_route_get error"); + return ret; + } + + val.drdy_xl = 1; + + ret = lsm6dsv16x_pin_int2_route_set(ctx, &val); + } + + return ret; +} + +/** + * lsm6dsv16x_enable_g_int - Gyro enable selected int pin to generate interrupt + */ +static int lsm6dsv16x_enable_g_int(const struct device *dev, int enable) +{ + const struct lsm6dsv16x_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + int ret; + + if (enable) { + int16_t buf[3]; + + /* dummy read: re-trigger interrupt */ + lsm6dsv16x_angular_rate_raw_get(ctx, buf); + } + + /* set interrupt */ + if (cfg->drdy_pin == 1) { + lsm6dsv16x_pin_int_route_t val; + + ret = lsm6dsv16x_pin_int1_route_get(ctx, &val); + if (ret < 0) { + LOG_ERR("pint_int1_route_get error"); + return ret; + } + + val.drdy_g = 1; + + ret = lsm6dsv16x_pin_int1_route_set(ctx, &val); + } else { + lsm6dsv16x_pin_int_route_t val; + + ret = lsm6dsv16x_pin_int2_route_get(ctx, &val); + if (ret < 0) { + LOG_ERR("pint_int2_route_get error"); + return ret; + } + + val.drdy_g = 1; + + ret = lsm6dsv16x_pin_int2_route_set(ctx, &val); + } + + return ret; +} + +/** + * lsm6dsv16x_trigger_set - link external trigger to event data ready + */ +int lsm6dsv16x_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + const struct lsm6dsv16x_config *cfg = dev->config; + struct lsm6dsv16x_data *lsm6dsv16x = dev->data; + + 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 defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) + else if (trig->chan == SENSOR_CHAN_DIE_TEMP) { + lsm6dsv16x->handler_drdy_temp = handler; + lsm6dsv16x->trig_drdy_temp = trig; + if (handler) { + return lsm6dsv16x_enable_t_int(dev, LSM6DSV16X_EN_BIT); + } else { + return lsm6dsv16x_enable_t_int(dev, LSM6DSV16X_DIS_BIT); + } + } +#endif + + return -ENOTSUP; +} + +/** + * lsm6dsv16x_handle_interrupt - handle the drdy event + * read data and call handler if registered any + */ +static void lsm6dsv16x_handle_interrupt(const struct device *dev) +{ + struct lsm6dsv16x_data *lsm6dsv16x = dev->data; + const struct lsm6dsv16x_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lsm6dsv16x_data_ready_t status; + + while (1) { + if (lsm6dsv16x_flag_data_ready_get(ctx, &status) < 0) { + LOG_DBG("failed reading status reg"); + return; + } + + if ((status.drdy_xl == 0) && (status.drdy_gy == 0) +#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) + && (status.drdy_temp == 0) +#endif + ) { + break; + } + + if ((status.drdy_xl) && (lsm6dsv16x->handler_drdy_acc != NULL)) { + lsm6dsv16x->handler_drdy_acc(dev, lsm6dsv16x->trig_drdy_acc); + } + + if ((status.drdy_gy) && (lsm6dsv16x->handler_drdy_gyr != NULL)) { + lsm6dsv16x->handler_drdy_gyr(dev, lsm6dsv16x->trig_drdy_gyr); + } + +#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) + if ((status.drdy_temp) && (lsm6dsv16x->handler_drdy_temp != NULL)) { + lsm6dsv16x->handler_drdy_temp(dev, lsm6dsv16x->trig_drdy_temp); + } +#endif + } + + gpio_pin_interrupt_configure_dt(&cfg->gpio_drdy, + GPIO_INT_EDGE_TO_ACTIVE); +} + +static void lsm6dsv16x_gpio_callback(const struct device *dev, + struct gpio_callback *cb, uint32_t pins) +{ + struct lsm6dsv16x_data *lsm6dsv16x = + CONTAINER_OF(cb, struct lsm6dsv16x_data, gpio_cb); + const struct lsm6dsv16x_config *cfg = lsm6dsv16x->dev->config; + + ARG_UNUSED(pins); + + gpio_pin_interrupt_configure_dt(&cfg->gpio_drdy, GPIO_INT_DISABLE); + +#if defined(CONFIG_LSM6DSV16X_TRIGGER_OWN_THREAD) + k_sem_give(&lsm6dsv16x->gpio_sem); +#elif defined(CONFIG_LSM6DSV16X_TRIGGER_GLOBAL_THREAD) + k_work_submit(&lsm6dsv16x->work); +#endif /* CONFIG_LSM6DSV16X_TRIGGER_OWN_THREAD */ +} + +#ifdef CONFIG_LSM6DSV16X_TRIGGER_OWN_THREAD +static void lsm6dsv16x_thread(struct lsm6dsv16x_data *lsm6dsv16x) +{ + while (1) { + k_sem_take(&lsm6dsv16x->gpio_sem, K_FOREVER); + lsm6dsv16x_handle_interrupt(lsm6dsv16x->dev); + } +} +#endif /* CONFIG_LSM6DSV16X_TRIGGER_OWN_THREAD */ + +#ifdef CONFIG_LSM6DSV16X_TRIGGER_GLOBAL_THREAD +static void lsm6dsv16x_work_cb(struct k_work *work) +{ + struct lsm6dsv16x_data *lsm6dsv16x = + CONTAINER_OF(work, struct lsm6dsv16x_data, work); + + lsm6dsv16x_handle_interrupt(lsm6dsv16x->dev); +} +#endif /* CONFIG_LSM6DSV16X_TRIGGER_GLOBAL_THREAD */ + +int lsm6dsv16x_init_interrupt(const struct device *dev) +{ + struct lsm6dsv16x_data *lsm6dsv16x = dev->data; + const struct lsm6dsv16x_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + int ret; + + /* setup data ready gpio interrupt (INT1 or INT2) */ + if (!device_is_ready(cfg->gpio_drdy.port)) { + LOG_ERR("Cannot get pointer to drdy_gpio device"); + return -EINVAL; + } + +#if defined(CONFIG_LSM6DSV16X_TRIGGER_OWN_THREAD) + k_sem_init(&lsm6dsv16x->gpio_sem, 0, K_SEM_MAX_LIMIT); + + k_thread_create(&lsm6dsv16x->thread, lsm6dsv16x->thread_stack, + CONFIG_LSM6DSV16X_THREAD_STACK_SIZE, + (k_thread_entry_t)lsm6dsv16x_thread, lsm6dsv16x, + NULL, NULL, K_PRIO_COOP(CONFIG_LSM6DSV16X_THREAD_PRIORITY), + 0, K_NO_WAIT); + k_thread_name_set(&lsm6dsv16x->thread, "lsm6dsv16x"); +#elif defined(CONFIG_LSM6DSV16X_TRIGGER_GLOBAL_THREAD) + lsm6dsv16x->work.handler = lsm6dsv16x_work_cb; +#endif /* CONFIG_LSM6DSV16X_TRIGGER_OWN_THREAD */ + + ret = gpio_pin_configure_dt(&cfg->gpio_drdy, GPIO_INPUT); + if (ret < 0) { + LOG_DBG("Could not configure gpio"); + return ret; + } + + gpio_init_callback(&lsm6dsv16x->gpio_cb, + lsm6dsv16x_gpio_callback, + BIT(cfg->gpio_drdy.pin)); + + if (gpio_add_callback(cfg->gpio_drdy.port, &lsm6dsv16x->gpio_cb) < 0) { + LOG_DBG("Could not set gpio callback"); + return -EIO; + } + + + /* set data ready mode on int1/int2 */ + LOG_DBG("drdy_pulsed is %d", (int)cfg->drdy_pulsed); + lsm6dsv16x_data_ready_mode_t mode = cfg->drdy_pulsed ? LSM6DSV16X_DRDY_PULSED : + LSM6DSV16X_DRDY_LATCHED; + + ret = lsm6dsv16x_data_ready_mode_set(ctx, mode); + if (ret < 0) { + LOG_ERR("drdy_pulsed config error %d", (int)cfg->drdy_pulsed); + return ret; + } + + return gpio_pin_interrupt_configure_dt(&cfg->gpio_drdy, + GPIO_INT_EDGE_TO_ACTIVE); +} diff --git a/dts/bindings/sensor/st,lsm6dsv16x-common.yaml b/dts/bindings/sensor/st,lsm6dsv16x-common.yaml new file mode 100644 index 00000000000..d12e8c32426 --- /dev/null +++ b/dts/bindings/sensor/st,lsm6dsv16x-common.yaml @@ -0,0 +1,147 @@ +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +include: sensor-device.yaml + +properties: + irq-gpios: + type: phandle-array + description: | + DRDY pin + + This pin defaults to active high when produced by the sensor. + The property value should ensure the flags properly describe + the signal that is presented to the driver. + + drdy-pin: + type: int + default: 1 + enum: + - 1 # drdy is generated from INT1 + - 2 # drdy is generated from INT2 + description: | + Select DRDY pin number (1 or 2). + + This number represents which of the two interrupt pins + (INT1 or INT2) the drdy line is attached to. This property is not + mandatory and if not present it defaults to 1 which is the + configuration at power-up. + + accel-range: + type: int + default: 0 + description: | + Range in g. Default is power-up configuration. + enum: + - 0 # 2g (0.061 mg/LSB) + - 1 # 4g (0.122 mg/LSB) + - 2 # 8g (0.244 mg/LSB) + - 3 # 16g (0.488 mg/LSB) + + accel-odr: + type: int + default: 0x0 + description: | + Specify the default accelerometer output data rate expressed in samples per second (Hz). + The values are taken in accordance to lsm6dsv16x_data_rate_t enumerative in hal/st + module. Please note that this values will not change the operating mode, which will remain + High Performance (device default) + Default is power-up configuration. + enum: + - 0x00 # Power-Down + - 0x01 # 1Hz875 + - 0x02 # 7Hz5 + - 0x03 # 15Hz + - 0x04 # 30Hz + - 0x05 # 60Hz + - 0x06 # 120Hz + - 0x07 # 240Hz + - 0x08 # 480Hz + - 0x09 # 960Hz + - 0x0a # 1920Hz + - 0x0b # 3840Hz + - 0x0c # 7680Hz + - 0x13 # 15Hz625 (High Accuracy 1) + - 0x14 # 31Hz25 (High Accuracy 1) + - 0x15 # 62Hz5 (High Accuracy 1) + - 0x16 # 125Hz (High Accuracy 1) + - 0x17 # 250Hz (High Accuracy 1) + - 0x18 # 500Hz (High Accuracy 1) + - 0x19 # 1000Hz (High Accuracy 1) + - 0x1a # 2000Hz (High Accuracy 1) + - 0x1b # 4000Hz (High Accuracy 1) + - 0x1c # 8000Hz (High Accuracy 1) + - 0x23 # 12Hz5 (High Accuracy 2) + - 0x24 # 25Hz (High Accuracy 2) + - 0x25 # 50Hz (High Accuracy 2) + - 0x26 # 100Hz (High Accuracy 2) + - 0x27 # 200Hz (High Accuracy 2) + - 0x28 # 400Hz (High Accuracy 2) + - 0x29 # 800Hz (High Accuracy 2) + - 0x2a # 1600Hz (High Accuracy 2) + - 0x2b # 3200Hz (High Accuracy 2) + - 0x2c # 6400Hz (High Accuracy 2) + + gyro-range: + type: int + default: 0 + description: | + Range in dps. Default is power-up configuration. + enum: + - 0 # 125 dps (4.375 mdps/LSB) + - 1 # 250 dps (8.75 mdps/LSB) + - 2 # 500 dps (17.50 mdps/LSB) + - 3 # 1000 dps (35 mdps/LSB) + - 4 # 2000 dps (70 mdps/LSB) + - 5 # 4000 dps (140 mdps/LSB) + + gyro-odr: + type: int + default: 0x0 + description: | + Specify the default gyro output data rate expressed in samples per second (Hz). + The values are taken in accordance to lsm6dsv16x_data_rate_t enumerative in hal/st + module. Please note that this values will not change the operating mode, which will remain + High Performance (device default). Moreover, the values here which will be selected in the + DT are the only way to specifiy the odr accuracy even at runtime with + SENSOR_ATTR_SAMPLING_FREQUENCY. + Default is power-up configuration. + enum: + - 0x00 # Power-Down + - 0x02 # 7Hz5 + - 0x03 # 15Hz + - 0x04 # 30Hz + - 0x05 # 60Hz + - 0x06 # 120Hz + - 0x07 # 240Hz + - 0x08 # 480Hz + - 0x09 # 960Hz + - 0x0a # 1920Hz + - 0x0b # 3840Hz + - 0x0c # 7680Hz + - 0x13 # 15Hz625 (High Accuracy 1) + - 0x14 # 31Hz25 (High Accuracy 1) + - 0x15 # 62Hz5 (High Accuracy 1) + - 0x16 # 125Hz (High Accuracy 1) + - 0x17 # 250Hz (High Accuracy 1) + - 0x18 # 500Hz (High Accuracy 1) + - 0x19 # 1000Hz (High Accuracy 1) + - 0x1a # 2000Hz (High Accuracy 1) + - 0x1b # 4000Hz (High Accuracy 1) + - 0x1c # 8000Hz (High Accuracy 1) + - 0x23 # 12Hz5 (High Accuracy 2) + - 0x24 # 25Hz (High Accuracy 2) + - 0x25 # 50Hz (High Accuracy 2) + - 0x26 # 100Hz (High Accuracy 2) + - 0x27 # 200Hz (High Accuracy 2) + - 0x28 # 400Hz (High Accuracy 2) + - 0x29 # 800Hz (High Accuracy 2) + - 0x2a # 1600Hz (High Accuracy 2) + - 0x2b # 3200Hz (High Accuracy 2) + - 0x2c # 6400Hz (High Accuracy 2) + + drdy-pulsed: + type: boolean + description: | + Selects the pulsed mode for data-ready interrupt when enabled, + and the latched mode when disabled. diff --git a/dts/bindings/sensor/st,lsm6dsv16x-i2c.yaml b/dts/bindings/sensor/st,lsm6dsv16x-i2c.yaml new file mode 100644 index 00000000000..b21b7975dcc --- /dev/null +++ b/dts/bindings/sensor/st,lsm6dsv16x-i2c.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LSM6DSV16X 6-axis IMU (Inertial Measurement Unit) sensor + accessed through I2C bus + +compatible: "st,lsm6dsv16x" + +include: ["i2c-device.yaml", "st,lsm6dsv16x-common.yaml"] diff --git a/dts/bindings/sensor/st,lsm6dsv16x-spi.yaml b/dts/bindings/sensor/st,lsm6dsv16x-spi.yaml new file mode 100644 index 00000000000..be860aba1b4 --- /dev/null +++ b/dts/bindings/sensor/st,lsm6dsv16x-spi.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LSM6DSV16X 6-axis IMU (Inertial Measurement Unit) sensor + accessed through SPI bus + +compatible: "st,lsm6dsv16x" + +include: ["spi-device.yaml", "st,lsm6dsv16x-common.yaml"] diff --git a/modules/Kconfig.st b/modules/Kconfig.st index 3642ff83eaf..489ef12b936 100644 --- a/modules/Kconfig.st +++ b/modules/Kconfig.st @@ -169,6 +169,9 @@ config USE_STDC_LSM6DSR config USE_STDC_LSM6DSRX bool +config USE_STDC_LSM6DSV16X + bool + config USE_STDC_LSM9DS1 bool diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 5922a647e5b..e117230ce40 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -728,3 +728,9 @@ test_i2c_lsm6dso16is: lsm6dso16is@6f { reg = <0x6f>; irq-gpios = <&test_gpio 0 0>; }; + +test_i2c_lsm6dsv16x: lsm6dsv16x@70 { + compatible = "st,lsm6dsv16x"; + reg = <0x70>; + irq-gpios = <&test_gpio 0 0>; +}; diff --git a/tests/drivers/build_all/sensor/sensors_shub.conf b/tests/drivers/build_all/sensor/sensors_shub.conf index a2f00df3fbd..f06a4fcaa47 100644 --- a/tests/drivers/build_all/sensor/sensors_shub.conf +++ b/tests/drivers/build_all/sensor/sensors_shub.conf @@ -21,3 +21,8 @@ CONFIG_LSM6DSO16IS_SENSORHUB=y CONFIG_LSM6DSO16IS_EXT_LIS2MDL=y CONFIG_LSM6DSO16IS_EXT_LPS22HB=y CONFIG_LSM6DSO16IS_EXT_HTS221=y + +CONFIG_LSM6DSV16X_SENSORHUB=y +CONFIG_LSM6DSV16X_EXT_LIS2MDL=y +CONFIG_LSM6DSV16X_EXT_LPS22HB=y +CONFIG_LSM6DSV16X_EXT_HTS221=y diff --git a/tests/drivers/build_all/sensor/sensors_trigger_global.conf b/tests/drivers/build_all/sensor/sensors_trigger_global.conf index 5634a9cbe33..ac5299f78d4 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_global.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_global.conf @@ -36,6 +36,7 @@ CONFIG_LPS22HH_TRIGGER_GLOBAL_THREAD=y CONFIG_LSM6DSL_TRIGGER_GLOBAL_THREAD=y CONFIG_LSM6DSO_TRIGGER_GLOBAL_THREAD=y CONFIG_LSM6DSO16IS_TRIGGER_GLOBAL_THREAD=y +CONFIG_LSM6DSV16X_TRIGGER_GLOBAL_THREAD=y CONFIG_MCP9808_TRIGGER_GLOBAL_THREAD=y CONFIG_MPU6050_TRIGGER_GLOBAL_THREAD=y CONFIG_MPU9250_TRIGGER_GLOBAL_THREAD=y diff --git a/tests/drivers/build_all/sensor/sensors_trigger_none.conf b/tests/drivers/build_all/sensor/sensors_trigger_none.conf index 0784bf94147..1653cb486c0 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_none.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_none.conf @@ -36,6 +36,7 @@ CONFIG_LPS22HH_TRIGGER_NONE=y CONFIG_LSM6DSL_TRIGGER_NONE=y CONFIG_LSM6DSO_TRIGGER_NONE=y CONFIG_LSM6DSO16IS_TRIGGER_NONE=y +CONFIG_LSM6DSV16X_TRIGGER_NONE=y CONFIG_MCP9808_TRIGGER_NONE=y CONFIG_MPU6050_TRIGGER_NONE=y CONFIG_MPU9250_TRIGGER_NONE=y diff --git a/tests/drivers/build_all/sensor/sensors_trigger_own.conf b/tests/drivers/build_all/sensor/sensors_trigger_own.conf index 4c2171471e0..83c5680648e 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_own.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_own.conf @@ -34,6 +34,7 @@ CONFIG_LPS22HH_TRIGGER_OWN_THREAD=y CONFIG_LSM6DSL_TRIGGER_OWN_THREAD=y CONFIG_LSM6DSO_TRIGGER_OWN_THREAD=y CONFIG_LSM6DSO16IS_TRIGGER_OWN_THREAD=y +CONFIG_LSM6DSV16X_TRIGGER_OWN_THREAD=y CONFIG_MCP9808_TRIGGER_OWN_THREAD=y CONFIG_MPU6050_TRIGGER_OWN_THREAD=y CONFIG_MPU9250_TRIGGER_OWN_THREAD=y diff --git a/tests/drivers/build_all/sensor/spi.dtsi b/tests/drivers/build_all/sensor/spi.dtsi index ef43541608c..8cdf2ef214b 100644 --- a/tests/drivers/build_all/sensor/spi.dtsi +++ b/tests/drivers/build_all/sensor/spi.dtsi @@ -388,3 +388,10 @@ test_spi_lsm6dso16is: lsm6dso16is@2f { spi-max-frequency = <0>; irq-gpios = <&test_gpio 0 0>; }; + +test_spi_lsm6dsv16x: lsm6dsv16x@30 { + compatible = "st,lsm6dsv16x"; + reg = <0x30>; + spi-max-frequency = <0>; + irq-gpios = <&test_gpio 0 0>; +};