Skip to content

Commit bf1334b

Browse files
maximevincenashif
authored andcommitted
drivers/sensor: lis2dw12: add threshold interrupt support
Add optional threshold interrupt support. Implemented using SENSOR_TRIG_THRESHOLD sensor trigger type. The features can be optionally enabled through Kconfig, or disabled for smaller code size. Signed-off-by: Maxime Vincent <[email protected]>
1 parent 652ab7f commit bf1334b

File tree

4 files changed

+154
-0
lines changed

4 files changed

+154
-0
lines changed

drivers/sensor/lis2dw12/Kconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,16 @@ config LIS2DW12_TAP
5959

6060
endif # LIS2DW12_TRIGGER
6161

62+
config LIS2DW12_THRESHOLD
63+
bool "Wakeup threshold trigger (via interrupt)"
64+
help
65+
Enable the wakeup threshold trigger feature.
66+
The wake-up interrupt signal is generated if a certain number of
67+
consecutive data exceed the configured threshold (config in DT).
68+
The threshold is applied to both positive and negative data: for
69+
a wake-up interrupt generation at least one of the three axes must
70+
be bigger than the threshold. See ST AN5038 for more details about
71+
the feature.
72+
73+
6274
endif # LIS2DW12

drivers/sensor/lis2dw12/lis2dw12.c

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#define DT_DRV_COMPAT st_lis2dw12
1212

1313
#include <init.h>
14+
#include <stdlib.h>
1415
#include <sys/__assert.h>
1516
#include <sys/byteorder.h>
1617
#include <logging/log.h>
@@ -157,11 +158,102 @@ static int lis2dw12_config(const struct device *dev, enum sensor_channel chan,
157158
return -ENOTSUP;
158159
}
159160

