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_pads_2511020213301
8 
9 #include <zephyr/logging/log.h>
10 
11 #include "wsen_pads_2511020213301.h"
12 
13 LOG_MODULE_DECLARE(WSEN_PADS_2511020213301, CONFIG_SENSOR_LOG_LEVEL);
14 
15 /* Enable/disable data-ready interrupt handling */
pads_2511020213301_setup_interrupt(const struct device * dev,bool enable)16 static inline int pads_2511020213301_setup_interrupt(const struct device *dev, bool enable)
17 {
18 	const struct pads_2511020213301_config *cfg = dev->config;
19 	unsigned int flags = enable ? GPIO_INT_EDGE_TO_ACTIVE : GPIO_INT_DISABLE;
20 
21 	return gpio_pin_interrupt_configure_dt(&cfg->interrupt_gpio, flags);
22 }
23 
24 /*
25  * Is called when an interrupt has occurred.
26  */
pads_2511020213301_handle_interrupt(const struct device * dev)27 static inline void pads_2511020213301_handle_interrupt(const struct device *dev)
28 {
29 	struct pads_2511020213301_data *data = dev->data;
30 
31 	/* Disable interrupt handling until the interrupt has been processed */
32 	pads_2511020213301_setup_interrupt(dev, false);
33 
34 #if defined(CONFIG_WSEN_PADS_2511020213301_TRIGGER_OWN_THREAD)
35 	k_sem_give(&data->sem);
36 #elif defined(CONFIG_WSEN_PADS_2511020213301_TRIGGER_GLOBAL_THREAD)
37 	k_work_submit(&data->work);
38 #endif
39 }
40 
41 /* Calls data-ready trigger handler (if any) */
pads_2511020213301_process_interrupt(const struct device * dev)42 static void pads_2511020213301_process_interrupt(const struct device *dev)
43 {
44 	struct pads_2511020213301_data *data = dev->data;
45 
46 #ifdef CONFIG_WSEN_PADS_2511020213301_PRESSURE_THRESHOLD
47 	if (data->pressure_low_trigger_handler != NULL ||
48 	    data->pressure_high_trigger_handler != NULL) {
49 		PADS_state_t pressure_high_state, pressure_low_state;
50 
51 		if (PADS_getHighPressureInterruptStatus(&data->sensor_interface,
52 							&pressure_high_state) != WE_SUCCESS) {
53 			LOG_ERR("Failed to read pressure high state");
54 			return;
55 		}
56 
57 		if (PADS_getLowPressureInterruptStatus(&data->sensor_interface,
58 						       &pressure_low_state) != WE_SUCCESS) {
59 			LOG_ERR("Failed to read pressure high state");
60 			return;
61 		}
62 
63 		if (data->pressure_high_trigger_handler != NULL &&
64 		    pressure_high_state == PADS_enable) {
65 			data->pressure_high_trigger_handler(dev, data->pressure_high_trigger);
66 		} else if (data->pressure_low_trigger_handler != NULL &&
67 			   pressure_low_state == PADS_enable) {
68 			data->pressure_low_trigger_handler(dev, data->pressure_low_trigger);
69 		}
70 	}
71 #else
72 	if (data->data_ready_trigger_handler != NULL) {
73 		data->data_ready_trigger_handler(dev, data->data_ready_trigger);
74 	}
75 #endif /* CONFIG_WSEN_PADS_2511020213301_PRESSURE_THRESHOLD */
76 
77 	pads_2511020213301_setup_interrupt(dev, true);
78 }
79 
pads_2511020213301_trigger_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)80 int pads_2511020213301_trigger_set(const struct device *dev, const struct sensor_trigger *trig,
81 				   sensor_trigger_handler_t handler)
82 {
83 	struct pads_2511020213301_data *data = dev->data;
84 	const struct pads_2511020213301_config *cfg = dev->config;
85 
86 	if (trig->chan != SENSOR_CHAN_PRESS) {
87 		LOG_ERR("Unsupported sensor trigger");
88 		return -ENOTSUP;
89 	}
90 
91 	switch ((int)trig->type) {
92 #ifdef CONFIG_WSEN_PADS_2511020213301_PRESSURE_THRESHOLD
93 	case SENSOR_TRIG_WSEN_PADS_2511020213301_THRESHOLD_LOWER:
94 	case SENSOR_TRIG_WSEN_PADS_2511020213301_THRESHOLD_UPPER: {
95 		switch ((int)trig->type) {
96 		case SENSOR_TRIG_WSEN_PADS_2511020213301_THRESHOLD_LOWER:
97 			data->pressure_low_trigger_handler = handler;
98 			data->pressure_low_trigger = trig;
99 			break;
100 		case SENSOR_TRIG_WSEN_PADS_2511020213301_THRESHOLD_UPPER:
101 			data->pressure_high_trigger_handler = handler;
102 			data->pressure_high_trigger = trig;
103 			break;
104 		default:
105 			break;
106 		}
107 
108 		if (PADS_setInterruptEventControl(&data->sensor_interface,
109 						  PADS_pressureHighOrLow) != WE_SUCCESS) {
110 			LOG_ERR("Failed to set interrupt event control to pressure high or low");
111 			return -EIO;
112 		}
113 
114 		if (PADS_enableDiffPressureInterrupt(&data->sensor_interface,
115 						     (data->pressure_high_trigger_handler ||
116 						      data->pressure_low_trigger_handler)
117 							     ? PADS_enable
118 							     : PADS_disable) != WE_SUCCESS) {
119 			LOG_ERR("Failed to enable pressure diff interrupt.");
120 			return -EIO;
121 		}
122 
123 		if (PADS_enableLowPressureInterrupt(&data->sensor_interface,
124 						    (data->pressure_low_trigger_handler == NULL)
125 							    ? PADS_disable
126 							    : PADS_enable) != WE_SUCCESS) {
127 			LOG_ERR("Failed to enable low pressure interrupt.");
128 			return -EIO;
129 		}
130 		if (PADS_enableHighPressureInterrupt(&data->sensor_interface,
131 						     (data->pressure_high_trigger_handler == NULL)
132 							     ? PADS_disable
133 							     : PADS_enable) != WE_SUCCESS) {
134 			LOG_ERR("Failed to enable high pressure interrupt.");
135 			return -EIO;
136 		}
137 
138 		pads_2511020213301_setup_interrupt(dev, data->pressure_high_trigger_handler ||
139 								data->pressure_low_trigger_handler);
140 		break;
141 	}
142 #else
143 	case SENSOR_TRIG_DATA_READY: {
144 		int32_t pressure_dummy;
145 		/* Read pressure to retrigger interrupt */
146 		if (PADS_getPressure_int(&data->sensor_interface, &pressure_dummy) != WE_SUCCESS) {
147 			LOG_ERR("Failed to read sample");
148 			return -EIO;
149 		}
150 
151 		if (PADS_setInterruptEventControl(&data->sensor_interface, PADS_dataReady)) {
152 			LOG_ERR("Failed to set interrupt event control to data ready");
153 			return -EIO;
154 		}
155 
156 		/* Enable data-ready interrupt */
157 		if (PADS_enableDataReadyInterrupt(&data->sensor_interface,
158 						  (handler == NULL) ? PADS_disable : PADS_enable) !=
159 		    WE_SUCCESS) {
160 			LOG_ERR("Failed to enable data-ready interrupt.");
161 			return -EIO;
162 		}
163 
164 		data->data_ready_trigger_handler = handler;
165 		data->data_ready_trigger = trig;
166 
167 		pads_2511020213301_setup_interrupt(dev, data->data_ready_trigger_handler);
168 
169 		break;
170 	}
171 #endif /* CONFIG_WSEN_PADS_2511020213301_PRESSURE_THRESHOLD */
172 	default:
173 		LOG_ERR("Unsupported sensor trigger");
174 		return -ENOTSUP;
175 	}
176 
177 	if (gpio_pin_get_dt(&cfg->interrupt_gpio) > 0) {
178 		pads_2511020213301_handle_interrupt(dev);
179 	}
180 
181 	return 0;
182 }
183 
pads_2511020213301_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)184 static void pads_2511020213301_callback(const struct device *dev, struct gpio_callback *cb,
185 					uint32_t pins)
186 {
187 	struct pads_2511020213301_data *data =
188 		CONTAINER_OF(cb, struct pads_2511020213301_data, interrupt_cb);
189 
190 	ARG_UNUSED(pins);
191 
192 	pads_2511020213301_handle_interrupt(data->dev);
193 }
194 
195 #ifdef CONFIG_WSEN_PADS_2511020213301_TRIGGER_OWN_THREAD
pads_2511020213301_thread(void * p1,void * p2,void * p3)196 static void pads_2511020213301_thread(void *p1, void *p2, void *p3)
197 {
198 	ARG_UNUSED(p2);
199 	ARG_UNUSED(p3);
200 
201 	struct pads_2511020213301_data *data = p1;
202 
203 	while (true) {
204 		k_sem_take(&data->sem, K_FOREVER);
205 		pads_2511020213301_process_interrupt(data->dev);
206 	}
207 }
208 #endif /* CONFIG_WSEN_PADS_2511020213301_TRIGGER_OWN_THREAD */
209 
210 #ifdef CONFIG_WSEN_PADS_2511020213301_TRIGGER_GLOBAL_THREAD
pads_2511020213301_work_cb(struct k_work * work)211 static void pads_2511020213301_work_cb(struct k_work *work)
212 {
213 	struct pads_2511020213301_data *data =
214 		CONTAINER_OF(work, struct pads_2511020213301_data, work);
215 
216 	pads_2511020213301_process_interrupt(data->dev);
217 }
218 #endif /* CONFIG_WSEN_PADS_2511020213301_TRIGGER_GLOBAL_THREAD */
219 
220 #ifdef CONFIG_WSEN_PADS_2511020213301_PRESSURE_THRESHOLD
221 /* Set threshold for the differential pressure interrupt. */
pads_2511020213301_threshold_set(const struct device * dev,const struct sensor_value * threshold)222 int pads_2511020213301_threshold_set(const struct device *dev, const struct sensor_value *threshold)
223 {
224 	struct pads_2511020213301_data *data = dev->data;
225 
226 	if (PADS_setPressureThreshold(&data->sensor_interface, (uint32_t)threshold->val1) !=
227 	    WE_SUCCESS) {
228 		LOG_ERR("Failed to set threshold");
229 		return -EIO;
230 	}
231 
232 	return 0;
233 }
234 
235 /* Get threshold for the differential pressure interrupt. */
pads_2511020213301_threshold_get(const struct device * dev,struct sensor_value * threshold)236 int pads_2511020213301_threshold_get(const struct device *dev, struct sensor_value *threshold)
237 {
238 
239 	struct pads_2511020213301_data *data = dev->data;
240 
241 	if (PADS_getPressureThreshold(&data->sensor_interface, (uint32_t *)&threshold->val1) !=
242 	    WE_SUCCESS) {
243 		LOG_ERR("Failed to get threshold");
244 		return -EIO;
245 	}
246 
247 	return 0;
248 }
249 
250 /* Set reference point to current measured pressure state. */
pads_2511020213301_reference_point_set(const struct device * dev,const struct sensor_value * reference_point)251 int pads_2511020213301_reference_point_set(const struct device *dev,
252 					   const struct sensor_value *reference_point)
253 {
254 	struct pads_2511020213301_data *data = dev->data;
255 
256 	if (reference_point != NULL) {
257 		LOG_ERR("Sensor value should be null");
258 		return -EIO;
259 	}
260 
261 	if (PADS_enableAutoRefp(&data->sensor_interface, PADS_enable) != WE_SUCCESS) {
262 		LOG_ERR("Failed to set additional low pass filter");
263 		return -EIO;
264 	}
265 
266 	return 0;
267 }
268 
269 /* Get reference point from registers. */
pads_2511020213301_reference_point_get(const struct device * dev,struct sensor_value * reference_point)270 int pads_2511020213301_reference_point_get(const struct device *dev,
271 					   struct sensor_value *reference_point)
272 {
273 
274 	struct pads_2511020213301_data *data = dev->data;
275 
276 	if (PADS_getReferencePressure(&data->sensor_interface,
277 				      (uint32_t *)&reference_point->val1) != WE_SUCCESS) {
278 		LOG_ERR("Failed to get reference point");
279 		return -EIO;
280 	}
281 
282 	return 0;
283 }
284 #endif /* CONFIG_WSEN_PADS_2511020213301_PRESSURE_THRESHOLD */
285 
pads_2511020213301_init_interrupt(const struct device * dev)286 int pads_2511020213301_init_interrupt(const struct device *dev)
287 {
288 	struct pads_2511020213301_data *data = dev->data;
289 	const struct pads_2511020213301_config *cfg = dev->config;
290 
291 	data->dev = dev;
292 
293 	if (cfg->interrupt_gpio.port == NULL) {
294 		LOG_ERR("interrupt-gpio is not defined in the device tree.");
295 		return -EINVAL;
296 	}
297 
298 	if (!gpio_is_ready_dt(&cfg->interrupt_gpio)) {
299 		LOG_ERR("Device %s is not ready", cfg->interrupt_gpio.port->name);
300 		return -ENODEV;
301 	}
302 
303 	if (gpio_pin_configure_dt(&cfg->interrupt_gpio, GPIO_INPUT) < 0) {
304 		LOG_ERR("Failed to configure %s.%02u", cfg->interrupt_gpio.port->name,
305 			cfg->interrupt_gpio.pin);
306 		return -EIO;
307 	}
308 
309 	gpio_init_callback(&data->interrupt_cb, pads_2511020213301_callback,
310 			   BIT(cfg->interrupt_gpio.pin));
311 
312 	if (gpio_add_callback(cfg->interrupt_gpio.port, &data->interrupt_cb) < 0) {
313 		LOG_ERR("Failed to set gpio callback.");
314 		return -EIO;
315 	}
316 #ifdef CONFIG_WSEN_PADS_2511020213301_PRESSURE_THRESHOLD
317 
318 	struct sensor_value threshold;
319 
320 	threshold.val1 = cfg->threshold;
321 	threshold.val2 = 0;
322 	if (pads_2511020213301_threshold_set(dev, &threshold) < 0) {
323 		LOG_ERR("Failed to set threshold.");
324 		return -EIO;
325 	}
326 
327 #endif /* CONFIG_WSEN_PADS_2511020213301_PRESSURE_THRESHOLD */
328 
329 #if defined(CONFIG_WSEN_PADS_2511020213301_TRIGGER_OWN_THREAD)
330 	k_sem_init(&data->sem, 0, K_SEM_MAX_LIMIT);
331 
332 	k_thread_create(&data->thread, data->thread_stack,
333 			CONFIG_WSEN_PADS_2511020213301_THREAD_STACK_SIZE, pads_2511020213301_thread,
334 			data, NULL, NULL,
335 			K_PRIO_COOP(CONFIG_WSEN_PADS_2511020213301_THREAD_PRIORITY), 0, K_NO_WAIT);
336 #elif defined(CONFIG_WSEN_PADS_2511020213301_TRIGGER_GLOBAL_THREAD)
337 	data->work.handler = pads_2511020213301_work_cb;
338 #endif
339 
340 	return 0;
341 }
342