drivers/sensor: add support to LIS2DU12 accelerometer

The LIS2DU12 is a linear 3-axis accelerometer with advanced digital
functions whose MEMS and ASIC have been expressly designed to build
an outstanding ultralow-power architecture in which the anti-aliasing
filter operates with a current consumption among the lowest in the
market.
This driver is based on stmemsc HAL i/f v2.3

https://www.st.com/en/datasheet/lis2du12.pdf

Signed-off-by: Armando Visconti <armando.visconti@st.com>
This commit is contained in:
Armando Visconti 2023-11-15 16:18:34 +01:00 committed by Carles Cufí
parent 858007dc93
commit 1badec4bfd
18 changed files with 997 additions and 1 deletions

View file

@ -68,6 +68,7 @@ add_subdirectory_ifdef(CONFIG_ISM330DHCX ism330dhcx)
add_subdirectory_ifdef(CONFIG_ITDS wsen_itds)
add_subdirectory_ifdef(CONFIG_LIS2DH lis2dh)
add_subdirectory_ifdef(CONFIG_LIS2DS12 lis2ds12)
add_subdirectory_ifdef(CONFIG_LIS2DU12 lis2du12)
add_subdirectory_ifdef(CONFIG_LIS2DW12 lis2dw12)
add_subdirectory_ifdef(CONFIG_LIS2MDL lis2mdl)
add_subdirectory_ifdef(CONFIG_LIS3MDL lis3mdl)

View file

@ -140,6 +140,7 @@ source "drivers/sensor/ite_tach_it8xxx2/Kconfig"
source "drivers/sensor/ite_vcmp_it8xxx2/Kconfig"
source "drivers/sensor/lis2dh/Kconfig"
source "drivers/sensor/lis2ds12/Kconfig"
source "drivers/sensor/lis2du12/Kconfig"
source "drivers/sensor/lis2dw12/Kconfig"
source "drivers/sensor/lis2mdl/Kconfig"
source "drivers/sensor/lis3mdl/Kconfig"

View file

@ -0,0 +1,12 @@
# ST Microelectronics LIS2DU12 3-axis accelerometer sensor driver
#
# Copyright (c) 2023 STMicroelectronics
#
# SPDX-License-Identifier: Apache-2.0
#
zephyr_library()
zephyr_library_sources(lis2du12.c)
zephyr_library_sources_ifdef(CONFIG_LIS2DU12_TRIGGER lis2du12_trigger.c)
zephyr_library_include_directories(../stmemsc)

View file

@ -0,0 +1,24 @@
# ST Microelectronics LIS2DU12 3-axis accelerometer sensor driver
# Copyright (c) 2023 STMicroelectronics
# SPDX-License-Identifier: Apache-2.0
menuconfig LIS2DU12
bool "LIS2DU12 I2C/SPI smartxl Chip"
default y
depends on DT_HAS_ST_LIS2DU12_ENABLED
select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2DU12),i2c)
select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2DU12),spi)
select HAS_STMEMSC
select USE_STDC_LIS2DU12
help
Enable driver for LIS2DU12 smartxl sensor.
if LIS2DU12
module = LIS2DU12
thread_priority = 10
thread_stack_size = 1024
source "drivers/sensor/Kconfig.trigger_template"
endif # LIS2DU12

View file

