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