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 #include <zephyr/pm/device.h>
17 #include <zephyr/pm/device_runtime.h>
18 #include <zephyr/sys/atomic.h>
19 #include <zephyr/sys/util.h>
20 
21 #include <zephyr/logging/log.h>
22 LOG_MODULE_REGISTER(input_gpio_qdec, CONFIG_INPUT_LOG_LEVEL);
23 
24 #define GPIO_QDEC_GPIO_NUM 2
25 
26 struct gpio_qdec_config {
27 	struct gpio_dt_spec ab_gpio[GPIO_QDEC_GPIO_NUM];
28 	const struct gpio_dt_spec *led_gpio;
29 	uint8_t led_gpio_count;
30 	uint32_t led_pre_us;
31 	uint32_t sample_time_us;
32 	uint32_t idle_poll_time_us;
33 	uint32_t idle_timeout_ms;
34 	uint16_t axis;
35 	uint8_t steps_per_period;
36 };
37 
38 struct gpio_qdec_data {
39 	const struct device *dev;
40 	struct k_timer sample_timer;
41 	uint8_t prev_step;
42 	int32_t acc;
43 	struct k_work event_work;
44 	struct k_work_delayable idle_work;
45 	struct gpio_callback gpio_cb;
46 	atomic_t polling;
47 #ifdef CONFIG_PM_DEVICE
48 	atomic_t suspended;
49 #endif
50 };
51 
52 /* Positive transitions */
53 #define QDEC_LL_LH 0x01
54 #define QDEC_LH_HH 0x13
55 #define QDEC_HH_HL 0x32
56 #define QDEC_HL_LL 0x20
57 
58 /* Negative transitions */
59 #define QDEC_LL_HL 0x02
60 #define QDEC_LH_LL 0x10
61 #define QDEC_HH_LH 0x31
62 #define QDEC_HL_HH 0x23
63 
gpio_qdec_irq_setup(const struct device * dev,bool enable)64 static void gpio_qdec_irq_setup(const struct device *dev, bool enable)
65 {
66 	const struct gpio_qdec_config *cfg = dev->config;
67 	gpio_flags_t flags = enable ? GPIO_INT_EDGE_BOTH : GPIO_INT_DISABLE;
68 	int ret;
69 
70 	for (int i = 0; i < GPIO_QDEC_GPIO_NUM; i++) {
71 		const struct gpio_dt_spec *gpio = &cfg->ab_gpio[i];
72 
73 		ret = gpio_pin_interrupt_configure_dt(gpio, flags);
74 		if (ret != 0) {
75 			LOG_ERR("Pin %d interrupt configuration failed: %d", i, ret);
76 			return;
77 		}
78 	}
79 }
80 
gpio_qdec_idle_polling_mode(const struct device * dev)81 static bool gpio_qdec_idle_polling_mode(const struct device *dev)
82 {
83 	const struct gpio_qdec_config *cfg = dev->config;
84 
85 	if (cfg->idle_poll_time_us > 0) {
86 		return true;
87 	}
88 
89 	return false;
90 }
91 
gpio_qdec_poll_mode(const struct device * dev)92 static void gpio_qdec_poll_mode(const struct device *dev)
93 {
94 	const struct gpio_qdec_config *cfg = dev->config;
95 	struct gpio_qdec_data *data = dev->data;
96 
97 	if (!gpio_qdec_idle_polling_mode(dev)) {
98 		gpio_qdec_irq_setup(dev, false);
99 	}
100 
101 	k_timer_start(&data->sample_timer, K_NO_WAIT,
102 		      K_USEC(cfg->sample_time_us));
103 
104 	atomic_set(&data->polling, 1);
105 
106 	LOG_DBG("polling start");
107 }
108 
gpio_qdec_idle_mode(const struct device * dev)109 static void gpio_qdec_idle_mode(const struct device *dev)
110 {
111 	const struct gpio_qdec_config *cfg = dev->config;
112 	struct gpio_qdec_data *data = dev->data;
113 
114 	if (gpio_qdec_idle_polling_mode(dev)) {
115 		k_timer_start(&data->sample_timer, K_NO_WAIT,
116 			      K_USEC(cfg->idle_poll_time_us));
117 	} else {
118 		k_timer_stop(&data->sample_timer);
119 		gpio_qdec_irq_setup(dev, true);
120 	}
121 
122 	atomic_set(&data->polling, 0);
123 
124 	LOG_DBG("polling stop");
125 }
126 
gpio_qdec_get_step(const struct device * dev)127 static uint8_t gpio_qdec_get_step(const struct device *dev)
128 {
129 	const struct gpio_qdec_config *cfg = dev->config;
130 	uint8_t step = 0x00;
131 
132 	if (gpio_qdec_idle_polling_mode(dev)) {
133 		for (int i = 0; i < cfg->led_gpio_count; i++) {
134 			gpio_pin_set_dt(&cfg->led_gpio[i], 1);
135 		}
136 
137 		k_busy_wait(cfg->led_pre_us);
138 	}
139 
140 	if (gpio_pin_get_dt(&cfg->ab_gpio[0])) {
141 		step |= 0x01;
142 	}
143 	if (gpio_pin_get_dt(&cfg->ab_gpio[1])) {
144 		step |= 0x02;
145 	}
146 
147 	if (gpio_qdec_idle_polling_mode(dev)) {
148 		for (int i = 0; i < cfg->led_gpio_count; i++) {
149 			gpio_pin_set_dt(&cfg->led_gpio[i], 0);
150 		}
151 	}
152 
153 	return step;
154 }
155 
gpio_qdec_sample_timer_timeout(struct k_timer * timer)156 static void gpio_qdec_sample_timer_timeout(struct k_timer *timer)
157 {
158 	const struct device *dev = k_timer_user_data_get(timer);
159 	const struct gpio_qdec_config *cfg = dev->config;
160 	struct gpio_qdec_data *data = dev->data;
161 	int8_t delta = 0;
162 	unsigned int key;
163 	uint8_t step;
164 
165 #ifdef CONFIG_PM_DEVICE
166 	if (atomic_get(&data->suspended) == 1) {
167 		return;
168 	}
169 #endif
170 
171 	step = gpio_qdec_get_step(dev);
172 
173 	if (data->prev_step == step) {
174 		return;
175 	}
176 
177 	if (gpio_qdec_idle_polling_mode(dev) &&
178 	    atomic_get(&data->polling) == 0) {
179 		gpio_qdec_poll_mode(dev);
180 	}
181 
182 	switch ((data->prev_step << 4U) | step) {
183 	case QDEC_LL_LH:
184 	case QDEC_LH_HH:
185 	case QDEC_HH_HL:
186 	case QDEC_HL_LL:
187 		delta = 1;
188 		break;
189 	case QDEC_LL_HL:
190 	case QDEC_LH_LL:
191 	case QDEC_HH_LH:
192 	case QDEC_HL_HH:
193 		delta = -1;
194 		break;
195 	default:
196 		LOG_WRN("%s: lost steps", dev->name);
197 	}
198 
199 	data->prev_step = step;
200 
201 	key = irq_lock();
202 	data->acc += delta;
203 	irq_unlock(key);
204 
205 	if (abs(data->acc) >= cfg->steps_per_period) {
206 		k_work_submit(&data->event_work);
207 	}
208 
209 	k_work_reschedule(&data->idle_work, K_MSEC(cfg->idle_timeout_ms));
210 }
211 
gpio_qdec_event_worker(struct k_work * work)212 static void gpio_qdec_event_worker(struct k_work *work)
213 {
214 	struct gpio_qdec_data *data = CONTAINER_OF(
215 			work, struct gpio_qdec_data, event_work);
216 	const struct device *dev = data->dev;
217 	const struct gpio_qdec_config *cfg = dev->config;
218 	unsigned int key;
219 	int32_t acc;
220 
221 	key = irq_lock();
222 	acc = data->acc / cfg->steps_per_period;
223 	data->acc -= acc * cfg->steps_per_period;
224 	irq_unlock(key);
225 
226 	if (acc != 0) {
227 		input_report_rel(data->dev, cfg->axis, acc, true, K_FOREVER);
228 	}
229 }
230 
gpio_qdec_idle_worker(struct k_work * work)231 static void gpio_qdec_idle_worker(struct k_work *work)
232 {
233 	struct k_work_delayable *dwork = k_work_delayable_from_work(work);
234 	struct gpio_qdec_data *data = CONTAINER_OF(
235 			dwork, struct gpio_qdec_data, idle_work);
236 	const struct device *dev = data->dev;
237 
238 	gpio_qdec_idle_mode(dev);
239 }
240 
gpio_qdec_cb(const struct device * gpio_dev,struct gpio_callback * cb,uint32_t pins)241 static void gpio_qdec_cb(const struct device *gpio_dev, struct gpio_callback *cb,
242 			 uint32_t pins)
243 {
244 	struct gpio_qdec_data *data = CONTAINER_OF(
245 			cb, struct gpio_qdec_data, gpio_cb);
246 	const struct device *dev = data->dev;
247 
248 	gpio_qdec_poll_mode(dev);
249 }
250 
gpio_qdec_init(const struct device * dev)251 static int gpio_qdec_init(const struct device *dev)
252 {
253 	const struct gpio_qdec_config *cfg = dev->config;
254 	struct gpio_qdec_data *data = dev->data;
255 	int ret;
256 
257 	data->dev = dev;
258 
259 	k_work_init(&data->event_work, gpio_qdec_event_worker);
260 	k_work_init_delayable(&data->idle_work, gpio_qdec_idle_worker);
261 
262 	k_timer_init(&data->sample_timer, gpio_qdec_sample_timer_timeout, NULL);
263 	k_timer_user_data_set(&data->sample_timer, (void *)dev);
264 
265 	gpio_init_callback(&data->gpio_cb, gpio_qdec_cb,
266 			   BIT(cfg->ab_gpio[0].pin) | BIT(cfg->ab_gpio[1].pin));
267 	for (int i = 0; i < GPIO_QDEC_GPIO_NUM; i++) {
268 		const struct gpio_dt_spec *gpio = &cfg->ab_gpio[i];
269 
270 		if (!gpio_is_ready_dt(gpio)) {
271 			LOG_ERR("%s is not ready", gpio->port->name);
272 			return -ENODEV;
273 		}
274 
275 		ret = gpio_pin_configure_dt(gpio, GPIO_INPUT);
276 		if (ret != 0) {
277 			LOG_ERR("Pin %d configuration failed: %d", i, ret);
278 			return ret;
279 		}
280 
281 		if (gpio_qdec_idle_polling_mode(dev)) {
282 			continue;
283 		}
284 
285 		ret = gpio_add_callback_dt(gpio, &data->gpio_cb);
286 		if (ret < 0) {
287 			LOG_ERR("Could not set gpio callback");
288 			return ret;
289 		}
290 	}
291 
292 	for (int i = 0; i < cfg->led_gpio_count; i++) {
293 		const struct gpio_dt_spec *gpio = &cfg->led_gpio[i];
294 		gpio_flags_t mode;
295 
296 		if (!gpio_is_ready_dt(gpio)) {
297 			LOG_ERR("%s is not ready", gpio->port->name);
298 			return -ENODEV;
299 		}
300 
301 		mode = gpio_qdec_idle_polling_mode(dev) ?
302 			GPIO_OUTPUT_INACTIVE : GPIO_OUTPUT_ACTIVE;
303 
304 		ret = gpio_pin_configure_dt(gpio, mode);
305 		if (ret != 0) {
306 			LOG_ERR("Pin %d configuration failed: %d", i, ret);
307 			return ret;
308 		}
309 	}
310 
311 	data->prev_step = gpio_qdec_get_step(dev);
312 
313 	gpio_qdec_idle_mode(dev);
314 
315 	ret = pm_device_runtime_enable(dev);
316 	if (ret < 0) {
317 		LOG_ERR("Failed to enable runtime power management");
318 		return ret;
319 	}
320 
321 	LOG_DBG("Device %s initialized", dev->name);
322 
323 	return 0;
324 }
325 
326 #ifdef CONFIG_PM_DEVICE
gpio_qdec_pin_suspend(const struct device * dev,bool suspend)327 static void gpio_qdec_pin_suspend(const struct device *dev, bool suspend)
328 {
329 	const struct gpio_qdec_config *cfg = dev->config;
330 	gpio_flags_t mode = suspend ? GPIO_DISCONNECTED : GPIO_INPUT;
331 	int ret;
332 
333 	for (int i = 0; i < GPIO_QDEC_GPIO_NUM; i++) {
334 		const struct gpio_dt_spec *gpio = &cfg->ab_gpio[i];
335 
336 		ret = gpio_pin_configure_dt(gpio, mode);
337 		if (ret != 0) {
338 			LOG_ERR("Pin %d configuration failed: %d", i, ret);
339 			return;
340 		}
341 	}
342 
343 	for (int i = 0; i < cfg->led_gpio_count; i++) {
344 		if (suspend) {
345 			gpio_pin_set_dt(&cfg->led_gpio[i], 0);
346 		} else if (!gpio_qdec_idle_polling_mode(dev)) {
347 			gpio_pin_set_dt(&cfg->led_gpio[i], 1);
348 		}
349 	}
350 }
351 
gpio_qdec_pm_action(const struct device * dev,enum pm_device_action action)352 static int gpio_qdec_pm_action(const struct device *dev,
353 			       enum pm_device_action action)
354 {
355 	struct gpio_qdec_data *data = dev->data;
356 
357 	switch (action) {
358 	case PM_DEVICE_ACTION_SUSPEND:
359 		struct k_work_sync sync;
360 
361 		atomic_set(&data->suspended, 1);
362 
363 		k_work_cancel_delayable_sync(&data->idle_work, &sync);
364 
365 		if (!gpio_qdec_idle_polling_mode(dev)) {
366 			gpio_qdec_irq_setup(dev, false);
367 		}
368 
369 		k_timer_stop(&data->sample_timer);
370 
371 		gpio_qdec_pin_suspend(dev, true);
372 
373 		break;
374 	case PM_DEVICE_ACTION_RESUME:
375 		atomic_set(&data->suspended, 0);
376 
377 		gpio_qdec_pin_suspend(dev, false);
378 
379 		data->prev_step = gpio_qdec_get_step(dev);
380 		data->acc = 0;
381 
382 		gpio_qdec_idle_mode(dev);
383 
384 		break;
385 	default:
386 		return -ENOTSUP;
387 	}
388 
389 	return 0;
390 }
391 #endif
392 
393 #define QDEC_GPIO_INIT(n)							\
394 	BUILD_ASSERT(DT_INST_PROP_LEN(n, gpios) == GPIO_QDEC_GPIO_NUM,		\
395 		     "input_gpio_qdec: gpios must have exactly two entries");	\
396 										\
397 	BUILD_ASSERT(!(DT_INST_NODE_HAS_PROP(n, led_gpios) &&			\
398 		       DT_INST_NODE_HAS_PROP(n, idle_poll_time_us)) ||		\
399 		     DT_INST_NODE_HAS_PROP(n, led_pre_us),			\
400 		     "led-pre-us must be specified when setting led-gpios and "	\
401 		     "idle-poll-time-us");					\
402 										\
403 	IF_ENABLED(DT_INST_NODE_HAS_PROP(n, led_gpios), (			\
404 	static const struct gpio_dt_spec gpio_qdec_led_gpio_##n[] = {		\
405 		DT_INST_FOREACH_PROP_ELEM_SEP(n, led_gpios,			\
406 					      GPIO_DT_SPEC_GET_BY_IDX, (,))	\
407 	};									\
408 	))									\
409 										\
410 	static const struct gpio_qdec_config gpio_qdec_cfg_##n = {		\
411 		.ab_gpio = {							\
412 			GPIO_DT_SPEC_INST_GET_BY_IDX(n, gpios, 0),		\
413 			GPIO_DT_SPEC_INST_GET_BY_IDX(n, gpios, 1),		\
414 		},								\
415 		IF_ENABLED(DT_INST_NODE_HAS_PROP(n, led_gpios), (		\
416 		.led_gpio = gpio_qdec_led_gpio_##n,				\
417 		.led_gpio_count = ARRAY_SIZE(gpio_qdec_led_gpio_##n),		\
418 		.led_pre_us = DT_INST_PROP_OR(n, led_pre_us, 0),		\
419 		))								\
420 		.sample_time_us = DT_INST_PROP(n, sample_time_us),		\
421 		.idle_poll_time_us = DT_INST_PROP_OR(n, idle_poll_time_us, 0),	\
422 		.idle_timeout_ms = DT_INST_PROP(n, idle_timeout_ms),		\
423 		.steps_per_period = DT_INST_PROP(n, steps_per_period),		\
424 		.axis = DT_INST_PROP(n, zephyr_axis),				\
425 	};									\
426 										\
427 	static struct gpio_qdec_data gpio_qdec_data_##n;			\
428 										\
429 	PM_DEVICE_DT_INST_DEFINE(n, gpio_qdec_pm_action);			\
430 										\
431 	DEVICE_DT_INST_DEFINE(n, gpio_qdec_init, PM_DEVICE_DT_INST_GET(n),	\
432 			      &gpio_qdec_data_##n,				\
433 			      &gpio_qdec_cfg_##n,				\
434 			      POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY,		\
435 			      NULL);
436 
437 DT_INST_FOREACH_STATUS_OKAY(QDEC_GPIO_INIT)
438