@ -0,0 +1,471 @@
/* ST Microelectronics LIS2DU12 3-axis accelerometer sensor driver
*
* Copyright (c) 2023 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*
* Datasheet:
* https://www.st.com/resource/en/datasheet/lis2du12.pdf
*/
#define DT_DRV_COMPAT st_lis2du12
#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 "lis2du12.h"
LOG_MODULE_REGISTER(LIS2DU12, CONFIG_SENSOR_LOG_LEVEL);
static const float lis2du12_odr_map[14] = {
0.0f, 1.6f, 3.0f, 6.0f, 6.0f, 12.5f, 25.0f,
50.0f, 100.0f, 200.0f, 400.0f, 800.0f, 0.0f, 0.0f};
static int lis2du12_freq_to_odr_val(const struct device *dev, uint16_t freq)
{
size_t i;
for (i = 0; i < ARRAY_SIZE(lis2du12_odr_map); i++) {
if (freq <= lis2du12_odr_map[i]) {
return i;
}
}
return -EINVAL;
}
static const uint16_t lis2du12_accel_fs_map[] = {2, 4, 8, 16};
static int lis2du12_accel_range_to_fs_val(int32_t range)
{
size_t i;
for (i = 0; i < ARRAY_SIZE(lis2du12_accel_fs_map); i++) {
if (range == lis2du12_accel_fs_map[i]) {
return i;
}
}
return -EINVAL;
}
static inline int lis2du12_reboot(const struct device *dev)
{
const struct lis2du12_config *cfg = dev->config;
stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
lis2du12_status_t status;
uint8_t tries = 10;
if (lis2du12_init_set(ctx, LIS2DU12_RESET) < 0) {
return -EIO;
}
do {
if (!--tries) {
LOG_ERR("sw reset timed out");
return -ETIMEDOUT;
}
k_usleep(50);
if (lis2du12_status_get(ctx, &status) < 0) {
return -EIO;
}
} while (status.sw_reset != 0);
if (lis2du12_init_set(ctx, LIS2DU12_DRV_RDY) < 0) {
return -EIO;
}
return 0;
}
static int lis2du12_accel_set_fs_raw(const struct device *dev, uint8_t fs)
{
const struct lis2du12_config *cfg = dev->config;
stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
struct lis2du12_data *data = dev->data;
lis2du12_md_t mode;
if (lis2du12_mode_get(ctx, &mode) < 0) {
return -EIO;
}
mode.fs = fs;
if (lis2du12_mode_set(ctx, &mode) < 0) {
return -EIO;
}
data->accel_fs = fs;
return 0;
}
static int lis2du12_accel_set_odr_raw(const struct device *dev, uint8_t odr)
{
const struct lis2du12_config *cfg = dev->config;
stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
struct lis2du12_data *data = dev->data;
lis2du12_md_t mode;
if (lis2du12_mode_get(ctx, &mode) < 0) {
return -EIO;
}
mode.odr = odr;
if (lis2du12_mode_set(ctx, &mode) < 0) {
return -EIO;
}
data->accel_freq = odr;
return 0;
}
static int lis2du12_accel_odr_set(const struct device *dev, uint16_t freq)
{
int odr;
odr = lis2du12_freq_to_odr_val(dev, freq);
if (odr < 0) {
return odr;
}
if (lis2du12_accel_set_odr_raw(dev, odr) < 0) {
LOG_ERR("failed to set accelerometer sampling rate");
return -EIO;
}
return 0;
}
static int lis2du12_accel_range_set(const struct device *dev, int32_t range)
{
int fs;
struct lis2du12_data *data = dev->data;
fs = lis2du12_accel_range_to_fs_val(range);
if (fs < 0) {
return fs;
}
if (lis2du12_accel_set_fs_raw(dev, fs) < 0) {
LOG_ERR("failed to set accelerometer full-scale");
return -EIO;
}
data->acc_gain = lis2du12_accel_fs_map[fs] * GAIN_UNIT_XL / 2;
return 0;
}
static int lis2du12_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 lis2du12_accel_range_set(dev, sensor_ms2_to_g(val));
case SENSOR_ATTR_SAMPLING_FREQUENCY:
return lis2du12_accel_odr_set(dev, val->val1);
default:
LOG_WRN("Accel attribute %d not supported.", attr);
return -ENOTSUP;
}
return 0;
}
static int lis2du12_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 lis2du12_accel_config(dev, chan, attr, val);
default:
LOG_WRN("attribute %d not supported on this channel.", chan);
return -ENOTSUP;
}
return 0;
}
static int lis2du12_sample_fetch_accel(const struct device *dev)
{
const struct lis2du12_config *cfg = dev->config;
stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
struct lis2du12_data *data = dev->data;
lis2du12_data_t xl_data;
lis2du12_md_t md;
md.fs = cfg->accel_range;
if (lis2du12_data_get(ctx, &md, &xl_data) < 0) {
LOG_ERR("Failed to read sample");
return -EIO;
}
data->acc[0] = xl_data.xl.raw[0];
data->acc[1] = xl_data.xl.raw[1];
data->acc[2] = xl_data.xl.raw[2];
return 0;
}
static int lis2du12_sample_fetch(const struct device *dev,
enum sensor_channel chan)
{
switch (chan) {
case SENSOR_CHAN_ACCEL_XYZ:
lis2du12_sample_fetch_accel(dev);
break;
case SENSOR_CHAN_ALL:
lis2du12_sample_fetch_accel(dev);
break;
default:
return -ENOTSUP;
}
return 0;
}
static inline void lis2du12_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 lis2du12_accel_get_channel(enum sensor_channel chan,
struct sensor_value *val,
struct lis2du12_data *data,
uint32_t sensitivity)
{
uint8_t i;
switch (chan) {
case SENSOR_CHAN_ACCEL_X:
lis2du12_accel_convert(val, data->acc[0], sensitivity);
break;
case SENSOR_CHAN_ACCEL_Y:
lis2du12_accel_convert(val, data->acc[1], sensitivity);
break;
case SENSOR_CHAN_ACCEL_Z:
lis2du12_accel_convert(val, data->acc[2], sensitivity);
break;
case SENSOR_CHAN_ACCEL_XYZ:
for (i = 0; i < 3; i++) {
lis2du12_accel_convert(val++, data->acc[i], sensitivity);
}
break;
default:
return -ENOTSUP;
}
return 0;
}
static int lis2du12_accel_channel_get(enum sensor_channel chan,
struct sensor_value *val,
struct lis2du12_data *data)
{
return lis2du12_accel_get_channel(chan, val, data, data->acc_gain);
}
static int lis2du12_channel_get(const struct device *dev,
enum sensor_channel chan,
struct sensor_value *val)
{
struct lis2du12_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:
lis2du12_accel_channel_get(chan, val, data);
break;
default:
return -ENOTSUP;
}
return 0;
}
static const struct sensor_driver_api lis2du12_driver_api = {
.attr_set = lis2du12_attr_set,
#if CONFIG_LIS2DU12_TRIGGER
.trigger_set = lis2du12_trigger_set,
#endif
.sample_fetch = lis2du12_sample_fetch,
.channel_get = lis2du12_channel_get,
};
static int lis2du12_init_chip(const struct device *dev)
{
const struct lis2du12_config *cfg = dev->config;
stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
struct lis2du12_data *lis2du12 = dev->data;
lis2du12_id_t chip_id;
uint8_t odr, fs;
if (lis2du12_id_get(ctx, &chip_id) < 0) {
LOG_ERR("Failed reading chip id");
return -EIO;
}
LOG_INF("chip id 0x%x", chip_id.whoami);
if (chip_id.whoami != LIS2DU12_ID) {
LOG_ERR("Invalid chip id 0x%x", chip_id.whoami);
return -EIO;
}
/* reboot device */
if (lis2du12_reboot(dev) < 0) {
return -EIO;
}
/* set FS from DT */
fs = cfg->accel_range;
LOG_DBG("accel range is %d", fs);
if (lis2du12_accel_set_fs_raw(dev, fs) < 0) {
LOG_ERR("failed to set accelerometer range %d", fs);
return -EIO;
}
lis2du12->acc_gain = lis2du12_accel_fs_map[fs] * GAIN_UNIT_XL / 2;
/* set odr from DT (the only way to go in high performance) */
odr = cfg->accel_odr;
LOG_DBG("accel odr is %d", odr);
if (lis2du12_accel_set_odr_raw(dev, odr) < 0) {
LOG_ERR("failed to set accelerometer odr %d", odr);
return -EIO;
}
return 0;
}
static int lis2du12_init(const struct device *dev)
{
#ifdef CONFIG_LIS2DU12_TRIGGER
const struct lis2du12_config *cfg = dev->config;
#endif
struct lis2du12_data *data = dev->data;
LOG_INF("Initialize device %s", dev->name);
data->dev = dev;
if (lis2du12_init_chip(dev) < 0) {
LOG_ERR("failed to initialize chip");
return -EIO;
}
#ifdef CONFIG_LIS2DU12_TRIGGER
if (cfg->trig_enabled) {
if (lis2du12_init_interrupt(dev) < 0) {
LOG_ERR("Failed to initialize interrupt.");
return -EIO;
}
}
#endif
return 0;
}
/*
* Device creation macro, shared by LIS2DU12_DEFINE_SPI() and
* LIS2DU12_DEFINE_I2C().
*/
#define LIS2DU12_DEVICE_INIT(inst) \
SENSOR_DEVICE_DT_INST_DEFINE(inst, \
lis2du12_init, \
NULL, \
&lis2du12_data_##inst, \
&lis2du12_config_##inst, \
POST_KERNEL, \
CONFIG_SENSOR_INIT_PRIORITY, \
&lis2du12_driver_api);
/*
* Instantiation macros used when a device is on a SPI bus.
*/
#ifdef CONFIG_LIS2DU12_TRIGGER
#define LIS2DU12_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), \
.drdy_pin = DT_INST_PROP(inst, drdy_pin)
#else
#define LIS2DU12_CFG_IRQ(inst)
#endif /* CONFIG_LIS2DU12_TRIGGER */
#define LIS2DU12_SPI_OP (SPI_WORD_SET(8) | \
SPI_OP_MODE_MASTER | \
SPI_MODE_CPOL | \
SPI_MODE_CPHA) \
#define LIS2DU12_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)), \
(LIS2DU12_CFG_IRQ(inst)))
/*
* Instantiation macros used when a device is on a SPI bus.
*/
#define LIS2DU12_CONFIG_SPI(inst) \
{ \
STMEMSC_CTX_SPI(&lis2du12_config_##inst.stmemsc_cfg), \
.stmemsc_cfg = { \
.spi = SPI_DT_SPEC_INST_GET(inst, \
LIS2DU12_SPI_OP, \
0), \
}, \
LIS2DU12_CONFIG_COMMON(inst) \
}
/*
* Instantiation macros used when a device is on an I2C bus.
*/
#define LIS2DU12_CONFIG_I2C(inst) \
{ \
STMEMSC_CTX_I2C(&lis2du12_config_##inst.stmemsc_cfg), \
.stmemsc_cfg = { \
.i2c = I2C_DT_SPEC_INST_GET(inst), \
}, \
LIS2DU12_CONFIG_COMMON(inst) \
}
/*
* Main instantiation macro. Use of COND_CODE_1() selects the right
* bus-specific macro at preprocessor time.
*/
#define LIS2DU12_DEFINE(inst) \
static struct lis2du12_data lis2du12_data_##inst; \
static const struct lis2du12_config lis2du12_config_##inst = \
COND_CODE_1(DT_INST_ON_BUS(inst, spi), \
(LIS2DU12_CONFIG_SPI(inst)), \
(LIS2DU12_CONFIG_I2C(inst))); \
LIS2DU12_DEVICE_INIT(inst)
DT_INST_FOREACH_STATUS_OKAY(LIS2DU12_DEFINE)

View file

@ -0,0 +1,98 @@
/* ST Microelectronics LIS2DU12 3-axis accelerometer sensor driver
*
* Copyright (c) 2023 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*
* Datasheet:
* https://www.st.com/resource/en/datasheet/lis2du12.pdf
*/
#ifndef ZEPHYR_DRIVERS_SENSOR_LIS2DU12_LIS2DU12_H_
#define ZEPHYR_DRIVERS_SENSOR_LIS2DU12_LIS2DU12_H_
#include <zephyr/drivers/sensor.h>
#include <zephyr/types.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/sys/util.h>
#include <stmemsc.h>
#include "lis2du12_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 LIS2DU12_EN_BIT 0x01
#define LIS2DU12_DIS_BIT 0x00
/* Accel sensor sensitivity grain is 61 ug/LSB */
#define GAIN_UNIT_XL (61LL)
#define SENSOR_G_DOUBLE (SENSOR_G / 1000000.0)
struct lis2du12_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_LIS2DU12_TRIGGER
const struct gpio_dt_spec int1_gpio;
const struct gpio_dt_spec int2_gpio;
uint8_t drdy_pin;
bool trig_enabled;
#endif /* CONFIG_LIS2DU12_TRIGGER */
};
union samples {
uint8_t raw[6];
struct {
int16_t axis[3];
};
} __aligned(2);
struct lis2du12_data {
const struct device *dev;
int16_t acc[3];
uint32_t acc_gain;
uint16_t accel_freq;
uint8_t accel_fs;
#ifdef CONFIG_LIS2DU12_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_LIS2DU12_TRIGGER_OWN_THREAD)
K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LIS2DU12_THREAD_STACK_SIZE);
struct k_thread thread;
struct k_sem gpio_sem;
#elif defined(CONFIG_LIS2DU12_TRIGGER_GLOBAL_THREAD)
struct k_work work;
#endif
#endif /* CONFIG_LIS2DU12_TRIGGER */
};
#ifdef CONFIG_LIS2DU12_TRIGGER
int lis2du12_trigger_set(const struct device *dev,
const struct sensor_trigger *trig,
sensor_trigger_handler_t handler);
int lis2du12_init_interrupt(const struct device *dev);
#endif
#endif /* ZEPHYR_DRIVERS_SENSOR_LIS2DU12_LIS2DU12_H_ */

