1 /* ST Microelectronics LPS2XDF pressure and temperature sensor
2 *
3 * Copyright (c) 2023 STMicroelectronics
4 * Copyright (c) 2023 PHYTEC Messtechnik GmbH
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 *
8 * Datasheet:
9 * https://www.st.com/resource/en/datasheet/lps22df.pdf
10 * https://www.st.com/resource/en/datasheet/lps28dfw.pdf
11 */
12
13 #include <zephyr/kernel.h>
14 #include <zephyr/drivers/sensor.h>
15 #include <zephyr/drivers/gpio.h>
16 #include <zephyr/logging/log.h>
17
18 #include "lps2xdf.h"
19
20 #if DT_HAS_COMPAT_STATUS_OKAY(st_lps22df)
21 #include "lps22df.h"
22 #endif
23
24 #if DT_HAS_COMPAT_STATUS_OKAY(st_lps28dfw)
25 #include "lps28dfw.h"
26 #endif
27
28 LOG_MODULE_DECLARE(LPS2XDF, CONFIG_SENSOR_LOG_LEVEL);
29
lps2xdf_config_int(const struct device * dev)30 int lps2xdf_config_int(const struct device *dev)
31 {
32 const struct lps2xdf_config *const cfg = dev->config;
33 const struct lps2xdf_chip_api *chip_api = cfg->chip_api;
34
35 return chip_api->config_interrupt(dev);
36 }
37
lps2xdf_trigger_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)38 int lps2xdf_trigger_set(const struct device *dev,
39 const struct sensor_trigger *trig,
40 sensor_trigger_handler_t handler)
41 {
42 const struct lps2xdf_config *const cfg = dev->config;
43 const struct lps2xdf_chip_api *chip_api = cfg->chip_api;
44
45 return chip_api->trigger_set(dev, trig, handler);
46 }
47
lps2xdf_intr_callback(struct lps2xdf_data * lps2xdf)48 static void lps2xdf_intr_callback(struct lps2xdf_data *lps2xdf)
49 {
50 #if defined(CONFIG_LPS2XDF_TRIGGER_OWN_THREAD)
51 k_sem_give(&lps2xdf->intr_sem);
52 #elif defined(CONFIG_LPS2XDF_TRIGGER_GLOBAL_THREAD)
53 k_work_submit(&lps2xdf->work);
54 #endif /* CONFIG_LPS2XDF_TRIGGER_OWN_THREAD */
55 }
56
lps2xdf_gpio_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)57 static void lps2xdf_gpio_callback(const struct device *dev,
58 struct gpio_callback *cb, uint32_t pins)
59 {
60 struct lps2xdf_data *lps2xdf =
61 CONTAINER_OF(cb, struct lps2xdf_data, gpio_cb);
62
63 ARG_UNUSED(pins);
64 const struct lps2xdf_config *cfg = lps2xdf->dev->config;
65 int ret;
66
67 ret = gpio_pin_interrupt_configure_dt(&cfg->gpio_int, GPIO_INT_DISABLE);
68 if (ret < 0) {
69 LOG_ERR("%s: Not able to configure pin_int", dev->name);
70 }
71
72 lps2xdf_intr_callback(lps2xdf);
73 }
74
75 #ifdef CONFIG_LPS2XDF_TRIGGER_OWN_THREAD
lps2xdf_thread(struct lps2xdf_data * lps2xdf)76 static void lps2xdf_thread(struct lps2xdf_data *lps2xdf)
77 {
78 const struct device *dev = lps2xdf->dev;
79 const struct lps2xdf_config *const cfg = dev->config;
80 const struct lps2xdf_chip_api *chip_api = cfg->chip_api;
81
82 while (1) {
83 k_sem_take(&lps2xdf->intr_sem, K_FOREVER);
84 chip_api->handle_interrupt(dev);
85 }
86 }
87 #endif /* CONFIG_LPS2XDF_TRIGGER_OWN_THREAD */
88
89 #ifdef CONFIG_LPS2XDF_TRIGGER_GLOBAL_THREAD
lps2xdf_work_cb(struct k_work * work)90 static void lps2xdf_work_cb(struct k_work *work)
91 {
92 struct lps2xdf_data *lps2xdf =
93 CONTAINER_OF(work, struct lps2xdf_data, work);
94 const struct device *dev = lps2xdf->dev;
95 const struct lps2xdf_config *const cfg = dev->config;
96 const struct lps2xdf_chip_api *chip_api = cfg->chip_api;
97
98 chip_api->handle_interrupt(dev);
99 }
100 #endif /* CONFIG_LPS2XDF_TRIGGER_GLOBAL_THREAD */
101
102 #if (DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps22df, i3c) ||\
103 DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps28dfw, i3c))
lps2xdf_ibi_cb(struct i3c_device_desc * target,struct i3c_ibi_payload * payload)104 static int lps2xdf_ibi_cb(struct i3c_device_desc *target,
105 struct i3c_ibi_payload *payload)
106 {
107 const struct device *dev = target->dev;
108 struct lps2xdf_data *lps2xdf = dev->data;
109
110 ARG_UNUSED(payload);
111
112 lps2xdf_intr_callback(lps2xdf);
113
114 return 0;
115 }
116 #endif
117
lps2xdf_init_interrupt(const struct device * dev,enum sensor_variant variant)118 int lps2xdf_init_interrupt(const struct device *dev, enum sensor_variant variant)
119 {
120 struct lps2xdf_data *lps2xdf = dev->data;
121 const struct lps2xdf_config *cfg = dev->config;
122 int ret;
123
124 /* setup data ready gpio interrupt */
125 if (!gpio_is_ready_dt(&cfg->gpio_int) && !ON_I3C_BUS(cfg)) {
126 if (cfg->gpio_int.port) {
127 LOG_ERR("%s: device %s is not ready", dev->name,
128 cfg->gpio_int.port->name);
129 return -ENODEV;
130 }
131
132 LOG_DBG("%s: gpio_int not defined in DT", dev->name);
133 return 0;
134 }
135
136 lps2xdf->dev = dev;
137
138 #if defined(CONFIG_LPS2XDF_TRIGGER_OWN_THREAD)
139 k_sem_init(&lps2xdf->intr_sem, 0, K_SEM_MAX_LIMIT);
140
141 k_thread_create(&lps2xdf->thread, lps2xdf->thread_stack,
142 CONFIG_LPS2XDF_THREAD_STACK_SIZE,
143 (k_thread_entry_t)lps2xdf_thread, lps2xdf,
144 NULL, NULL, K_PRIO_COOP(CONFIG_LPS2XDF_THREAD_PRIORITY),
145 0, K_NO_WAIT);
146 #elif defined(CONFIG_LPS2XDF_TRIGGER_GLOBAL_THREAD)
147 lps2xdf->work.handler = lps2xdf_work_cb;
148 #endif /* CONFIG_LPS2XDF_TRIGGER_OWN_THREAD */
149
150 if (!ON_I3C_BUS(cfg)) {
151 ret = gpio_pin_configure_dt(&cfg->gpio_int, GPIO_INPUT);
152 if (ret < 0) {
153 LOG_ERR("Could not configure gpio");
154 return ret;
155 }
156
157 LOG_INF("%s: int on %s.%02u", dev->name, cfg->gpio_int.port->name,
158 cfg->gpio_int.pin);
159
160 gpio_init_callback(&lps2xdf->gpio_cb,
161 lps2xdf_gpio_callback,
162 BIT(cfg->gpio_int.pin));
163
164 ret = gpio_add_callback(cfg->gpio_int.port, &lps2xdf->gpio_cb);
165 if (ret < 0) {
166 LOG_ERR("Could not set gpio callback");
167 return ret;
168 }
169 }
170
171 LOG_DBG("drdy_pulsed is %d", (int)cfg->drdy_pulsed);
172
173 /* enable drdy in pulsed/latched mode */
174 ret = lps2xdf_config_int(dev);
175 if (ret < 0) {
176 LOG_ERR("Could not configure interrupt mode");
177 return ret;
178 }
179
180 #if (DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps22df, i3c) ||\
181 DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps28dfw, i3c))
182 if (cfg->i3c.bus != NULL) {
183 /* I3C IBI does not utilize GPIO interrupt. */
184 lps2xdf->i3c_dev->ibi_cb = lps2xdf_ibi_cb;
185
186 if (i3c_ibi_enable(lps2xdf->i3c_dev) != 0) {
187 LOG_DBG("Could not enable I3C IBI");
188 return -EIO;
189 }
190
191 return 0;
192 }
193 #endif
194
195 return gpio_pin_interrupt_configure_dt(&cfg->gpio_int,
196 GPIO_INT_EDGE_TO_ACTIVE);
197 }
198