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_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
85 #ifdef CONFIG_LIS2DW12_FREEFALL
86 /**
87 * Trigger fires when the readings does not include Earth's
88 * gravitional force for configured duration and threshold.
89 * The duration and the threshold can be configured in the
90 * devicetree source of the accelerometer node.
91 */
92 case SENSOR_TRIG_FREEFALL:
93 LOG_DBG("Setting int1_ff: %d\n", enable);
94 lis2dw12_pin_int1_route_get(ctx,
95 &int_route.ctrl4_int1_pad_ctrl);
96 int_route.ctrl4_int1_pad_ctrl.int1_ff = enable;
97 return lis2dw12_pin_int1_route_set(ctx,
98 &int_route.ctrl4_int1_pad_ctrl);
99 #endif /* CONFIG_LIS2DW12_FREEFALL */
100 default:
101 LOG_ERR("Unsupported trigger interrupt route %d", type);
102 return -ENOTSUP;
103 }
104 }
105
106 /**
107 * lis2dw12_trigger_set - link external trigger to event data ready
108 */
lis2dw12_trigger_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)109 int lis2dw12_trigger_set(const struct device *dev,
110 const struct sensor_trigger *trig,
111 sensor_trigger_handler_t handler)
112 {
113 const struct lis2dw12_device_config *cfg = dev->config;
114 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
115 struct lis2dw12_data *lis2dw12 = dev->data;
116 int16_t raw[3];
117 int state = (handler != NULL) ? PROPERTY_ENABLE : PROPERTY_DISABLE;
118
119 if (cfg->gpio_int.port == NULL) {
120 LOG_ERR("trigger_set is not supported");
121 return -ENOTSUP;
122 }
123
124 switch (trig->type) {
125 case SENSOR_TRIG_DATA_READY:
126 lis2dw12->drdy_handler = handler;
127 lis2dw12->drdy_trig = trig;
128 if (state) {
129 /* dummy read: re-trigger interrupt */
130 lis2dw12_acceleration_raw_get(ctx, raw);
131 }
132 return lis2dw12_enable_int(dev, SENSOR_TRIG_DATA_READY, state);
133 break;
134 #ifdef CONFIG_LIS2DW12_TAP
135 case SENSOR_TRIG_TAP:
136 case SENSOR_TRIG_DOUBLE_TAP:
137 /* check if tap detection is enabled */
138 if ((cfg->tap_threshold[0] == 0) &&
139 (cfg->tap_threshold[1] == 0) &&
140 (cfg->tap_threshold[2] == 0)) {
141 LOG_ERR("Unsupported sensor trigger");
142 return -ENOTSUP;
143 }
144
145 /* Set single TAP trigger */
146 if (trig->type == SENSOR_TRIG_TAP) {
147 lis2dw12->tap_handler = handler;
148 lis2dw12->tap_trig = trig;
149 return lis2dw12_enable_int(dev, SENSOR_TRIG_TAP, state);
150 }
151
152 /* Set double TAP trigger */
153 lis2dw12->double_tap_handler = handler;
154 lis2dw12->double_tap_trig = trig;
155 return lis2dw12_enable_int(dev, SENSOR_TRIG_DOUBLE_TAP, state);
156 #endif /* CONFIG_LIS2DW12_TAP */
157 #ifdef CONFIG_LIS2DW12_THRESHOLD
158 case SENSOR_TRIG_THRESHOLD:
159 {
160 LOG_DBG("Set trigger %d (handler: %p)\n", trig->type, handler);
161 lis2dw12->threshold_handler = handler;
162 lis2dw12->threshold_trig = trig;
163 return lis2dw12_enable_int(dev, SENSOR_TRIG_THRESHOLD, state);
164 }
165 #endif
166 #ifdef CONFIG_LIS2DW12_FREEFALL
167 case SENSOR_TRIG_FREEFALL:
168 LOG_DBG("Set freefall %d (handler: %p)\n", trig->type, handler);
169 lis2dw12->freefall_handler = handler;
170 lis2dw12->freefall_trig = trig;
171 return lis2dw12_enable_int(dev, SENSOR_TRIG_FREEFALL, state);
172 break;
173 #endif /* CONFIG_LIS2DW12_FREEFALL */
174 default:
175 LOG_ERR("Unsupported sensor trigger");
176 return -ENOTSUP;
177 }
178 }
179
lis2dw12_handle_drdy_int(const struct device * dev)180 static int lis2dw12_handle_drdy_int(const struct device *dev)
181 {
182 struct lis2dw12_data *data = dev->data;
183
184 if (data->drdy_handler) {
185 data->drdy_handler(dev, data->drdy_trig);
186 }
187
188 return 0;
189 }
190
191 #ifdef CONFIG_LIS2DW12_TAP
lis2dw12_handle_single_tap_int(const struct device * dev)192 static int lis2dw12_handle_single_tap_int(const struct device *dev)
193 {
194 struct lis2dw12_data *data = dev->data;
195 sensor_trigger_handler_t handler = data->tap_handler;
196
197 if (handler) {
198 handler(dev, data->tap_trig);
199 }
200
201 return 0;
202 }
203
lis2dw12_handle_double_tap_int(const struct device * dev)204 static int lis2dw12_handle_double_tap_int(const struct device *dev)
205 {
206 struct lis2dw12_data *data = dev->data;
207 sensor_trigger_handler_t handler = data->double_tap_handler;
208
209 if (handler) {
210 handler(dev, data->double_tap_trig);
211 }
212
213 return 0;
214 }
215 #endif /* CONFIG_LIS2DW12_TAP */
216
217 #ifdef CONFIG_LIS2DW12_THRESHOLD
lis2dw12_handle_wu_ia_int(const struct device * dev)218 static int lis2dw12_handle_wu_ia_int(const struct device *dev)
219 {
220 struct lis2dw12_data *lis2dw12 = dev->data;
221 sensor_trigger_handler_t handler = lis2dw12->threshold_handler;
222
223 if (handler) {
224 handler(dev, lis2dw12->threshold_trig);
225 }
226
227 return 0;
228 }
229 #endif
230
231 #ifdef CONFIG_LIS2DW12_FREEFALL
lis2dw12_handle_ff_ia_int(const struct device * dev)232 static int lis2dw12_handle_ff_ia_int(const struct device *dev)
233 {
234 struct lis2dw12_data *lis2dw12 = dev->data;
235 sensor_trigger_handler_t handler = lis2dw12->freefall_handler;
236
237 if (handler) {
238 handler(dev, lis2dw12->freefall_trig);
239 }
240
241 return 0;
242 }
243 #endif /* CONFIG_LIS2DW12_FREEFALL */
244
245 /**
246 * lis2dw12_handle_interrupt - handle the drdy event
247 * read data and call handler if registered any
248 */
lis2dw12_handle_interrupt(const struct device * dev)249 static void lis2dw12_handle_interrupt(const struct device *dev)
250 {
251 const struct lis2dw12_device_config *cfg = dev->config;
252 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
253 lis2dw12_all_sources_t sources;
254
255 lis2dw12_all_sources_get(ctx, &sources);
256
257 if (sources.status_dup.drdy) {
258 lis2dw12_handle_drdy_int(dev);
259 }
260 #ifdef CONFIG_LIS2DW12_TAP
261 if (sources.status_dup.single_tap) {
262 lis2dw12_handle_single_tap_int(dev);
263 }
264 if (sources.status_dup.double_tap) {
265 lis2dw12_handle_double_tap_int(dev);
266 }
267 #endif /* CONFIG_LIS2DW12_TAP */
268 #ifdef CONFIG_LIS2DW12_THRESHOLD
269 if (sources.all_int_src.wu_ia) {
270 lis2dw12_handle_wu_ia_int(dev);
271 }
272 #endif
273 #ifdef CONFIG_LIS2DW12_FREEFALL
274 if (sources.all_int_src.ff_ia) {
275 lis2dw12_handle_ff_ia_int(dev);
276 }
277 #endif /* CONFIG_LIS2DW12_FREEFALL */
278
279 gpio_pin_interrupt_configure_dt(&cfg->gpio_int,
280 GPIO_INT_EDGE_TO_ACTIVE);
281 }
282
lis2dw12_gpio_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)283 static void lis2dw12_gpio_callback(const struct device *dev,
284 struct gpio_callback *cb, uint32_t pins)
285 {
286 struct lis2dw12_data *lis2dw12 =
287 CONTAINER_OF(cb, struct lis2dw12_data, gpio_cb);
288 const struct lis2dw12_device_config *cfg = lis2dw12->dev->config;
289
290 if ((pins & BIT(cfg->gpio_int.pin)) == 0U) {
291 return;
292 }
293
294 gpio_pin_interrupt_configure_dt(&cfg->gpio_int, GPIO_INT_DISABLE);
295
296 #if defined(CONFIG_LIS2DW12_TRIGGER_OWN_THREAD)
297 k_sem_give(&lis2dw12->gpio_sem);
298 #elif defined(CONFIG_LIS2DW12_TRIGGER_GLOBAL_THREAD)
299 k_work_submit(&lis2dw12->work);
300 #endif /* CONFIG_LIS2DW12_TRIGGER_OWN_THREAD */
301 }
302
303 #ifdef CONFIG_LIS2DW12_TRIGGER_OWN_THREAD
lis2dw12_thread(struct lis2dw12_data * lis2dw12)304 static void lis2dw12_thread(struct lis2dw12_data *lis2dw12)
305 {
306 while (1) {
307 k_sem_take(&lis2dw12->gpio_sem, K_FOREVER);
308 lis2dw12_handle_interrupt(lis2dw12->dev);
309 }
310 }
311 #endif /* CONFIG_LIS2DW12_TRIGGER_OWN_THREAD */
312
313 #ifdef CONFIG_LIS2DW12_TRIGGER_GLOBAL_THREAD
lis2dw12_work_cb(struct k_work * work)314 static void lis2dw12_work_cb(struct k_work *work)
315 {
316 struct lis2dw12_data *lis2dw12 =
317 CONTAINER_OF(work, struct lis2dw12_data, work);
318
319 lis2dw12_handle_interrupt(lis2dw12->dev);
320 }
321 #endif /* CONFIG_LIS2DW12_TRIGGER_GLOBAL_THREAD */
322
323 #ifdef CONFIG_LIS2DW12_TAP
lis2dw12_tap_init(const struct device * dev)324 static int lis2dw12_tap_init(const struct device *dev)
325 {
326 const struct lis2dw12_device_config *cfg = dev->config;
327 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
328
329 LOG_DBG("TAP: tap mode is %d", cfg->tap_mode);
330 if (lis2dw12_tap_mode_set(ctx, cfg->tap_mode) < 0) {
331 LOG_ERR("Failed to select tap trigger mode");
332 return -EIO;
333 }
334
335 LOG_DBG("TAP: ths_x is %02x", cfg->tap_threshold[0]);
336 if (lis2dw12_tap_threshold_x_set(ctx, cfg->tap_threshold[0]) < 0) {
337 LOG_ERR("Failed to set tap X axis threshold");
338 return -EIO;
339 }
340
341 LOG_DBG("TAP: ths_y is %02x", cfg->tap_threshold[1]);
342 if (lis2dw12_tap_threshold_y_set(ctx, cfg->tap_threshold[1]) < 0) {
343 LOG_ERR("Failed to set tap Y axis threshold");
344 return -EIO;
345 }
346
347 LOG_DBG("TAP: ths_z is %02x", cfg->tap_threshold[2]);
348 if (lis2dw12_tap_threshold_z_set(ctx, cfg->tap_threshold[2]) < 0) {
349 LOG_ERR("Failed to set tap Z axis threshold");
350 return -EIO;
351 }
352
353 if (cfg->tap_threshold[0] > 0) {
354 LOG_DBG("TAP: tap_x enabled");
355 if (lis2dw12_tap_detection_on_x_set(ctx, 1) < 0) {
356 LOG_ERR("Failed to set tap detection on X axis");
357 return -EIO;
358 }
359 }
360
361 if (cfg->tap_threshold[1] > 0) {
362 LOG_DBG("TAP: tap_y enabled");
363 if (lis2dw12_tap_detection_on_y_set(ctx, 1) < 0) {
364 LOG_ERR("Failed to set tap detection on Y axis");
365 return -EIO;
366 }
367 }
368
369 if (cfg->tap_threshold[2] > 0) {
370 LOG_DBG("TAP: tap_z enabled");
371 if (lis2dw12_tap_detection_on_z_set(ctx, 1) < 0) {
372 LOG_ERR("Failed to set tap detection on Z axis");
373 return -EIO;
374 }
375 }
376
377 LOG_DBG("TAP: shock is %02x", cfg->tap_shock);
378 if (lis2dw12_tap_shock_set(ctx, cfg->tap_shock) < 0) {
379 LOG_ERR("Failed to set tap shock duration");
380 return -EIO;
381 }
382
383 LOG_DBG("TAP: latency is %02x", cfg->tap_latency);
384 if (lis2dw12_tap_dur_set(ctx, cfg->tap_latency) < 0) {
385 LOG_ERR("Failed to set tap latency");
386 return -EIO;
387 }
388
389 LOG_DBG("TAP: quiet time is %02x", cfg->tap_quiet);
390 if (lis2dw12_tap_quiet_set(ctx, cfg->tap_quiet) < 0) {
391 LOG_ERR("Failed to set tap quiet time");
392 return -EIO;
393 }
394
395 return 0;
396 }
397 #endif /* CONFIG_LIS2DW12_TAP */
398
399 #ifdef CONFIG_LIS2DW12_FREEFALL
lis2dw12_ff_init(const struct device * dev)400 static int lis2dw12_ff_init(const struct device *dev)
401 {
402 int rc;
403 const struct lis2dw12_device_config *cfg = dev->config;
404 struct lis2dw12_data *lis2dw12 = dev->data;
405 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
406 uint16_t duration;
407
408 duration = (lis2dw12->odr * cfg->freefall_duration) / 1000;
409
410 LOG_DBG("FREEFALL: duration is %d ms", cfg->freefall_duration);
411 rc = lis2dw12_ff_dur_set(ctx, duration);
412 if (rc != 0) {
413 LOG_ERR("Failed to set freefall duration");
414 return -EIO;
415 }
416
417 LOG_DBG("FREEFALL: threshold is %02x", cfg->freefall_threshold);
418 rc = lis2dw12_ff_threshold_set(ctx, cfg->freefall_threshold);
419 if (rc != 0) {
420 LOG_ERR("Failed to set freefall thrshold");
421 return -EIO;
422 }
423 return 0;
424 }
425 #endif /* CONFIG_LIS2DW12_FREEFALL */
426
lis2dw12_init_interrupt(const struct device * dev)427 int lis2dw12_init_interrupt(const struct device *dev)
428 {
429 struct lis2dw12_data *lis2dw12 = dev->data;
430 const struct lis2dw12_device_config *cfg = dev->config;
431 stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
432 int ret;
433
434 /* setup data ready gpio interrupt (INT1 or INT2) */
435 if (!gpio_is_ready_dt(&cfg->gpio_int)) {
436 if (cfg->gpio_int.port) {
437 LOG_ERR("%s: device %s is not ready", dev->name,
438 cfg->gpio_int.port->name);
439 return -ENODEV;
440 }
441
442 LOG_DBG("%s: gpio_int not defined in DT", dev->name);
443 return 0;
444 }
445
446 lis2dw12->dev = dev;
447
448 LOG_INF("%s: int-pin is on INT%d", dev->name, cfg->int_pin);
449 #if defined(CONFIG_LIS2DW12_TRIGGER_OWN_THREAD)
450 k_sem_init(&lis2dw12->gpio_sem, 0, K_SEM_MAX_LIMIT);
451
452 k_thread_create(&lis2dw12->thread, lis2dw12->thread_stack,
453 CONFIG_LIS2DW12_THREAD_STACK_SIZE,
454 (k_thread_entry_t)lis2dw12_thread, lis2dw12,
455 NULL, NULL, K_PRIO_COOP(CONFIG_LIS2DW12_THREAD_PRIORITY),
456 0, K_NO_WAIT);
457 #elif defined(CONFIG_LIS2DW12_TRIGGER_GLOBAL_THREAD)
458 lis2dw12->work.handler = lis2dw12_work_cb;
459 #endif /* CONFIG_LIS2DW12_TRIGGER_OWN_THREAD */
460
461 ret = gpio_pin_configure_dt(&cfg->gpio_int, GPIO_INPUT);
462 if (ret < 0) {
463 LOG_ERR("Could not configure gpio");
464 return ret;
465 }
466
467 LOG_INF("%s: int on %s.%02u", dev->name, cfg->gpio_int.port->name,
468 cfg->gpio_int.pin);
469
470 gpio_init_callback(&lis2dw12->gpio_cb,
471 lis2dw12_gpio_callback,
472 BIT(cfg->gpio_int.pin));
473
474 if (gpio_add_callback(cfg->gpio_int.port, &lis2dw12->gpio_cb) < 0) {
475 LOG_DBG("Could not set gpio callback");
476 return -EIO;
477 }
478
479 /* set data ready mode on int1/int2 */
480 LOG_DBG("drdy_pulsed is %d", (int)cfg->drdy_pulsed);
481 lis2dw12_drdy_pulsed_t mode = cfg->drdy_pulsed ? LIS2DW12_DRDY_PULSED :
482 LIS2DW12_DRDY_LATCHED;
483
484 ret = lis2dw12_data_ready_mode_set(ctx, mode);
485 if (ret < 0) {
486 LOG_ERR("drdy_pulsed config error %d", (int)cfg->drdy_pulsed);
487 return ret;
488 }
489
490 #ifdef CONFIG_LIS2DW12_TAP
491 ret = lis2dw12_tap_init(dev);
492 if (ret < 0) {
493 return ret;
494 }
495 #endif /* CONFIG_LIS2DW12_TAP */
496
497 #ifdef CONFIG_LIS2DW12_FREEFALL
498 ret = lis2dw12_ff_init(dev);
499 if (ret < 0) {
500 return ret;
501 }
502 #endif /* CONFIG_LIS2DW12_FREEFALL */
503
504 return gpio_pin_interrupt_configure_dt(&cfg->gpio_int,
505 GPIO_INT_EDGE_TO_ACTIVE);
506 }
507