View file

@ -0,0 +1,215 @@
/* ST Microelectronics LIS2DU12 3-axis accelerometer sensor driver
*
* Copyright (c) 2023 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*
* Datasheet:
* https://www.st.com/resource/en/datasheet/lis2du12.pdf
*/
#define DT_DRV_COMPAT st_lis2du12
#include <zephyr/kernel.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/logging/log.h>
#include "lis2du12.h"
LOG_MODULE_DECLARE(LIS2DU12, CONFIG_SENSOR_LOG_LEVEL);
/**
* lis2du12_enable_xl_int - XL enable selected int pin to generate interrupt
*/
static int lis2du12_enable_xl_int(const struct device *dev, int enable)
{
const struct lis2du12_config *cfg = dev->config;
stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
int ret;
if (enable) {
lis2du12_md_t md;
lis2du12_data_t xl_data;
/* dummy read: re-trigger interrupt */
md.fs = cfg->accel_range;
lis2du12_data_get(ctx, &md, &xl_data);
}
/* set interrupt */
if (cfg->drdy_pin == 1) {
lis2du12_pin_int_route_t val;
ret = lis2du12_pin_int1_route_get(ctx, &val);
if (ret < 0) {
LOG_ERR("pint_int1_route_get error");
return ret;
}
val.drdy_xl = 1;
ret = lis2du12_pin_int1_route_set(ctx, &val);
} else {
lis2du12_pin_int_route_t val;
ret = lis2du12_pin_int2_route_get(ctx, &val);
if (ret < 0) {
LOG_ERR("pint_int2_route_get error");
return ret;
}
val.drdy_xl = 1;
ret = lis2du12_pin_int2_route_set(ctx, &val);
}
return ret;
}
/**
* lis2du12_trigger_set - link external trigger to event data ready
*/
int lis2du12_trigger_set(const struct device *dev,
const struct sensor_trigger *trig,
sensor_trigger_handler_t handler)
{
const struct lis2du12_config *cfg = dev->config;
struct lis2du12_data *lis2du12 = dev->data;
if (!cfg->trig_enabled) {
LOG_ERR("trigger_set op not supported");
return -ENOTSUP;
}
switch (trig->chan) {
case SENSOR_CHAN_ACCEL_XYZ:
lis2du12->handler_drdy_acc = handler;
lis2du12->trig_drdy_acc = trig;
if (handler) {
return lis2du12_enable_xl_int(dev, LIS2DU12_EN_BIT);
}
return lis2du12_enable_xl_int(dev, LIS2DU12_DIS_BIT);
default:
return -ENOTSUP;
}
}
/**
* lis2du12_handle_interrupt - handle the drdy event
* read data and call handler if registered any
*/
static void lis2du12_handle_interrupt(const struct device *dev)
{
struct lis2du12_data *lis2du12 = dev->data;
const struct lis2du12_config *cfg = dev->config;
stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
lis2du12_status_t status;
while (1) {
if (lis2du12_status_get(ctx, &status) < 0) {
LOG_ERR("failed reading status reg");
return;
}
if (status.drdy_xl == 0) {
break;
}
if ((status.drdy_xl) && (lis2du12->handler_drdy_acc != NULL)) {
lis2du12->handler_drdy_acc(dev, lis2du12->trig_drdy_acc);
}
}
gpio_pin_interrupt_configure_dt(lis2du12->drdy_gpio,
GPIO_INT_EDGE_TO_ACTIVE);
}
static void lis2du12_gpio_callback(const struct device *dev,
struct gpio_callback *cb, uint32_t pins)
{
struct lis2du12_data *lis2du12 =
CONTAINER_OF(cb, struct lis2du12_data, gpio_cb);
ARG_UNUSED(pins);
gpio_pin_interrupt_configure_dt(lis2du12->drdy_gpio, GPIO_INT_DISABLE);
#if defined(CONFIG_LIS2DU12_TRIGGER_OWN_THREAD)
k_sem_give(&lis2du12->gpio_sem);
#elif defined(CONFIG_LIS2DU12_TRIGGER_GLOBAL_THREAD)
k_work_submit(&lis2du12->work);
#endif /* CONFIG_LIS2DU12_TRIGGER_OWN_THREAD */
}
#ifdef CONFIG_LIS2DU12_TRIGGER_OWN_THREAD
static void lis2du12_thread(struct lis2du12_data *lis2du12)
{
while (1) {
k_sem_take(&lis2du12->gpio_sem, K_FOREVER);
lis2du12_handle_interrupt(lis2du12->dev);
}
}
#endif /* CONFIG_LIS2DU12_TRIGGER_OWN_THREAD */
#ifdef CONFIG_LIS2DU12_TRIGGER_GLOBAL_THREAD
static void lis2du12_work_cb(struct k_work *work)
{
struct lis2du12_data *lis2du12 =
CONTAINER_OF(work, struct lis2du12_data, work);
lis2du12_handle_interrupt(lis2du12->dev);
}
#endif /* CONFIG_LIS2DU12_TRIGGER_GLOBAL_THREAD */
int lis2du12_init_interrupt(const struct device *dev)
{
struct lis2du12_data *lis2du12 = dev->data;
const struct lis2du12_config *cfg = dev->config;
int ret;
lis2du12->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(lis2du12->drdy_gpio)) {
LOG_ERR("Cannot get pointer to drdy_gpio device (%p)",
lis2du12->drdy_gpio);
return -EINVAL;
}
#if defined(CONFIG_LIS2DU12_TRIGGER_OWN_THREAD)
k_sem_init(&lis2du12->gpio_sem, 0, K_SEM_MAX_LIMIT);
k_thread_create(&lis2du12->thread, lis2du12->thread_stack,
CONFIG_LIS2DU12_THREAD_STACK_SIZE,
(k_thread_entry_t)lis2du12_thread, lis2du12,
NULL, NULL, K_PRIO_COOP(CONFIG_LIS2DU12_THREAD_PRIORITY),
0, K_NO_WAIT);
k_thread_name_set(&lis2du12->thread, dev->name);
#elif defined(CONFIG_LIS2DU12_TRIGGER_GLOBAL_THREAD)
lis2du12->work.handler = lis2du12_work_cb;
#endif /* CONFIG_LIS2DU12_TRIGGER_OWN_THREAD */
ret = gpio_pin_configure_dt(lis2du12->drdy_gpio, GPIO_INPUT);
if (ret < 0) {
LOG_ERR("Could not configure gpio: %d", ret);
return ret;
}
gpio_init_callback(&lis2du12->gpio_cb,
lis2du12_gpio_callback,
BIT(lis2du12->drdy_gpio->pin));
if (gpio_add_callback(lis2du12->drdy_gpio->port, &lis2du12->gpio_cb) < 0) {
LOG_ERR("Could not set gpio callback");
return -EIO;
}
return gpio_pin_interrupt_configure_dt(lis2du12->drdy_gpio,
GPIO_INT_EDGE_TO_ACTIVE);
}

