drivers: sensor: lis2dw12: add inactivity detection

Add inactivity mode or stationary detection

Signed-off-by: Andrew Sonzogni <andrew@safehear.fr>
This commit is contained in:
Andrew Sonzogni 2024-09-23 15:25:49 +02:00 committed by Fabio Baltieri
commit 70de35d9c9
6 changed files with 163 additions and 34 deletions

View file

@ -63,10 +63,15 @@ config LIS2DW12_TAP
endif # LIS2DW12_TRIGGER endif # LIS2DW12_TRIGGER
config LIS2DW12_THRESHOLD config LIS2DW12_SLEEP
bool "Wakeup threshold trigger (via interrupt)" bool "Sleep mode"
help help
Enable the wakeup threshold trigger feature. Enable sleep (inactivity) mode with ODR change when detected
config LIS2DW12_WAKEUP
bool "Wakeup detection (via interrupt)"
help
Enable the wakeup detection feature.
The wake-up interrupt signal is generated if a certain number of The wake-up interrupt signal is generated if a certain number of
consecutive data exceed the configured threshold (config in DT). consecutive data exceed the configured threshold (config in DT).
The threshold is applied to both positive and negative data: for The threshold is applied to both positive and negative data: for

View file

@ -187,7 +187,7 @@ static inline int32_t sensor_ms2_to_mg(const struct sensor_value *ms2)
} }
} }
#if CONFIG_LIS2DW12_THRESHOLD #if (CONFIG_LIS2DW12_SLEEP || CONFIG_LIS2DW12_WAKEUP)
/* Converts a lis2dw12_fs_t range to its value in milli-g /* Converts a lis2dw12_fs_t range to its value in milli-g
* Range can be 2/4/8/16G * Range can be 2/4/8/16G
@ -290,27 +290,50 @@ static int lis2dw12_attr_set_ff_dur(const struct device *dev,
} }
#endif #endif
#ifdef CONFIG_LIS2DW12_SLEEP
static int lis2dw12_attr_set_act_mode(const struct device *dev,
enum sensor_channel chan,
enum sensor_attribute attr,
const struct sensor_value *val)
{
const struct lis2dw12_device_config *cfg = dev->config;
struct lis2dw12_data *lis2dw12 = dev->data;
stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
lis2dw12_sleep_on_t sleep_val = val->val1 & 0x03U;
/* can only be set for all directions at once */
if (chan != SENSOR_CHAN_ACCEL_XYZ) {
return -EINVAL;
}
return lis2dw12_act_mode_set(ctx, sleep_val);
}
#endif
static int lis2dw12_attr_set(const struct device *dev, static int lis2dw12_attr_set(const struct device *dev,
enum sensor_channel chan, enum sensor_channel chan,
enum sensor_attribute attr, enum sensor_attribute attr,
const struct sensor_value *val) const struct sensor_value *val)
{ {
#if CONFIG_LIS2DW12_THRESHOLD
switch (attr) { switch (attr) {
#if (CONFIG_LIS2DW12_SLEEP || CONFIG_LIS2DW12_WAKEUP)
case SENSOR_ATTR_UPPER_THRESH: case SENSOR_ATTR_UPPER_THRESH:
case SENSOR_ATTR_LOWER_THRESH: case SENSOR_ATTR_LOWER_THRESH:
return lis2dw12_attr_set_thresh(dev, chan, attr, val); return lis2dw12_attr_set_thresh(dev, chan, attr, val);
#endif
#ifdef CONFIG_LIS2DW12_FREEFALL
case SENSOR_ATTR_FF_DUR:
return lis2dw12_attr_set_ff_dur(dev, chan, attr, val);
#endif
#ifdef CONFIG_LIS2DW12_SLEEP
case SENSOR_ATTR_FEATURE_MASK:
return lis2dw12_attr_set_act_mode(dev, chan, attr, val);
#endif
default: default:
/* Do nothing */ /* Do nothing */
break; break;
} }
#endif
#ifdef CONFIG_LIS2DW12_FREEFALL
if (attr == SENSOR_ATTR_FF_DUR) {
return lis2dw12_attr_set_ff_dur(dev, chan, attr, val);
}
#endif
switch (chan) { switch (chan) {
case SENSOR_CHAN_ACCEL_X: case SENSOR_CHAN_ACCEL_X:
@ -527,13 +550,20 @@ static int lis2dw12_init(const struct device *dev)
return ret; return ret;
} }
#ifdef CONFIG_LIS2DW12_THRESHOLD #ifdef CONFIG_LIS2DW12_WAKEUP
ret = lis2dw12_wkup_dur_set(ctx, cfg->wakeup_duration); ret = lis2dw12_wkup_dur_set(ctx, cfg->wakeup_duration);
if (ret < 0) { if (ret < 0) {
LOG_ERR("wakeup duration config error %d", ret); LOG_ERR("wakeup duration config error %d", ret);
return ret; return ret;
} }
#endif /* CONFIG_LIS2DW12_THRESHOLD */ #endif /* CONFIG_LIS2DW12_WAKEUP */
#ifdef CONFIG_LIS2DW12_SLEEP
ret = lis2dw12_act_sleep_dur_set(ctx, cfg->sleep_duration);
if (ret < 0) {
LOG_ERR("sleep duration config error %d", ret);
return ret;
}
#endif /* CONFIG_LIS2DW12_SLEEP */
return 0; return 0;
} }
@ -580,11 +610,18 @@ static int lis2dw12_init(const struct device *dev)
#define LIS2DW12_CONFIG_FREEFALL(inst) #define LIS2DW12_CONFIG_FREEFALL(inst)
#endif /* CONFIG_LIS2DW12_FREEFALL */ #endif /* CONFIG_LIS2DW12_FREEFALL */
#ifdef CONFIG_LIS2DW12_THRESHOLD #ifdef CONFIG_LIS2DW12_WAKEUP
#define LIS2DW12_CONFIG_THRESHOLD(inst) \ #define LIS2DW12_CONFIG_WAKEUP(inst) \
.wakeup_duration = DT_INST_PROP(inst, wakeup_duration), .wakeup_duration = DT_INST_PROP(inst, wakeup_duration),
#else #else
#define LIS2DW12_CONFIG_THRESHOLD(inst) #define LIS2DW12_CONFIG_WAKEUP(inst)
#endif
#ifdef CONFIG_LIS2DW12_SLEEP
#define LIS2DW12_CONFIG_SLEEP(inst) \
.sleep_duration = DT_INST_PROP(inst, sleep_duration),
#else
#define LIS2DW12_CONFIG_SLEEP(inst)
#endif #endif
#ifdef CONFIG_LIS2DW12_TRIGGER #ifdef CONFIG_LIS2DW12_TRIGGER
@ -606,7 +643,8 @@ static int lis2dw12_init(const struct device *dev)
.drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed), \ .drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed), \
LIS2DW12_CONFIG_TAP(inst) \ LIS2DW12_CONFIG_TAP(inst) \
LIS2DW12_CONFIG_FREEFALL(inst) \ LIS2DW12_CONFIG_FREEFALL(inst) \
LIS2DW12_CONFIG_THRESHOLD(inst) \ LIS2DW12_CONFIG_WAKEUP(inst) \
LIS2DW12_CONFIG_SLEEP(inst) \
COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, irq_gpios), \ COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, irq_gpios), \
(LIS2DW12_CFG_IRQ(inst)), ()) (LIS2DW12_CFG_IRQ(inst)), ())

