1 /*
2  * Copyright 2023 Google LLC
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT gpio_qdec
8 
9 #include <stdint.h>
10 #include <stdlib.h>
11 
12 #include <zephyr/device.h>
13 #include <zephyr/drivers/gpio.h>
14 #include <zephyr/input/input.h>
15 #include <zephyr/kernel.h>
16 
17 #include <zephyr/logging/log.h>
18 LOG_MODULE_REGISTER(input_gpio_qdec, CONFIG_INPUT_LOG_LEVEL);
19 
20 #define GPIO_QDEC_GPIO_NUM 2
21 
22 struct gpio_qdec_config {
23 	struct gpio_dt_spec gpio[GPIO_QDEC_GPIO_NUM];
24 	uint32_t sample_time_us;
25 	uint32_t idle_timeout_ms;
26 	uint16_t axis;
27 	uint8_t steps_per_period;
28 };
29 
30 struct gpio_qdec_data {
31 	const struct device *dev;
32 	struct k_timer sample_timer;
33 	uint8_t prev_step;
34 	int32_t acc;
35 	struct k_work event_work;
36 	struct k_work_delayable idle_work;
37 	struct gpio_callback gpio_cb;
38 };
39 
40 /* Positive transitions */
41 #define QDEC_LL_LH 0x01
42 #define QDEC_LH_HH 0x13
43 #define QDEC_HH_HL 0x32
44 #define QDEC_HL_LL 0x20
45 
46 /* Negative transitions */
47 #define QDEC_LL_HL 0x02
48 #define QDEC_LH_LL 0x10
49 #define QDEC_HH_LH 0x31
50 #define QDEC_HL_HH 0x23
51 
gpio_qdec_get_step(const struct device * dev)52 static uint8_t gpio_qdec_get_step(const struct device *dev)
53 {
54 	const struct gpio_qdec_config *cfg = dev->config;
55 	uint8_t step = 0x00;
56 
57 	if (gpio_pin_get_dt(&cfg->gpio[0])) {
58 		step |= 0x01;
59 	}
60 	if (gpio_pin_get_dt(&cfg->gpio[1])) {
61 		step |= 0x02;
62 	}
63 
64 	return step;
65 }
66 
gpio_qdec_sample_timer_timeout(struct k_timer * timer)67 static void gpio_qdec_sample_timer_timeout(struct k_timer *timer)
68 {
69 	const struct device *dev = k_timer_user_data_get(timer);
70 	const struct gpio_qdec_config *cfg = dev->config;
71 	struct gpio_qdec_data *data = dev->data;
72 	int8_t delta = 0;
73 	unsigned int key;
74 	uint8_t step;
75 
76 	step = gpio_qdec_get_step(dev);
77 
78 	if (data->prev_step == step) {
79 		return;
80 	}
81 
82 	switch ((data->prev_step << 4U) | step) {
83 	case QDEC_LL_LH:
84 	case QDEC_LH_HH:
85 	case QDEC_HH_HL:
86 	case QDEC_HL_LL:
87 		delta = 1;
88 		break;
89 	case QDEC_LL_HL:
90 	case QDEC_LH_LL:
91 	case QDEC_HH_LH:
92 	case QDEC_HL_HH:
93 		delta = -1;
94 		break;
95 	default:
96 		LOG_WRN("%s: lost steps", dev->name);
97 	}
98 
99 	data->prev_step = step;
100 
101 	key = irq_lock();
102 	data->acc += delta;
103 	irq_unlock(key);
104 
105 	if (abs(data->acc) >= cfg->steps_per_period) {
106 		k_work_submit(&data->event_work);
107 	}
108 
109 	k_work_reschedule(&data->idle_work, K_MSEC(cfg->idle_timeout_ms));
110 }
111 
gpio_qdec_event_worker(struct k_work * work)112 static void gpio_qdec_event_worker(struct k_work *work)
113 {
114 	struct gpio_qdec_data *data = CONTAINER_OF(
115 			work, struct gpio_qdec_data, event_work);
116 	const struct device *dev = data->dev;
117 	const struct gpio_qdec_config *cfg = dev->config;
118 	unsigned int key;
119 	int32_t acc;
120 
121 	key = irq_lock();
122 	acc = data->acc / cfg->steps_per_period;
123 	data->acc -= acc * cfg->steps_per_period;
124 	irq_unlock(key);
125 
126 	if (acc != 0) {
127 		input_report_rel(data->dev, cfg->axis, acc, true, K_FOREVER);
128 	}
129 }
130 
gpio_qdec_irq_setup(const struct device * dev,bool enable)131 static void gpio_qdec_irq_setup(const struct device *dev, bool enable)
132 {
133 	const struct gpio_qdec_config *cfg = dev->config;
134 	unsigned int flags = enable ? GPIO_INT_EDGE_BOTH : GPIO_INT_DISABLE;
135 	int ret;
136 
137 	for (int i = 0; i < GPIO_QDEC_GPIO_NUM; i++) {
138 		const struct gpio_dt_spec *gpio = &cfg->gpio[i];
139 
140 		ret = gpio_pin_interrupt_configure_dt(gpio, flags);
141 		if (ret != 0) {
142 			LOG_ERR("Pin %d interrupt configuration failed: %d", i, ret);
143 			return;
144 		}
145 	}
146 }
147 
gpio_qdec_idle_worker(struct k_work * work)148 static void gpio_qdec_idle_worker(struct k_work *work)
149 {
150 	struct k_work_delayable *dwork = k_work_delayable_from_work(work);
151 	struct gpio_qdec_data *data = CONTAINER_OF(
152 			dwork, struct gpio_qdec_data, idle_work);
153 	const struct device *dev = data->dev;
154 
155 	k_timer_stop(&data->sample_timer);
156 
157 	gpio_qdec_irq_setup(dev, true);
158 
159 	LOG_DBG("polling stop");
160 }
161 
gpio_qdec_cb(const struct device * gpio_dev,struct gpio_callback * cb,uint32_t pins)162 static void gpio_qdec_cb(const struct device *gpio_dev, struct gpio_callback *cb,
163 			 uint32_t pins)
164 {
165 	struct gpio_qdec_data *data = CONTAINER_OF(
166 			cb, struct gpio_qdec_data, gpio_cb);
167 	const struct device *dev = data->dev;
168 	const struct gpio_qdec_config *cfg = dev->config;
169 
170 	gpio_qdec_irq_setup(dev, false);
171 
172 	k_timer_start(&data->sample_timer, K_NO_WAIT,
173 		      K_USEC(cfg->sample_time_us));
174 
175 	LOG_DBG("polling start");
176 }
177 
gpio_qdec_init(const struct device * dev)178 static int gpio_qdec_init(const struct device *dev)
179 {
180 	const struct gpio_qdec_config *cfg = dev->config;
181 	struct gpio_qdec_data *data = dev->data;
182 	int ret;
183 
184 	data->dev = dev;
185 
186 	k_work_init(&data->event_work, gpio_qdec_event_worker);
187 	k_work_init_delayable(&data->idle_work, gpio_qdec_idle_worker);
188 
189 	k_timer_init(&data->sample_timer, gpio_qdec_sample_timer_timeout, NULL);
190 	k_timer_user_data_set(&data->sample_timer, (void *)dev);
191 
192 	gpio_init_callback(&data->gpio_cb, gpio_qdec_cb,
193 			   BIT(cfg->gpio[0].pin) | BIT(cfg->gpio[1].pin));
194 	for (int i = 0; i < GPIO_QDEC_GPIO_NUM; i++) {
195 		const struct gpio_dt_spec *gpio = &cfg->gpio[i];
196 
197 		if (!gpio_is_ready_dt(gpio)) {
198 			LOG_ERR("%s is not ready", gpio->port->name);
199 			return -ENODEV;
200 		}
201 
202 		ret = gpio_pin_configure_dt(gpio, GPIO_INPUT);
203 		if (ret != 0) {
204 			LOG_ERR("Pin %d configuration failed: %d", i, ret);
205 			return ret;
206 		}
207 
208 		ret = gpio_add_callback_dt(gpio, &data->gpio_cb);
209 		if (ret < 0) {
210 			LOG_ERR("Could not set gpio callback");
211 			return ret;
212 		}
213 	}
214 
215 	data->prev_step = gpio_qdec_get_step(dev);
216 
217 	gpio_qdec_irq_setup(dev, true);
218 
219 	LOG_DBG("Device %s initialized", dev->name);
220 
221 	return 0;
222 }
223 
224 #define QDEC_GPIO_INIT(n)							\
225 	BUILD_ASSERT(DT_INST_PROP_LEN(n, gpios) == GPIO_QDEC_GPIO_NUM,		\
226 		     "input_gpio_qdec: gpios must have exactly two entries");	\
227 										\
228 	static const struct gpio_qdec_config gpio_qdec_cfg_##n = {		\
229 		.gpio = {GPIO_DT_SPEC_INST_GET_BY_IDX(n, gpios, 0),		\
230 			 GPIO_DT_SPEC_INST_GET_BY_IDX(n, gpios, 1)},		\
231 		.sample_time_us = DT_INST_PROP(n, sample_time_us),		\
232 		.idle_timeout_ms = DT_INST_PROP(n, idle_timeout_ms),		\
233 		.steps_per_period = DT_INST_PROP(n, steps_per_period),		\
234 		.axis = DT_INST_PROP(n, zephyr_axis),				\
235 	};									\
236 										\
237 	static struct gpio_qdec_data gpio_qdec_data_##n;			\
238 										\
239 	DEVICE_DT_INST_DEFINE(n, gpio_qdec_init, NULL,				\
240 			      &gpio_qdec_data_##n,				\
241 			      &gpio_qdec_cfg_##n,				\
242 			      POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY,		\
243 			      NULL);
244 
245 DT_INST_FOREACH_STATUS_OKAY(QDEC_GPIO_INIT)
246