View file

@ -0,0 +1,97 @@
# Copyright (c) 2023 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 lis2du12.h and use the macros defined there.
Example:
#include <zephyr/dt-bindings/sensor/lis2du12.h>
lis2du12: lis2du12@0 {
...
accel-range = <LSM6DSV16X_DT_FS_8G>;
accel-odr = <LSM6DSV16X_DT_ODR_AT_60Hz>;
};
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
description: |
Select DRDY pin number (1 or 2).
1 = drdy is generated from INT1
2 = drdy is generated from INT2
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.
enum: [1, 2]
accel-range:
type: int
default: 0
description: |
Range in g. Default is power-up configuration.
0 # LIS2DU12_DT_FS_2G (0.061 mg/LSB)
1 # LIS2DU12_DT_FS_4G (0.122 mg/LSB)
2 # LIS2DU12_DT_FS_8G (0.244 mg/LSB)
3 # LIS2DU12_DT_FS_16G (0.488 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 lis2du12_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 # LIS2DU12_DT_ODR_OFF
0x01 # 1Hz6 (ultra low power)
0x02 # 3Hz (ultra low power)
0x03 # 25Hz (ultra low power)
0x04 # 6Hz (low power)
0x05 # 12Hz5 (low power)
0x06 # 25Hz (low power)
0x07 # 50Hz (low power)
0x08 # 100Hz (low power)
0x09 # 200Hz (low power)
0x0a # 400Hz (low power)
0x0b # 800Hz (low power)
0x0e # Single-shot high latency by INT2
0x0f # Single-shot high latency by IF
enum: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0e, 0x0f]
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) 2023 STMicroelectronics
# SPDX-License-Identifier: Apache-2.0
description: |
STMicroelectronics LIS2DU12 3-axis ultra-low power accelerometer sensor
accessed through I2C bus
compatible: "st,lis2du12"
include: ["i2c-device.yaml", "st,lis2du12-common.yaml"]