View file

@ -97,13 +97,16 @@ struct lis2dw12_device_config {
uint8_t tap_latency; uint8_t tap_latency;
uint8_t tap_quiet; uint8_t tap_quiet;
#endif /* CONFIG_LIS2DW12_TAP */ #endif /* CONFIG_LIS2DW12_TAP */
#ifdef CONFIG_LIS2DW12_SLEEP
uint8_t sleep_duration;
#endif
#ifdef CONFIG_LIS2DW12_FREEFALL #ifdef CONFIG_LIS2DW12_FREEFALL
uint8_t freefall_duration; uint8_t freefall_duration;
uint8_t freefall_threshold; uint8_t freefall_threshold;
#endif /* CONFIG_LIS2DW12_FREEFALL */ #endif /* CONFIG_LIS2DW12_FREEFALL */
#ifdef CONFIG_LIS2DW12_THRESHOLD #ifdef CONFIG_LIS2DW12_WAKEUP
uint8_t wakeup_duration; uint8_t wakeup_duration;
#endif /* CONFIG_LIS2DW12_THRESHOLD */ #endif /* CONFIG_LIS2DW12_WAKEUP */
#endif /* CONFIG_LIS2DW12_TRIGGER */ #endif /* CONFIG_LIS2DW12_TRIGGER */
}; };
@ -131,10 +134,14 @@ struct lis2dw12_data {
sensor_trigger_handler_t double_tap_handler; sensor_trigger_handler_t double_tap_handler;
const struct sensor_trigger *double_tap_trig; const struct sensor_trigger *double_tap_trig;
#endif /* CONFIG_LIS2DW12_TAP */ #endif /* CONFIG_LIS2DW12_TAP */
#ifdef CONFIG_LIS2DW12_THRESHOLD #ifdef CONFIG_LIS2DW12_WAKEUP
sensor_trigger_handler_t threshold_handler; sensor_trigger_handler_t motion_handler;
const struct sensor_trigger *threshold_trig; const struct sensor_trigger *motion_trig;
#endif /* CONFIG_LIS2DW12_THRESHOLD */ #endif /* CONFIG_LIS2DW12_WAKEUP */
#ifdef CONFIG_LIS2DW12_SLEEP
sensor_trigger_handler_t stationary_handler;
const struct sensor_trigger *stationary_trig;
#endif
#ifdef CONFIG_LIS2DW12_FREEFALL #ifdef CONFIG_LIS2DW12_FREEFALL
sensor_trigger_handler_t freefall_handler; sensor_trigger_handler_t freefall_handler;
const struct sensor_trigger *freefall_trig; const struct sensor_trigger *freefall_trig;

View file

@ -67,14 +67,14 @@ static int lis2dw12_enable_int(const struct device *dev,
return lis2dw12_pin_int1_route_set(ctx, return lis2dw12_pin_int1_route_set(ctx,
&int_route.ctrl4_int1_pad_ctrl); &int_route.ctrl4_int1_pad_ctrl);
#endif /* CONFIG_LIS2DW12_TAP */ #endif /* CONFIG_LIS2DW12_TAP */
#ifdef CONFIG_LIS2DW12_THRESHOLD #ifdef CONFIG_LIS2DW12_WAKEUP
/** /**
* Trigger fires when channel reading transitions configured * Trigger fires when channel reading transitions configured
* thresholds. The thresholds are configured via the @ref * thresholds. The thresholds are configured via the @ref
* SENSOR_ATTR_LOWER_THRESH and @ref SENSOR_ATTR_UPPER_THRESH * SENSOR_ATTR_LOWER_THRESH and @ref SENSOR_ATTR_UPPER_THRESH
* attributes. * attributes.
*/ */
case SENSOR_TRIG_THRESHOLD: case SENSOR_TRIG_MOTION:
LOG_DBG("Setting int1_wu: %d\n", enable); LOG_DBG("Setting int1_wu: %d\n", enable);
lis2dw12_pin_int1_route_get(ctx, lis2dw12_pin_int1_route_get(ctx,
&int_route.ctrl4_int1_pad_ctrl); &int_route.ctrl4_int1_pad_ctrl);
@ -82,6 +82,21 @@ static int lis2dw12_enable_int(const struct device *dev,
return lis2dw12_pin_int1_route_set(ctx, return lis2dw12_pin_int1_route_set(ctx,
&int_route.ctrl4_int1_pad_ctrl); &int_route.ctrl4_int1_pad_ctrl);
#endif #endif
#ifdef CONFIG_LIS2DW12_SLEEP
/**
* Trigger fires when channel reading transitions configured
* thresholds for a certain time. The thresholds are configured
* via the @ref SENSOR_ATTR_LOWER_THRESH and @ref SENSOR_ATTR_UPPER_THRESH
* attributes.
*/
case SENSOR_TRIG_STATIONARY:
LOG_DBG("Setting int2_sleep_chg: %d\n", enable);
lis2dw12_pin_int2_route_get(ctx,
&int_route.ctrl5_int2_pad_ctrl);
int_route.ctrl5_int2_pad_ctrl.int2_sleep_chg = enable;
return lis2dw12_pin_int2_route_set(ctx,
&int_route.ctrl5_int2_pad_ctrl);
#endif
#ifdef CONFIG_LIS2DW12_FREEFALL #ifdef CONFIG_LIS2DW12_FREEFALL
/** /**
* Trigger fires when the readings does not include Earth's * Trigger fires when the readings does not include Earth's
@ -154,13 +169,22 @@ int lis2dw12_trigger_set(const struct device *dev,
lis2dw12->double_tap_trig = trig; lis2dw12->double_tap_trig = trig;
return lis2dw12_enable_int(dev, SENSOR_TRIG_DOUBLE_TAP, state); return lis2dw12_enable_int(dev, SENSOR_TRIG_DOUBLE_TAP, state);
#endif /* CONFIG_LIS2DW12_TAP */ #endif /* CONFIG_LIS2DW12_TAP */
#ifdef CONFIG_LIS2DW12_THRESHOLD #ifdef CONFIG_LIS2DW12_WAKEUP
case SENSOR_TRIG_THRESHOLD: case SENSOR_TRIG_MOTION:
{ {
LOG_DBG("Set trigger %d (handler: %p)\n", trig->type, handler); LOG_DBG("Set trigger %d (handler: %p)\n", trig->type, handler);
lis2dw12->threshold_handler = handler; lis2dw12->motion_handler = handler;
lis2dw12->threshold_trig = trig; lis2dw12->motion_trig = trig;
return lis2dw12_enable_int(dev, SENSOR_TRIG_THRESHOLD, state); return lis2dw12_enable_int(dev, SENSOR_TRIG_MOTION, state);
}
#endif
#ifdef CONFIG_LIS2DW12_SLEEP
case SENSOR_TRIG_STATIONARY:
{
LOG_DBG("Set trigger %d (handler: %p)\n", trig->type, handler);
lis2dw12->stationary_handler = handler;
lis2dw12->stationary_trig = trig;
return lis2dw12_enable_int(dev, SENSOR_TRIG_STATIONARY, state);
} }
#endif #endif
#ifdef CONFIG_LIS2DW12_FREEFALL #ifdef CONFIG_LIS2DW12_FREEFALL
@ -214,14 +238,28 @@ static int lis2dw12_handle_double_tap_int(const struct device *dev)
} }
#endif /* CONFIG_LIS2DW12_TAP */ #endif /* CONFIG_LIS2DW12_TAP */
#ifdef CONFIG_LIS2DW12_THRESHOLD #ifdef CONFIG_LIS2DW12_WAKEUP
static int lis2dw12_handle_wu_ia_int(const struct device *dev) static int lis2dw12_handle_wu_ia_int(const struct device *dev)
{ {
struct lis2dw12_data *lis2dw12 = dev->data; struct lis2dw12_data *lis2dw12 = dev->data;
sensor_trigger_handler_t handler = lis2dw12->threshold_handler; sensor_trigger_handler_t handler = lis2dw12->motion_handler;
if (handler) { if (handler) {
handler(dev, lis2dw12->threshold_trig); handler(dev, lis2dw12->motion_trig);
}
return 0;
}
#endif
#ifdef CONFIG_LIS2DW12_SLEEP
static int lis2dw12_handle_sleep_change_int(const struct device *dev)
{
struct lis2dw12_data *lis2dw12 = dev->data;
sensor_trigger_handler_t handler = lis2dw12->stationary_handler;
if (handler) {
handler(dev, lis2dw12->stationary_trig);
} }
return 0; return 0;
@ -265,11 +303,16 @@ static void lis2dw12_handle_interrupt(const struct device *dev)
lis2dw12_handle_double_tap_int(dev); lis2dw12_handle_double_tap_int(dev);
} }
#endif /* CONFIG_LIS2DW12_TAP */ #endif /* CONFIG_LIS2DW12_TAP */
#ifdef CONFIG_LIS2DW12_THRESHOLD #ifdef CONFIG_LIS2DW12_WAKEUP
if (sources.all_int_src.wu_ia) { if (sources.all_int_src.wu_ia) {
lis2dw12_handle_wu_ia_int(dev); lis2dw12_handle_wu_ia_int(dev);
} }
#endif #endif
#ifdef CONFIG_LIS2DW12_SLEEP
if (sources.all_int_src.sleep_change_ia) {
lis2dw12_handle_sleep_change_int(dev);
}
#endif
#ifdef CONFIG_LIS2DW12_FREEFALL #ifdef CONFIG_LIS2DW12_FREEFALL
if (sources.all_int_src.ff_ia) { if (sources.all_int_src.ff_ia) {
lis2dw12_handle_ff_ia_int(dev); lis2dw12_handle_ff_ia_int(dev);

View file

@ -247,3 +247,21 @@ properties:
- 3 # LIS2DW12_DT_WAKEUP_4_ODR - 3 # LIS2DW12_DT_WAKEUP_4_ODR
enum: [0, 1, 2, 3] enum: [0, 1, 2, 3]
sleep-duration:
type: int
default: 0
description: |
The sleep duration. Default value is the register reset value (0000 -> 16*1/ODR).
If the accelerometer readings of the all axes are lower
than the wakeup threshold value for the sleep duration long,
then a sleep trigger occurs or the device goes in sleep mode. This value is 4 bits long in the
register and 1 LSB = 512 * 1/ODR.
Value goes from 0 to 15
- 0 # LIS2DW12_DT_SLEEP_0_ODR
...
- 15 # LIS2DW12_DT_SLEEP_15_ODR
enum: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]

View file

@ -39,4 +39,22 @@
#define LIS2DW12_DT_WAKEUP_3_ODR 2 #define LIS2DW12_DT_WAKEUP_3_ODR 2
#define LIS2DW12_DT_WAKEUP_4_ODR 3 #define LIS2DW12_DT_WAKEUP_4_ODR 3
/* sleep duration */
#define LIS2DW12_DT_SLEEP_0_ODR 0
#define LIS2DW12_DT_SLEEP_1_ODR 1
#define LIS2DW12_DT_SLEEP_2_ODR 2
#define LIS2DW12_DT_SLEEP_3_ODR 3
#define LIS2DW12_DT_SLEEP_4_ODR 4
#define LIS2DW12_DT_SLEEP_5_ODR 5
#define LIS2DW12_DT_SLEEP_6_ODR 6
#define LIS2DW12_DT_SLEEP_7_ODR 7
#define LIS2DW12_DT_SLEEP_8_ODR 8
#define LIS2DW12_DT_SLEEP_9_ODR 9
#define LIS2DW12_DT_SLEEP_10_ODR 10
#define LIS2DW12_DT_SLEEP_11_ODR 11
#define LIS2DW12_DT_SLEEP_12_ODR 12
#define LIS2DW12_DT_SLEEP_13_ODR 13
#define LIS2DW12_DT_SLEEP_14_ODR 14
#define LIS2DW12_DT_SLEEP_15_ODR 15
#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DW12_H_ */ #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DW12_H_ */