1 /*
2 * Copyright (c) 2017 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT st_lis2dh
8
9 #include <zephyr/sys/util.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/logging/log.h>
12
13 #define START_TRIG_INT1 0
14 #define START_TRIG_INT2 1
15 #define TRIGGED_INT1 4
16 #define TRIGGED_INT2 5
17
18 LOG_MODULE_DECLARE(lis2dh, CONFIG_SENSOR_LOG_LEVEL);
19 #include "lis2dh.h"
20
setup_int1(const struct device * dev,bool enable)21 static inline void setup_int1(const struct device *dev,
22 bool enable)
23 {
24 const struct lis2dh_config *cfg = dev->config;
25
26 gpio_pin_interrupt_configure_dt(&cfg->gpio_drdy,
27 enable
28 ? GPIO_INT_LEVEL_ACTIVE
29 : GPIO_INT_DISABLE);
30 }
31
lis2dh_trigger_drdy_set(const struct device * dev,enum sensor_channel chan,sensor_trigger_handler_t handler,const struct sensor_trigger * trig)32 static int lis2dh_trigger_drdy_set(const struct device *dev,
33 enum sensor_channel chan,
34 sensor_trigger_handler_t handler,
35 const struct sensor_trigger *trig)
36 {
37 const struct lis2dh_config *cfg = dev->config;
38 struct lis2dh_data *lis2dh = dev->data;
39 int status;
40
41 if (cfg->gpio_drdy.port == NULL) {
42 LOG_ERR("trigger_set DRDY int not supported");
43 return -ENOTSUP;
44 }
45
46 setup_int1(dev, false);
47
48 /* cancel potentially pending trigger */
49 atomic_clear_bit(&lis2dh->trig_flags, TRIGGED_INT1);
50
51 status = lis2dh->hw_tf->update_reg(dev, LIS2DH_REG_CTRL3,
52 LIS2DH_EN_DRDY1_INT1, 0);
53
54 lis2dh->handler_drdy = handler;
55 lis2dh->trig_drdy = trig;
56 if ((handler == NULL) || (status < 0)) {
57 return status;
58 }
59
60 lis2dh->chan_drdy = chan;
61
62 /* serialize start of int1 in thread to synchronize output sampling
63 * and first interrupt. this avoids concurrent bus context access.
64 */
65 atomic_set_bit(&lis2dh->trig_flags, START_TRIG_INT1);
66 #if defined(CONFIG_LIS2DH_TRIGGER_OWN_THREAD)
67 k_sem_give(&lis2dh->gpio_sem);
68 #elif defined(CONFIG_LIS2DH_TRIGGER_GLOBAL_THREAD)
69 k_work_submit(&lis2dh->work);
70 #endif
71
72 return 0;
73 }
74
lis2dh_start_trigger_int1(const struct device * dev)75 static int lis2dh_start_trigger_int1(const struct device *dev)
76 {
77 int status;
78 uint8_t raw[LIS2DH_BUF_SZ];
79 uint8_t ctrl1 = 0U;
80 struct lis2dh_data *lis2dh = dev->data;
81
82 /* power down temporarily to align interrupt & data output sampling */
83 status = lis2dh->hw_tf->read_reg(dev, LIS2DH_REG_CTRL1, &ctrl1);
84 if (unlikely(status < 0)) {
85 return status;
86 }
87 status = lis2dh->hw_tf->write_reg(dev, LIS2DH_REG_CTRL1,
88 ctrl1 & ~LIS2DH_ODR_MASK);
89
90 if (unlikely(status < 0)) {
91 return status;
92 }
93
94 LOG_DBG("ctrl1=0x%x @tick=%u", ctrl1, k_cycle_get_32());
95
96 /* empty output data */
97 status = lis2dh->hw_tf->read_data(dev, LIS2DH_REG_STATUS,
98 raw, sizeof(raw));
99 if (unlikely(status < 0)) {
100 return status;
101 }
102
103 setup_int1(dev, true);
104
105 /* re-enable output sampling */
106 status = lis2dh->hw_tf->write_reg(dev, LIS2DH_REG_CTRL1, ctrl1);
107 if (unlikely(status < 0)) {
108 return status;
109 }
110
111 return lis2dh->hw_tf->update_reg(dev, LIS2DH_REG_CTRL3,
112 LIS2DH_EN_DRDY1_INT1,
113 LIS2DH_EN_DRDY1_INT1);
114 }
115
116 #define LIS2DH_ANYM_CFG (LIS2DH_INT_CFG_ZHIE_ZUPE | LIS2DH_INT_CFG_YHIE_YUPE |\
117 LIS2DH_INT_CFG_XHIE_XUPE)
118
setup_int2(const struct device * dev,bool enable)119 static inline void setup_int2(const struct device *dev,
120 bool enable)
121 {
122 const struct lis2dh_config *cfg = dev->config;
123
124 gpio_pin_interrupt_configure_dt(&cfg->gpio_int,
125 enable
126 ? GPIO_INT_LEVEL_ACTIVE
127 : GPIO_INT_DISABLE);
128 }
129
lis2dh_trigger_anym_set(const struct device * dev,sensor_trigger_handler_t handler,const struct sensor_trigger * trig)130 static int lis2dh_trigger_anym_set(const struct device *dev,
131 sensor_trigger_handler_t handler,
132 const struct sensor_trigger *trig)
133 {
134 const struct lis2dh_config *cfg = dev->config;
135 struct lis2dh_data *lis2dh = dev->data;
136 int status;
137 uint8_t reg_val;
138
139 if (cfg->gpio_int.port == NULL) {
140 LOG_ERR("trigger_set AnyMotion int not supported");
141 return -ENOTSUP;
142 }
143
144 setup_int2(dev, false);
145
146 /* cancel potentially pending trigger */
147 atomic_clear_bit(&lis2dh->trig_flags, TRIGGED_INT2);
148
149 if (cfg->hw.anym_on_int1) {
150 status = lis2dh->hw_tf->update_reg(dev, LIS2DH_REG_CTRL3,
151 LIS2DH_EN_DRDY1_INT1, 0);
152 }
153
154 /* disable any movement interrupt events */
155 status = lis2dh->hw_tf->write_reg(
156 dev,
157 cfg->hw.anym_on_int1 ? LIS2DH_REG_INT1_CFG : LIS2DH_REG_INT2_CFG,
158 0);
159
160 /* make sure any pending interrupt is cleared */
161 status = lis2dh->hw_tf->read_reg(
162 dev,
163 cfg->hw.anym_on_int1 ? LIS2DH_REG_INT1_SRC : LIS2DH_REG_INT2_SRC,
164 ®_val);
165
166 lis2dh->handler_anymotion = handler;
167 lis2dh->trig_anymotion = trig;
168 if ((handler == NULL) || (status < 0)) {
169 return status;
170 }
171
172 /* serialize start of int2 in thread to synchronize output sampling
173 * and first interrupt. this avoids concurrent bus context access.
174 */
175 atomic_set_bit(&lis2dh->trig_flags, START_TRIG_INT2);
176 #if defined(CONFIG_LIS2DH_TRIGGER_OWN_THREAD)
177 k_sem_give(&lis2dh->gpio_sem);
178 #elif defined(CONFIG_LIS2DH_TRIGGER_GLOBAL_THREAD)
179 k_work_submit(&lis2dh->work);
180 #endif
181 return 0;
182 }
183
lis2dh_start_trigger_int2(const struct device * dev)184 static int lis2dh_start_trigger_int2(const struct device *dev)
185 {
186 struct lis2dh_data *lis2dh = dev->data;
187 const struct lis2dh_config *cfg = dev->config;
188
189 setup_int2(dev, true);
190
191 return lis2dh->hw_tf->write_reg(
192 dev,
193 cfg->hw.anym_on_int1 ? LIS2DH_REG_INT1_CFG : LIS2DH_REG_INT2_CFG,
194 (cfg->hw.anym_mode << LIS2DH_INT_CFG_MODE_SHIFT) | LIS2DH_ANYM_CFG);
195 }
196
lis2dh_trigger_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)197 int lis2dh_trigger_set(const struct device *dev,
198 const struct sensor_trigger *trig,
199 sensor_trigger_handler_t handler)
200 {
201 if (trig->type == SENSOR_TRIG_DATA_READY &&
202 trig->chan == SENSOR_CHAN_ACCEL_XYZ) {
203 return lis2dh_trigger_drdy_set(dev, trig->chan, handler, trig);
204 } else if (trig->type == SENSOR_TRIG_DELTA) {
205 return lis2dh_trigger_anym_set(dev, handler, trig);
206 }
207
208 return -ENOTSUP;
209 }
210
lis2dh_acc_slope_config(const struct device * dev,enum sensor_attribute attr,const struct sensor_value * val)211 int lis2dh_acc_slope_config(const struct device *dev,
212 enum sensor_attribute attr,
213 const struct sensor_value *val)
214 {
215 struct lis2dh_data *lis2dh = dev->data;
216 const struct lis2dh_config *cfg = dev->config;
217 int status;
218
219 if (attr == SENSOR_ATTR_SLOPE_TH) {
220 uint8_t range_g, reg_val;
221 uint32_t slope_th_ums2;
222
223 status = lis2dh->hw_tf->read_reg(dev, LIS2DH_REG_CTRL4,
224 ®_val);
225 if (status < 0) {
226 return status;
227 }
228
229 /* fs reg value is in the range 0 (2g) - 3 (16g) */
230 range_g = 2 * (1 << ((LIS2DH_FS_MASK & reg_val)
231 >> LIS2DH_FS_SHIFT));
232
233 slope_th_ums2 = val->val1 * 1000000 + val->val2;
234
235 /* make sure the provided threshold does not exceed range */
236 if ((slope_th_ums2 - 1) > (range_g * SENSOR_G)) {
237 return -EINVAL;
238 }
239
240 /* 7 bit full range value */
241 reg_val = 128 / range_g * (slope_th_ums2 - 1) / SENSOR_G;
242
243 LOG_INF("int2_ths=0x%x range_g=%d ums2=%u", reg_val,
244 range_g, slope_th_ums2 - 1);
245
246 status = lis2dh->hw_tf->write_reg(dev,
247 cfg->hw.anym_on_int1 ?
248 LIS2DH_REG_INT1_THS :
249 LIS2DH_REG_INT2_THS,
250 reg_val);
251 } else { /* SENSOR_ATTR_SLOPE_DUR */
252 /*
253 * slope duration is measured in number of samples:
254 * N/ODR where N is the register value
255 */
256 if (val->val1 < 0 || val->val1 > 127) {
257 return -ENOTSUP;
258 }
259
260 LOG_INF("int2_dur=0x%x", val->val1);
261
262 status = lis2dh->hw_tf->write_reg(dev,
263 cfg->hw.anym_on_int1 ?
264 LIS2DH_REG_INT1_DUR :
265 LIS2DH_REG_INT2_DUR,
266 val->val1);
267 }
268
269 return status;
270 }
271
272 #ifdef CONFIG_LIS2DH_ACCEL_HP_FILTERS
lis2dh_acc_hp_filter_set(const struct device * dev,int32_t val)273 int lis2dh_acc_hp_filter_set(const struct device *dev, int32_t val)
274 {
275 struct lis2dh_data *lis2dh = dev->data;
276 int status;
277
278 status = lis2dh->hw_tf->update_reg(dev, LIS2DH_REG_CTRL2,
279 LIS2DH_HPIS_EN_MASK, val);
280 if (status < 0) {
281 LOG_ERR("Failed to set high pass filters");
282 }
283
284 return status;
285 }
286 #endif
287
lis2dh_gpio_int1_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)288 static void lis2dh_gpio_int1_callback(const struct device *dev,
289 struct gpio_callback *cb, uint32_t pins)
290 {
291 struct lis2dh_data *lis2dh =
292 CONTAINER_OF(cb, struct lis2dh_data, gpio_int1_cb);
293
294 ARG_UNUSED(pins);
295
296 atomic_set_bit(&lis2dh->trig_flags, TRIGGED_INT1);
297
298 /* int is level triggered so disable until processed */
299 setup_int1(lis2dh->dev, false);
300
301 #if defined(CONFIG_LIS2DH_TRIGGER_OWN_THREAD)
302 k_sem_give(&lis2dh->gpio_sem);
303 #elif defined(CONFIG_LIS2DH_TRIGGER_GLOBAL_THREAD)
304 k_work_submit(&lis2dh->work);
305 #endif
306 }
307
lis2dh_gpio_int2_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)308 static void lis2dh_gpio_int2_callback(const struct device *dev,
309 struct gpio_callback *cb, uint32_t pins)
310 {
311 struct lis2dh_data *lis2dh =
312 CONTAINER_OF(cb, struct lis2dh_data, gpio_int2_cb);
313
314 ARG_UNUSED(pins);
315
316 atomic_set_bit(&lis2dh->trig_flags, TRIGGED_INT2);
317
318 /* int is level triggered so disable until processed */
319 setup_int2(lis2dh->dev, false);
320
321 #if defined(CONFIG_LIS2DH_TRIGGER_OWN_THREAD)
322 k_sem_give(&lis2dh->gpio_sem);
323 #elif defined(CONFIG_LIS2DH_TRIGGER_GLOBAL_THREAD)
324 k_work_submit(&lis2dh->work);
325 #endif
326 }
327
lis2dh_thread_cb(const struct device * dev)328 static void lis2dh_thread_cb(const struct device *dev)
329 {
330 struct lis2dh_data *lis2dh = dev->data;
331 const struct lis2dh_config *cfg = dev->config;
332 int status;
333
334 if (cfg->gpio_drdy.port &&
335 unlikely(atomic_test_and_clear_bit(&lis2dh->trig_flags,
336 START_TRIG_INT1))) {
337 status = lis2dh_start_trigger_int1(dev);
338
339 if (unlikely(status < 0)) {
340 LOG_ERR("lis2dh_start_trigger_int1: %d", status);
341 }
342 return;
343 }
344
345 if (cfg->gpio_int.port &&
346 unlikely(atomic_test_and_clear_bit(&lis2dh->trig_flags,
347 START_TRIG_INT2))) {
348 status = lis2dh_start_trigger_int2(dev);
349
350 if (unlikely(status < 0)) {
351 LOG_ERR("lis2dh_start_trigger_int2: %d", status);
352 }
353 return;
354 }
355
356 if (cfg->gpio_drdy.port &&
357 atomic_test_and_clear_bit(&lis2dh->trig_flags,
358 TRIGGED_INT1)) {
359 if (likely(lis2dh->handler_drdy != NULL)) {
360 lis2dh->handler_drdy(dev, lis2dh->trig_drdy);
361
362 }
363
364 /* Reactivate level triggered interrupt if handler did not
365 * disable itself
366 */
367 if (likely(lis2dh->handler_drdy != NULL)) {
368 setup_int1(dev, true);
369 }
370
371 return;
372 }
373
374 if (cfg->gpio_int.port &&
375 atomic_test_and_clear_bit(&lis2dh->trig_flags,
376 TRIGGED_INT2)) {
377 uint8_t reg_val;
378
379 if (cfg->hw.anym_latch) {
380 /* clear interrupt to de-assert int line */
381 status = lis2dh->hw_tf->read_reg(dev,
382 cfg->hw.anym_on_int1 ?
383 LIS2DH_REG_INT1_SRC :
384 LIS2DH_REG_INT2_SRC,
385 ®_val);
386 if (status < 0) {
387 LOG_ERR("clearing interrupt 2 failed: %d", status);
388 return;
389 }
390 }
391
392 if (likely(lis2dh->handler_anymotion != NULL)) {
393 lis2dh->handler_anymotion(dev, lis2dh->trig_anymotion);
394 }
395
396 /* Reactivate level triggered interrupt if handler did not
397 * disable itself
398 */
399 if (lis2dh->handler_anymotion != NULL) {
400 setup_int2(dev, true);
401 }
402
403 LOG_DBG("@tick=%u int2_src=0x%x", k_cycle_get_32(),
404 reg_val);
405
406 return;
407 }
408 }
409
410 #ifdef CONFIG_LIS2DH_TRIGGER_OWN_THREAD
lis2dh_thread(struct lis2dh_data * lis2dh)411 static void lis2dh_thread(struct lis2dh_data *lis2dh)
412 {
413 while (1) {
414 k_sem_take(&lis2dh->gpio_sem, K_FOREVER);
415 lis2dh_thread_cb(lis2dh->dev);
416 }
417 }
418 #endif
419
420 #ifdef CONFIG_LIS2DH_TRIGGER_GLOBAL_THREAD
lis2dh_work_cb(struct k_work * work)421 static void lis2dh_work_cb(struct k_work *work)
422 {
423 struct lis2dh_data *lis2dh =
424 CONTAINER_OF(work, struct lis2dh_data, work);
425
426 lis2dh_thread_cb(lis2dh->dev);
427 }
428 #endif
429
lis2dh_init_interrupt(const struct device * dev)430 int lis2dh_init_interrupt(const struct device *dev)
431 {
432 struct lis2dh_data *lis2dh = dev->data;
433 const struct lis2dh_config *cfg = dev->config;
434 int status;
435 uint8_t raw[2];
436
437 lis2dh->dev = dev;
438
439 #if defined(CONFIG_LIS2DH_TRIGGER_OWN_THREAD)
440 k_sem_init(&lis2dh->gpio_sem, 0, K_SEM_MAX_LIMIT);
441
442 k_thread_create(&lis2dh->thread, lis2dh->thread_stack, CONFIG_LIS2DH_THREAD_STACK_SIZE,
443 (k_thread_entry_t)lis2dh_thread, lis2dh, NULL, NULL,
444 K_PRIO_COOP(CONFIG_LIS2DH_THREAD_PRIORITY), 0, K_NO_WAIT);
445 #elif defined(CONFIG_LIS2DH_TRIGGER_GLOBAL_THREAD)
446 lis2dh->work.handler = lis2dh_work_cb;
447 #endif
448
449 /*
450 * Setup INT1 (for DRDY) if defined in DT
451 */
452
453 /* setup data ready gpio interrupt */
454 if (!device_is_ready(cfg->gpio_drdy.port)) {
455 /* API may return false even when ptr is NULL */
456 if (cfg->gpio_drdy.port != NULL) {
457 LOG_ERR("device %s is not ready", cfg->gpio_drdy.port->name);
458 return -ENODEV;
459 }
460
461 LOG_DBG("gpio_drdy not defined in DT");
462 status = 0;
463 goto check_gpio_int;
464 }
465
466 /* data ready int1 gpio configuration */
467 status = gpio_pin_configure_dt(&cfg->gpio_drdy, GPIO_INPUT);
468 if (status < 0) {
469 LOG_ERR("Could not configure %s.%02u",
470 cfg->gpio_drdy.port->name, cfg->gpio_drdy.pin);
471 return status;
472 }
473
474 gpio_init_callback(&lis2dh->gpio_int1_cb,
475 lis2dh_gpio_int1_callback,
476 BIT(cfg->gpio_drdy.pin));
477
478 status = gpio_add_callback(cfg->gpio_drdy.port, &lis2dh->gpio_int1_cb);
479 if (status < 0) {
480 LOG_ERR("Could not add gpio int1 callback");
481 return status;
482 }
483
484 LOG_INF("%s: int1 on %s.%02u", dev->name,
485 cfg->gpio_drdy.port->name,
486 cfg->gpio_drdy.pin);
487
488 check_gpio_int:
489 /*
490 * Setup Interrupt (for Any Motion) if defined in DT
491 */
492
493 /* setup any motion gpio interrupt */
494 if (!device_is_ready(cfg->gpio_int.port)) {
495 /* API may return false even when ptr is NULL */
496 if (cfg->gpio_int.port != NULL) {
497 LOG_ERR("device %s is not ready", cfg->gpio_int.port->name);
498 return -ENODEV;
499 }
500
501 LOG_DBG("gpio_int not defined in DT");
502 status = 0;
503 goto end;
504 }
505
506 /* any motion int2 gpio configuration */
507 status = gpio_pin_configure_dt(&cfg->gpio_int, GPIO_INPUT);
508 if (status < 0) {
509 LOG_ERR("Could not configure %s.%02u",
510 cfg->gpio_int.port->name, cfg->gpio_int.pin);
511 return status;
512 }
513
514 gpio_init_callback(&lis2dh->gpio_int2_cb,
515 lis2dh_gpio_int2_callback,
516 BIT(cfg->gpio_int.pin));
517
518 /* callback is going to be enabled by trigger setting function */
519 status = gpio_add_callback(cfg->gpio_int.port, &lis2dh->gpio_int2_cb);
520 if (status < 0) {
521 LOG_ERR("Could not add gpio int2 callback (%d)", status);
522 return status;
523 }
524
525 LOG_INF("%s: int2 on %s.%02u", dev->name,
526 cfg->gpio_int.port->name,
527 cfg->gpio_int.pin);
528
529 /* disable interrupt in case of warm (re)boot */
530 status = lis2dh->hw_tf->write_reg(
531 dev,
532 cfg->hw.anym_on_int1 ? LIS2DH_REG_INT1_CFG : LIS2DH_REG_INT2_CFG,
533 0);
534 if (status < 0) {
535 LOG_ERR("Interrupt disable reg write failed (%d)", status);
536 return status;
537 }
538
539 (void)memset(raw, 0, sizeof(raw));
540 status = lis2dh->hw_tf->write_data(
541 dev,
542 cfg->hw.anym_on_int1 ? LIS2DH_REG_INT1_THS : LIS2DH_REG_INT2_THS,
543 raw, sizeof(raw));
544 if (status < 0) {
545 LOG_ERR("Burst write to THS failed (%d)", status);
546 return status;
547 }
548
549 if (cfg->hw.anym_on_int1) {
550 /* enable interrupt 1 on int1 line */
551 status = lis2dh->hw_tf->update_reg(dev, LIS2DH_REG_CTRL3,
552 LIS2DH_EN_INT1_INT1,
553 LIS2DH_EN_INT1_INT1);
554 if (cfg->hw.anym_latch) {
555 /* latch int1 line interrupt */
556 status = lis2dh->hw_tf->write_reg(dev, LIS2DH_REG_CTRL5,
557 LIS2DH_EN_LIR_INT1);
558 }
559 } else {
560 /* enable interrupt 2 on int2 line */
561 status = lis2dh->hw_tf->update_reg(dev, LIS2DH_REG_CTRL6,
562 LIS2DH_EN_INT2_INT2,
563 LIS2DH_EN_INT2_INT2);
564 if (cfg->hw.anym_latch) {
565 /* latch int2 line interrupt */
566 status = lis2dh->hw_tf->write_reg(dev, LIS2DH_REG_CTRL5,
567 LIS2DH_EN_LIR_INT2);
568 }
569 }
570
571 if (status < 0) {
572 LOG_ERR("enable reg write failed (%d)", status);
573 return status;
574 }
575
576 end:
577 return status;
578 }
579