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>
This commit is contained in:
parent
2725155832
commit
e5b7799ce3
18 changed files with 2603 additions and 0 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
Normal file
13
drivers/sensor/lsm6dsv16x/CMakeLists.txt
Normal file
|
|
@ -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
Normal file
94
drivers/sensor/lsm6dsv16x/Kconfig
Normal file
|
|
@ -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
Normal file
981
drivers/sensor/lsm6dsv16x/lsm6dsv16x.c
Normal file
|
|
@ -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
Normal file
140
drivers/sensor/lsm6dsv16x/lsm6dsv16x.h
Normal file
|
|
@ -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
Normal file
848
drivers/sensor/lsm6dsv16x/lsm6dsv16x_shub.c
Normal file
|
|
@ -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
Normal file
333
drivers/sensor/lsm6dsv16x/lsm6dsv16x_trigger.c
Normal file
|
|
@ -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
Normal file
147
dts/bindings/sensor/st,lsm6dsv16x-common.yaml
Normal file
|
|
@ -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
Normal file
10
dts/bindings/sensor/st,lsm6dsv16x-i2c.yaml
Normal file
|
|
@ -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
Normal file
10
dts/bindings/sensor/st,lsm6dsv16x-spi.yaml
Normal file
|
|
@ -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"]
|
||||
|
|
@ -169,6 +169,9 @@ config USE_STDC_LSM6DSR
|
|||
config USE_STDC_LSM6DSRX
|
||||
bool
|
||||
|
||||
config USE_STDC_LSM6DSV16X
|
||||
bool
|
||||
|
||||
config USE_STDC_LSM9DS1
|
||||
bool
|
||||
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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…
Reference in a new issue