From dcf65905c52cb318cd81ccbabd56d4e4f02c4dd4 Mon Sep 17 00:00:00 2001 From: Kyle Dunn Date: Wed, 15 Nov 2023 13:35:26 -0700 Subject: [PATCH] drivers: sensor: lis2dux12: Add lis2dux12 driver Adds support for the STMicroelectronics LIS2DUX12 3-axis accelerometer. Signed-off-by: Kyle Dunn --- drivers/sensor/CMakeLists.txt | 1 + drivers/sensor/Kconfig | 1 + drivers/sensor/lis2dux12/CMakeLists.txt | 8 + drivers/sensor/lis2dux12/Kconfig | 30 ++ drivers/sensor/lis2dux12/lis2dux12.c | 412 ++++++++++++++++++ drivers/sensor/lis2dux12/lis2dux12.h | 86 ++++ drivers/sensor/lis2dux12/lis2dux12_trigger.c | 198 +++++++++ dts/bindings/sensor/st,lis2dux12-common.yaml | 95 ++++ dts/bindings/sensor/st,lis2dux12-i2c.yaml | 8 + dts/bindings/sensor/st,lis2dux12-spi.yaml | 9 + include/zephyr/dt-bindings/sensor/lis2dux12.h | 38 ++ modules/hal_st/Kconfig | 3 + tests/drivers/build_all/sensor/app.overlay | 3 +- tests/drivers/build_all/sensor/i2c.dtsi | 11 + .../build_all/sensor/sensors_die_temp.conf | 1 + .../sensor/sensors_trigger_global.conf | 1 + .../sensor/sensors_trigger_none.conf | 1 + .../build_all/sensor/sensors_trigger_own.conf | 1 + tests/drivers/build_all/sensor/spi.dtsi | 9 + 19 files changed, 915 insertions(+), 1 deletion(-) create mode 100644 drivers/sensor/lis2dux12/CMakeLists.txt create mode 100644 drivers/sensor/lis2dux12/Kconfig create mode 100644 drivers/sensor/lis2dux12/lis2dux12.c create mode 100644 drivers/sensor/lis2dux12/lis2dux12.h create mode 100644 drivers/sensor/lis2dux12/lis2dux12_trigger.c create mode 100644 dts/bindings/sensor/st,lis2dux12-common.yaml create mode 100644 dts/bindings/sensor/st,lis2dux12-i2c.yaml create mode 100644 dts/bindings/sensor/st,lis2dux12-spi.yaml create mode 100644 include/zephyr/dt-bindings/sensor/lis2dux12.h diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index 52962a0b2fda810..69e7b3ef1f82cc6 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -78,6 +78,7 @@ add_subdirectory_ifdef(CONFIG_LIS2DE12 lis2de12) add_subdirectory_ifdef(CONFIG_LIS2DS12 lis2ds12) add_subdirectory_ifdef(CONFIG_LIS2DU12 lis2du12) add_subdirectory_ifdef(CONFIG_LIS2DW12 lis2dw12) +add_subdirectory_ifdef(CONFIG_LIS2DUX12 lis2dux12) add_subdirectory_ifdef(CONFIG_LIS2MDL lis2mdl) add_subdirectory_ifdef(CONFIG_LIS3MDL lis3mdl) add_subdirectory_ifdef(CONFIG_LM75 lm75) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index 27d6c1651970ed2..4e9129e0439ab50 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -158,6 +158,7 @@ source "drivers/sensor/lis2de12/Kconfig" source "drivers/sensor/lis2ds12/Kconfig" source "drivers/sensor/lis2du12/Kconfig" source "drivers/sensor/lis2dw12/Kconfig" +source "drivers/sensor/lis2dux12/Kconfig" source "drivers/sensor/lis2mdl/Kconfig" source "drivers/sensor/lis3mdl/Kconfig" source "drivers/sensor/lm75/Kconfig" diff --git a/drivers/sensor/lis2dux12/CMakeLists.txt b/drivers/sensor/lis2dux12/CMakeLists.txt new file mode 100644 index 000000000000000..87f0e6b89284f96 --- /dev/null +++ b/drivers/sensor/lis2dux12/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(lis2dux12.c) +zephyr_library_sources_ifdef(CONFIG_LIS2DUX12_TRIGGER lis2dux12_trigger.c) + +zephyr_library_include_directories(../stmemsc) diff --git a/drivers/sensor/lis2dux12/Kconfig b/drivers/sensor/lis2dux12/Kconfig new file mode 100644 index 000000000000000..d27344484a79f43 --- /dev/null +++ b/drivers/sensor/lis2dux12/Kconfig @@ -0,0 +1,30 @@ +# ST Microelectronics LIS2DUX12 3-axis accelerometer driver + +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +menuconfig LIS2DUX12 + bool "LIS2DUX12 I2C/SPI accelerometer sensor driver" + default y + depends on DT_HAS_ST_LIS2DUX12_ENABLED + depends on ZEPHYR_HAL_ST_MODULE + select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2DUX12),i2c) + select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2DUX12),spi) + select HAS_STMEMSC + select USE_STDC_LIS2DUX12 + help + Enable driver for LIS2DUX12 accelerometer sensor driver + +if LIS2DUX12 + +module = LIS2DUX12 +thread_priority = 10 +thread_stack_size = 1024 +source "drivers/sensor/Kconfig.trigger_template" + +config LIS2DUX12_ENABLE_TEMP + bool "Temperature" + help + Enable/disable temperature + +endif # LIS2DUX12 diff --git a/drivers/sensor/lis2dux12/lis2dux12.c b/drivers/sensor/lis2dux12/lis2dux12.c new file mode 100644 index 000000000000000..b1ee9e9ce924f38 --- /dev/null +++ b/drivers/sensor/lis2dux12/lis2dux12.c @@ -0,0 +1,412 @@ +/* ST Microelectronics LIS2DUX12 3-axis accelerometer driver + * + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lis2dux12.pdf + */ + +#define DT_DRV_COMPAT st_lis2dux12 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lis2dux12.h" + +LOG_MODULE_REGISTER(LIS2DUX12, CONFIG_SENSOR_LOG_LEVEL); + +static int lis2dux12_set_odr(const struct device *dev, uint8_t odr) +{ + const struct lis2dux12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lis2dux12_md_t mode = {.odr = odr}; + + return lis2dux12_mode_set(ctx, &mode); +} + +static int lis2dux12_set_range(const struct device *dev, uint8_t range) +{ + int err = 0; + struct lis2dux12_data *data = dev->data; + const struct lis2dux12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lis2dux12_md_t val = { .odr = cfg->odr, .fs = range }; + + err = lis2dux12_mode_set(ctx, &val); + + if (!err) { + switch (range) { + default: + case LIS2DUX12_DT_FS_2G: + data->gain = lis2dux12_from_fs2g_to_mg(1); + break; + case LIS2DUX12_DT_FS_4G: + data->gain = lis2dux12_from_fs4g_to_mg(1); + break; + case LIS2DUX12_DT_FS_8G: + data->gain = lis2dux12_from_fs8g_to_mg(1); + break; + case LIS2DUX12_DT_FS_16G: + data->gain = lis2dux12_from_fs16g_to_mg(1); + break; + } + } + + return err; +} + +#define FOREACH_ODR_ENUM(ODR_VAL) \ + ODR_VAL(LIS2DUX12_DT_ODR_OFF, 0.0f) \ + ODR_VAL(LIS2DUX12_DT_ODR_1Hz_ULP, 1.0f) \ + ODR_VAL(LIS2DUX12_DT_ODR_3Hz_ULP, 3.0f) \ + ODR_VAL(LIS2DUX12_DT_ODR_25Hz_ULP, 25.0f) \ + ODR_VAL(LIS2DUX12_DT_ODR_6Hz, 6.0f) \ + ODR_VAL(LIS2DUX12_DT_ODR_12Hz5, 12.50f) \ + ODR_VAL(LIS2DUX12_DT_ODR_25Hz, 25.0f) \ + ODR_VAL(LIS2DUX12_DT_ODR_50Hz, 50.0f) \ + ODR_VAL(LIS2DUX12_DT_ODR_100Hz, 100.0f) \ + ODR_VAL(LIS2DUX12_DT_ODR_200Hz, 200.0f) \ + ODR_VAL(LIS2DUX12_DT_ODR_400Hz, 400.0f) \ + ODR_VAL(LIS2DUX12_DT_ODR_800Hz, 800.0f) + +#define GENERATE_VAL(ENUM, VAL) VAL, + +static const float lis2dux12_odr_map[LIS2DUX12_DT_ODR_END] = {FOREACH_ODR_ENUM(GENERATE_VAL)}; + +static int lis2dux12_freq_to_odr_val(const struct device *dev, uint16_t freq) +{ + const struct lis2dux12_config *cfg = dev->config; + + /* constrain loop to prevent erroneous power mode/odr combinations */ + size_t i = (cfg->pm != LIS2DUX12_OPER_MODE_LOW_POWER) ? LIS2DUX12_DT_ODR_6Hz + : LIS2DUX12_DT_ODR_1Hz_ULP; + size_t len = (cfg->pm != LIS2DUX12_OPER_MODE_LOW_POWER) ? LIS2DUX12_DT_ODR_END + : LIS2DUX12_DT_ODR_6Hz; + + while (i < len) { + if (freq <= lis2dux12_odr_map[i]) { + return i; + } + ++i; + } + + return -EINVAL; +} + +static int lis2dux12_accel_config(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ + switch (attr) { + case SENSOR_ATTR_FULL_SCALE: + return lis2dux12_set_range(dev, sensor_ms2_to_g(val)); + case SENSOR_ATTR_SAMPLING_FREQUENCY: + LOG_DBG("%s: set odr to %d Hz", dev->name, val->val1); + int odr_val = lis2dux12_freq_to_odr_val(dev, val->val1); + + if (odr_val < 0) { + LOG_ERR("frequency not unsupported or wrong operating mode."); + return odr_val; + } + return lis2dux12_set_odr(dev, odr_val); + default: + LOG_ERR("Accel attribute not supported."); + return -ENOTSUP; + } + + return 0; +} + +static int lis2dux12_attr_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ + switch (chan) { + case SENSOR_CHAN_ACCEL_XYZ: + return lis2dux12_accel_config(dev, chan, attr, val); + default: + LOG_ERR("attr_set() not supported on this channel."); + return -ENOTSUP; + } + + return 0; +} + +static int lis2dux12_sample_fetch_accel(const struct device *dev) +{ + struct lis2dux12_data *data = dev->data; + const struct lis2dux12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + + /* fetch raw data sample */ + lis2dux12_md_t mode = {.fs = cfg->range}; + lis2dux12_xl_data_t xzy_data = {0}; + + if (lis2dux12_xl_data_get(ctx, &mode, &xzy_data) < 0) { + LOG_ERR("Failed to fetch raw data sample"); + return -EIO; + } + + data->sample_x = sys_le16_to_cpu(xzy_data.raw[0]); + data->sample_y = sys_le16_to_cpu(xzy_data.raw[1]); + data->sample_z = sys_le16_to_cpu(xzy_data.raw[2]); + + return 0; +} + +#ifdef CONFIG_LIS2DUX12_ENABLE_TEMP +static int lis2dux12_sample_fetch_temp(const struct device *dev) +{ + struct lis2dux12_data *data = dev->data; + const struct lis2dux12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + + /* fetch raw data sample */ + lis2dux12_md_t mode; + lis2dux12_outt_data_t temp_data = {0}; + + if (lis2dux12_outt_data_get(ctx, &mode, &temp_data) < 0) { + LOG_ERR("Failed to fetch raw temperature data sample"); + return -EIO; + } + + data->sample_temp = sys_le16_to_cpu(temp_data.heat.raw); + + return 0; +} +#endif + +static int lis2dux12_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + switch (chan) { + case SENSOR_CHAN_ACCEL_XYZ: + lis2dux12_sample_fetch_accel(dev); + break; +#if defined(CONFIG_LIS2DUX12_ENABLE_TEMP) + case SENSOR_CHAN_DIE_TEMP: + lis2dux12_sample_fetch_temp(dev); + break; +#endif + case SENSOR_CHAN_ALL: + lis2dux12_sample_fetch_accel(dev); +#if defined(CONFIG_LIS2DUX12_ENABLE_TEMP) + lis2dux12_sample_fetch_temp(dev); +#endif + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static inline void lis2dux12_convert(struct sensor_value *val, int raw_val, float gain) +{ + int64_t dval; + + /* Gain is in mg/LSB */ + /* Convert to m/s^2 */ + dval = ((int64_t)raw_val * gain * SENSOR_G) / 1000; + val->val1 = dval / 1000000LL; + val->val2 = dval % 1000000LL; +} + +static inline int lis2dux12_get_channel(enum sensor_channel chan, struct sensor_value *val, + struct lis2dux12_data *data, float gain) +{ + switch (chan) { + case SENSOR_CHAN_ACCEL_X: + lis2dux12_convert(val, data->sample_x, gain); + break; + case SENSOR_CHAN_ACCEL_Y: + lis2dux12_convert(val, data->sample_y, gain); + break; + case SENSOR_CHAN_ACCEL_Z: + lis2dux12_convert(val, data->sample_z, gain); + break; + case SENSOR_CHAN_ACCEL_XYZ: + lis2dux12_convert(val, data->sample_x, gain); + lis2dux12_convert(val + 1, data->sample_y, gain); + lis2dux12_convert(val + 2, data->sample_z, gain); + break; +#if defined(CONFIG_LIS2DUX12_ENABLE_TEMP) + case SENSOR_CHAN_DIE_TEMP: + sensor_value_from_double(val, data->sample_temp); + break; +#endif + default: + return -ENOTSUP; + } + + return 0; +} + +static int lis2dux12_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct lis2dux12_data *data = dev->data; + + return lis2dux12_get_channel(chan, val, data, data->gain); +} + +static const struct sensor_driver_api lis2dux12_driver_api = { + .attr_set = lis2dux12_attr_set, +#if defined(CONFIG_LIS2DUX12_TRIGGER) + .trigger_set = lis2dux12_trigger_set, +#endif + .sample_fetch = lis2dux12_sample_fetch, + .channel_get = lis2dux12_channel_get, +}; + +static int lis2dux12_init(const struct device *dev) +{ + const struct lis2dux12_config *const cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + uint8_t chip_id; + int ret; + + lis2dux12_exit_deep_power_down(ctx); + k_busy_wait(25000); /* 25ms */ + + /* check chip ID */ + ret = lis2dux12_device_id_get(ctx, &chip_id); + if (ret < 0) { + LOG_ERR("%s: Not able to read dev id", dev->name); + return ret; + } + + if (chip_id != LIS2DUX12_ID) { + LOG_ERR("%s: Invalid chip ID 0x%02x", dev->name, chip_id); + return -EINVAL; + } + + /* reset device */ + ret = lis2dux12_init_set(ctx, LIS2DUX12_RESET); + if (ret < 0) { + return ret; + } + + k_busy_wait(100); + + LOG_INF("%s: chip id 0x%x", dev->name, chip_id); + + /* Set bdu and if_inc recommended for driver usage */ + lis2dux12_init_set(ctx, LIS2DUX12_SENSOR_ONLY_ON); + + lis2dux12_timestamp_set(ctx, PROPERTY_ENABLE); + +#ifdef CONFIG_LIS2DUX12_TRIGGER + if (cfg->trig_enabled) { + ret = lis2dux12_trigger_init(dev); + if (ret < 0) { + LOG_ERR("%s: Failed to initialize triggers", dev->name); + return ret; + } + } +#endif + + /* set sensor default pm and odr */ + LOG_INF("%s: pm: %d, odr: %d", dev->name, cfg->pm, cfg->odr); + lis2dux12_md_t mode = { + .odr = cfg->odr, + .fs = cfg->range, + }; + ret = lis2dux12_mode_set(ctx, &mode); + if (ret < 0) { + LOG_ERR("%s: odr init error (12.5 Hz)", dev->name); + return ret; + } + + /* set sensor default scale (used to convert sample values) */ + LOG_INF("%s: range is %d", dev->name, cfg->range); + ret = lis2dux12_set_range(dev, cfg->range); + if (ret < 0) { + LOG_ERR("%s: range init error %d", dev->name, cfg->range); + return ret; + } + + return 0; +} + +/* + * Device creation macro, shared by LIS2DUX12_DEFINE_SPI() and + * LIS2DUX12_DEFINE_I2C(). + */ + +#define LIS2DUX12_DEVICE_INIT(inst) \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, lis2dux12_init, NULL, &lis2dux12_data_##inst, \ + &lis2dux12_config_##inst, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &lis2dux12_driver_api); + +/* + * Instantiation macros used when a device is on a SPI bus. + */ + +#ifdef CONFIG_LIS2DUX12_TRIGGER +#define LIS2DUX12_CFG_IRQ(inst) \ + .trig_enabled = true, \ + .int1_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int1_gpios, {0}), \ + .int2_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int2_gpios, {0}), \ + .drdy_pin = DT_INST_PROP(inst, drdy_pin), +#else +#define LIS2DUX12_CFG_IRQ(inst) +#endif /* CONFIG_LIS2DUX12_TRIGGER */ + +#define LIS2DUX12_SPI_OPERATION \ + (SPI_WORD_SET(8) | SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_CPHA) + +#define LIS2DUX12_CONFIG_SPI(inst) \ + { \ + STMEMSC_CTX_SPI(&lis2dux12_config_##inst.stmemsc_cfg), \ + .stmemsc_cfg = \ + { \ + .spi = SPI_DT_SPEC_INST_GET(inst, LIS2DUX12_SPI_OPERATION, 0), \ + }, \ + .range = DT_INST_PROP(inst, range), \ + .pm = DT_INST_PROP(inst, power_mode), \ + .odr = DT_INST_PROP(inst, odr), \ + IF_ENABLED(UTIL_OR(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \ + DT_INST_NODE_HAS_PROP(inst, int2_gpios)), \ + (LIS2DUX12_CFG_IRQ(inst))) \ + } + +/* + * Instantiation macros used when a device is on an I2C bus. + */ + +#define LIS2DUX12_CONFIG_I2C(inst) \ + { \ + STMEMSC_CTX_I2C(&lis2dux12_config_##inst.stmemsc_cfg), \ + .stmemsc_cfg = \ + { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + }, \ + .range = DT_INST_PROP(inst, range), \ + .pm = DT_INST_PROP(inst, power_mode), \ + .odr = DT_INST_PROP(inst, odr), \ + IF_ENABLED(UTIL_OR(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \ + DT_INST_NODE_HAS_PROP(inst, int2_gpios)), \ + (LIS2DUX12_CFG_IRQ(inst))) \ + } + +/* + * Main instantiation macro. Use of COND_CODE_1() selects the right + * bus-specific macro at preprocessor time. + */ + +#define LIS2DUX12_DEFINE(inst) \ + static struct lis2dux12_data lis2dux12_data_##inst; \ + static const struct lis2dux12_config lis2dux12_config_##inst = \ + COND_CODE_1(DT_INST_ON_BUS(inst, spi), (LIS2DUX12_CONFIG_SPI(inst)), \ + (LIS2DUX12_CONFIG_I2C(inst))); \ + LIS2DUX12_DEVICE_INIT(inst) + +DT_INST_FOREACH_STATUS_OKAY(LIS2DUX12_DEFINE) diff --git a/drivers/sensor/lis2dux12/lis2dux12.h b/drivers/sensor/lis2dux12/lis2dux12.h new file mode 100644 index 000000000000000..82a2a693a43b92d --- /dev/null +++ b/drivers/sensor/lis2dux12/lis2dux12.h @@ -0,0 +1,86 @@ +/* ST Microelectronics LIS2DUX12 3-axis accelerometer driver + * + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lis2dux12.pdf + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_LIS2DUX12_LIS2DUX12_H_ +#define ZEPHYR_DRIVERS_SENSOR_LIS2DUX12_LIS2DUX12_H_ + +#include +#include +#include +#include +#include "lis2dux12_reg.h" + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) +#include +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) +#include +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */ + +struct lis2dux12_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 range; + uint8_t pm; + uint8_t odr; +#ifdef CONFIG_LIS2DUX12_TRIGGER + const struct gpio_dt_spec int1_gpio; + const struct gpio_dt_spec int2_gpio; + uint8_t drdy_pin; + bool trig_enabled; +#endif +}; + +struct lis2dux12_data { + int sample_x; + int sample_y; + int sample_z; + float gain; + +#ifdef CONFIG_LIS2DUX12_ENABLE_TEMP + int sample_temp; +#endif + +#ifdef CONFIG_LIS2DUX12_TRIGGER + struct gpio_dt_spec *drdy_gpio; + struct gpio_callback gpio_cb; + + const struct sensor_trigger *data_ready_trigger; + sensor_trigger_handler_t data_ready_handler; + const struct device *dev; + +#if defined(CONFIG_LIS2DUX12_TRIGGER_OWN_THREAD) + K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LIS2DUX12_THREAD_STACK_SIZE); + struct k_thread thread; + struct k_sem trig_sem; +#elif defined(CONFIG_LIS2DUX12_TRIGGER_GLOBAL_THREAD) + struct k_work work; +#endif + +#endif /* CONFIG_LIS2DUX12_TRIGGER */ +}; + +#ifdef CONFIG_LIS2DUX12_TRIGGER +int lis2dux12_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); + +int lis2dux12_trigger_init(const struct device *dev); +#endif + +#endif /* ZEPHYR_DRIVERS_SENSOR_LIS2DUX12_LIS2DUX12_H_ */ diff --git a/drivers/sensor/lis2dux12/lis2dux12_trigger.c b/drivers/sensor/lis2dux12/lis2dux12_trigger.c new file mode 100644 index 000000000000000..9d711d95a629caf --- /dev/null +++ b/drivers/sensor/lis2dux12/lis2dux12_trigger.c @@ -0,0 +1,198 @@ +/* ST Microelectronics LIS2DUX12 3-axis accelerometer driver + * + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lis2dux12.pdf + */ + +#define DT_DRV_COMPAT st_lis2dux12 + +#include +#include "lis2dux12.h" + +LOG_MODULE_DECLARE(LIS2DUX12, CONFIG_SENSOR_LOG_LEVEL); + +static void lis2dux12_gpio_callback(const struct device *dev, struct gpio_callback *cb, + uint32_t pins) +{ + struct lis2dux12_data *data = CONTAINER_OF(cb, struct lis2dux12_data, gpio_cb); + int ret; + + ARG_UNUSED(pins); + + ret = gpio_pin_interrupt_configure_dt(data->drdy_gpio, GPIO_INT_DISABLE); + if (ret < 0) { + LOG_ERR("%s: Not able to configure pin_int", dev->name); + } + +#if defined(CONFIG_LIS2DUX12_TRIGGER_OWN_THREAD) + k_sem_give(&data->trig_sem); +#elif defined(CONFIG_LIS2DUX12_TRIGGER_GLOBAL_THREAD) + k_work_submit(&data->work); +#endif +} + +static void lis2dux12_handle_drdy_int(const struct device *dev) +{ + struct lis2dux12_data *data = dev->data; + + if (data->data_ready_handler != NULL) { + data->data_ready_handler(dev, data->data_ready_trigger); + } +} + +static void lis2dux12_handle_int(const struct device *dev) +{ + struct lis2dux12_data *lis2dux12 = dev->data; + const struct lis2dux12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lis2dux12_all_sources_t sources; + int ret; + + lis2dux12_all_sources_get(ctx, &sources); + + if (sources.drdy) { + lis2dux12_handle_drdy_int(dev); + } + + ret = gpio_pin_interrupt_configure_dt(lis2dux12->drdy_gpio, GPIO_INT_EDGE_TO_ACTIVE); + if (ret < 0) { + LOG_ERR("%s: Not able to configure pin_int", dev->name); + } +} + +#ifdef CONFIG_LIS2DUX12_TRIGGER_OWN_THREAD +static void lis2dux12_thread(struct lis2dux12_data *data) +{ + while (1) { + k_sem_take(&data->trig_sem, K_FOREVER); + lis2dux12_handle_int(data->dev); + } +} +#endif + +#ifdef CONFIG_LIS2DUX12_TRIGGER_GLOBAL_THREAD +static void lis2dux12_work_cb(struct k_work *work) +{ + struct lis2dux12_data *data = CONTAINER_OF(work, struct lis2dux12_data, work); + + lis2dux12_handle_int(data->dev); +} +#endif + +static int lis2dux12_init_interrupt(const struct device *dev) +{ + const struct lis2dux12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lis2dux12_pin_int_route_t route; + int err; + + /* Enable pulsed mode */ + err = lis2dux12_data_ready_mode_set(ctx, LIS2DUX12_DRDY_PULSED); + if (err < 0) { + return err; + } + + /* route data-ready interrupt on int1 */ + err = lis2dux12_pin_int1_route_get(ctx, &route); + if (err < 0) { + return err; + } + + route.drdy = 1; + + err = lis2dux12_pin_int1_route_set(ctx, &route); + if (err < 0) { + return err; + } + + return 0; +} + +int lis2dux12_trigger_init(const struct device *dev) +{ + struct lis2dux12_data *data = dev->data; + const struct lis2dux12_config *cfg = dev->config; + int ret; + + data->drdy_gpio = (cfg->drdy_pin == 1) ? (struct gpio_dt_spec *)&cfg->int1_gpio + : (struct gpio_dt_spec *)&cfg->int2_gpio; + + /* setup data ready gpio interrupt (INT1 or INT2) */ + if (!gpio_is_ready_dt(data->drdy_gpio)) { + LOG_ERR("Cannot get pointer to drdy_gpio device"); + return -ENODEV; + } + + data->dev = dev; + + ret = gpio_pin_configure_dt(data->drdy_gpio, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Could not configure gpio"); + return ret; + } + + gpio_init_callback(&data->gpio_cb, lis2dux12_gpio_callback, BIT(data->drdy_gpio->pin)); + + ret = gpio_add_callback(data->drdy_gpio->port, &data->gpio_cb); + if (ret < 0) { + LOG_ERR("Could not set gpio callback"); + return ret; + } + +#if defined(CONFIG_LIS2DUX12_TRIGGER_OWN_THREAD) + k_sem_init(&data->trig_sem, 0, K_SEM_MAX_LIMIT); + + k_thread_create(&data->thread, data->thread_stack, CONFIG_LIS2DUX12_THREAD_STACK_SIZE, + (k_thread_entry_t)lis2dux12_thread, data, NULL, NULL, + K_PRIO_COOP(CONFIG_LIS2DUX12_THREAD_PRIORITY), 0, K_NO_WAIT); +#elif defined(CONFIG_LIS2DUX12_TRIGGER_GLOBAL_THREAD) + data->work.handler = lis2dux12_work_cb; +#endif + + return gpio_pin_interrupt_configure_dt(data->drdy_gpio, GPIO_INT_EDGE_TO_ACTIVE); +} + +int lis2dux12_trigger_set(const struct device *dev, const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + struct lis2dux12_data *data = dev->data; + const struct lis2dux12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lis2dux12_xl_data_t xldata; + lis2dux12_md_t mode; + int ret; + + if (!cfg->trig_enabled) { + LOG_ERR("trigger_set op not supported"); + return -ENOTSUP; + } + + if (data->drdy_gpio->port == NULL) { + LOG_ERR("trigger_set is not supported"); + return -ENOTSUP; + } + + ret = gpio_pin_interrupt_configure_dt(data->drdy_gpio, GPIO_INT_DISABLE); + if (ret < 0) { + LOG_ERR("%s: Not able to configure pin_int", dev->name); + return ret; + } + + data->data_ready_handler = handler; + if (handler == NULL) { + LOG_WRN("lis2dux12: no handler"); + return 0; + } + + /* re-trigger lost interrupt */ + lis2dux12_xl_data_get(ctx, &mode, &xldata); + + data->data_ready_trigger = trig; + + lis2dux12_init_interrupt(dev); + return gpio_pin_interrupt_configure_dt(data->drdy_gpio, GPIO_INT_EDGE_TO_ACTIVE); +} diff --git a/dts/bindings/sensor/st,lis2dux12-common.yaml b/dts/bindings/sensor/st,lis2dux12-common.yaml new file mode 100644 index 000000000000000..e9885dd37ae6a4f --- /dev/null +++ b/dts/bindings/sensor/st,lis2dux12-common.yaml @@ -0,0 +1,95 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + When setting the odr, power-mode, and range properties in a .dts or .dtsi file you may include + st_lis2dux12.h and use the macros defined there. + Example: + #include + lis2dux12: lis2dux12@0 { + ... + power-mode = ; + odr = ; + range = ; + }; + +include: sensor-device.yaml + +properties: + int1-gpios: + type: phandle-array + description: | + INT1 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. + int2-gpios: + type: phandle-array + description: | + INT2 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. + + + range: + type: int + default: 0 + description: | + Range in g. Default is power-up configuration. + + - 3 # LIS2DUX12_DT_FS_16G + - 2 # LIS2DUX12_DT_FS_8G + - 1 # LIS2DUX12_DT_FS_4G + - 0 # LIS2DUX12_DT_FS_2G + + enum: [0, 1, 2, 3] + + power-mode: + type: int + default: 0 + description: | + Specify the sensor power mode. Default is power-down mode + + - 0 # LIS2DUX12_OPER_MODE_POWER_DOWN + - 1 # LIS2DUX12_OPER_MODE_LOW_POWER + - 2 # LIS2DUX12_OPER_MODE_HIGH_RESOLUTION + - 3 # LIS2DUX12_OPER_MODE_HIGH_FREQUENCY + + enum: [0, 1, 2, 3] + + odr: + type: int + default: 0 + description: | + Specify the default output data rate expressed in samples per second (Hz). + Default is power-down mode + - 0 # LIS2DUX12_DT_ODR_OFF + - 1 # LIS2DUX12_DT_ODR_1Hz_ULP + - 2 # LIS2DUX12_DT_ODR_3Hz_ULP + - 3 # LIS2DUX12_DT_ODR_25Hz_ULP + - 4 # LIS2DUX12_DT_ODR_6Hz + - 5 # LIS2DUX12_DT_ODR_12Hz5 + - 6 # LIS2DUX12_DT_ODR_25Hz + - 7 # LIS2DUX12_DT_ODR_50Hz + - 8 # LIS2DUX12_DT_ODR_100Hz + - 9 # LIS2DUX12_DT_ODR_200Hz + - 10 # LIS2DUX12_DT_ODR_400Hz + - 11 # LIS2DUX12_DT_ODR_800Hz + + enum: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] diff --git a/dts/bindings/sensor/st,lis2dux12-i2c.yaml b/dts/bindings/sensor/st,lis2dux12-i2c.yaml new file mode 100644 index 000000000000000..8f6535c804dcb0c --- /dev/null +++ b/dts/bindings/sensor/st,lis2dux12-i2c.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: STMicroelectronics LIS2DUX12 3-axis accelerometer + +compatible: "st,lis2dux12" + +include: ["i2c-device.yaml", "st,lis2dux12-common.yaml"] diff --git a/dts/bindings/sensor/st,lis2dux12-spi.yaml b/dts/bindings/sensor/st,lis2dux12-spi.yaml new file mode 100644 index 000000000000000..191a59cfb89e379 --- /dev/null +++ b/dts/bindings/sensor/st,lis2dux12-spi.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LIS2DUX12 3-axis accelerometer accessed through SPI bus + +compatible: "st,lis2dux12" + +include: ["spi-device.yaml", "st,lis2dux12-common.yaml"] diff --git a/include/zephyr/dt-bindings/sensor/lis2dux12.h b/include/zephyr/dt-bindings/sensor/lis2dux12.h new file mode 100644 index 000000000000000..48e8dfbdd4a34eb --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/lis2dux12.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_LIS2DUX12_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_LIS2DUX12_H_ + +#include + +/* Operating Mode */ +#define LIS2DUX12_OPER_MODE_POWER_DOWN 0 +#define LIS2DUX12_OPER_MODE_LOW_POWER 1 +#define LIS2DUX12_OPER_MODE_HIGH_RESOLUTION 2 +#define LIS2DUX12_OPER_MODE_HIGH_FREQUENCY 3 + +/* Data rate */ +#define LIS2DUX12_DT_ODR_OFF 0 +#define LIS2DUX12_DT_ODR_1Hz_ULP 1 /* available in ultra-low power mode */ +#define LIS2DUX12_DT_ODR_3Hz_ULP 2 /* available in ultra-low power mode */ +#define LIS2DUX12_DT_ODR_25Hz_ULP 3 /* available in ultra-low power mode */ +#define LIS2DUX12_DT_ODR_6Hz 4 /* available in LP and HP mode */ +#define LIS2DUX12_DT_ODR_12Hz5 5 /* available in LP and HP mode */ +#define LIS2DUX12_DT_ODR_25Hz 6 /* available in LP and HP mode */ +#define LIS2DUX12_DT_ODR_50Hz 7 /* available in LP and HP mode */ +#define LIS2DUX12_DT_ODR_100Hz 8 /* available in LP and HP mode */ +#define LIS2DUX12_DT_ODR_200Hz 9 /* available in LP and HP mode */ +#define LIS2DUX12_DT_ODR_400Hz 10 /* available in LP and HP mode */ +#define LIS2DUX12_DT_ODR_800Hz 11 /* available in LP and HP mode */ +#define LIS2DUX12_DT_ODR_END 12 + +/* Accelerometer Full-scale */ +#define LIS2DUX12_DT_FS_2G 0 /* 2g (0.061 mg/LSB) */ +#define LIS2DUX12_DT_FS_4G 1 /* 4g (0.122 mg/LSB) */ +#define LIS2DUX12_DT_FS_8G 2 /* 8g (0.244 mg/LSB) */ +#define LIS2DUX12_DT_FS_16G 3 /* 16g (0.488 mg/LSB) */ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_LIS2DUX12_H_ */ diff --git a/modules/hal_st/Kconfig b/modules/hal_st/Kconfig index 020dbdc5d358105..579f7f7d3f8c87a 100644 --- a/modules/hal_st/Kconfig +++ b/modules/hal_st/Kconfig @@ -93,6 +93,9 @@ config USE_STDC_LIS2DTW12 config USE_STDC_LIS2DU12 bool +config USE_STDC_LIS2DUX12 + bool + config USE_STDC_LIS2DW12 bool diff --git a/tests/drivers/build_all/sensor/app.overlay b/tests/drivers/build_all/sensor/app.overlay index 898ae96ec0d6c5a..4a6503ea0ab993b 100644 --- a/tests/drivers/build_all/sensor/app.overlay +++ b/tests/drivers/build_all/sensor/app.overlay @@ -126,7 +126,8 @@ <&test_gpio 0 0>, /* 0x28 */ <&test_gpio 0 0>, /* 0x29 */ <&test_gpio 0 0>, /* 0x2A */ - <&test_gpio 0 0>; /* 0x2B */ + <&test_gpio 0 0>, /* 0x2B */ + <&test_gpio 0 0>; /* 0x2C */ #include "spi.dtsi" }; diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index a51a525fd6fbb49..4773e392c4cbe70 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -1009,5 +1010,15 @@ test_i2c_aht20: aht20@88 { test_i2c_am2301b: am2301b@89 { compatible = "aosong,am2301b"; reg = <0x89>; +}; + +test_i2c_lis2dux12: lis2dux12@8a { + compatible = "st,lis2dux12"; + reg = <0x8a>; + int1-gpios = <&test_gpio 0 0>; + int2-gpios = <&test_gpio 0 0>; + range = ; + odr = ; + power-mode = ; status = "okay"; }; diff --git a/tests/drivers/build_all/sensor/sensors_die_temp.conf b/tests/drivers/build_all/sensor/sensors_die_temp.conf index f66af170c559818..e2e793990433ef4 100644 --- a/tests/drivers/build_all/sensor/sensors_die_temp.conf +++ b/tests/drivers/build_all/sensor/sensors_die_temp.conf @@ -5,5 +5,6 @@ CONFIG_LSM6DSV16X_ENABLE_TEMP=y CONFIG_LSM6DSO_ENABLE_TEMP=y CONFIG_LIS2DE12_ENABLE_TEMP=y CONFIG_LIS2DS12_ENABLE_TEMP=y +CONFIG_LIS2DUX12_ENABLE_TEMP=y CONFIG_LSM6DSO16IS_ENABLE_TEMP=y CONFIG_LSM6DSL_ENABLE_TEMP=y diff --git a/tests/drivers/build_all/sensor/sensors_trigger_global.conf b/tests/drivers/build_all/sensor/sensors_trigger_global.conf index d6cdef2021cb5c9..0f9369de3211d72 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_global.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_global.conf @@ -36,6 +36,7 @@ CONFIG_LIS2DH_TRIGGER_GLOBAL_THREAD=y CONFIG_LIS2DE12_TRIGGER_GLOBAL_THREAD=y CONFIG_LIS2DS12_TRIGGER_GLOBAL_THREAD=y CONFIG_LIS2DU12_TRIGGER_GLOBAL_THREAD=y +CONFIG_LIS2DUX12_TRIGGER_GLOBAL_THREAD=y CONFIG_LIS2DW12_TRIGGER_GLOBAL_THREAD=y CONFIG_LIS2MDL_TRIGGER_GLOBAL_THREAD=y CONFIG_LIS3MDL_TRIGGER_GLOBAL_THREAD=y diff --git a/tests/drivers/build_all/sensor/sensors_trigger_none.conf b/tests/drivers/build_all/sensor/sensors_trigger_none.conf index 375e7d8ebe3f755..3782a0923a39372 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_none.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_none.conf @@ -36,6 +36,7 @@ CONFIG_LIS2DH_TRIGGER_NONE=y CONFIG_LIS2DE12_TRIGGER_NONE=y CONFIG_LIS2DS12_TRIGGER_NONE=y CONFIG_LIS2DU12_TRIGGER_NONE=y +CONFIG_LIS2DUX12_TRIGGER_NONE=y CONFIG_LIS2DW12_TRIGGER_NONE=y CONFIG_LIS2MDL_TRIGGER_NONE=y CONFIG_LIS3MDL_TRIGGER_NONE=y diff --git a/tests/drivers/build_all/sensor/sensors_trigger_own.conf b/tests/drivers/build_all/sensor/sensors_trigger_own.conf index 76691a6994a3932..878a4ba34ab238c 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_own.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_own.conf @@ -34,6 +34,7 @@ CONFIG_LIS2DH_TRIGGER_OWN_THREAD=y CONFIG_LIS2DE12_TRIGGER_OWN_THREAD=y CONFIG_LIS2DS12_TRIGGER_OWN_THREAD=y CONFIG_LIS2DU12_TRIGGER_OWN_THREAD=y +CONFIG_LIS2DUX12_TRIGGER_OWN_THREAD=y CONFIG_LIS2DW12_TRIGGER_OWN_THREAD=y CONFIG_LIS2MDL_TRIGGER_OWN_THREAD=y CONFIG_LIS3MDL_TRIGGER_OWN_THREAD=y diff --git a/tests/drivers/build_all/sensor/spi.dtsi b/tests/drivers/build_all/sensor/spi.dtsi index c7edf35689322ff..aa93793712b04bb 100644 --- a/tests/drivers/build_all/sensor/spi.dtsi +++ b/tests/drivers/build_all/sensor/spi.dtsi @@ -352,3 +352,12 @@ test_spi_bd8lb600fs: bd8lb600fs@2b { #sensor-cells = <0>; }; }; + +test_spi_lis2dux12: lis2dux12@2c { + compatible = "st,lis2dux12"; + reg = <0x2c>; + spi-max-frequency = <0>; + int1-gpios = <&test_gpio 0 0>; + int2-gpios = <&test_gpio 0 0>; + status = "okay"; +};