1 /*
2 * Copyright (c) 2016 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT semtech_sx9500
8
9 #include <errno.h>
10
11 #include <zephyr/kernel.h>
12 #include <zephyr/drivers/i2c.h>
13 #include <zephyr/drivers/sensor.h>
14 #include <zephyr/drivers/gpio.h>
15 #include <zephyr/sys/util.h>
16
17 #include "sx9500.h"
18
19 #include <zephyr/logging/log.h>
20 LOG_MODULE_DECLARE(SX9500, CONFIG_SENSOR_LOG_LEVEL);
21
22 #ifdef CONFIG_SX9500_TRIGGER_OWN_THREAD
23 static K_KERNEL_STACK_DEFINE(sx9500_thread_stack, CONFIG_SX9500_THREAD_STACK_SIZE);
24 static struct k_thread sx9500_thread;
25 #endif
26
sx9500_trigger_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)27 int sx9500_trigger_set(const struct device *dev,
28 const struct sensor_trigger *trig,
29 sensor_trigger_handler_t handler)
30 {
31 struct sx9500_data *data = dev->data;
32 const struct sx9500_config *cfg = dev->config;
33
34 if (!cfg->int_gpio.port) {
35 return -ENOTSUP;
36 }
37
38 switch (trig->type) {
39 case SENSOR_TRIG_DATA_READY:
40 if (i2c_reg_update_byte_dt(&cfg->i2c,
41 SX9500_REG_IRQ_MSK,
42 SX9500_CONV_DONE_IRQ,
43 SX9500_CONV_DONE_IRQ) < 0) {
44 return -EIO;
45 }
46 data->handler_drdy = handler;
47 data->trigger_drdy = trig;
48 break;
49
50 case SENSOR_TRIG_NEAR_FAR:
51 if (i2c_reg_update_byte_dt(&cfg->i2c,
52 SX9500_REG_IRQ_MSK,
53 SX9500_NEAR_FAR_IRQ,
54 SX9500_NEAR_FAR_IRQ) < 0) {
55 return -EIO;
56 }
57 data->handler_near_far = handler;
58 data->trigger_near_far = trig;
59 break;
60
61 default:
62 return -EINVAL;
63 }
64
65 return 0;
66 }
67
sx9500_gpio_thread_cb(const struct device * dev)68 static void sx9500_gpio_thread_cb(const struct device *dev)
69 {
70 struct sx9500_data *data = dev->data;
71 const struct sx9500_config *cfg = dev->config;
72 uint8_t reg_val;
73
74 if (i2c_reg_read_byte_dt(&cfg->i2c, SX9500_REG_IRQ_SRC, ®_val) < 0) {
75 LOG_DBG("sx9500: error reading IRQ source register");
76 return;
77 }
78
79 if ((reg_val & SX9500_CONV_DONE_IRQ) && data->handler_drdy) {
80 data->handler_drdy(dev, data->trigger_drdy);
81 }
82
83 if ((reg_val & SX9500_NEAR_FAR_IRQ) && data->handler_near_far) {
84 data->handler_near_far(dev, data->trigger_near_far);
85 }
86 }
87
88 #ifdef CONFIG_SX9500_TRIGGER_OWN_THREAD
89
sx9500_gpio_cb(const struct device * port,struct gpio_callback * cb,uint32_t pins)90 static void sx9500_gpio_cb(const struct device *port,
91 struct gpio_callback *cb, uint32_t pins)
92 {
93 struct sx9500_data *data =
94 CONTAINER_OF(cb, struct sx9500_data, gpio_cb);
95
96 ARG_UNUSED(pins);
97
98 k_sem_give(&data->sem);
99 }
100
sx9500_thread_main(void * p1,void * p2,void * p3)101 static void sx9500_thread_main(void *p1, void *p2, void *p3)
102 {
103 ARG_UNUSED(p2);
104 ARG_UNUSED(p3);
105
106 struct sx9500_data *data = p1;
107
108 while (1) {
109 k_sem_take(&data->sem, K_FOREVER);
110 sx9500_gpio_thread_cb(data->dev);
111 }
112 }
113
114 #else /* CONFIG_SX9500_TRIGGER_GLOBAL_THREAD */
115
sx9500_gpio_cb(const struct device * port,struct gpio_callback * cb,uint32_t pins)116 static void sx9500_gpio_cb(const struct device *port,
117 struct gpio_callback *cb, uint32_t pins)
118 {
119 struct sx9500_data *data =
120 CONTAINER_OF(cb, struct sx9500_data, gpio_cb);
121
122 ARG_UNUSED(pins);
123
124 k_work_submit(&data->work);
125 }
126 #endif /* CONFIG_SX9500_TRIGGER_GLOBAL_THREAD */
127
128 #ifdef CONFIG_SX9500_TRIGGER_GLOBAL_THREAD
sx9500_work_cb(struct k_work * work)129 static void sx9500_work_cb(struct k_work *work)
130 {
131 struct sx9500_data *data =
132 CONTAINER_OF(work, struct sx9500_data, work);
133
134 sx9500_gpio_thread_cb(data->dev);
135 }
136 #endif
137
sx9500_setup_interrupt(const struct device * dev)138 int sx9500_setup_interrupt(const struct device *dev)
139 {
140 struct sx9500_data *data = dev->data;
141 const struct sx9500_config *cfg = dev->config;
142 int ret;
143
144 #ifdef CONFIG_SX9500_TRIGGER_OWN_THREAD
145 k_sem_init(&data->sem, 0, K_SEM_MAX_LIMIT);
146 #else
147 data->work.handler = sx9500_work_cb;
148 #endif
149
150 data->dev = dev;
151
152 if (!gpio_is_ready_dt(&cfg->int_gpio)) {
153 LOG_ERR("%s: device %s is not ready", dev->name,
154 cfg->int_gpio.port->name);
155 return -ENODEV;
156 }
157
158 ret = gpio_pin_configure_dt(&cfg->int_gpio, GPIO_INPUT);
159 if (ret < 0) {
160 return ret;
161 }
162
163 gpio_init_callback(&data->gpio_cb, sx9500_gpio_cb, BIT(cfg->int_gpio.pin));
164
165 ret = gpio_add_callback(cfg->int_gpio.port, &data->gpio_cb);
166 if (ret < 0) {
167 return ret;
168 }
169
170 ret = gpio_pin_interrupt_configure_dt(&cfg->int_gpio, GPIO_INT_EDGE_TO_ACTIVE);
171 if (ret < 0) {
172 return ret;
173 }
174
175 #ifdef CONFIG_SX9500_TRIGGER_OWN_THREAD
176 k_thread_create(&sx9500_thread, sx9500_thread_stack,
177 CONFIG_SX9500_THREAD_STACK_SIZE,
178 sx9500_thread_main, data, 0, NULL,
179 K_PRIO_COOP(CONFIG_SX9500_THREAD_PRIORITY),
180 0, K_NO_WAIT);
181 #endif
182
183 return 0;
184 }
185