drivers: sensor: lis2dux12: Add lis2dux12 driver

Adds support for the STMicroelectronics LIS2DUX12 3-axis accelerometer.

Signed-off-by: Kyle Dunn <kdunn926@gmail.com>
This commit is contained in:
Kyle Dunn 2023-11-15 13:35:26 -07:00 committed by Fabio Baltieri
parent fd1a129a3e
commit a846b81d58
19 changed files with 921 additions and 1 deletions

View file

@ -78,6 +78,7 @@ 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_LIS2DUX12 lis2dux12)
add_subdirectory_ifdef(CONFIG_LIS2DW12 lis2dw12)
add_subdirectory_ifdef(CONFIG_LIS2MDL lis2mdl)
add_subdirectory_ifdef(CONFIG_LIS3MDL lis3mdl)

View file

@ -158,6 +158,7 @@ source "drivers/sensor/lis2dh/Kconfig"
source "drivers/sensor/lis2de12/Kconfig"
source "drivers/sensor/lis2ds12/Kconfig"
source "drivers/sensor/lis2du12/Kconfig"
source "drivers/sensor/lis2dux12/Kconfig"
source "drivers/sensor/lis2dw12/Kconfig"
source "drivers/sensor/lis2mdl/Kconfig"
source "drivers/sensor/lis3mdl/Kconfig"

View file

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

View file

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

View file

@ -0,0 +1,417 @@
/* 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 <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/sys/util_macro.h>
#include <zephyr/logging/log.h>
#include <zephyr/dt-bindings/sensor/lis2dux12.h>
#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;
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) {
return err;
}
switch (range) {
default:
LOG_ERR("range [%d] not supported.", range);
return -EINVAL;
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 0;
}
#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)
{
int odr_val;
switch (attr) {
case SENSOR_ATTR_FULL_SCALE:
return lis2dux12_set_range(dev, sensor_ms2_to_g(val));
case SENSOR_ATTR_SAMPLING_FREQUENCY:
odr_val = lis2dux12_freq_to_odr_val(dev, val->val1);
if (odr_val < 0) {
LOG_ERR("%d Hz not supported or wrong operating mode.", val->val1);
return odr_val;
}
LOG_DBG("%s: set odr to %d Hz", dev->name, val->val1);
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);
/* 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_DBG("%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_DBG("%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)

View file

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

View file

@ -0,0 +1,199 @@
/* 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 <zephyr/logging/log.h>
#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);
k_thread_name_set(&data->thread, dev->name);
#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);
}

View file

@ -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 <zephyr/dt-bindings/sensor/st_lis2dux12.h>
lis2dux12: lis2dux12@0 {
...
power-mode = <LIS2DUX12_OPER_MODE_LOW_POWER>;
odr = <LIS2DUX12_DT_ODR_12Hz5>;
range = <LIS2DUX12_DT_FS_16G>;
};
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]

View file

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

View file

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

View file

@ -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 <zephyr/dt-bindings/dt-util.h>
/* 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_ */

View file

@ -93,6 +93,9 @@ config USE_STDC_LIS2DTW12
config USE_STDC_LIS2DU12
bool
config USE_STDC_LIS2DUX12
bool
config USE_STDC_LIS2DW12
bool

View file

@ -127,7 +127,8 @@
<&test_gpio 0 0>,
<&test_gpio 0 0>,
<&test_gpio 0 0>,
<&test_gpio 0 0>; /* 0x2C */
<&test_gpio 0 0>,
<&test_gpio 0 0>;
#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/lis2dux12.h>
#include <zephyr/dt-bindings/sensor/lis2de12.h>
#include <zephyr/dt-bindings/sensor/tmag5273.h>
#include <zephyr/dt-bindings/sensor/stts22h.h>
@ -1009,6 +1010,16 @@ 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 = <LIS2DUX12_DT_FS_16G>;
odr = <LIS2DUX12_DT_ODR_100Hz>;
power-mode = <LIS2DUX12_OPER_MODE_HIGH_FREQUENCY>;
status = "okay";
};

View file

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

View file

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

View file

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

View file

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

View file

@ -361,3 +361,12 @@ test_spi_iis328dq: iis328dq@2c {
int1-gpios = <&test_gpio 0 0>;
drdy-int-pad = <1>;
};
test_spi_lis2dux12: lis2dux12@2d {
compatible = "st,lis2dux12";
reg = <0x2d>;
spi-max-frequency = <0>;
int1-gpios = <&test_gpio 0 0>;
int2-gpios = <&test_gpio 0 0>;
status = "okay";
};