161+
162+
static inline int32_t sensor_ms2_to_mg(const struct sensor_value *ms2)
163+
{
164+
int64_t nano_ms2 = (ms2->val1 * 1000000LL + ms2->val2) * 1000LL;
165+
166+
if (nano_ms2 > 0) {
167+
return (nano_ms2 + SENSOR_G / 2) / SENSOR_G;
168+
} else {
169+
return (nano_ms2 - SENSOR_G / 2) / SENSOR_G;
170+
}
171+
}
172+
173+
#if CONFIG_LIS2DW12_THRESHOLD
174+
175+
/* Converts a lis2dw12_fs_t range to its value in milli-g
176+
* Range can be 2/4/8/16G
177+
*/
178+
#define FS_RANGE_TO_MG(fs_range) ((2U << fs_range) * 1000U)
179+
180+
/* Converts a range in mg to the lsb value for the WK_THS register
181+
* For the reg value: 1 LSB = 1/64 of FS
182+
* Range can be 2/4/8/16G
183+
*/
184+
#define MG_TO_WK_THS_LSB(range_mg) (range_mg / 64)
185+
186+
/* Calculates the WK_THS reg value
187+
* from the threshold in mg and the lsb value in mg
188+
* with correct integer rounding
189+
*/
190+
#define THRESHOLD_MG_TO_WK_THS_REG(thr_mg, lsb_mg) \
191+
((thr_mg + (lsb_mg / 2)) / lsb_mg)
192+
193+
static int lis2dw12_attr_set_thresh(const struct device *dev,
194+
enum sensor_channel chan,
195+
enum sensor_attribute attr,
196+
const struct sensor_value *val)
197+
{
198+
uint8_t reg;
199+
size_t ret;
200+
int lsb_mg;
201+
const struct lis2dw12_device_config *cfg = dev->config;
202+
stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
203+
204+
LOG_DBG("%s on channel %d", __func__, chan);
205+
206+
/* can only be set for all directions at once */
207+
if (chan != SENSOR_CHAN_ACCEL_XYZ) {
208+
return -EINVAL;
209+
}
210+
211+
/* Configure wakeup threshold threshold. */
212+
lis2dw12_fs_t range;
213+
int err = lis2dw12_full_scale_get(ctx, &range);
214+
215+
if (err) {
216+
return err;
217+
}
218+
219+
uint32_t thr_mg = abs(sensor_ms2_to_mg(val));
220+
221+
/* Check maximum value: depends on current FS value */
222+
if (thr_mg >= FS_RANGE_TO_MG(range)) {
223+
return -EINVAL;
224+
}
225+
226+
/* The threshold is applied to both positive and negative data:
227+
* for a wake-up interrupt generation at least one of the three axes must be
228+
* bigger than the threshold.
229+
*/
230+
lsb_mg = MG_TO_WK_THS_LSB(FS_RANGE_TO_MG(range));
231+
reg = THRESHOLD_MG_TO_WK_THS_REG(thr_mg, lsb_mg);
232+
233+
LOG_DBG("Threshold %d mg -> fs: %u mg -> reg = %d LSBs",
234+
thr_mg, FS_RANGE_TO_MG(range), reg);
235+
ret = 0;
236+
237+
return lis2dw12_wkup_threshold_set(ctx, reg);
238+
}
239+
#endif
240+
160241
static int lis2dw12_attr_set(const struct device *dev,
161242
enum sensor_channel chan,
162243
enum sensor_attribute attr,
163244
const struct sensor_value *val)
164245
{
246+
#if CONFIG_LIS2DW12_THRESHOLD
247+
switch (attr) {
248+
case SENSOR_ATTR_UPPER_THRESH:
249+
case SENSOR_ATTR_LOWER_THRESH:
250+
return lis2dw12_attr_set_thresh(dev, chan, attr, val);
251+
default:
252+
/* Do nothing */
253+
break;
254+
}
255+
#endif
256+
165257
switch (chan) {
166258
case SENSOR_CHAN_ACCEL_X:
167259
case SENSOR_CHAN_ACCEL_Y:

drivers/sensor/lis2dw12/lis2dw12.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ struct lis2dw12_data {
101101
sensor_trigger_handler_t tap_handler;
102102
sensor_trigger_handler_t double_tap_handler;
103103
#endif /* CONFIG_LIS2DW12_TAP */
104+
#ifdef CONFIG_LIS2DW12_THRESHOLD
105+
sensor_trigger_handler_t threshold_handler;
106+
#endif /* CONFIG_LIS2DW12_THRESHOLD */
104107
#if defined(CONFIG_LIS2DW12_TRIGGER_OWN_THREAD)
105108
K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LIS2DW12_THREAD_STACK_SIZE);
106109
struct k_thread thread;

drivers/sensor/lis2dw12/lis2dw12_trigger.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,21 @@ static int lis2dw12_enable_int(const struct device *dev,
6767
return lis2dw12_pin_int1_route_set(ctx,
6868
&int_route.ctrl4_int1_pad_ctrl);
6969
#endif /* CONFIG_LIS2DW12_TAP */
70+
#ifdef CONFIG_LIS2DW12_THRESHOLD
71+
/**
72+
* Trigger fires when channel reading transitions configured
73+
* thresholds. The thresholds are configured via the @ref
74+
* SENSOR_ATTR_LOWER_THRESH and @ref SENSOR_ATTR_UPPER_THRESH
75+
* attributes.
76+
*/
77+
case SENSOR_TRIG_THRESHOLD:
78+
LOG_DBG("Setting int1_wu: %d\n", enable);
79+
lis2dw12_pin_int1_route_get(ctx,
80+
&int_route.ctrl4_int1_pad_ctrl);
81+
int_route.ctrl4_int1_pad_ctrl.int1_wu = enable;
82+
return lis2dw12_pin_int1_route_set(ctx,
83+
&int_route.ctrl4_int1_pad_ctrl);
84+
#endif
7085
default:
7186
LOG_ERR("Unsupported trigger interrupt route %d", type);
7287
return -ENOTSUP;
@@ -121,6 +136,14 @@ int lis2dw12_trigger_set(const struct device *dev,
121136
lis2dw12->double_tap_handler = handler;
122137
return lis2dw12_enable_int(dev, SENSOR_TRIG_DOUBLE_TAP, state);
123138
#endif /* CONFIG_LIS2DW12_TAP */
139+
#ifdef CONFIG_LIS2DW12_THRESHOLD
140+
case SENSOR_TRIG_THRESHOLD:
141+
{
142+
LOG_DBG("Set trigger %d (handler: %p)\n", trig->type, handler);
143+
lis2dw12->threshold_handler = handler;
144+
return lis2dw12_enable_int(dev, SENSOR_TRIG_THRESHOLD, state);
145+
}
146+
#endif
124147
default:
125148
LOG_ERR("Unsupported sensor trigger");
126149
return -ENOTSUP;
@@ -179,6 +202,25 @@ static int lis2dw12_handle_double_tap_int(const struct device *dev)
179202
}
180203
#endif /* CONFIG_LIS2DW12_TAP */
181204

205+
#ifdef CONFIG_LIS2DW12_THRESHOLD
206+
static int lis2dw12_handle_wu_ia_int(const struct device *dev)
207+
{
208+
struct lis2dw12_data *lis2dw12 = dev->data;
209+
sensor_trigger_handler_t handler = lis2dw12->threshold_handler;
210+
211+
struct sensor_trigger thresh_trig = {
212+
.type = SENSOR_TRIG_THRESHOLD,
213+
.chan = SENSOR_CHAN_ALL,
214+
};
215+
216+
if (handler) {
217+
handler(dev, &thresh_trig);
218+
}
219+
220+
return 0;
221+
}
222+
#endif
223+
182224
/**
183225
* lis2dw12_handle_interrupt - handle the drdy event
184226
* read data and call handler if registered any
@@ -202,6 +244,11 @@ static void lis2dw12_handle_interrupt(const struct device *dev)
202244
lis2dw12_handle_double_tap_int(dev);
203245
}
204246
#endif /* CONFIG_LIS2DW12_TAP */
247+
#ifdef CONFIG_LIS2DW12_THRESHOLD
248+
if (sources.all_int_src.wu_ia) {
249+
lis2dw12_handle_wu_ia_int(dev);
250+
}
251+
#endif
205252

206253
gpio_pin_interrupt_configure_dt(&cfg->gpio_int,
207254
GPIO_INT_EDGE_TO_ACTIVE);

0 commit comments

Comments
 (0)