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