1 /*
2 * Copyright (c) 2025 Würth Elektronik eiSos GmbH & Co. KG
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT we_wsen_tids_2521020222501
8
9 #include <stdlib.h>
10
11 #include <zephyr/logging/log.h>
12
13 #include "wsen_tids_2521020222501.h"
14
15 LOG_MODULE_DECLARE(WSEN_TIDS_2521020222501, CONFIG_SENSOR_LOG_LEVEL);
16
17 /* Enable/disable interrupt handling */
tids_2521020222501_setup_interrupt(const struct device * dev,bool enable)18 static inline void tids_2521020222501_setup_interrupt(const struct device *dev, bool enable)
19 {
20 const struct tids_2521020222501_config *cfg = dev->config;
21 unsigned int flags = enable ? GPIO_INT_EDGE_TO_ACTIVE : GPIO_INT_DISABLE;
22
23 gpio_pin_interrupt_configure_dt(&cfg->interrupt_gpio, flags);
24 }
25
26 /*
27 * Is called when an interrupt has occurred.
28 */
tids_2521020222501_handle_interrupt(const struct device * dev)29 static void tids_2521020222501_handle_interrupt(const struct device *dev)
30 {
31 struct tids_2521020222501_data *data = dev->data;
32
33 /* Disable interrupt handling until the interrupt has been processed */
34 tids_2521020222501_setup_interrupt(dev, false);
35
36 #if defined(CONFIG_WSEN_TIDS_2521020222501_TRIGGER_OWN_THREAD)
37 k_sem_give(&data->sem);
38 #elif defined(CONFIG_WSEN_TIDS_2521020222501_TRIGGER_GLOBAL_THREAD)
39 k_work_submit(&data->work);
40 #endif
41 }
42
43 /*
44 * Calls trigger handles.
45 */
tids_2521020222501_process_interrupt(const struct device * dev)46 static void tids_2521020222501_process_interrupt(const struct device *dev)
47 {
48 struct tids_2521020222501_data *data = dev->data;
49
50 if (data->temperature_high_handler != NULL || data->temperature_low_handler != NULL) {
51 /*
52 * Read the sensor's status register - this also causes the interrupt pin
53 * to be de-asserted
54 */
55 TIDS_status_t status;
56
57 if (TIDS_getStatusRegister(&data->sensor_interface, &status) != WE_SUCCESS) {
58 LOG_ERR("Failed to read status register");
59 return;
60 }
61
62 if (data->temperature_high_handler != NULL &&
63 status.upperLimitExceeded == TIDS_enable) {
64 data->temperature_high_handler(dev, data->temperature_high_trigger);
65 } else if (data->temperature_low_handler != NULL &&
66 status.lowerLimitExceeded == TIDS_enable) {
67 data->temperature_low_handler(dev, data->temperature_low_trigger);
68 }
69 }
70
71 tids_2521020222501_setup_interrupt(dev, true);
72 }
73
74 /* Enables/disables processing of the "threshold exceeded" interrupt. */
tids_2521020222501_trigger_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)75 int tids_2521020222501_trigger_set(const struct device *dev, const struct sensor_trigger *trig,
76 sensor_trigger_handler_t handler)
77 {
78 struct tids_2521020222501_data *data = dev->data;
79 const struct tids_2521020222501_config *cfg = dev->config;
80
81 switch (trig->chan) {
82 case SENSOR_CHAN_ALL:
83 case SENSOR_CHAN_AMBIENT_TEMP:
84 break;
85 default:
86 LOG_ERR("Unsupported sensor trigger");
87 return -ENOTSUP;
88 }
89
90 struct sensor_value interruptOFF = {.val1 = -40, .val2 = -320000};
91 struct sensor_value threshold;
92
93 switch ((int)trig->type) {
94 case SENSOR_TRIG_WSEN_TIDS_2521020222501_THRESHOLD_LOWER: {
95
96 threshold.val1 = data->sensor_low_threshold / 1000;
97 threshold.val2 = ((int32_t)data->sensor_low_threshold % 1000) * (1000000 / 1000);
98
99 if (tids_2521020222501_threshold_lower_set(
100 dev, (handler == NULL) ? &interruptOFF : &threshold) < 0) {
101 LOG_ERR("Failed to set low temp threshold");
102 }
103 data->temperature_low_handler = handler;
104 data->temperature_low_trigger = trig;
105 break;
106 }
107 case SENSOR_TRIG_WSEN_TIDS_2521020222501_THRESHOLD_UPPER: {
108
109 threshold.val1 = data->sensor_high_threshold / 1000;
110 threshold.val2 = ((int32_t)data->sensor_high_threshold % 1000) * (1000000 / 1000);
111
112 if (tids_2521020222501_threshold_upper_set(
113 dev, (handler == NULL) ? &interruptOFF : &threshold) < 0) {
114 LOG_ERR("Failed to set high temp threshold");
115 }
116 data->temperature_high_handler = handler;
117 data->temperature_high_trigger = trig;
118 break;
119 }
120 default:
121 LOG_ERR("Unsupported sensor trigger");
122 return -ENOTSUP;
123 }
124
125 tids_2521020222501_setup_interrupt(dev, data->temperature_high_handler ||
126 data->temperature_low_handler);
127
128 if (gpio_pin_get_dt(&cfg->interrupt_gpio) > 0) {
129 tids_2521020222501_handle_interrupt(dev);
130 }
131
132 return 0;
133 }
134
tids_2521020222501_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)135 static void tids_2521020222501_callback(const struct device *dev, struct gpio_callback *cb,
136 uint32_t pins)
137 {
138 struct tids_2521020222501_data *data =
139 CONTAINER_OF(cb, struct tids_2521020222501_data, interrupt_cb);
140
141 ARG_UNUSED(pins);
142
143 tids_2521020222501_handle_interrupt(data->dev);
144 }
145
146 #ifdef CONFIG_WSEN_TIDS_2521020222501_TRIGGER_OWN_THREAD
tids_2521020222501_thread(void * p1,void * p2,void * p3)147 static void tids_2521020222501_thread(void *p1, void *p2, void *p3)
148 {
149 ARG_UNUSED(p2);
150 ARG_UNUSED(p3);
151
152 struct tids_2521020222501_data *tids_2521020222501 = p1;
153
154 while (true) {
155 k_sem_take(&tids_2521020222501->sem, K_FOREVER);
156 tids_2521020222501_process_interrupt(tids_2521020222501->dev);
157 }
158 }
159 #endif /* CONFIG_WSEN_TIDS_2521020222501_TRIGGER_OWN_THREAD */
160
161 #ifdef CONFIG_WSEN_TIDS_2521020222501_TRIGGER_GLOBAL_THREAD
tids_2521020222501_work_cb(struct k_work * work)162 static void tids_2521020222501_work_cb(struct k_work *work)
163 {
164 struct tids_2521020222501_data *tids_2521020222501 =
165 CONTAINER_OF(work, struct tids_2521020222501_data, work);
166
167 tids_2521020222501_process_interrupt(tids_2521020222501->dev);
168 }
169 #endif /* CONFIG_WSEN_TIDS_2521020222501_TRIGGER_GLOBAL_THREAD */
170
tids_2521020222501_threshold_upper_set(const struct device * dev,const struct sensor_value * thresh_value)171 int tids_2521020222501_threshold_upper_set(const struct device *dev,
172 const struct sensor_value *thresh_value)
173 {
174 struct tids_2521020222501_data *data = dev->data;
175 int32_t thresh = thresh_value->val1 * 1000 + thresh_value->val2 / 1000;
176
177 if (TIDS_setTempHighLimit(&data->sensor_interface, thresh) != WE_SUCCESS) {
178 LOG_ERR("Failed to set high temperature threshold.");
179 return -EIO;
180 }
181
182 data->sensor_high_threshold = thresh;
183
184 return 0;
185 }
186
tids_2521020222501_threshold_upper_get(const struct device * dev,struct sensor_value * thresh_value)187 int tids_2521020222501_threshold_upper_get(const struct device *dev,
188 struct sensor_value *thresh_value)
189 {
190 struct tids_2521020222501_data *data = dev->data;
191 int32_t thresh;
192
193 if (TIDS_getTempHighLimit(&data->sensor_interface, &thresh) != WE_SUCCESS) {
194 LOG_ERR("Failed to get high temperature threshold.");
195 return -EIO;
196 }
197
198 thresh_value->val1 = thresh / 1000;
199 thresh_value->val2 = (thresh % 1000) * (1000000 / 1000);
200
201 return 0;
202 }
203
tids_2521020222501_threshold_lower_set(const struct device * dev,const struct sensor_value * thresh_value)204 int tids_2521020222501_threshold_lower_set(const struct device *dev,
205 const struct sensor_value *thresh_value)
206 {
207 struct tids_2521020222501_data *data = dev->data;
208 int32_t thresh = thresh_value->val1 * 1000 + thresh_value->val2 / 1000;
209
210 if (TIDS_setTempLowLimit(&data->sensor_interface, thresh) != WE_SUCCESS) {
211 LOG_ERR("Failed to set low temperature threshold.");
212 return -EIO;
213 }
214
215 data->sensor_low_threshold = thresh;
216
217 return 0;
218 }
219
tids_2521020222501_threshold_lower_get(const struct device * dev,struct sensor_value * thresh_value)220 int tids_2521020222501_threshold_lower_get(const struct device *dev,
221 struct sensor_value *thresh_value)
222 {
223 struct tids_2521020222501_data *data = dev->data;
224 int32_t thresh;
225
226 if (TIDS_getTempLowLimit(&data->sensor_interface, &thresh) != WE_SUCCESS) {
227 LOG_ERR("Failed to get low temperature threshold.");
228 return -EIO;
229 }
230
231 thresh_value->val1 = thresh / 1000;
232 thresh_value->val2 = (thresh % 1000) * (1000000 / 1000);
233
234 return 0;
235 }
236
tids_2521020222501_init_interrupt(const struct device * dev)237 int tids_2521020222501_init_interrupt(const struct device *dev)
238 {
239 struct tids_2521020222501_data *data = dev->data;
240 const struct tids_2521020222501_config *cfg = dev->config;
241 struct sensor_value upper_limit, lower_limit;
242
243 if (cfg->interrupt_gpio.port == NULL) {
244 LOG_ERR("interrupt-gpios is not defined in the device tree.");
245 return -EINVAL;
246 }
247
248 if (!gpio_is_ready_dt(&cfg->interrupt_gpio)) {
249 LOG_ERR("Device %s is not ready", cfg->interrupt_gpio.port->name);
250 return -ENODEV;
251 }
252
253 data->dev = dev;
254
255 /* Setup threshold gpio interrupt */
256 if (gpio_pin_configure_dt(&cfg->interrupt_gpio, GPIO_INPUT) < 0) {
257 LOG_ERR("Failed to configure %s.%02u", cfg->interrupt_gpio.port->name,
258 cfg->interrupt_gpio.pin);
259 return -EIO;
260 }
261
262 gpio_init_callback(&data->interrupt_cb, tids_2521020222501_callback,
263 BIT(cfg->interrupt_gpio.pin));
264
265 if (gpio_add_callback(cfg->interrupt_gpio.port, &data->interrupt_cb) < 0) {
266 LOG_ERR("Failed to set gpio callback.");
267 return -EIO;
268 }
269
270 /*
271 * Enable interrupt on high/low temperature (interrupt generation is enabled if at
272 * least one threshold is non-zero)
273 */
274
275 upper_limit.val1 = cfg->high_threshold / 1000;
276 upper_limit.val2 = ((int32_t)cfg->high_threshold % 1000) * (1000000 / 1000);
277
278 lower_limit.val1 = cfg->low_threshold / 1000;
279 lower_limit.val2 = ((int32_t)cfg->low_threshold % 1000) * (1000000 / 1000);
280
281 if (tids_2521020222501_threshold_upper_set(dev, &upper_limit) < 0) {
282 LOG_ERR("Failed to set upper threshold");
283 return -EIO;
284 }
285
286 if (tids_2521020222501_threshold_lower_set(dev, &lower_limit) < 0) {
287 LOG_ERR("Failed to set lower threshold");
288 return -EIO;
289 }
290
291 #if defined(CONFIG_WSEN_TIDS_2521020222501_TRIGGER_OWN_THREAD)
292 k_sem_init(&data->sem, 0, K_SEM_MAX_LIMIT);
293
294 k_thread_create(&data->thread, data->thread_stack,
295 CONFIG_WSEN_TIDS_2521020222501_THREAD_STACK_SIZE, tids_2521020222501_thread,
296 data, NULL, NULL,
297 K_PRIO_COOP(CONFIG_WSEN_TIDS_2521020222501_THREAD_PRIORITY), 0, K_NO_WAIT);
298 #elif defined(CONFIG_WSEN_TIDS_2521020222501_TRIGGER_GLOBAL_THREAD)
299 data->work.handler = tids_2521020222501_work_cb;
300 #endif
301
302 return 0;
303 }
304