1 /*
2 * Copyright (c) 2022, Basalte bv
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT ti_bq274xx
8
9 #include <zephyr/drivers/sensor.h>
10 #include <zephyr/drivers/gpio.h>
11 #include <zephyr/logging/log.h>
12
13 #ifdef CONFIG_BQ274XX_PM
14 #include <zephyr/pm/device.h>
15 #endif
16
17 #include "bq274xx.h"
18
19 LOG_MODULE_DECLARE(bq274xx, CONFIG_SENSOR_LOG_LEVEL);
20
bq274xx_handle_interrupts(const struct device * dev)21 static void bq274xx_handle_interrupts(const struct device *dev)
22 {
23 struct bq274xx_data *data = dev->data;
24
25 if (data->ready_handler) {
26 data->ready_handler(dev, data->ready_trig);
27 }
28 }
29
30 #ifdef CONFIG_BQ274XX_TRIGGER_OWN_THREAD
31 static K_KERNEL_STACK_DEFINE(bq274xx_thread_stack, CONFIG_BQ274XX_THREAD_STACK_SIZE);
32 static struct k_thread bq274xx_thread;
33
bq274xx_thread_main(void * p1,void * p2,void * p3)34 static void bq274xx_thread_main(void *p1, void *p2, void *p3)
35 {
36 ARG_UNUSED(p2);
37 ARG_UNUSED(p3);
38
39 struct bq274xx_data *data = p1;
40
41 while (1) {
42 k_sem_take(&data->sem, K_FOREVER);
43 bq274xx_handle_interrupts(data->dev);
44 }
45 }
46 #endif
47
48 #ifdef CONFIG_BQ274XX_TRIGGER_GLOBAL_THREAD
bq274xx_work_handler(struct k_work * work)49 static void bq274xx_work_handler(struct k_work *work)
50 {
51 struct bq274xx_data *data = CONTAINER_OF(work, struct bq274xx_data, work);
52
53 bq274xx_handle_interrupts(data->dev);
54 }
55 #endif
56
bq274xx_ready_callback_handler(const struct device * port,struct gpio_callback * cb,gpio_port_pins_t pins)57 static void bq274xx_ready_callback_handler(const struct device *port,
58 struct gpio_callback *cb,
59 gpio_port_pins_t pins)
60 {
61 struct bq274xx_data *data = CONTAINER_OF(cb, struct bq274xx_data,
62 ready_callback);
63
64 ARG_UNUSED(port);
65 ARG_UNUSED(pins);
66
67 #if defined(CONFIG_BQ274XX_TRIGGER_OWN_THREAD)
68 k_sem_give(&data->sem);
69 #elif defined(CONFIG_BQ274XX_TRIGGER_GLOBAL_THREAD)
70 k_work_submit(&data->work);
71 #endif
72 }
73
bq274xx_trigger_mode_init(const struct device * dev)74 int bq274xx_trigger_mode_init(const struct device *dev)
75 {
76 const struct bq274xx_config *const config = dev->config;
77 struct bq274xx_data *data = dev->data;
78 int ret;
79
80 data->dev = dev;
81
82 #if defined(CONFIG_BQ274XX_TRIGGER_OWN_THREAD)
83 k_sem_init(&data->sem, 0, K_SEM_MAX_LIMIT);
84
85 k_thread_create(&bq274xx_thread, bq274xx_thread_stack,
86 CONFIG_BQ274XX_THREAD_STACK_SIZE,
87 bq274xx_thread_main,
88 data, NULL, NULL,
89 K_PRIO_COOP(CONFIG_BQ274XX_THREAD_PRIORITY),
90 0, K_NO_WAIT);
91 #elif defined(CONFIG_BQ274XX_TRIGGER_GLOBAL_THREAD)
92 k_work_init(&data->work, bq274xx_work_handler);
93 #endif
94
95 ret = gpio_pin_configure_dt(&config->int_gpios, GPIO_INPUT);
96 if (ret < 0) {
97 LOG_ERR("Unable to configure interrupt pin");
98 return ret;
99 }
100 gpio_init_callback(&data->ready_callback,
101 bq274xx_ready_callback_handler,
102 BIT(config->int_gpios.pin));
103
104 return 0;
105 }
106
bq274xx_trigger_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)107 int bq274xx_trigger_set(const struct device *dev,
108 const struct sensor_trigger *trig,
109 sensor_trigger_handler_t handler)
110 {
111 const struct bq274xx_config *config = dev->config;
112 struct bq274xx_data *data = dev->data;
113 int ret;
114
115 #ifdef CONFIG_BQ274XX_PM
116 enum pm_device_state state;
117
118 (void)pm_device_state_get(dev, &state);
119 if (state != PM_DEVICE_STATE_ACTIVE) {
120 return -EBUSY;
121 }
122 #endif
123
124 if (trig->type != SENSOR_TRIG_DATA_READY) {
125 return -ENOTSUP;
126 }
127
128 if (!gpio_is_ready_dt(&config->int_gpios)) {
129 LOG_ERR("GPIO device is not ready");
130 return -ENODEV;
131 }
132
133 data->ready_handler = handler;
134 data->ready_trig = trig;
135
136 if (handler) {
137 ret = gpio_pin_configure_dt(&config->int_gpios, GPIO_INPUT);
138 if (ret < 0) {
139 LOG_ERR("Unable to configure interrupt pin: %d", ret);
140 return ret;
141 }
142
143 ret = gpio_add_callback(config->int_gpios.port,
144 &data->ready_callback);
145 if (ret < 0) {
146 LOG_ERR("Unable to add interrupt callback: %d", ret);
147 return ret;
148 }
149
150 ret = gpio_pin_interrupt_configure_dt(&config->int_gpios,
151 GPIO_INT_EDGE_TO_ACTIVE);
152 if (ret < 0) {
153 LOG_ERR("Unable to configure interrupt: %d", ret);
154 return ret;
155 }
156 } else {
157 ret = gpio_remove_callback(config->int_gpios.port,
158 &data->ready_callback);
159 if (ret < 0) {
160 LOG_ERR("Unable to remove interrupt callback: %d", ret);
161 return ret;
162 }
163
164 ret = gpio_pin_interrupt_configure_dt(&config->int_gpios, GPIO_INT_DISABLE);
165 if (ret < 0) {
166 LOG_ERR("Unable to disable interrupt: %d", ret);
167 return ret;
168 }
169 }
170
171 return 0;
172 }
173