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 		&reg_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 						 &reg_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 							 &reg_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