1 /*
2  * Copyright (c) 2023 Analog Devices Inc.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/device.h>
8 #include <zephyr/drivers/gpio.h>
9 #include <zephyr/sys/util.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/drivers/sensor.h>
12 #include "adxl367.h"
13 
14 #include <zephyr/logging/log.h>
15 LOG_MODULE_DECLARE(ADXL367, CONFIG_SENSOR_LOG_LEVEL);
16 
17 #if defined(CONFIG_ADXL367_TRIGGER_OWN_THREAD) || defined(CONFIG_ADXL367_TRIGGER_GLOBAL_THREAD)
adxl367_thread_cb(const struct device * dev)18 static void adxl367_thread_cb(const struct device *dev)
19 {
20 	const struct adxl367_dev_config *cfg = dev->config;
21 	struct adxl367_data *drv_data = dev->data;
22 	uint8_t status;
23 	int ret;
24 
25 	/* Clear the status */
26 	ret = drv_data->hw_tf->read_reg(dev, ADXL367_STATUS, &status);
27 	if (ret != 0) {
28 		return;
29 	}
30 
31 	if (drv_data->th_handler != NULL) {
32 		if (((FIELD_GET(ADXL367_STATUS_INACT, status)) != 0) ||
33 			(FIELD_GET(ADXL367_STATUS_ACT, status)) != 0) {
34 			drv_data->th_handler(dev, drv_data->th_trigger);
35 		}
36 	}
37 
38 	if ((drv_data->drdy_handler != NULL) &&
39 		(FIELD_GET(ADXL367_STATUS_DATA_RDY, status) != 0)) {
40 		drv_data->drdy_handler(dev, drv_data->drdy_trigger);
41 	}
42 
43 	ret = gpio_pin_interrupt_configure_dt(&cfg->interrupt,
44 					      GPIO_INT_EDGE_TO_ACTIVE);
45 	__ASSERT(ret == 0, "Interrupt configuration failed");
46 }
47 #endif /* CONFIG_ADXL367_TRIGGER_OWN_THREAD || CONFIG_ADXL367_TRIGGER_GLOBAL_THREAD */
48 
adxl367_gpio_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)49 static void adxl367_gpio_callback(const struct device *dev,
50 				  struct gpio_callback *cb, uint32_t pins)
51 {
52 	struct adxl367_data *drv_data =
53 		CONTAINER_OF(cb, struct adxl367_data, gpio_cb);
54 	const struct adxl367_dev_config *cfg = drv_data->dev->config;
55 
56 	gpio_pin_interrupt_configure_dt(&cfg->interrupt, GPIO_INT_DISABLE);
57 
58 	if (IS_ENABLED(CONFIG_ADXL367_STREAM)) {
59 		adxl367_stream_irq_handler(drv_data->dev);
60 	}
61 
62 #if defined(CONFIG_ADXL367_TRIGGER_OWN_THREAD)
63 	k_sem_give(&drv_data->gpio_sem);
64 #elif defined(CONFIG_ADXL367_TRIGGER_GLOBAL_THREAD)
65 	k_work_submit(&drv_data->work);
66 #endif
67 }
68 
69 #if defined(CONFIG_ADXL367_TRIGGER_OWN_THREAD)
adxl367_thread(struct adxl367_data * drv_data)70 static void adxl367_thread(struct adxl367_data *drv_data)
71 {
72 	while (true) {
73 		k_sem_take(&drv_data->gpio_sem, K_FOREVER);
74 		adxl367_thread_cb(drv_data->dev);
75 	}
76 }
77 
78 #elif defined(CONFIG_ADXL367_TRIGGER_GLOBAL_THREAD)
adxl367_work_cb(struct k_work * work)79 static void adxl367_work_cb(struct k_work *work)
80 {
81 	struct adxl367_data *drv_data =
82 		CONTAINER_OF(work, struct adxl367_data, work);
83 
84 	adxl367_thread_cb(drv_data->dev);
85 }
86 #endif
87 
adxl367_trigger_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)88 int adxl367_trigger_set(const struct device *dev,
89 			const struct sensor_trigger *trig,
90 			sensor_trigger_handler_t handler)
91 {
92 	const struct adxl367_dev_config *cfg = dev->config;
93 	struct adxl367_data *drv_data = dev->data;
94 	uint8_t int_mask, int_en, status;
95 	int ret;
96 
97 	ret = gpio_pin_interrupt_configure_dt(&cfg->interrupt,
98 					      GPIO_INT_DISABLE);
99 	if (ret != 0) {
100 		return ret;
101 	}
102 
103 	switch (trig->type) {
104 	case SENSOR_TRIG_THRESHOLD:
105 		drv_data->th_handler = handler;
106 		drv_data->th_trigger = trig;
107 		int_mask = ADXL367_ACT_INT | ADXL367_INACT_INT;
108 		break;
109 	case SENSOR_TRIG_DATA_READY:
110 		drv_data->drdy_handler = handler;
111 		drv_data->drdy_trigger = trig;
112 		int_mask = ADXL367_DATA_RDY;
113 		break;
114 	default:
115 		LOG_ERR("Unsupported sensor trigger");
116 		return -ENOTSUP;
117 	}
118 
119 	if (handler != NULL) {
120 		int_en = int_mask;
121 	} else {
122 		int_en = 0U;
123 	}
124 
125 	ret = drv_data->hw_tf->write_reg_mask(dev, ADXL367_INTMAP1_LOWER, int_mask, int_en);
126 	if (ret != 0) {
127 		return ret;
128 	}
129 
130 	/* Clear status */
131 	ret = drv_data->hw_tf->read_reg(dev, ADXL367_STATUS, &status);
132 	if (ret != 0) {
133 		return ret;
134 	}
135 
136 	ret = gpio_pin_interrupt_configure_dt(&cfg->interrupt,
137 					      GPIO_INT_EDGE_TO_ACTIVE);
138 	if (ret != 0) {
139 		return ret;
140 	}
141 
142 	return 0;
143 }
144 
adxl367_init_interrupt(const struct device * dev)145 int adxl367_init_interrupt(const struct device *dev)
146 {
147 	const struct adxl367_dev_config *cfg = dev->config;
148 	struct adxl367_data *drv_data = dev->data;
149 	int ret;
150 
151 	if (!gpio_is_ready_dt(&cfg->interrupt)) {
152 		LOG_ERR("GPIO port %s not ready", cfg->interrupt.port->name);
153 		return -EINVAL;
154 	}
155 
156 	ret = gpio_pin_configure_dt(&cfg->interrupt, GPIO_INPUT);
157 	if (ret != 0) {
158 		return ret;
159 	}
160 
161 	gpio_init_callback(&drv_data->gpio_cb,
162 			   adxl367_gpio_callback,
163 			   BIT(cfg->interrupt.pin));
164 
165 	ret = gpio_add_callback(cfg->interrupt.port, &drv_data->gpio_cb);
166 	if (ret != 0) {
167 		LOG_ERR("Failed to set gpio callback!");
168 		return ret;
169 	}
170 
171 	drv_data->dev = dev;
172 
173 #if defined(CONFIG_ADXL367_TRIGGER_OWN_THREAD)
174 	k_sem_init(&drv_data->gpio_sem, 0, K_SEM_MAX_LIMIT);
175 
176 	k_thread_create(&drv_data->thread, drv_data->thread_stack,
177 			CONFIG_ADXL367_THREAD_STACK_SIZE,
178 			(k_thread_entry_t)adxl367_thread, drv_data,
179 			NULL, NULL, K_PRIO_COOP(CONFIG_ADXL367_THREAD_PRIORITY),
180 			0, K_NO_WAIT);
181 
182 	k_thread_name_set(&drv_data->thread, dev->name);
183 #elif defined(CONFIG_ADXL367_TRIGGER_GLOBAL_THREAD)
184 	drv_data->work.handler = adxl367_work_cb;
185 #endif
186 
187 	return 0;
188 }
189