Browse Source

drivers/sensor: add support to LSM6DSV16X IMU sensor

The LSM6DSV16X is a system-in-package featuring a 3-axis digital
accelerometer and a 3-axis digital gyroscope for industrial and IoT
solutions. The LSM6DSV16X embeds advanced dedicated features such as
a finite state machine (FSM) for configurable motion tracking and a
machine learning core (MLC) for context awareness.

https://www.st.com/en/mems-and-sensors/lsm6dsv16x.html

This driver is based on stmemsc HAL i/f v2.02

Signed-off-by: Armando Visconti <armando.visconti@st.com>
pull/58167/head
Armando Visconti 2 years ago committed by Maureen Helm
parent
commit
e5b7799ce3
  1. 1
      drivers/sensor/CMakeLists.txt
  2. 2
      drivers/sensor/Kconfig
  3. 13
      drivers/sensor/lsm6dsv16x/CMakeLists.txt
  4. 94
      drivers/sensor/lsm6dsv16x/Kconfig
  5. 981
      drivers/sensor/lsm6dsv16x/lsm6dsv16x.c
  6. 140
      drivers/sensor/lsm6dsv16x/lsm6dsv16x.h
  7. 848
      drivers/sensor/lsm6dsv16x/lsm6dsv16x_shub.c
  8. 333
      drivers/sensor/lsm6dsv16x/lsm6dsv16x_trigger.c
  9. 147
      dts/bindings/sensor/st,lsm6dsv16x-common.yaml
  10. 10
      dts/bindings/sensor/st,lsm6dsv16x-i2c.yaml
  11. 10
      dts/bindings/sensor/st,lsm6dsv16x-spi.yaml
  12. 3
      modules/Kconfig.st
  13. 6
      tests/drivers/build_all/sensor/i2c.dtsi
  14. 5
      tests/drivers/build_all/sensor/sensors_shub.conf
  15. 1
      tests/drivers/build_all/sensor/sensors_trigger_global.conf
  16. 1
      tests/drivers/build_all/sensor/sensors_trigger_none.conf
  17. 1
      tests/drivers/build_all/sensor/sensors_trigger_own.conf
  18. 7
      tests/drivers/build_all/sensor/spi.dtsi

1
drivers/sensor/CMakeLists.txt

@ -68,6 +68,7 @@ add_subdirectory_ifdef(CONFIG_LSM6DS0 lsm6ds0) @@ -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)

2
drivers/sensor/Kconfig

@ -177,6 +177,8 @@ source "drivers/sensor/lsm6dso/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"

13
drivers/sensor/lsm6dsv16x/CMakeLists.txt

@ -0,0 +1,13 @@ @@ -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)

94
drivers/sensor/lsm6dsv16x/Kconfig

@ -0,0 +1,94 @@ @@ -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

981
drivers/sensor/lsm6dsv16x/lsm6dsv16x.c

@ -0,0 +1,981 @@ @@ -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 <zephyr/drivers/sensor.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/init.h>
#include <string.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/sys/__assert.h>
#include <zephyr/logging/log.h>
#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)

140
drivers/sensor/lsm6dsv16x/lsm6dsv16x.h

@ -0,0 +1,140 @@ @@ -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 <zephyr/drivers/sensor.h>
#include <zephyr/types.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/sys/util.h>
#include <stmemsc.h>
#include "lsm6dsv16x_reg.h"
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
#include <zephyr/drivers/spi.h>
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
#include <zephyr/drivers/i2c.h>
#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_ */

848
drivers/sensor/lsm6dsv16x/lsm6dsv16x_shub.c

@ -0,0 +1,848 @@ @@ -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 <zephyr/device.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/sys/__assert.h>
#include <zephyr/sys/util.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/logging/log.h>
#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;
}

333
drivers/sensor/lsm6dsv16x/lsm6dsv16x_trigger.c

@ -0,0 +1,333 @@ @@ -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 <zephyr/kernel.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/logging/log.h>
#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);
}

147
dts/bindings/sensor/st,lsm6dsv16x-common.yaml

@ -0,0 +1,147 @@ @@ -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.

10
dts/bindings/sensor/st,lsm6dsv16x-i2c.yaml

@ -0,0 +1,10 @@ @@ -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"]

10
dts/bindings/sensor/st,lsm6dsv16x-spi.yaml

@ -0,0 +1,10 @@ @@ -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"]

3
modules/Kconfig.st

@ -169,6 +169,9 @@ config USE_STDC_LSM6DSR @@ -169,6 +169,9 @@ config USE_STDC_LSM6DSR
config USE_STDC_LSM6DSRX
bool
config USE_STDC_LSM6DSV16X
bool
config USE_STDC_LSM9DS1
bool

6
tests/drivers/build_all/sensor/i2c.dtsi

@ -728,3 +728,9 @@ test_i2c_lsm6dso16is: lsm6dso16is@6f { @@ -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>;
};

5
tests/drivers/build_all/sensor/sensors_shub.conf

@ -21,3 +21,8 @@ CONFIG_LSM6DSO16IS_SENSORHUB=y @@ -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

1
tests/drivers/build_all/sensor/sensors_trigger_global.conf

@ -36,6 +36,7 @@ CONFIG_LPS22HH_TRIGGER_GLOBAL_THREAD=y @@ -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

1
tests/drivers/build_all/sensor/sensors_trigger_none.conf

@ -36,6 +36,7 @@ CONFIG_LPS22HH_TRIGGER_NONE=y @@ -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

1
tests/drivers/build_all/sensor/sensors_trigger_own.conf

@ -34,6 +34,7 @@ CONFIG_LPS22HH_TRIGGER_OWN_THREAD=y @@ -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

7
tests/drivers/build_all/sensor/spi.dtsi

@ -388,3 +388,10 @@ test_spi_lsm6dso16is: lsm6dso16is@2f { @@ -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>;
};

Loading…
Cancel
Save