1 /*
2 * Copyright (c) 2021 Linumiz
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT hzgrow_r502a
8
9 #include <zephyr/kernel.h>
10 #include <zephyr/drivers/gpio.h>
11 #include <zephyr/drivers/sensor.h>
12 #include <zephyr/drivers/uart.h>
13 #include <zephyr/logging/log.h>
14
15 #include <zephyr/drivers/sensor/grow_r502a.h>
16 #include "grow_r502a.h"
17
18 LOG_MODULE_DECLARE(GROW_R502A, CONFIG_SENSOR_LOG_LEVEL);
19
setup_int(const struct device * dev,bool enable)20 static void setup_int(const struct device *dev, bool enable)
21 {
22 const struct grow_r502a_config *cfg = dev->config;
23
24 gpio_flags_t flags =
25 enable ? GPIO_INT_EDGE_TO_ACTIVE : GPIO_INT_DISABLE;
26
27 gpio_pin_interrupt_configure_dt(&cfg->int_gpios, flags);
28 }
29
process_int(const struct device * dev)30 static void process_int(const struct device *dev)
31 {
32 struct grow_r502a_data *drv_data = dev->data;
33
34 if (drv_data->th_handler != NULL) {
35 drv_data->th_handler(dev, drv_data->th_trigger);
36 }
37 setup_int(dev, true);
38 }
39
grow_r502a_trigger_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)40 int grow_r502a_trigger_set(const struct device *dev,
41 const struct sensor_trigger *trig,
42 sensor_trigger_handler_t handler)
43 {
44 struct grow_r502a_data *drv_data = dev->data;
45
46 if ((enum sensor_trigger_type_grow_r502a)trig->type == SENSOR_TRIG_TOUCH) {
47 drv_data->th_handler = handler;
48 drv_data->th_trigger = trig;
49 setup_int(dev, true);
50 } else {
51 LOG_ERR("Unsupported sensor trigger");
52 return -ENOTSUP;
53 }
54
55 return 0;
56 }
57
grow_r502a_gpio_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)58 static void grow_r502a_gpio_callback(const struct device *dev,
59 struct gpio_callback *cb, uint32_t pins)
60 {
61 struct grow_r502a_data *drv_data =
62 CONTAINER_OF(cb, struct grow_r502a_data, gpio_cb);
63
64 setup_int(drv_data->gpio_dev, false);
65
66 #if defined(CONFIG_GROW_R502A_TRIGGER_OWN_THREAD)
67 k_sem_give(&drv_data->gpio_sem);
68 #elif defined(CONFIG_GROW_R502A_TRIGGER_GLOBAL_THREAD)
69 k_work_submit(&drv_data->work);
70 #endif
71 }
72
73 #if defined(CONFIG_GROW_R502A_TRIGGER_OWN_THREAD)
grow_r502a_thread(struct grow_r502a_data * drv_data)74 static void grow_r502a_thread(struct grow_r502a_data *drv_data)
75 {
76 while (true) {
77 k_sem_take(&drv_data->gpio_sem, K_FOREVER);
78 process_int(drv_data->gpio_dev);
79 }
80 }
81
82 #elif defined(CONFIG_GROW_R502A_TRIGGER_GLOBAL_THREAD)
grow_r502a_work_cb(struct k_work * work)83 static void grow_r502a_work_cb(struct k_work *work)
84 {
85 struct grow_r502a_data *drv_data =
86 CONTAINER_OF(work, struct grow_r502a_data, work);
87
88 process_int(drv_data->gpio_dev);
89 }
90 #endif
91
grow_r502a_init_interrupt(const struct device * dev)92 int grow_r502a_init_interrupt(const struct device *dev)
93 {
94 struct grow_r502a_data *drv_data = dev->data;
95 const struct grow_r502a_config *cfg = dev->config;
96 int rc;
97
98 if (!gpio_is_ready_dt(&cfg->int_gpios)) {
99 LOG_ERR("GPIO port %s not ready", cfg->int_gpios.port->name);
100 return -ENODEV;
101 }
102
103 rc = gpio_pin_configure_dt(&cfg->int_gpios, GPIO_INPUT);
104 if (rc < 0) {
105 return rc;
106 }
107
108 drv_data->gpio_dev = dev;
109 #if defined(CONFIG_GROW_R502A_TRIGGER_OWN_THREAD)
110 k_sem_init(&drv_data->gpio_sem, 0, K_SEM_MAX_LIMIT);
111
112 k_thread_create(&drv_data->thread, drv_data->thread_stack,
113 CONFIG_GROW_R502A_THREAD_STACK_SIZE,
114 (k_thread_entry_t)grow_r502a_thread, drv_data, NULL,
115 NULL, K_PRIO_COOP(CONFIG_GROW_R502A_THREAD_PRIORITY), 0,
116 K_NO_WAIT);
117 #elif defined(CONFIG_GROW_R502A_TRIGGER_GLOBAL_THREAD)
118 drv_data->work.handler = grow_r502a_work_cb;
119 #endif
120
121 gpio_init_callback(&drv_data->gpio_cb, grow_r502a_gpio_callback,
122 BIT(cfg->int_gpios.pin));
123
124 rc = gpio_add_callback(cfg->int_gpios.port, &drv_data->gpio_cb);
125 if (rc < 0) {
126 LOG_ERR("Could not set gpio callback.");
127 return rc;
128 }
129
130 return 0;
131 }
132