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