From 4828340b92a950213a7012cdf68bf34259ff7bf0 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Fri, 12 Jan 2024 13:55:14 +0100 Subject: [PATCH] drivers/sensor: add support to LIS2DE12 accelerometer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The LIS2DE12 is an ultra-low-power high- performance three-axis linear accelerometer belonging to the “femto” family with digital I2C/SPI serial interface standard output. This driver is based on stmemsc HAL i/f v2.3 https://www.st.com/en/datasheet/lis2de12.pdf Signed-off-by: Armando Visconti --- drivers/sensor/CMakeLists.txt | 1 + drivers/sensor/Kconfig | 1 + drivers/sensor/lis2de12/CMakeLists.txt | 12 + drivers/sensor/lis2de12/Kconfig | 30 ++ drivers/sensor/lis2de12/lis2de12.c | 471 ++++++++++++++++++ drivers/sensor/lis2de12/lis2de12.h | 95 ++++ drivers/sensor/lis2de12/lis2de12_trigger.c | 195 ++++++++ dts/bindings/sensor/st,lis2de12-common.yaml | 78 +++ dts/bindings/sensor/st,lis2de12-i2c.yaml | 10 + dts/bindings/sensor/st,lis2de12-spi.yaml | 10 + include/zephyr/dt-bindings/sensor/lis2de12.h | 27 + tests/drivers/build_all/sensor/app.overlay | 3 +- tests/drivers/build_all/sensor/i2c.dtsi | 10 + .../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 + 18 files changed, 955 insertions(+), 1 deletion(-) create mode 100644 drivers/sensor/lis2de12/CMakeLists.txt create mode 100644 drivers/sensor/lis2de12/Kconfig create mode 100644 drivers/sensor/lis2de12/lis2de12.c create mode 100644 drivers/sensor/lis2de12/lis2de12.h create mode 100644 drivers/sensor/lis2de12/lis2de12_trigger.c create mode 100644 dts/bindings/sensor/st,lis2de12-common.yaml create mode 100644 dts/bindings/sensor/st,lis2de12-i2c.yaml create mode 100644 dts/bindings/sensor/st,lis2de12-spi.yaml create mode 100644 include/zephyr/dt-bindings/sensor/lis2de12.h diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index a2c3a0f34cb..effdf205427 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -70,6 +70,7 @@ add_subdirectory_ifdef(CONFIG_ISL29035 isl29035) add_subdirectory_ifdef(CONFIG_ISM330DHCX ism330dhcx) add_subdirectory_ifdef(CONFIG_ITDS wsen_itds) add_subdirectory_ifdef(CONFIG_LIS2DH lis2dh) +add_subdirectory_ifdef(CONFIG_LIS2DE12 lis2de12) add_subdirectory_ifdef(CONFIG_LIS2DS12 lis2ds12) add_subdirectory_ifdef(CONFIG_LIS2DU12 lis2du12) add_subdirectory_ifdef(CONFIG_LIS2DW12 lis2dw12) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index 4a446e59783..c3b682175c8 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -150,6 +150,7 @@ source "drivers/sensor/ism330dhcx/Kconfig" source "drivers/sensor/ite_tach_it8xxx2/Kconfig" source "drivers/sensor/ite_vcmp_it8xxx2/Kconfig" source "drivers/sensor/lis2dh/Kconfig" +source "drivers/sensor/lis2de12/Kconfig" source "drivers/sensor/lis2ds12/Kconfig" source "drivers/sensor/lis2du12/Kconfig" source "drivers/sensor/lis2dw12/Kconfig" diff --git a/drivers/sensor/lis2de12/CMakeLists.txt b/drivers/sensor/lis2de12/CMakeLists.txt new file mode 100644 index 00000000000..d1ae338bc83 --- /dev/null +++ b/drivers/sensor/lis2de12/CMakeLists.txt @@ -0,0 +1,12 @@ +# ST Microelectronics LIS2DE12 3-axis accelerometer sensor driver +# +# Copyright (c) 2024 STMicroelectronics +# +# SPDX-License-Identifier: Apache-2.0 +# +zephyr_library() + +zephyr_library_sources(lis2de12.c) +zephyr_library_sources_ifdef(CONFIG_LIS2DE12_TRIGGER lis2de12_trigger.c) + +zephyr_library_include_directories(../stmemsc) diff --git a/drivers/sensor/lis2de12/Kconfig b/drivers/sensor/lis2de12/Kconfig new file mode 100644 index 00000000000..fe8402ce6e9 --- /dev/null +++ b/drivers/sensor/lis2de12/Kconfig @@ -0,0 +1,30 @@ +# ST Microelectronics LIS2DE12 3-axis accelerometer sensor driver + +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +menuconfig LIS2DE12 + bool "LIS2DE12 I2C/SPI smartxl Chip" + default y + depends on DT_HAS_ST_LIS2DE12_ENABLED + depends on ZEPHYR_HAL_ST_MODULE + select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2DE12),i2c) + select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2DE12),spi) + select HAS_STMEMSC + select USE_STDC_LIS2DE12 + help + Enable driver for LIS2DE12 smartxl sensor. + +if LIS2DE12 + +module = LIS2DE12 +thread_priority = 10 +thread_stack_size = 1024 +source "drivers/sensor/Kconfig.trigger_template" + +config LIS2DE12_ENABLE_TEMP + bool "Die temperature sensor" + help + Enable/disable die temperature sensor + +endif # LIS2DE12 diff --git a/drivers/sensor/lis2de12/lis2de12.c b/drivers/sensor/lis2de12/lis2de12.c new file mode 100644 index 00000000000..9cceccdeb20 --- /dev/null +++ b/drivers/sensor/lis2de12/lis2de12.c @@ -0,0 +1,471 @@ +/* ST Microelectronics LIS2DE12 3-axis accelerometer sensor driver + * + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lis2de12.pdf + */ + +#define DT_DRV_COMPAT st_lis2de12 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lis2de12.h" + +LOG_MODULE_REGISTER(LIS2DE12, CONFIG_SENSOR_LOG_LEVEL); + +static const uint16_t lis2de12_odr_map[10] = { 0, 1, 10, 25, 50, 100, 200, 400, 1620, 5376}; + +static int lis2de12_freq_to_odr_val(const struct device *dev, uint16_t freq) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(lis2de12_odr_map); i++) { + if (freq <= lis2de12_odr_map[i]) { + return i; + } + } + + return -EINVAL; +} + +typedef struct { + uint16_t fs; + uint32_t gain; /* Accel sensor sensitivity in ug/LSB */ +} fs_map; + +static const fs_map lis2de12_accel_fs_map[] = { + {2, 15600}, + {4, 31200}, + {8, 62500}, + {16, 187500}, + }; + +static int lis2de12_accel_range_to_fs_val(int32_t range) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(lis2de12_accel_fs_map); i++) { + if (range == lis2de12_accel_fs_map[i].fs) { + return i; + } + } + + return -EINVAL; +} + +static int lis2de12_accel_set_fs_raw(const struct device *dev, uint8_t fs) +{ + const struct lis2de12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lis2de12_data *data = dev->data; + + if (lis2de12_full_scale_set(ctx, fs) < 0) { + return -EIO; + } + + data->accel_fs = fs; + + return 0; +} + +static int lis2de12_accel_set_odr_raw(const struct device *dev, uint8_t odr) +{ + const struct lis2de12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lis2de12_data *data = dev->data; + + if (lis2de12_data_rate_set(ctx, odr) < 0) { + return -EIO; + } + + data->accel_freq = odr; + + return 0; +} + +static int lis2de12_accel_odr_set(const struct device *dev, uint16_t freq) +{ + int odr; + + odr = lis2de12_freq_to_odr_val(dev, freq); + if (odr < 0) { + return odr; + } + + if (lis2de12_accel_set_odr_raw(dev, odr) < 0) { + LOG_ERR("failed to set accelerometer sampling rate"); + return -EIO; + } + + return 0; +} + +static int lis2de12_accel_range_set(const struct device *dev, int32_t range) +{ + int fs; + struct lis2de12_data *data = dev->data; + + fs = lis2de12_accel_range_to_fs_val(range); + if (fs < 0) { + return fs; + } + + if (lis2de12_accel_set_fs_raw(dev, fs) < 0) { + LOG_ERR("failed to set accelerometer full-scale"); + return -EIO; + } + + data->acc_gain = lis2de12_accel_fs_map[fs].gain; + return 0; +} + +static int lis2de12_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 lis2de12_accel_range_set(dev, sensor_ms2_to_g(val)); + case SENSOR_ATTR_SAMPLING_FREQUENCY: + return lis2de12_accel_odr_set(dev, val->val1); + default: + LOG_WRN("Accel attribute %d not supported.", attr); + return -ENOTSUP; + } +} + +static int lis2de12_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 lis2de12_accel_config(dev, chan, attr, val); + default: + LOG_WRN("attribute %d not supported on this channel.", chan); + return -ENOTSUP; + } +} + +static int lis2de12_sample_fetch_accel(const struct device *dev) +{ + const struct lis2de12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lis2de12_data *data = dev->data; + + if (lis2de12_acceleration_raw_get(ctx, data->acc) < 0) { + LOG_ERR("Failed to read sample"); + return -EIO; + } + + return 0; +} + +#if defined(CONFIG_LIS2DE12_ENABLE_TEMP) +static int lis2de12_sample_fetch_temp(const struct device *dev) +{ + const struct lis2de12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lis2de12_data *data = dev->data; + + if (lis2de12_temperature_raw_get(ctx, &data->temp_sample) < 0) { + LOG_DBG("Failed to read sample"); + return -EIO; + } + + return 0; +} +#endif + +static int lis2de12_sample_fetch(const struct device *dev, + enum sensor_channel chan) +{ + switch (chan) { + case SENSOR_CHAN_ACCEL_XYZ: + lis2de12_sample_fetch_accel(dev); + break; +#if defined(CONFIG_LIS2DE12_ENABLE_TEMP) + case SENSOR_CHAN_DIE_TEMP: + lis2de12_sample_fetch_temp(dev); + break; +#endif + case SENSOR_CHAN_ALL: + lis2de12_sample_fetch_accel(dev); +#if defined(CONFIG_LIS2DE12_ENABLE_TEMP) + lis2de12_sample_fetch_temp(dev); +#endif + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static inline void lis2de12_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 / 256) * sensitivity * SENSOR_G_DOUBLE; + val->val1 = (int32_t)(dval / 1000000); + val->val2 = (int32_t)(dval % 1000000); + +} + +static inline int lis2de12_accel_get_channel(enum sensor_channel chan, + struct sensor_value *val, + struct lis2de12_data *data, + uint32_t sensitivity) +{ + uint8_t i; + + switch (chan) { + case SENSOR_CHAN_ACCEL_X: + lis2de12_accel_convert(val, data->acc[0], sensitivity); + break; + case SENSOR_CHAN_ACCEL_Y: + lis2de12_accel_convert(val, data->acc[1], sensitivity); + break; + case SENSOR_CHAN_ACCEL_Z: + lis2de12_accel_convert(val, data->acc[2], sensitivity); + break; + case SENSOR_CHAN_ACCEL_XYZ: + for (i = 0; i < 3; i++) { + lis2de12_accel_convert(val++, data->acc[i], sensitivity); + } + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static int lis2de12_accel_channel_get(enum sensor_channel chan, + struct sensor_value *val, + struct lis2de12_data *data) +{ + return lis2de12_accel_get_channel(chan, val, data, data->acc_gain); +} + +#if defined(CONFIG_LIS2DE12_ENABLE_TEMP) +static void lis2de12_temp_channel_get(struct sensor_value *val, struct lis2de12_data *data) +{ + int64_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 = ((int64_t)data->temp_sample * 1000000) / 256; + + val->val1 = micro_c / 1000000 + 25; + val->val2 = micro_c % 1000000; +} +#endif + +static int lis2de12_channel_get(const struct device *dev, + enum sensor_channel chan, + struct sensor_value *val) +{ + struct lis2de12_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: + lis2de12_accel_channel_get(chan, val, data); + break; +#if defined(CONFIG_LIS2DE12_ENABLE_TEMP) + case SENSOR_CHAN_DIE_TEMP: + lis2de12_temp_channel_get(val, data); + break; +#endif + default: + return -ENOTSUP; + } + + return 0; +} + +static const struct sensor_driver_api lis2de12_driver_api = { + .attr_set = lis2de12_attr_set, +#if CONFIG_LIS2DE12_TRIGGER + .trigger_set = lis2de12_trigger_set, +#endif + .sample_fetch = lis2de12_sample_fetch, + .channel_get = lis2de12_channel_get, +}; + +static int lis2de12_init_chip(const struct device *dev) +{ + const struct lis2de12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lis2de12_data *lis2de12 = dev->data; + uint8_t chip_id; + uint8_t odr, fs; + + if (lis2de12_device_id_get(ctx, &chip_id) < 0) { + LOG_ERR("Failed reading chip id"); + return -EIO; + } + + if (chip_id != LIS2DE12_ID) { + LOG_ERR("Invalid chip id 0x%x", chip_id); + return -EIO; + } + + LOG_INF("chip id 0x%x", chip_id); + + if (lis2de12_block_data_update_set(ctx, 1) < 0) { + LOG_ERR("failed to set BDU"); + return -EIO; + } + + /* set FS from DT */ + fs = cfg->accel_range; + LOG_DBG("accel range is %d", fs); + if (lis2de12_accel_set_fs_raw(dev, fs) < 0) { + LOG_ERR("failed to set accelerometer range %d", fs); + return -EIO; + } + lis2de12->acc_gain = lis2de12_accel_fs_map[fs].gain; + + /* set odr from DT (the only way to go in high performance) */ + odr = cfg->accel_odr; + LOG_DBG("accel odr is %d", odr); + if (lis2de12_accel_set_odr_raw(dev, odr) < 0) { + LOG_ERR("failed to set accelerometer odr %d", odr); + return -EIO; + } + +#if defined(CONFIG_LIS2DE12_ENABLE_TEMP) + lis2de12_temperature_meas_set(ctx, LIS2DE12_TEMP_ENABLE); +#endif + + return 0; +} + +static int lis2de12_init(const struct device *dev) +{ +#ifdef CONFIG_LIS2DE12_TRIGGER + const struct lis2de12_config *cfg = dev->config; +#endif + struct lis2de12_data *data = dev->data; + + LOG_INF("Initialize device %s", dev->name); + data->dev = dev; + + if (lis2de12_init_chip(dev) < 0) { + LOG_ERR("failed to initialize chip"); + return -EIO; + } + +#ifdef CONFIG_LIS2DE12_TRIGGER + if (cfg->trig_enabled) { + if (lis2de12_init_interrupt(dev) < 0) { + LOG_ERR("Failed to initialize interrupt."); + return -EIO; + } + } +#endif + + return 0; +} + +/* + * Device creation macro, shared by LIS2DE12_DEFINE_SPI() and + * LIS2DE12_DEFINE_I2C(). + */ + +#define LIS2DE12_DEVICE_INIT(inst) \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, \ + lis2de12_init, \ + NULL, \ + &lis2de12_data_##inst, \ + &lis2de12_config_##inst, \ + POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, \ + &lis2de12_driver_api); + +/* + * Instantiation macros used when a device is on a SPI bus. + */ + +#ifdef CONFIG_LIS2DE12_TRIGGER +#define LIS2DE12_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_pulsed = DT_INST_PROP(inst, drdy_pulsed) +#else +#define LIS2DE12_CFG_IRQ(inst) +#endif /* CONFIG_LIS2DE12_TRIGGER */ + +#define LIS2DE12_SPI_OP (SPI_WORD_SET(8) | \ + SPI_OP_MODE_MASTER | \ + SPI_MODE_CPOL | \ + SPI_MODE_CPHA) \ + +#define LIS2DE12_CONFIG_COMMON(inst) \ + .accel_odr = DT_INST_PROP(inst, accel_odr), \ + .accel_range = DT_INST_PROP(inst, accel_range), \ + IF_ENABLED(UTIL_OR(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \ + DT_INST_NODE_HAS_PROP(inst, int2_gpios)), \ + (LIS2DE12_CFG_IRQ(inst))) + +/* + * Instantiation macros used when a device is on a SPI bus. + */ + +#define LIS2DE12_CONFIG_SPI(inst) \ + { \ + STMEMSC_CTX_SPI(&lis2de12_config_##inst.stmemsc_cfg), \ + .stmemsc_cfg = { \ + .spi = SPI_DT_SPEC_INST_GET(inst, LIS2DE12_SPI_OP, 0), \ + }, \ + LIS2DE12_CONFIG_COMMON(inst) \ + } + +/* + * Instantiation macros used when a device is on an I2C bus. + */ + +#define LIS2DE12_CONFIG_I2C(inst) \ + { \ + STMEMSC_CTX_I2C_INCR(&lis2de12_config_##inst.stmemsc_cfg), \ + .stmemsc_cfg = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + }, \ + LIS2DE12_CONFIG_COMMON(inst) \ + } + +/* + * Main instantiation macro. Use of COND_CODE_1() selects the right + * bus-specific macro at preprocessor time. + */ + +#define LIS2DE12_DEFINE(inst) \ + static struct lis2de12_data lis2de12_data_##inst; \ + static const struct lis2de12_config lis2de12_config_##inst = \ + COND_CODE_1(DT_INST_ON_BUS(inst, spi), \ + (LIS2DE12_CONFIG_SPI(inst)), \ + (LIS2DE12_CONFIG_I2C(inst))); \ + LIS2DE12_DEVICE_INIT(inst) + +DT_INST_FOREACH_STATUS_OKAY(LIS2DE12_DEFINE) diff --git a/drivers/sensor/lis2de12/lis2de12.h b/drivers/sensor/lis2de12/lis2de12.h new file mode 100644 index 00000000000..575fd50f962 --- /dev/null +++ b/drivers/sensor/lis2de12/lis2de12.h @@ -0,0 +1,95 @@ +/* ST Microelectronics LIS2DE12 3-axis accelerometer sensor driver + * + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lis2de12.pdf + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_LIS2DE12_LIS2DE12_H_ +#define ZEPHYR_DRIVERS_SENSOR_LIS2DE12_LIS2DE12_H_ + +#include +#include +#include +#include +#include +#include "lis2de12_reg.h" + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) +#include +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) +#include +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */ + +#define LIS2DE12_EN_BIT 0x01 +#define LIS2DE12_DIS_BIT 0x00 + +#define SENSOR_G_DOUBLE (SENSOR_G / 1000000.0) + +struct lis2de12_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 drdy_pulsed; +#ifdef CONFIG_LIS2DE12_TRIGGER + const struct gpio_dt_spec int1_gpio; + const struct gpio_dt_spec int2_gpio; + bool trig_enabled; +#endif /* CONFIG_LIS2DE12_TRIGGER */ +}; + +union samples { + uint8_t raw[6]; + struct { + int16_t axis[3]; + }; +} __aligned(2); + +struct lis2de12_data { + const struct device *dev; + int16_t acc[3]; + int16_t temp_sample; + uint32_t acc_gain; + uint8_t accel_freq; + uint8_t accel_fs; + +#ifdef CONFIG_LIS2DE12_TRIGGER + struct gpio_dt_spec *drdy_gpio; + + struct gpio_callback gpio_cb; + sensor_trigger_handler_t handler_drdy_acc; + const struct sensor_trigger *trig_drdy_acc; + +#if defined(CONFIG_LIS2DE12_TRIGGER_OWN_THREAD) + K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LIS2DE12_THREAD_STACK_SIZE); + struct k_thread thread; + struct k_sem gpio_sem; +#elif defined(CONFIG_LIS2DE12_TRIGGER_GLOBAL_THREAD) + struct k_work work; +#endif +#endif /* CONFIG_LIS2DE12_TRIGGER */ +}; + +#ifdef CONFIG_LIS2DE12_TRIGGER +int lis2de12_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); + +int lis2de12_init_interrupt(const struct device *dev); +#endif + +#endif /* ZEPHYR_DRIVERS_SENSOR_LIS2DE12_LIS2DE12_H_ */ diff --git a/drivers/sensor/lis2de12/lis2de12_trigger.c b/drivers/sensor/lis2de12/lis2de12_trigger.c new file mode 100644 index 00000000000..feee823bb91 --- /dev/null +++ b/drivers/sensor/lis2de12/lis2de12_trigger.c @@ -0,0 +1,195 @@ +/* ST Microelectronics LIS2DE12 3-axis accelerometer sensor driver + * + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lis2de12.pdf + */ + +#define DT_DRV_COMPAT st_lis2de12 + +#include +#include +#include +#include + +#include "lis2de12.h" + +LOG_MODULE_DECLARE(LIS2DE12, CONFIG_SENSOR_LOG_LEVEL); + +/** + * lis2de12_enable_xl_int - XL enable selected int pin to generate interrupt + */ +static int lis2de12_enable_xl_int(const struct device *dev, int enable) +{ + const struct lis2de12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lis2de12_ctrl_reg3_t val = {0}; + int ret; + + if (enable) { + int16_t xl_data[3]; + + /* dummy read: re-trigger interrupt */ + lis2de12_acceleration_raw_get(ctx, xl_data); + } + + /* set interrupt */ + ret = lis2de12_pin_int1_config_get(ctx, &val); + if (ret < 0) { + LOG_ERR("pint_int1_route_get error"); + return ret; + } + + val.i1_zyxda = 1; + + return lis2de12_pin_int1_config_set(ctx, &val); +} + +/** + * lis2de12_trigger_set - link external trigger to event data ready + */ +int lis2de12_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + const struct lis2de12_config *cfg = dev->config; + struct lis2de12_data *lis2de12 = dev->data; + + if (!cfg->trig_enabled) { + LOG_ERR("trigger_set op not supported"); + return -ENOTSUP; + } + + switch (trig->chan) { + case SENSOR_CHAN_ACCEL_XYZ: + lis2de12->handler_drdy_acc = handler; + lis2de12->trig_drdy_acc = trig; + if (handler) { + return lis2de12_enable_xl_int(dev, LIS2DE12_EN_BIT); + } + + return lis2de12_enable_xl_int(dev, LIS2DE12_DIS_BIT); + + default: + return -ENOTSUP; + } + +} + +/** + * lis2de12_handle_interrupt - handle the drdy event + * read data and call handler if registered any + */ +static void lis2de12_handle_interrupt(const struct device *dev) +{ + struct lis2de12_data *lis2de12 = dev->data; + const struct lis2de12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lis2de12_status_reg_t status; + + while (1) { + if (lis2de12_status_get(ctx, &status) < 0) { + LOG_ERR("failed reading status reg"); + return; + } + + if (status.zyxda == 0) { + /* spurious interrupt */ + break; + } + + if ((status.zyxda) && (lis2de12->handler_drdy_acc != NULL)) { + lis2de12->handler_drdy_acc(dev, lis2de12->trig_drdy_acc); + } + } + + gpio_pin_interrupt_configure_dt(lis2de12->drdy_gpio, + GPIO_INT_EDGE_TO_ACTIVE); +} + +static void lis2de12_gpio_callback(const struct device *dev, + struct gpio_callback *cb, uint32_t pins) +{ + struct lis2de12_data *lis2de12 = + CONTAINER_OF(cb, struct lis2de12_data, gpio_cb); + + ARG_UNUSED(pins); + + gpio_pin_interrupt_configure_dt(lis2de12->drdy_gpio, GPIO_INT_DISABLE); + +#if defined(CONFIG_LIS2DE12_TRIGGER_OWN_THREAD) + k_sem_give(&lis2de12->gpio_sem); +#elif defined(CONFIG_LIS2DE12_TRIGGER_GLOBAL_THREAD) + k_work_submit(&lis2de12->work); +#endif /* CONFIG_LIS2DE12_TRIGGER_OWN_THREAD */ +} + +#ifdef CONFIG_LIS2DE12_TRIGGER_OWN_THREAD +static void lis2de12_thread(struct lis2de12_data *lis2de12) +{ + while (1) { + k_sem_take(&lis2de12->gpio_sem, K_FOREVER); + lis2de12_handle_interrupt(lis2de12->dev); + } +} +#endif /* CONFIG_LIS2DE12_TRIGGER_OWN_THREAD */ + +#ifdef CONFIG_LIS2DE12_TRIGGER_GLOBAL_THREAD +static void lis2de12_work_cb(struct k_work *work) +{ + struct lis2de12_data *lis2de12 = + CONTAINER_OF(work, struct lis2de12_data, work); + + lis2de12_handle_interrupt(lis2de12->dev); +} +#endif /* CONFIG_LIS2DE12_TRIGGER_GLOBAL_THREAD */ + +int lis2de12_init_interrupt(const struct device *dev) +{ + struct lis2de12_data *lis2de12 = dev->data; + const struct lis2de12_config *cfg = dev->config; + int ret; + + lis2de12->drdy_gpio = (struct gpio_dt_spec *)&cfg->int1_gpio; + + /* setup data ready gpio interrupt */ + if (!gpio_is_ready_dt(lis2de12->drdy_gpio)) { + LOG_ERR("Cannot get pointer to drdy_gpio device (%p)", + lis2de12->drdy_gpio); + return -EINVAL; + } + +#if defined(CONFIG_LIS2DE12_TRIGGER_OWN_THREAD) + k_sem_init(&lis2de12->gpio_sem, 0, K_SEM_MAX_LIMIT); + + k_thread_create(&lis2de12->thread, lis2de12->thread_stack, + CONFIG_LIS2DE12_THREAD_STACK_SIZE, + (k_thread_entry_t)lis2de12_thread, lis2de12, + NULL, NULL, K_PRIO_COOP(CONFIG_LIS2DE12_THREAD_PRIORITY), + 0, K_NO_WAIT); + k_thread_name_set(&lis2de12->thread, dev->name); +#elif defined(CONFIG_LIS2DE12_TRIGGER_GLOBAL_THREAD) + lis2de12->work.handler = lis2de12_work_cb; +#endif /* CONFIG_LIS2DE12_TRIGGER_OWN_THREAD */ + + ret = gpio_pin_configure_dt(lis2de12->drdy_gpio, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Could not configure gpio: %d", ret); + return ret; + } + + gpio_init_callback(&lis2de12->gpio_cb, + lis2de12_gpio_callback, + BIT(lis2de12->drdy_gpio->pin)); + + if (gpio_add_callback(lis2de12->drdy_gpio->port, &lis2de12->gpio_cb) < 0) { + LOG_ERR("Could not set gpio callback"); + return -EIO; + } + + return gpio_pin_interrupt_configure_dt(lis2de12->drdy_gpio, + GPIO_INT_EDGE_TO_ACTIVE); +} diff --git a/dts/bindings/sensor/st,lis2de12-common.yaml b/dts/bindings/sensor/st,lis2de12-common.yaml new file mode 100644 index 00000000000..502efd15bdd --- /dev/null +++ b/dts/bindings/sensor/st,lis2de12-common.yaml @@ -0,0 +1,78 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + When setting the accel-range, accel-odr, properties in a .dts or .dtsi + file you may include lis2de12.h and use the macros defined there. + + Example: + #include + + lis2de12: lis2de12@0 { + ... + + accel-range = ; + accel-odr = ; + }; + +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. + + accel-range: + type: int + default: 0 + description: | + Range in g. Default is power-up configuration. + + 0 # LIS2DE12_DT_FS_2G (15.6 mg/LSB) + 1 # LIS2DE12_DT_FS_4G (31.2 mg/LSB) + 2 # LIS2DE12_DT_FS_8G (62.5 mg/LSB) + 3 # LIS2DE12_DT_FS_16G (187.5 mg/LSB) + + enum: [0, 1, 2, 3] + + 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 lis2de12_md_t enumerative in hal/st + module. Please note that this values will also enable/disable High performance mode. + Default is power-up configuration. + + 0x00 # LIS2DE12_DT_ODR_OFF + 0x01 # LIS2DE12_DT_ODR_AT_1Hz + 0x02 # LIS2DE12_DT_ODR_AT_10Hz + 0x03 # LIS2DE12_DT_ODR_AT_25Hz + 0x04 # LIS2DE12_DT_ODR_AT_50Hz + 0x05 # LIS2DE12_DT_ODR_AT_100Hz + 0x06 # LIS2DE12_DT_ODR_AT_200Hz + 0x07 # LIS2DE12_DT_ODR_AT_400Hz + 0x08 # LIS2DE12_DT_ODR_AT_1kHz620 + 0x09 # LIS2DE12_DT_ODR_AT_5kHz376 + + enum: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09] + + drdy-pulsed: + type: boolean + description: | + Selects the pulsed mode for data-ready interrupt when enabled, + and the latched mode when disabled. diff --git a/dts/bindings/sensor/st,lis2de12-i2c.yaml b/dts/bindings/sensor/st,lis2de12-i2c.yaml new file mode 100644 index 00000000000..3e1b5b70f35 --- /dev/null +++ b/dts/bindings/sensor/st,lis2de12-i2c.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LIS2DE12 3-axis ultra-low power accelerometer sensor + accessed through I2C bus + +compatible: "st,lis2de12" + +include: ["i2c-device.yaml", "st,lis2de12-common.yaml"] diff --git a/dts/bindings/sensor/st,lis2de12-spi.yaml b/dts/bindings/sensor/st,lis2de12-spi.yaml new file mode 100644 index 00000000000..525d587279a --- /dev/null +++ b/dts/bindings/sensor/st,lis2de12-spi.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LIS2DE12 3-axis ultra-low power accelerometer sensor + accessed through SPI bus + +compatible: "st,lis2de12" + +include: ["spi-device.yaml", "st,lis2de12-common.yaml"] diff --git a/include/zephyr/dt-bindings/sensor/lis2de12.h b/include/zephyr/dt-bindings/sensor/lis2de12.h new file mode 100644 index 00000000000..afc1b8ee931 --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/lis2de12.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DE12_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DE12_H_ + +/* Accel range */ +#define LIS2DE12_DT_FS_2G 0 +#define LIS2DE12_DT_FS_4G 1 +#define LIS2DE12_DT_FS_8G 2 +#define LIS2DE12_DT_FS_16G 3 + +/* Accel rates */ +#define LIS2DE12_DT_ODR_OFF 0x00 /* Power-Down */ +#define LIS2DE12_DT_ODR_AT_1Hz 0x01 /* 1Hz (normal) */ +#define LIS2DE12_DT_ODR_AT_10Hz 0x02 /* 10Hz (normal) */ +#define LIS2DE12_DT_ODR_AT_25Hz 0x03 /* 25Hz (normal) */ +#define LIS2DE12_DT_ODR_AT_50Hz 0x04 /* 50Hz (normal) */ +#define LIS2DE12_DT_ODR_AT_100Hz 0x05 /* 100Hz (normal) */ +#define LIS2DE12_DT_ODR_AT_200Hz 0x06 /* 200Hz (normal) */ +#define LIS2DE12_DT_ODR_AT_400Hz 0x07 /* 400Hz (normal) */ +#define LIS2DE12_DT_ODR_AT_1kHz620 0x08 /* 1KHz620 (normal) */ +#define LIS2DE12_DT_ODR_AT_5kHz376 0x09 /* 5KHz376 (normal) */ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DE12_H_ */ diff --git a/tests/drivers/build_all/sensor/app.overlay b/tests/drivers/build_all/sensor/app.overlay index c836a2b5fa8..e70d62e666d 100644 --- a/tests/drivers/build_all/sensor/app.overlay +++ b/tests/drivers/build_all/sensor/app.overlay @@ -123,7 +123,8 @@ <&test_gpio 0 0>, /* 0x25 */ <&test_gpio 0 0>, /* 0x26 */ <&test_gpio 0 0>, /* 0x27 */ - <&test_gpio 0 0>; /* 0x28 */ + <&test_gpio 0 0>, /* 0x28 */ + <&test_gpio 0 0>; /* 0x29 */ #include "spi.dtsi" }; diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 4de9e954c1e..0a10dec83d3 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 /**************************************** * PLEASE KEEP REG ADDRESSES SEQUENTIAL * @@ -895,3 +896,12 @@ test_i2c_bmp581: bmp581@7f { reg = <0x7f>; int-gpios = <&test_gpio 0 0>; }; + +test_i2c_lis2de12: lis2de12@80 { + compatible = "st,lis2de12"; + reg = <0x80>; + int1-gpios = <&test_gpio 0 0>; + int2-gpios = <&test_gpio 0 0>; + accel-range = ; + accel-odr = ; +}; diff --git a/tests/drivers/build_all/sensor/sensors_die_temp.conf b/tests/drivers/build_all/sensor/sensors_die_temp.conf index 1d629e9b94f..f66af170c55 100644 --- a/tests/drivers/build_all/sensor/sensors_die_temp.conf +++ b/tests/drivers/build_all/sensor/sensors_die_temp.conf @@ -3,6 +3,7 @@ CONFIG_IIS2ICLX_ENABLE_TEMP=y CONFIG_LSM6DS0_ENABLE_TEMP=y CONFIG_LSM6DSV16X_ENABLE_TEMP=y CONFIG_LSM6DSO_ENABLE_TEMP=y +CONFIG_LIS2DE12_ENABLE_TEMP=y CONFIG_LIS2DS12_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 2dc30736420..ed045efbfb3 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_global.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_global.conf @@ -32,6 +32,7 @@ CONFIG_IIS3DHHC_TRIGGER_GLOBAL_THREAD=y CONFIG_ISL29035_TRIGGER_GLOBAL_THREAD=y CONFIG_ISM330DHCX_TRIGGER_GLOBAL_THREAD=y 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_LIS2DW12_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 3012c09845b..a9036f88ca4 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_none.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_none.conf @@ -32,6 +32,7 @@ CONFIG_IIS3DHHC_TRIGGER_NONE=y CONFIG_ISL29035_TRIGGER_NONE=y CONFIG_ISM330DHCX_TRIGGER_NONE=y CONFIG_LIS2DH_TRIGGER_NONE=y +CONFIG_LIS2DE12_TRIGGER_NONE=y CONFIG_LIS2DS12_TRIGGER_NONE=y CONFIG_LIS2DU12_TRIGGER_NONE=y CONFIG_LIS2DW12_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 79ee1f82eae..1ffe64cf304 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_own.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_own.conf @@ -30,6 +30,7 @@ CONFIG_IIS3DHHC_TRIGGER_OWN_THREAD=y CONFIG_ISL29035_TRIGGER_OWN_THREAD=y CONFIG_ISM330DHCX_TRIGGER_OWN_THREAD=y 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_LIS2DW12_TRIGGER_OWN_THREAD=y diff --git a/tests/drivers/build_all/sensor/spi.dtsi b/tests/drivers/build_all/sensor/spi.dtsi index 120b990fccd..0cbef7f130f 100644 --- a/tests/drivers/build_all/sensor/spi.dtsi +++ b/tests/drivers/build_all/sensor/spi.dtsi @@ -321,3 +321,12 @@ test_spi_lis2du12: lis2du12@28 { int2-gpios = <&test_gpio 0 0>; status = "okay"; }; + +test_spi_lis2de12: lis2de12@29 { + compatible = "st,lis2de12"; + reg = <0x29>; + spi-max-frequency = <0>; + int1-gpios = <&test_gpio 0 0>; + int2-gpios = <&test_gpio 0 0>; + status = "okay"; +};