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(void * p1,void * p2,void * p3)74 static void grow_r502a_thread(void *p1, void *p2, void *p3)
75 {
76 	ARG_UNUSED(p2);
77 	ARG_UNUSED(p3);
78 
79 	struct grow_r502a_data *drv_data = p1;
80 
81 	while (true) {
82 		k_sem_take(&drv_data->gpio_sem, K_FOREVER);
83 		process_int(drv_data->gpio_dev);
84 	}
85 }
86 
87 #elif defined(CONFIG_GROW_R502A_TRIGGER_GLOBAL_THREAD)
grow_r502a_work_cb(struct k_work * work)88 static void grow_r502a_work_cb(struct k_work *work)
89 {
90 	struct grow_r502a_data *drv_data =
91 		CONTAINER_OF(work, struct grow_r502a_data, work);
92 
93 	process_int(drv_data->gpio_dev);
94 }
95 #endif
96 
grow_r502a_init_interrupt(const struct device * dev)97 int grow_r502a_init_interrupt(const struct device *dev)
98 {
99 	struct grow_r502a_data *drv_data = dev->data;
100 	const struct grow_r502a_config *cfg = dev->config;
101 	int rc;
102 
103 	if (!gpio_is_ready_dt(&cfg->int_gpios)) {
104 		LOG_ERR("GPIO port %s not ready", cfg->int_gpios.port->name);
105 		return -ENODEV;
106 	}
107 
108 	rc = gpio_pin_configure_dt(&cfg->int_gpios, GPIO_INPUT);
109 	if (rc < 0) {
110 		return rc;
111 	}
112 
113 	drv_data->gpio_dev = dev;
114 #if defined(CONFIG_GROW_R502A_TRIGGER_OWN_THREAD)
115 	k_sem_init(&drv_data->gpio_sem, 0, K_SEM_MAX_LIMIT);
116 
117 	k_thread_create(&drv_data->thread, drv_data->thread_stack,
118 			CONFIG_GROW_R502A_THREAD_STACK_SIZE,
119 			grow_r502a_thread, drv_data, NULL,
120 			NULL, K_PRIO_COOP(CONFIG_GROW_R502A_THREAD_PRIORITY), 0,
121 			K_NO_WAIT);
122 #elif defined(CONFIG_GROW_R502A_TRIGGER_GLOBAL_THREAD)
123 	drv_data->work.handler = grow_r502a_work_cb;
124 #endif
125 
126 	gpio_init_callback(&drv_data->gpio_cb, grow_r502a_gpio_callback,
127 			   BIT(cfg->int_gpios.pin));
128 
129 	rc = gpio_add_callback(cfg->int_gpios.port, &drv_data->gpio_cb);
130 	if (rc < 0) {
131 		LOG_ERR("Could not set gpio callback.");
132 		return rc;
133 	}
134 
135 	return 0;
136 }
137