View file

@ -0,0 +1,10 @@
# Copyright (c) 2023 STMicroelectronics
# SPDX-License-Identifier: Apache-2.0
description: |
STMicroelectronics LIS2DU12 3-axis ultra-low power accelerometer sensor
accessed through SPI bus
compatible: "st,lis2du12"
include: ["spi-device.yaml", "st,lis2du12-common.yaml"]

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2023 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DU12_H_
#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DU12_H_
/* Accel range */
#define LIS2DU12_DT_FS_2G 0
#define LIS2DU12_DT_FS_4G 1
#define LIS2DU12_DT_FS_8G 2
#define LIS2DU12_DT_FS_16G 3
/* Accel rates */
#define LIS2DU12_DT_ODR_OFF 0x00 /* Power-Down */
#define LIS2DU12_DT_ODR_AT_1Hz6_ULP 0x01 /* 1Hz6 (ultra low power) */
#define LIS2DU12_DT_ODR_AT_3Hz_ULP 0x02 /* 3Hz (ultra low power) */
#define LIS2DU12_DT_ODR_AT_6Hz_ULP 0x03 /* 6Hz (ultra low power) */
#define LIS2DU12_DT_ODR_AT_6Hz 0x04 /* 6Hz (normal) */
#define LIS2DU12_DT_ODR_AT_12Hz 0x05 /* 12Hz5 (normal) */
#define LIS2DU12_DT_ODR_AT_25Hz 0x06 /* 25Hz (normal) */
#define LIS2DU12_DT_ODR_AT_50Hz 0x07 /* 50Hz (normal) */
#define LIS2DU12_DT_ODR_AT_100Hz 0x08 /* 100Hz (normal) */
#define LIS2DU12_DT_ODR_AT_200Hz 0x09 /* 200Hz (normal) */
#define LIS2DU12_DT_ODR_AT_400Hz 0x0a /* 400Hz (normal) */
#define LIS2DU12_DT_ODR_AT_800Hz 0x0b /* 800Hz (normal) */
#define LIS2DU12_DT_ODR_TRIG_PIN 0x0e /* Single-shot high latency by INT2 */
#define LIS2DU12_DT_ODR_TRIG_SW 0x0f /* Single-shot high latency by IF */
#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DU12_H_ */

