1 /*
2 * Copyright (c) 2020, Laird Connectivity
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT honeywell_sm351lt
8
9 #include "sm351lt.h"
10
11 #include <zephyr/init.h>
12 #include <zephyr/sys/byteorder.h>
13 #include <zephyr/logging/log.h>
14 #include <stdio.h>
15 #include <zephyr/sys/util.h>
16 #include <zephyr/drivers/gpio.h>
17 #include <zephyr/drivers/sensor.h>
18 #include <string.h>
19
20 LOG_MODULE_REGISTER(SM351LT, CONFIG_SENSOR_LOG_LEVEL);
21
22 #if CONFIG_SM351LT_TRIGGER
sm351lt_trigger_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)23 static int sm351lt_trigger_set(const struct device *dev,
24 const struct sensor_trigger *trig,
25 sensor_trigger_handler_t handler)
26 {
27 const struct sm351lt_config *const config = dev->config;
28 struct sm351lt_data *data = dev->data;
29 int ret = -ENOTSUP;
30
31 if (trig->chan == SENSOR_CHAN_PROX) {
32 data->changed_handler = handler;
33 data->changed_trigger = trig;
34 ret = gpio_pin_interrupt_configure_dt(&config->int_gpio,
35 (handler ? data->trigger_type
36 : GPIO_INT_DISABLE));
37
38 if (ret < 0) {
39 return ret;
40 }
41
42 if (handler) {
43 ret = gpio_add_callback(config->int_gpio.port,
44 &data->gpio_cb);
45 } else {
46 ret = gpio_remove_callback(config->int_gpio.port,
47 &data->gpio_cb);
48 }
49 }
50
51 return ret;
52 }
53
sm351lt_gpio_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)54 static void sm351lt_gpio_callback(const struct device *dev,
55 struct gpio_callback *cb, uint32_t pins)
56 {
57 struct sm351lt_data *data =
58 CONTAINER_OF(cb, struct sm351lt_data, gpio_cb);
59
60 #if defined(CONFIG_SM351LT_TRIGGER_OWN_THREAD)
61 k_sem_give(&data->gpio_sem);
62 #elif defined(CONFIG_SM351LT_TRIGGER_GLOBAL_THREAD)
63 k_work_submit(&data->work);
64 #endif
65 }
66
sm351lt_thread_cb(const struct device * dev)67 static void sm351lt_thread_cb(const struct device *dev)
68 {
69 struct sm351lt_data *data = dev->data;
70
71 if (likely(data->changed_handler != NULL)) {
72 data->changed_handler(dev, data->changed_trigger);
73 }
74
75 return;
76 }
77
78 #if defined(CONFIG_SM351LT_TRIGGER_OWN_THREAD)
sm351lt_thread(void * arg1,void * unused2,void * unused3)79 static void sm351lt_thread(void *arg1, void *unused2, void *unused3)
80 {
81 struct sm351lt_data *data = arg1;
82
83 ARG_UNUSED(unused2);
84 ARG_UNUSED(unused3);
85
86 while (1) {
87 k_sem_take(&data->gpio_sem, K_FOREVER);
88 sm351lt_thread_cb(data->dev);
89 }
90 }
91 #endif
92
93 #if defined(CONFIG_SM351LT_TRIGGER_GLOBAL_THREAD)
sm351lt_work_cb(struct k_work * work)94 static void sm351lt_work_cb(struct k_work *work)
95 {
96 struct sm351lt_data *data =
97 CONTAINER_OF(work, struct sm351lt_data, work);
98
99 sm351lt_thread_cb(data->dev);
100 }
101 #endif
102 #endif
103
sm351lt_sample_fetch(const struct device * dev,enum sensor_channel chan)104 static int sm351lt_sample_fetch(const struct device *dev,
105 enum sensor_channel chan)
106 {
107 const struct sm351lt_config *config = dev->config;
108 struct sm351lt_data *data = dev->data;
109
110 if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_PROX) {
111 return -ENOTSUP;
112 }
113
114 data->sample_status = gpio_pin_get_dt(&config->int_gpio);
115
116 return 0;
117 }
118
sm351lt_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)119 static int sm351lt_channel_get(const struct device *dev,
120 enum sensor_channel chan,
121 struct sensor_value *val)
122 {
123 struct sm351lt_data *data = dev->data;
124
125 if (chan == SENSOR_CHAN_PROX) {
126 val->val1 = data->sample_status;
127 val->val2 = 0;
128 } else {
129 return -ENOTSUP;
130 }
131
132 return 0;
133 }
134
135 #if CONFIG_SM351LT_TRIGGER
sm351lt_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)136 static int sm351lt_attr_set(const struct device *dev,
137 enum sensor_channel chan,
138 enum sensor_attribute attr,
139 const struct sensor_value *val)
140 {
141 struct sm351lt_data *data = dev->data;
142
143 if (chan == SENSOR_CHAN_PROX) {
144 if (attr == SENSOR_ATTR_SM351LT_TRIGGER_TYPE) {
145 /* Interrupt triggering type */
146 data->trigger_type = val->val1;
147 } else {
148 return -ENOTSUP;
149 }
150 } else {
151 return -ENOTSUP;
152 }
153
154 return 0;
155 }
156
sm351lt_attr_get(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,struct sensor_value * val)157 static int sm351lt_attr_get(const struct device *dev,
158 enum sensor_channel chan,
159 enum sensor_attribute attr,
160 struct sensor_value *val)
161 {
162 struct sm351lt_data *data = dev->data;
163
164 if (chan == SENSOR_CHAN_PROX) {
165 if (attr == SENSOR_ATTR_SM351LT_TRIGGER_TYPE) {
166 /* Interrupt triggering type */
167 val->val1 = data->trigger_type;
168 val->val2 = 0;
169 } else {
170 return -ENOTSUP;
171 }
172 } else {
173 return -ENOTSUP;
174 }
175
176 return 0;
177 }
178 #endif
179
180 static const struct sensor_driver_api sm351lt_api_funcs = {
181 .sample_fetch = sm351lt_sample_fetch,
182 .channel_get = sm351lt_channel_get,
183 #if CONFIG_SM351LT_TRIGGER
184 .attr_set = sm351lt_attr_set,
185 .attr_get = sm351lt_attr_get,
186 .trigger_set = sm351lt_trigger_set,
187 #endif
188 };
189
sm351lt_init(const struct device * dev)190 static int sm351lt_init(const struct device *dev)
191 {
192 const struct sm351lt_config *const config = dev->config;
193 uint32_t ret;
194
195 if (!gpio_is_ready_dt(&config->int_gpio)) {
196 LOG_ERR("GPIO device not ready");
197 return -ENODEV;
198 }
199
200 ret = gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT);
201 if (ret) {
202 LOG_ERR("failed to configure gpio: %d", ret);
203 return ret;
204 }
205
206 #if defined(CONFIG_SM351LT_TRIGGER)
207 struct sm351lt_data *data = dev->data;
208 data->dev = dev;
209
210 #if defined(CONFIG_SM351LT_TRIGGER_OWN_THREAD)
211 k_sem_init(&data->gpio_sem, 0, K_SEM_MAX_LIMIT);
212
213 k_thread_create(&data->thread, data->thread_stack,
214 CONFIG_SM351LT_THREAD_STACK_SIZE,
215 sm351lt_thread, data, NULL,
216 NULL, K_PRIO_COOP(CONFIG_SM351LT_THREAD_PRIORITY),
217 0, K_NO_WAIT);
218
219 #if defined(CONFIG_THREAD_NAME) && defined(CONFIG_THREAD_MAX_NAME_LEN)
220 /* Sets up thread name as the device name */
221 k_thread_name_set(&data->thread, dev->name);
222 #endif
223
224 #elif defined(CONFIG_SM351LT_TRIGGER_GLOBAL_THREAD)
225 data->work.handler = sm351lt_work_cb;
226 #endif
227
228 data->trigger_type = GPIO_INT_DISABLE;
229
230 ret = gpio_pin_interrupt_configure_dt(&config->int_gpio,
231 GPIO_INT_DISABLE);
232 if (ret) {
233 LOG_ERR("failed to configure gpio interrupt: %d", ret);
234 return ret;
235 }
236
237 /* Setup callback struct but do not add it yet */
238 gpio_init_callback(&data->gpio_cb, sm351lt_gpio_callback,
239 BIT(config->int_gpio.pin));
240 #endif
241
242 return 0;
243 }
244
245 /* Instantiation macros for each individual device. */
246 #define SM351LT_DEFINE(inst) \
247 static struct sm351lt_data sm351lt_data_##inst; \
248 static const struct sm351lt_config sm351lt_config_##inst = { \
249 .int_gpio = GPIO_DT_SPEC_INST_GET(inst, gpios), \
250 }; \
251 \
252 SENSOR_DEVICE_DT_INST_DEFINE(inst, \
253 sm351lt_init, \
254 NULL, \
255 &sm351lt_data_##inst, \
256 &sm351lt_config_##inst, \
257 POST_KERNEL, \
258 CONFIG_SENSOR_INIT_PRIORITY, \
259 &sm351lt_api_funcs);
260
261
262 /* Main instantiation macro for every configured device in DTS. */
263 DT_INST_FOREACH_STATUS_OKAY(SM351LT_DEFINE)
264