1 /*
2  * SPDX-License-Identifier: Apache-2.0
3  *
4  * Würth Elektronic WSEN-ITDS 3-axis accel sensor driver
5  *
6  * Copyright (c) 2020 Linumiz
7  * Author: Saravanan Sekar <saravanan@linumiz.com>
8  */
9 
10 #include <zephyr/kernel.h>
11 #include <zephyr/drivers/sensor.h>
12 #include <zephyr/drivers/gpio.h>
13 #include <zephyr/logging/log.h>
14 
15 #include "itds.h"
16 LOG_MODULE_DECLARE(ITDS, CONFIG_SENSOR_LOG_LEVEL);
17 
itds_trigger_drdy_set(const struct device * dev,enum sensor_channel chan,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)18 static int itds_trigger_drdy_set(const struct device *dev,
19 				 enum sensor_channel chan,
20 				 const struct sensor_trigger *trig,
21 				 sensor_trigger_handler_t handler)
22 {
23 	struct itds_device_data *ddata = dev->data;
24 	const struct itds_device_config *cfg = dev->config;
25 	uint8_t drdy_en = 0U;
26 	int ret;
27 
28 	ddata->handler_drdy = handler;
29 	ddata->trigger_drdy = trig;
30 	if (ddata->handler_drdy) {
31 		drdy_en = ITDS_MASK_INT_DRDY;
32 	}
33 
34 	ret = i2c_reg_update_byte_dt(&cfg->i2c, ITDS_REG_CTRL4,
35 				  ITDS_MASK_INT_DRDY, drdy_en);
36 	if (ret) {
37 		return ret;
38 	}
39 
40 	return 0;
41 }
42 
itds_trigger_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)43 int itds_trigger_set(const struct device *dev,
44 		     const struct sensor_trigger *trig,
45 		     sensor_trigger_handler_t handler)
46 {
47 	const struct itds_device_config *cfg = dev->config;
48 
49 	if (!cfg->int_gpio.port) {
50 		return -ENOTSUP;
51 	}
52 
53 	if (trig->chan != SENSOR_CHAN_ACCEL_XYZ) {
54 		return -ENOTSUP;
55 	}
56 
57 	switch (trig->type) {
58 	case SENSOR_TRIG_DATA_READY:
59 		return itds_trigger_drdy_set(dev, trig->chan, trig, handler);
60 
61 	default:
62 		return -ENOTSUP;
63 	}
64 }
65 
itds_work_handler(struct k_work * work)66 static void itds_work_handler(struct k_work *work)
67 {
68 	struct itds_device_data *ddata =
69 			CONTAINER_OF(work, struct itds_device_data, work);
70 	const struct device *dev = (const struct device *)ddata->dev;
71 	const struct itds_device_config *cfg = dev->config;
72 	uint8_t status;
73 
74 	if (i2c_reg_read_byte_dt(&cfg->i2c, ITDS_REG_STATUS,
75 			      &status) < 0) {
76 		return;
77 	}
78 
79 	if (status & ITDS_EVENT_DRDY) {
80 		if (ddata->handler_drdy) {
81 			ddata->handler_drdy(dev, ddata->trigger_drdy);
82 		}
83 	}
84 }
85 
itds_gpio_callback(const struct device * port,struct gpio_callback * cb,uint32_t pin)86 static void itds_gpio_callback(const struct device *port,
87 			       struct gpio_callback *cb, uint32_t pin)
88 {
89 	struct itds_device_data *ddata =
90 			CONTAINER_OF(cb, struct itds_device_data, gpio_cb);
91 
92 	ARG_UNUSED(port);
93 	ARG_UNUSED(pin);
94 
95 	k_work_submit(&ddata->work);
96 }
97 
itds_trigger_mode_init(const struct device * dev)98 int itds_trigger_mode_init(const struct device *dev)
99 {
100 	struct itds_device_data *ddata = dev->data;
101 	const struct itds_device_config *cfg = dev->config;
102 
103 	/* dts doesn't have GPIO int pin set, so we dont support
104 	 * trigger mode for this instance
105 	 */
106 	if (!cfg->int_gpio.port) {
107 		return 0;
108 	}
109 
110 	if (!gpio_is_ready_dt(&cfg->int_gpio)) {
111 		LOG_ERR("%s: device %s is not ready", dev->name,
112 				cfg->int_gpio.port->name);
113 		return -ENODEV;
114 	}
115 
116 	ddata->work.handler = itds_work_handler;
117 	ddata->dev = dev;
118 
119 	gpio_pin_configure_dt(&cfg->int_gpio, GPIO_INPUT);
120 
121 	gpio_init_callback(&ddata->gpio_cb, itds_gpio_callback,
122 			   BIT(cfg->int_gpio.pin));
123 
124 	gpio_add_callback(cfg->int_gpio.port, &ddata->gpio_cb);
125 	gpio_pin_interrupt_configure_dt(&cfg->int_gpio, GPIO_INT_EDGE_TO_ACTIVE);
126 
127 	/* enable global interrupt */
128 	return i2c_reg_update_byte_dt(&cfg->i2c, ITDS_REG_CTRL7,
129 				   ITDS_MASK_INT_EN, ITDS_MASK_INT_EN);
130 }
131