View file

@ -88,6 +88,9 @@ config USE_STDC_LIS2DS12
config USE_STDC_LIS2DTW12
bool
config USE_STDC_LIS2DU12
bool
config USE_STDC_LIS2DW12
bool

View file

@ -122,7 +122,8 @@
<&test_gpio 0 0>,
<&test_gpio 0 0>, /* 0x25 */
<&test_gpio 0 0>, /* 0x26 */
<&test_gpio 0 0>; /* 0x27 */
<&test_gpio 0 0>, /* 0x27 */
<&test_gpio 0 0>; /* 0x28 */
#include "spi.dtsi"
};

View file

@ -17,6 +17,7 @@
#include <zephyr/dt-bindings/sensor/iis2dlpc.h>
#include <zephyr/dt-bindings/sensor/lis2dh.h>
#include <zephyr/dt-bindings/sensor/iis2iclx.h>
#include <zephyr/dt-bindings/sensor/lis2du12.h>
/****************************************
* PLEASE KEEP REG ADDRESSES SEQUENTIAL *
@ -869,3 +870,12 @@ test_i2c_lps28dfw: lps28dfw@7b {
avg = <LPS2xDF_DT_AVG_128_SAMPLES>;
fs = <LPS28DFW_DT_FS_MODE_1_1260>;
};
test_i2c_lis2du12: lis2du12@7c {
compatible = "st,lis2du12";
reg = <0x7c>;
int1-gpios = <&test_gpio 0 0>;
int2-gpios = <&test_gpio 0 0>;
accel-range = <LIS2DU12_DT_FS_16G>;
accel-odr = <LIS2DU12_DT_ODR_AT_800Hz>;
};

View file

@ -33,6 +33,7 @@ CONFIG_ISL29035_TRIGGER_GLOBAL_THREAD=y
CONFIG_ISM330DHCX_TRIGGER_GLOBAL_THREAD=y
CONFIG_LIS2DH_TRIGGER_GLOBAL_THREAD=y
CONFIG_LIS2DS12_TRIGGER_GLOBAL_THREAD=y
CONFIG_LIS2DU12_TRIGGER_GLOBAL_THREAD=y
CONFIG_LIS2DW12_TRIGGER_GLOBAL_THREAD=y
CONFIG_LIS2MDL_TRIGGER_GLOBAL_THREAD=y
CONFIG_LIS3MDL_TRIGGER_GLOBAL_THREAD=y

View file

@ -33,6 +33,7 @@ CONFIG_ISL29035_TRIGGER_NONE=y
CONFIG_ISM330DHCX_TRIGGER_NONE=y
CONFIG_LIS2DH_TRIGGER_NONE=y
CONFIG_LIS2DS12_TRIGGER_NONE=y
CONFIG_LIS2DU12_TRIGGER_NONE=y
CONFIG_LIS2DW12_TRIGGER_NONE=y
CONFIG_LIS2MDL_TRIGGER_NONE=y
CONFIG_LIS3MDL_TRIGGER_NONE=y

View file

@ -31,6 +31,7 @@ CONFIG_ISL29035_TRIGGER_OWN_THREAD=y
CONFIG_ISM330DHCX_TRIGGER_OWN_THREAD=y
CONFIG_LIS2DH_TRIGGER_OWN_THREAD=y
CONFIG_LIS2DS12_TRIGGER_OWN_THREAD=y
CONFIG_LIS2DU12_TRIGGER_OWN_THREAD=y
CONFIG_LIS2DW12_TRIGGER_OWN_THREAD=y
CONFIG_LIS2MDL_TRIGGER_OWN_THREAD=y
CONFIG_LIS3MDL_TRIGGER_OWN_THREAD=y

View file

@ -312,3 +312,12 @@ test_spi_lps22df: lps22df@27 {
drdy-gpios = <&test_gpio 0 0>;
status = "okay";
};
test_spi_lis2du12: lis2du12@28 {
compatible = "st,lis2du12";
reg = <0x28>;
spi-max-frequency = <0>;
int1-gpios = <&test_gpio 0 0>;
int2-gpios = <&test_gpio 0 0>;
status = "okay";
};