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