Browse Source
The LIS2DUXS12 is a smart, digital, 3-axis linear accelerometer whose MEMS and ASIC have been expressly designed to combine the lowest current consumption possible with features such as always-on antialiasing filtering, a finite state machine (FSM) and machine learning core (MLC) with adaptive self-configuration (ASC), and an analog hub / Qvar sensing channel. (https://www.st.com/en/mems-and-sensors/lis2duxs12.html) Signed-off-by: Armando Visconti <armando.visconti@st.com>pull/83428/head
12 changed files with 340 additions and 11 deletions
@ -0,0 +1,237 @@ |
|||||||
|
/* ST Microelectronics LIS2DUXS12 smart accelerometer APIs
|
||||||
|
* |
||||||
|
* Copyright (c) 2024 STMicroelectronics |
||||||
|
* Copyright (c) 2023 PHYTEC Messtechnik GmbH |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "lis2dux12.h" |
||||||
|
#include "lis2duxs12_api.h" |
||||||
|
#include <zephyr/logging/log.h> |
||||||
|
|
||||||
|
LOG_MODULE_DECLARE(LIS2DUX12, CONFIG_SENSOR_LOG_LEVEL); |
||||||
|
|
||||||
|
static int32_t st_lis2duxs12_set_odr_raw(const struct device *dev, uint8_t odr) |
||||||
|
{ |
||||||
|
struct lis2dux12_data *data = dev->data; |
||||||
|
const struct lis2dux12_config *cfg = dev->config; |
||||||
|
stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; |
||||||
|
lis2duxs12_md_t mode = {.odr = odr, .fs = data->range}; |
||||||
|
|
||||||
|
data->odr = odr; |
||||||
|
return lis2duxs12_mode_set(ctx, &mode); |
||||||
|
} |
||||||
|
|
||||||
|
static int32_t st_lis2duxs12_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; |
||||||
|
lis2duxs12_md_t val = { .odr = data->odr, .fs = range }; |
||||||
|
|
||||||
|
err = lis2duxs12_mode_set(ctx, &val); |
||||||
|
if (err) { |
||||||
|
return err; |
||||||
|
} |
||||||
|
|
||||||
|
switch (range) { |
||||||
|
case LIS2DUX12_DT_FS_2G: |
||||||
|
data->gain = lis2duxs12_from_fs2g_to_mg(1); |
||||||
|
break; |
||||||
|
case LIS2DUX12_DT_FS_4G: |
||||||
|
data->gain = lis2duxs12_from_fs4g_to_mg(1); |
||||||
|
break; |
||||||
|
case LIS2DUX12_DT_FS_8G: |
||||||
|
data->gain = lis2duxs12_from_fs8g_to_mg(1); |
||||||
|
break; |
||||||
|
case LIS2DUX12_DT_FS_16G: |
||||||
|
data->gain = lis2duxs12_from_fs16g_to_mg(1); |
||||||
|
break; |
||||||
|
default: |
||||||
|
LOG_ERR("range %d not supported.", range); |
||||||
|
return -EINVAL; |
||||||
|
} |
||||||
|
|
||||||
|
data->range = range; |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int32_t st_lis2duxs12_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 */ |
||||||
|
lis2duxs12_md_t mode = {.fs = data->range}; |
||||||
|
lis2duxs12_xl_data_t xzy_data = {0}; |
||||||
|
|
||||||
|
if (lis2duxs12_xl_data_get(ctx, &mode, &xzy_data) < 0) { |
||||||
|
LOG_ERR("Failed to fetch raw data sample"); |
||||||
|
return -EIO; |
||||||
|
} |
||||||
|
|
||||||
|
data->sample_x = xzy_data.raw[0]; |
||||||
|
data->sample_y = xzy_data.raw[1]; |
||||||
|
data->sample_z = xzy_data.raw[2]; |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
#ifdef CONFIG_LIS2DUX12_ENABLE_TEMP |
||||||
|
static int32_t st_lis2duxs12_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 */ |
||||||
|
lis2duxs12_outt_data_t temp_data = {0}; |
||||||
|
|
||||||
|
if (lis2duxs12_outt_data_get(ctx, &temp_data) < 0) { |
||||||
|
LOG_ERR("Failed to fetch raw temperature data sample"); |
||||||
|
return -EIO; |
||||||
|
} |
||||||
|
|
||||||
|
data->sample_temp = temp_data.heat.deg_c; |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef CONFIG_LIS2DUX12_TRIGGER |
||||||
|
static void st_lis2duxs12_handle_interrupt(const struct device *dev) |
||||||
|
{ |
||||||
|
struct lis2dux12_data *lis2duxs12 = dev->data; |
||||||
|
const struct lis2dux12_config *cfg = dev->config; |
||||||
|
stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; |
||||||
|
lis2duxs12_all_sources_t sources; |
||||||
|
int ret; |
||||||
|
|
||||||
|
lis2duxs12_all_sources_get(ctx, &sources); |
||||||
|
|
||||||
|
if (sources.drdy == 0) { |
||||||
|
goto exit; /* spurious interrupt */ |
||||||
|
} |
||||||
|
|
||||||
|
if (lis2duxs12->data_ready_handler != NULL) { |
||||||
|
lis2duxs12->data_ready_handler(dev, lis2duxs12->data_ready_trigger); |
||||||
|
} |
||||||
|
|
||||||
|
exit: |
||||||
|
ret = gpio_pin_interrupt_configure_dt(lis2duxs12->drdy_gpio, GPIO_INT_EDGE_TO_ACTIVE); |
||||||
|
if (ret < 0) { |
||||||
|
LOG_ERR("%s: Not able to configure pin_int", dev->name); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static int32_t st_lis2duxs12_init_interrupt(const struct device *dev) |
||||||
|
{ |
||||||
|
const struct lis2dux12_config *cfg = dev->config; |
||||||
|
stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; |
||||||
|
lis2duxs12_pin_int_route_t route; |
||||||
|
int err; |
||||||
|
|
||||||
|
/* Enable pulsed mode */ |
||||||
|
err = lis2duxs12_data_ready_mode_set(ctx, LIS2DUXS12_DRDY_PULSED); |
||||||
|
if (err < 0) { |
||||||
|
return err; |
||||||
|
} |
||||||
|
|
||||||
|
/* route data-ready interrupt on int1 */ |
||||||
|
err = lis2duxs12_pin_int1_route_get(ctx, &route); |
||||||
|
if (err < 0) { |
||||||
|
return err; |
||||||
|
} |
||||||
|
|
||||||
|
route.drdy = 1; |
||||||
|
|
||||||
|
err = lis2duxs12_pin_int1_route_set(ctx, &route); |
||||||
|
if (err < 0) { |
||||||
|
return err; |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
const struct lis2dux12_chip_api st_lis2duxs12_chip_api = { |
||||||
|
.set_odr_raw = st_lis2duxs12_set_odr_raw, |
||||||
|
.set_range = st_lis2duxs12_set_range, |
||||||
|
.sample_fetch_accel = st_lis2duxs12_sample_fetch_accel, |
||||||
|
#ifdef CONFIG_LIS2DUX12_ENABLE_TEMP |
||||||
|
.sample_fetch_temp = st_lis2duxs12_sample_fetch_temp, |
||||||
|
#endif |
||||||
|
#ifdef CONFIG_LIS2DUX12_TRIGGER |
||||||
|
.handle_interrupt = st_lis2duxs12_handle_interrupt, |
||||||
|
.init_interrupt = st_lis2duxs12_init_interrupt, |
||||||
|
#endif |
||||||
|
}; |
||||||
|
|
||||||
|
int st_lis2duxs12_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; |
||||||
|
|
||||||
|
lis2duxs12_exit_deep_power_down(ctx); |
||||||
|
k_busy_wait(25000); |
||||||
|
|
||||||
|
/* check chip ID */ |
||||||
|
ret = lis2duxs12_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 != LIS2DUXS12_ID) { |
||||||
|
LOG_ERR("%s: Invalid chip ID 0x%02x", dev->name, chip_id); |
||||||
|
return -EINVAL; |
||||||
|
} |
||||||
|
|
||||||
|
/* reset device */ |
||||||
|
ret = lis2duxs12_init_set(ctx, LIS2DUXS12_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 */ |
||||||
|
lis2duxs12_init_set(ctx, LIS2DUXS12_SENSOR_ONLY_ON); |
||||||
|
|
||||||
|
lis2duxs12_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); |
||||||
|
ret = st_lis2duxs12_set_odr_raw(dev, cfg->odr); |
||||||
|
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 = st_lis2duxs12_set_range(dev, cfg->range); |
||||||
|
if (ret < 0) { |
||||||
|
LOG_ERR("%s: range init error %d", dev->name, cfg->range); |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
@ -0,0 +1,24 @@ |
|||||||
|
/* ST Microelectronics LIS2DUXS12 smart accelerometer APIs
|
||||||
|
* |
||||||
|
* Copyright (c) 2024 STMicroelectronics |
||||||
|
* Copyright (c) 2023 PHYTEC Messtechnik GmbH |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <stdint.h> |
||||||
|
#include <stmemsc.h> |
||||||
|
|
||||||
|
#include "lis2duxs12_reg.h" |
||||||
|
#include <zephyr/dt-bindings/sensor/lis2dux12.h> |
||||||
|
|
||||||
|
#include <zephyr/drivers/sensor.h> |
||||||
|
|
||||||
|
#ifndef ZEPHYR_DRIVERS_SENSOR_LIS2DUXS12_LIS2DUXS12_API_H_ |
||||||
|
#define ZEPHYR_DRIVERS_SENSOR_LIS2DUXS12_LIS2DUXS12_API_H_ |
||||||
|
|
||||||
|
extern const struct lis2dux12_chip_api st_lis2duxs12_chip_api; |
||||||
|
|
||||||
|
int st_lis2duxs12_init(const struct device *dev); |
||||||
|
|
||||||
|
#endif /* ZEPHYR_DRIVERS_SENSOR_LIS2DUXS12_LIS2DUXS12_API_H_ */ |
@ -0,0 +1,17 @@ |
|||||||
|
# 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> |
||||||
|
lis2duxs12: lis2duxs12@0 { |
||||||
|
... |
||||||
|
power-mode = <LIS2DUX12_OPER_MODE_LOW_POWER>; |
||||||
|
odr = <LIS2DUX12_DT_ODR_12Hz5>; |
||||||
|
range = <LIS2DUX12_DT_FS_16G>; |
||||||
|
}; |
||||||
|
|
||||||
|
# LIS2DUXS12 is a superset of LIS2DUX12 |
||||||
|
include: st,lis2dux12-common.yaml |
@ -0,0 +1,8 @@ |
|||||||
|
# Copyright (c) 2024 STMicroelectronics |
||||||
|
# SPDX-License-Identifier: Apache-2.0 |
||||||
|
|
||||||
|
description: STMicroelectronics LIS2DUXS12 3-axis accelerometer |
||||||
|
|
||||||
|
compatible: "st,lis2duxs12" |
||||||
|
|
||||||
|
include: ["i2c-device.yaml", "st,lis2duxs12-common.yaml"] |
@ -0,0 +1,9 @@ |
|||||||
|
# Copyright (c) 2024 STMicroelectronics |
||||||
|
# SPDX-License-Identifier: Apache-2.0 |
||||||
|
|
||||||
|
description: | |
||||||
|
STMicroelectronics LIS2DUXS12 3-axis accelerometer accessed through SPI bus |
||||||
|
|
||||||
|
compatible: "st,lis2duxs12" |
||||||
|
|
||||||
|
include: ["spi-device.yaml", "st,lis2duxs12-common.yaml"] |
Loading…
Reference in new issue