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