drivers/sensor: add support to LIS2DE12 accelerometer

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 <armando.visconti@st.com>
This commit is contained in:
Armando Visconti 2024-01-12 13:55:14 +01:00 committed by Henrik Brix Andersen
commit 4828340b92
18 changed files with 955 additions and 1 deletions

View file

@ -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)

View file

@ -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"

View file

@ -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)

View file

@ -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

View file

@ -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 <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 "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)

View file

@ -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 <zephyr/drivers/sensor.h>
#include <zephyr/types.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/sys/util.h>
#include <stmemsc.h>
#include "lis2de12_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 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_ */

View file

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

View file

@ -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 <zephyr/dt-bindings/sensor/lis2de12.h>
lis2de12: lis2de12@0 {
...
accel-range = <LIS2DE12_DT_FS_16G>;
accel-odr = <LIS2DE12_DT_ODR_AT_100Hz>;
};
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.

View file

@ -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"]

View file

@ -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"]

View file

@ -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_ */

View file

@ -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"
};

View file

@ -18,6 +18,7 @@
#include <zephyr/dt-bindings/sensor/lis2dh.h>
#include <zephyr/dt-bindings/sensor/iis2iclx.h>
#include <zephyr/dt-bindings/sensor/lis2du12.h>
#include <zephyr/dt-bindings/sensor/lis2de12.h>
/****************************************
* 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 = <LIS2DE12_DT_FS_16G>;
accel-odr = <LIS2DE12_DT_ODR_AT_100Hz>;
};

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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";
};