1 /* ST Microelectronics LIS2DW12 3-axis accelerometer driver
2 *
3 * Copyright (c) 2019 STMicroelectronics
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Datasheet:
8 * https://www.st.com/resource/en/datasheet/lis2dw12.pdf
9 */
10
11 #define DT_DRV_COMPAT st_lis2dw12
12
13 #include <zephyr/kernel.h>
14 #include <zephyr/drivers/sensor.h>
15 #include <zephyr/drivers/gpio.h>
16 #include <zephyr/logging/log.h>
17
18 #include "lis2dw12.h"
19
20 LOG_MODULE_DECLARE(LIS2DW12, CONFIG_SENSOR_LOG_LEVEL);
21
22 /**
23 * lis2dw12_enable_int - enable selected int pin to generate interrupt
24 */
lis2dw12_enable_int(const struct device * dev,enum sensor_trigger_type type,int enable)25 static int lis2dw12_enable_int(const struct device *dev,
26 enum sensor_trigger_type type, int enable)
27 {
28 const struct lis2dw12_device_config *cfg = dev->config;
29 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
30 lis2dw12_reg_t int_route;
31
32 switch (type) {
33 case SENSOR_TRIG_DATA_READY:
34 if (cfg->int_pin == 1) {
35 /* set interrupt for pin INT1 */
36 lis2dw12_pin_int1_route_get(ctx,
37 &int_route.ctrl4_int1_pad_ctrl);
38 int_route.ctrl4_int1_pad_ctrl.int1_drdy = enable;
39
40 return lis2dw12_pin_int1_route_set(ctx,
41 &int_route.ctrl4_int1_pad_ctrl);
42 } else {
43 /* set interrupt for pin INT2 */
44 lis2dw12_pin_int2_route_get(ctx,
45 &int_route.ctrl5_int2_pad_ctrl);
46 int_route.ctrl5_int2_pad_ctrl.int2_drdy = enable;
47
48 return lis2dw12_pin_int2_route_set(ctx,
49 &int_route.ctrl5_int2_pad_ctrl);
50 }
51 break;
52 #ifdef CONFIG_LIS2DW12_TAP
53 case SENSOR_TRIG_TAP:
54 /* set interrupt for pin INT1 */
55 lis2dw12_pin_int1_route_get(ctx,
56 &int_route.ctrl4_int1_pad_ctrl);
57 int_route.ctrl4_int1_pad_ctrl.int1_single_tap = enable;
58
59 return lis2dw12_pin_int1_route_set(ctx,
60 &int_route.ctrl4_int1_pad_ctrl);
61 case SENSOR_TRIG_DOUBLE_TAP:
62 /* set interrupt for pin INT1 */
63 lis2dw12_pin_int1_route_get(ctx,
64 &int_route.ctrl4_int1_pad_ctrl);
65 int_route.ctrl4_int1_pad_ctrl.int1_tap = enable;
66
67 return lis2dw12_pin_int1_route_set(ctx,
68 &int_route.ctrl4_int1_pad_ctrl);
69 #endif /* CONFIG_LIS2DW12_TAP */
70 #ifdef CONFIG_LIS2DW12_WAKEUP
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_MOTION:
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
85 #ifdef CONFIG_LIS2DW12_SLEEP
86 /**
87 * Trigger fires when channel reading transitions configured
88 * thresholds for a certain time. The thresholds are configured
89 * via the @ref SENSOR_ATTR_LOWER_THRESH and @ref SENSOR_ATTR_UPPER_THRESH
90 * attributes.
91 */
92 case SENSOR_TRIG_STATIONARY:
93 LOG_DBG("Setting int2_sleep_chg: %d\n", enable);
94 lis2dw12_pin_int2_route_get(ctx,
95 &int_route.ctrl5_int2_pad_ctrl);
96 int_route.ctrl5_int2_pad_ctrl.int2_sleep_chg = enable;
97 return lis2dw12_pin_int2_route_set(ctx,
98 &int_route.ctrl5_int2_pad_ctrl);
99 #endif
100 #ifdef CONFIG_LIS2DW12_FREEFALL
101 /**
102 * Trigger fires when the readings does not include Earth's
103 * gravitional force for configured duration and threshold.
104 * The duration and the threshold can be configured in the
105 * devicetree source of the accelerometer node.
106 */
107 case SENSOR_TRIG_FREEFALL:
108 LOG_DBG("Setting int1_ff: %d\n", enable);
109 lis2dw12_pin_int1_route_get(ctx,
110 &int_route.ctrl4_int1_pad_ctrl);
111 int_route.ctrl4_int1_pad_ctrl.int1_ff = enable;
112 return lis2dw12_pin_int1_route_set(ctx,
113 &int_route.ctrl4_int1_pad_ctrl);
114 #endif /* CONFIG_LIS2DW12_FREEFALL */
115 default:
116 LOG_ERR("Unsupported trigger interrupt route %d", type);
117 return -ENOTSUP;
118 }
119 }
120
121 /**
122 * lis2dw12_trigger_set - link external trigger to event data ready
123 */
lis2dw12_trigger_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)124 int lis2dw12_trigger_set(const struct device *dev,
125 const struct sensor_trigger *trig,
126 sensor_trigger_handler_t handler)
127 {
128 const struct lis2dw12_device_config *cfg = dev->config;
129 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
130 struct lis2dw12_data *lis2dw12 = dev->data;
131 int16_t raw[3];
132 int state = (handler != NULL) ? PROPERTY_ENABLE : PROPERTY_DISABLE;
133
134 if (cfg->gpio_int.port == NULL) {
135 LOG_ERR("trigger_set is not supported");
136 return -ENOTSUP;
137 }
138
139 switch (trig->type) {
140 case SENSOR_TRIG_DATA_READY:
141 lis2dw12->drdy_handler = handler;
142 lis2dw12->drdy_trig = trig;
143 if (state) {
144 /* dummy read: re-trigger interrupt */
145 lis2dw12_acceleration_raw_get(ctx, raw);
146 }
147 return lis2dw12_enable_int(dev, SENSOR_TRIG_DATA_READY, state);
148 break;
149 #ifdef CONFIG_LIS2DW12_TAP
150 case SENSOR_TRIG_TAP:
151 case SENSOR_TRIG_DOUBLE_TAP:
152 /* check if tap detection is enabled */
153 if ((cfg->tap_threshold[0] == 0) &&
154 (cfg->tap_threshold[1] == 0) &&
155 (cfg->tap_threshold[2] == 0)) {
156 LOG_ERR("Unsupported sensor trigger");
157 return -ENOTSUP;
158 }
159
160 /* Set single TAP trigger */
161 if (trig->type == SENSOR_TRIG_TAP) {
162 lis2dw12->tap_handler = handler;
163 lis2dw12->tap_trig = trig;
164 return lis2dw12_enable_int(dev, SENSOR_TRIG_TAP, state);
165 }
166
167 /* Set double TAP trigger */
168 lis2dw12->double_tap_handler = handler;
169 lis2dw12->double_tap_trig = trig;
170 return lis2dw12_enable_int(dev, SENSOR_TRIG_DOUBLE_TAP, state);
171 #endif /* CONFIG_LIS2DW12_TAP */
172 #ifdef CONFIG_LIS2DW12_WAKEUP
173 case SENSOR_TRIG_MOTION:
174 {
175 LOG_DBG("Set trigger %d (handler: %p)\n", trig->type, handler);
176 lis2dw12->motion_handler = handler;
177 lis2dw12->motion_trig = trig;
178 return lis2dw12_enable_int(dev, SENSOR_TRIG_MOTION, state);
179 }
180 #endif
181 #ifdef CONFIG_LIS2DW12_SLEEP
182 case SENSOR_TRIG_STATIONARY:
183 {
184 LOG_DBG("Set trigger %d (handler: %p)\n", trig->type, handler);
185 lis2dw12->stationary_handler = handler;
186 lis2dw12->stationary_trig = trig;
187 return lis2dw12_enable_int(dev, SENSOR_TRIG_STATIONARY, state);
188 }
189 #endif
190 #ifdef CONFIG_LIS2DW12_FREEFALL
191 case SENSOR_TRIG_FREEFALL:
192 LOG_DBG("Set freefall %d (handler: %p)\n", trig->type, handler);
193 lis2dw12->freefall_handler = handler;
194 lis2dw12->freefall_trig = trig;
195 return lis2dw12_enable_int(dev, SENSOR_TRIG_FREEFALL, state);
196 break;
197 #endif /* CONFIG_LIS2DW12_FREEFALL */
198 default:
199 LOG_ERR("Unsupported sensor trigger");
200 return -ENOTSUP;
201 }
202 }
203
lis2dw12_handle_drdy_int(const struct device * dev)204 static int lis2dw12_handle_drdy_int(const struct device *dev)
205 {
206 struct lis2dw12_data *data = dev->data;
207
208 if (data->drdy_handler) {
209 data->drdy_handler(dev, data->drdy_trig);
210 }
211
212 return 0;
213 }
214
215 #ifdef CONFIG_LIS2DW12_TAP
lis2dw12_handle_single_tap_int(const struct device * dev)216 static int lis2dw12_handle_single_tap_int(const struct device *dev)
217 {
218 struct lis2dw12_data *data = dev->data;
219 sensor_trigger_handler_t handler = data->tap_handler;
220
221 if (handler) {
222 handler(dev, data->tap_trig);
223 }
224
225 return 0;
226 }
227
lis2dw12_handle_double_tap_int(const struct device * dev)228 static int lis2dw12_handle_double_tap_int(const struct device *dev)
229 {
230 struct lis2dw12_data *data = dev->data;
231 sensor_trigger_handler_t handler = data->double_tap_handler;
232
233 if (handler) {
234 handler(dev, data->double_tap_trig);
235 }
236
237 return 0;
238 }
239 #endif /* CONFIG_LIS2DW12_TAP */
240
241 #ifdef CONFIG_LIS2DW12_WAKEUP
lis2dw12_handle_wu_ia_int(const struct device * dev)242 static int lis2dw12_handle_wu_ia_int(const struct device *dev)
243 {
244 struct lis2dw12_data *lis2dw12 = dev->data;
245 sensor_trigger_handler_t handler = lis2dw12->motion_handler;
246
247 if (handler) {
248 handler(dev, lis2dw12->motion_trig);
249 }
250
251 return 0;
252 }
253 #endif
254
255 #ifdef CONFIG_LIS2DW12_SLEEP
lis2dw12_handle_sleep_change_int(const struct device * dev)256 static int lis2dw12_handle_sleep_change_int(const struct device *dev)
257 {
258 struct lis2dw12_data *lis2dw12 = dev->data;
259 sensor_trigger_handler_t handler = lis2dw12->stationary_handler;
260
261 if (handler) {
262 handler(dev, lis2dw12->stationary_trig);
263 }
264
265 return 0;
266 }
267 #endif
268
269 #ifdef CONFIG_LIS2DW12_FREEFALL
lis2dw12_handle_ff_ia_int(const struct device * dev)270 static int lis2dw12_handle_ff_ia_int(const struct device *dev)
271 {
272 struct lis2dw12_data *lis2dw12 = dev->data;
273 sensor_trigger_handler_t handler = lis2dw12->freefall_handler;
274
275 if (handler) {
276 handler(dev, lis2dw12->freefall_trig);
277 }
278
279 return 0;
280 }
281 #endif /* CONFIG_LIS2DW12_FREEFALL */
282
283 /**
284 * lis2dw12_handle_interrupt - handle the drdy event
285 * read data and call handler if registered any
286 */
lis2dw12_handle_interrupt(const struct device * dev)287 static void lis2dw12_handle_interrupt(const struct device *dev)
288 {
289 const struct lis2dw12_device_config *cfg = dev->config;
290 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
291 lis2dw12_all_sources_t sources;
292
293 lis2dw12_all_sources_get(ctx, &sources);
294
295 if (sources.status_dup.drdy) {
296 lis2dw12_handle_drdy_int(dev);
297 }
298 #ifdef CONFIG_LIS2DW12_TAP
299 if (sources.status_dup.single_tap) {
300 lis2dw12_handle_single_tap_int(dev);
301 }
302 if (sources.status_dup.double_tap) {
303 lis2dw12_handle_double_tap_int(dev);
304 }
305 #endif /* CONFIG_LIS2DW12_TAP */
306 #ifdef CONFIG_LIS2DW12_WAKEUP
307 if (sources.all_int_src.wu_ia) {
308 lis2dw12_handle_wu_ia_int(dev);
309 }
310 #endif
311 #ifdef CONFIG_LIS2DW12_SLEEP
312 if (sources.all_int_src.sleep_change_ia) {
313 lis2dw12_handle_sleep_change_int(dev);
314 }
315 #endif
316 #ifdef CONFIG_LIS2DW12_FREEFALL
317 if (sources.all_int_src.ff_ia) {
318 lis2dw12_handle_ff_ia_int(dev);
319 }
320 #endif /* CONFIG_LIS2DW12_FREEFALL */
321
322 gpio_pin_interrupt_configure_dt(&cfg->gpio_int,
323 GPIO_INT_EDGE_TO_ACTIVE);
324 }
325
lis2dw12_gpio_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)326 static void lis2dw12_gpio_callback(const struct device *dev,
327 struct gpio_callback *cb, uint32_t pins)
328 {
329 struct lis2dw12_data *lis2dw12 =
330 CONTAINER_OF(cb, struct lis2dw12_data, gpio_cb);
331 const struct lis2dw12_device_config *cfg = lis2dw12->dev->config;
332
333 if ((pins & BIT(cfg->gpio_int.pin)) == 0U) {
334 return;
335 }
336
337 gpio_pin_interrupt_configure_dt(&cfg->gpio_int, GPIO_INT_DISABLE);
338
339 #if defined(CONFIG_LIS2DW12_TRIGGER_OWN_THREAD)
340 k_sem_give(&lis2dw12->gpio_sem);
341 #elif defined(CONFIG_LIS2DW12_TRIGGER_GLOBAL_THREAD)
342 k_work_submit(&lis2dw12->work);
343 #endif /* CONFIG_LIS2DW12_TRIGGER_OWN_THREAD */
344 }
345
346 #ifdef CONFIG_LIS2DW12_TRIGGER_OWN_THREAD
lis2dw12_thread(void * p1,void * p2,void * p3)347 static void lis2dw12_thread(void *p1, void *p2, void *p3)
348 {
349 ARG_UNUSED(p2);
350 ARG_UNUSED(p3);
351
352 struct lis2dw12_data *lis2dw12 = p1;
353
354 while (1) {
355 k_sem_take(&lis2dw12->gpio_sem, K_FOREVER);
356 lis2dw12_handle_interrupt(lis2dw12->dev);
357 }
358 }
359 #endif /* CONFIG_LIS2DW12_TRIGGER_OWN_THREAD */
360
361 #ifdef CONFIG_LIS2DW12_TRIGGER_GLOBAL_THREAD
lis2dw12_work_cb(struct k_work * work)362 static void lis2dw12_work_cb(struct k_work *work)
363 {
364 struct lis2dw12_data *lis2dw12 =
365 CONTAINER_OF(work, struct lis2dw12_data, work);
366
367 lis2dw12_handle_interrupt(lis2dw12->dev);
368 }
369 #endif /* CONFIG_LIS2DW12_TRIGGER_GLOBAL_THREAD */
370
371 #ifdef CONFIG_LIS2DW12_TAP
lis2dw12_tap_init(const struct device * dev)372 static int lis2dw12_tap_init(const struct device *dev)
373 {
374 const struct lis2dw12_device_config *cfg = dev->config;
375 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
376
377 LOG_DBG("TAP: tap mode is %d", cfg->tap_mode);
378 if (lis2dw12_tap_mode_set(ctx, cfg->tap_mode) < 0) {
379 LOG_ERR("Failed to select tap trigger mode");
380 return -EIO;
381 }
382
383 LOG_DBG("TAP: ths_x is %02x", cfg->tap_threshold[0]);
384 if (lis2dw12_tap_threshold_x_set(ctx, cfg->tap_threshold[0]) < 0) {
385 LOG_ERR("Failed to set tap X axis threshold");
386 return -EIO;
387 }
388
389 LOG_DBG("TAP: ths_y is %02x", cfg->tap_threshold[1]);
390 if (lis2dw12_tap_threshold_y_set(ctx, cfg->tap_threshold[1]) < 0) {
391 LOG_ERR("Failed to set tap Y axis threshold");
392 return -EIO;
393 }
394
395 LOG_DBG("TAP: ths_z is %02x", cfg->tap_threshold[2]);
396 if (lis2dw12_tap_threshold_z_set(ctx, cfg->tap_threshold[2]) < 0) {
397 LOG_ERR("Failed to set tap Z axis threshold");
398 return -EIO;
399 }
400
401 if (cfg->tap_threshold[0] > 0) {
402 LOG_DBG("TAP: tap_x enabled");
403 if (lis2dw12_tap_detection_on_x_set(ctx, 1) < 0) {
404 LOG_ERR("Failed to set tap detection on X axis");
405 return -EIO;
406 }
407 }
408
409 if (cfg->tap_threshold[1] > 0) {
410 LOG_DBG("TAP: tap_y enabled");
411 if (lis2dw12_tap_detection_on_y_set(ctx, 1) < 0) {
412 LOG_ERR("Failed to set tap detection on Y axis");
413 return -EIO;
414 }
415 }
416
417 if (cfg->tap_threshold[2] > 0) {
418 LOG_DBG("TAP: tap_z enabled");
419 if (lis2dw12_tap_detection_on_z_set(ctx, 1) < 0) {
420 LOG_ERR("Failed to set tap detection on Z axis");
421 return -EIO;
422 }
423 }
424
425 LOG_DBG("TAP: shock is %02x", cfg->tap_shock);
426 if (lis2dw12_tap_shock_set(ctx, cfg->tap_shock) < 0) {
427 LOG_ERR("Failed to set tap shock duration");
428 return -EIO;
429 }
430
431 LOG_DBG("TAP: latency is %02x", cfg->tap_latency);
432 if (lis2dw12_tap_dur_set(ctx, cfg->tap_latency) < 0) {
433 LOG_ERR("Failed to set tap latency");
434 return -EIO;
435 }
436
437 LOG_DBG("TAP: quiet time is %02x", cfg->tap_quiet);
438 if (lis2dw12_tap_quiet_set(ctx, cfg->tap_quiet) < 0) {
439 LOG_ERR("Failed to set tap quiet time");
440 return -EIO;
441 }
442
443 return 0;
444 }
445 #endif /* CONFIG_LIS2DW12_TAP */
446
447 #ifdef CONFIG_LIS2DW12_FREEFALL
lis2dw12_ff_init(const struct device * dev)448 static int lis2dw12_ff_init(const struct device *dev)
449 {
450 int rc;
451 const struct lis2dw12_device_config *cfg = dev->config;
452 struct lis2dw12_data *lis2dw12 = dev->data;
453 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
454 uint16_t duration;
455
456 duration = (lis2dw12->odr * cfg->freefall_duration) / 1000;
457
458 LOG_DBG("FREEFALL: duration is %d ms", cfg->freefall_duration);
459 rc = lis2dw12_ff_dur_set(ctx, duration);
460 if (rc != 0) {
461 LOG_ERR("Failed to set freefall duration");
462 return -EIO;
463 }
464
465 LOG_DBG("FREEFALL: threshold is %02x", cfg->freefall_threshold);
466 rc = lis2dw12_ff_threshold_set(ctx, cfg->freefall_threshold);
467 if (rc != 0) {
468 LOG_ERR("Failed to set freefall thrshold");
469 return -EIO;
470 }
471 return 0;
472 }
473 #endif /* CONFIG_LIS2DW12_FREEFALL */
474
lis2dw12_init_interrupt(const struct device * dev)475 int lis2dw12_init_interrupt(const struct device *dev)
476 {
477 struct lis2dw12_data *lis2dw12 = dev->data;
478 const struct lis2dw12_device_config *cfg = dev->config;
479 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
480 int ret;
481
482 /* setup data ready gpio interrupt (INT1 or INT2) */
483 if (!gpio_is_ready_dt(&cfg->gpio_int)) {
484 if (cfg->gpio_int.port) {
485 LOG_ERR("%s: device %s is not ready", dev->name,
486 cfg->gpio_int.port->name);
487 return -ENODEV;
488 }
489
490 LOG_DBG("%s: gpio_int not defined in DT", dev->name);
491 return 0;
492 }
493
494 lis2dw12->dev = dev;
495
496 LOG_INF("%s: int-pin is on INT%d", dev->name, cfg->int_pin);
497 #if defined(CONFIG_LIS2DW12_TRIGGER_OWN_THREAD)
498 k_sem_init(&lis2dw12->gpio_sem, 0, K_SEM_MAX_LIMIT);
499
500 k_thread_create(&lis2dw12->thread, lis2dw12->thread_stack,
501 CONFIG_LIS2DW12_THREAD_STACK_SIZE,
502 lis2dw12_thread, lis2dw12,
503 NULL, NULL, K_PRIO_COOP(CONFIG_LIS2DW12_THREAD_PRIORITY),
504 0, K_NO_WAIT);
505 #elif defined(CONFIG_LIS2DW12_TRIGGER_GLOBAL_THREAD)
506 lis2dw12->work.handler = lis2dw12_work_cb;
507 #endif /* CONFIG_LIS2DW12_TRIGGER_OWN_THREAD */
508
509 ret = gpio_pin_configure_dt(&cfg->gpio_int, GPIO_INPUT);
510 if (ret < 0) {
511 LOG_ERR("Could not configure gpio");
512 return ret;
513 }
514
515 LOG_INF("%s: int on %s.%02u", dev->name, cfg->gpio_int.port->name,
516 cfg->gpio_int.pin);
517
518 gpio_init_callback(&lis2dw12->gpio_cb,
519 lis2dw12_gpio_callback,
520 BIT(cfg->gpio_int.pin));
521
522 if (gpio_add_callback(cfg->gpio_int.port, &lis2dw12->gpio_cb) < 0) {
523 LOG_DBG("Could not set gpio callback");
524 return -EIO;
525 }
526
527 /* set data ready mode on int1/int2 */
528 LOG_DBG("drdy_pulsed is %d", (int)cfg->drdy_pulsed);
529 lis2dw12_drdy_pulsed_t mode = cfg->drdy_pulsed ? LIS2DW12_DRDY_PULSED :
530 LIS2DW12_DRDY_LATCHED;
531
532 ret = lis2dw12_data_ready_mode_set(ctx, mode);
533 if (ret < 0) {
534 LOG_ERR("drdy_pulsed config error %d", (int)cfg->drdy_pulsed);
535 return ret;
536 }
537
538 #ifdef CONFIG_LIS2DW12_TAP
539 ret = lis2dw12_tap_init(dev);
540 if (ret < 0) {
541 return ret;
542 }
543 #endif /* CONFIG_LIS2DW12_TAP */
544
545 #ifdef CONFIG_LIS2DW12_FREEFALL
546 ret = lis2dw12_ff_init(dev);
547 if (ret < 0) {
548 return ret;
549 }
550 #endif /* CONFIG_LIS2DW12_FREEFALL */
551
552 return gpio_pin_interrupt_configure_dt(&cfg->gpio_int,
553 GPIO_INT_EDGE_TO_ACTIVE);
554 }
555