1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
273969ff0SDaniel Mack /*
373969ff0SDaniel Mack * rotary_encoder.c
473969ff0SDaniel Mack *
573969ff0SDaniel Mack * (c) 2009 Daniel Mack <daniel@caiaq.de>
6e70bdd41SJohan Hovold * Copyright (C) 2011 Johan Hovold <jhovold@gmail.com>
773969ff0SDaniel Mack *
873969ff0SDaniel Mack * state machine code inspired by code from Tim Ruetz
973969ff0SDaniel Mack *
1073969ff0SDaniel Mack * A generic driver for rotary encoders connected to GPIO lines.
115fb94e9cSMauro Carvalho Chehab * See file:Documentation/input/devices/rotary-encoder.rst for more information
1273969ff0SDaniel Mack */
1373969ff0SDaniel Mack
1473969ff0SDaniel Mack #include <linux/kernel.h>
1573969ff0SDaniel Mack #include <linux/module.h>
1673969ff0SDaniel Mack #include <linux/interrupt.h>
1773969ff0SDaniel Mack #include <linux/input.h>
1873969ff0SDaniel Mack #include <linux/device.h>
1973969ff0SDaniel Mack #include <linux/platform_device.h>
2077a8f0adSDmitry Torokhov #include <linux/gpio/consumer.h>
215a0e3ad6STejun Heo #include <linux/slab.h>
222e45e539SSachin Kamat #include <linux/of.h>
2347ec6e5aSSylvain Rochet #include <linux/pm.h>
24a9e340dcSDmitry Torokhov #include <linux/property.h>
2573969ff0SDaniel Mack
2673969ff0SDaniel Mack #define DRV_NAME "rotary-encoder"
2773969ff0SDaniel Mack
28d205a218SUwe Kleine-König enum rotary_encoder_encoding {
29d205a218SUwe Kleine-König ROTENC_GRAY,
30d205a218SUwe Kleine-König ROTENC_BINARY,
31d205a218SUwe Kleine-König };
32d205a218SUwe Kleine-König
3373969ff0SDaniel Mack struct rotary_encoder {
3473969ff0SDaniel Mack struct input_dev *input;
35a9e340dcSDmitry Torokhov
36dee520e3STimo Teräs struct mutex access_mutex;
37bd3ce655SH Hartley Sweeten
38a9e340dcSDmitry Torokhov u32 steps;
39a9e340dcSDmitry Torokhov u32 axis;
40a9e340dcSDmitry Torokhov bool relative_axis;
41a9e340dcSDmitry Torokhov bool rollover;
42d205a218SUwe Kleine-König enum rotary_encoder_encoding encoding;
43a9e340dcSDmitry Torokhov
44bd3ce655SH Hartley Sweeten unsigned int pos;
45bd3ce655SH Hartley Sweeten
467dde4e74SUwe Kleine-König struct gpio_descs *gpios;
4777a8f0adSDmitry Torokhov
487dde4e74SUwe Kleine-König unsigned int *irq;
49bd3ce655SH Hartley Sweeten
50bd3ce655SH Hartley Sweeten bool armed;
517dde4e74SUwe Kleine-König signed char dir; /* 1 - clockwise, -1 - CCW */
52e70bdd41SJohan Hovold
53d96caf8cSClifton Barnes unsigned int last_stable;
5473969ff0SDaniel Mack };
5573969ff0SDaniel Mack
rotary_encoder_get_state(struct rotary_encoder * encoder)56d96caf8cSClifton Barnes static unsigned int rotary_encoder_get_state(struct rotary_encoder *encoder)
5773969ff0SDaniel Mack {
587dde4e74SUwe Kleine-König int i;
59d96caf8cSClifton Barnes unsigned int ret = 0;
6073969ff0SDaniel Mack
617dde4e74SUwe Kleine-König for (i = 0; i < encoder->gpios->ndescs; ++i) {
627dde4e74SUwe Kleine-König int val = gpiod_get_value_cansleep(encoder->gpios->desc[i]);
63d205a218SUwe Kleine-König
647dde4e74SUwe Kleine-König /* convert from gray encoding to normal */
65d205a218SUwe Kleine-König if (encoder->encoding == ROTENC_GRAY && ret & 1)
667dde4e74SUwe Kleine-König val = !val;
677dde4e74SUwe Kleine-König
687dde4e74SUwe Kleine-König ret = ret << 1 | val;
697dde4e74SUwe Kleine-König }
707dde4e74SUwe Kleine-König
717dde4e74SUwe Kleine-König return ret & 3;
72521a8f5cSJohan Hovold }
7373969ff0SDaniel Mack
rotary_encoder_report_event(struct rotary_encoder * encoder)74521a8f5cSJohan Hovold static void rotary_encoder_report_event(struct rotary_encoder *encoder)
75521a8f5cSJohan Hovold {
76a9e340dcSDmitry Torokhov if (encoder->relative_axis) {
77521a8f5cSJohan Hovold input_report_rel(encoder->input,
787dde4e74SUwe Kleine-König encoder->axis, encoder->dir);
79bd3ce655SH Hartley Sweeten } else {
80bd3ce655SH Hartley Sweeten unsigned int pos = encoder->pos;
81bd3ce655SH Hartley Sweeten
827dde4e74SUwe Kleine-König if (encoder->dir < 0) {
8373969ff0SDaniel Mack /* turning counter-clockwise */
84a9e340dcSDmitry Torokhov if (encoder->rollover)
85a9e340dcSDmitry Torokhov pos += encoder->steps;
86bd3ce655SH Hartley Sweeten if (pos)
87bd3ce655SH Hartley Sweeten pos--;
8873969ff0SDaniel Mack } else {
8973969ff0SDaniel Mack /* turning clockwise */
90a9e340dcSDmitry Torokhov if (encoder->rollover || pos < encoder->steps)
91bd3ce655SH Hartley Sweeten pos++;
9273969ff0SDaniel Mack }
93521a8f5cSJohan Hovold
94a9e340dcSDmitry Torokhov if (encoder->rollover)
95a9e340dcSDmitry Torokhov pos %= encoder->steps;
9673969ff0SDaniel Mack
97521a8f5cSJohan Hovold encoder->pos = pos;
98a9e340dcSDmitry Torokhov input_report_abs(encoder->input, encoder->axis, encoder->pos);
99521a8f5cSJohan Hovold }
100521a8f5cSJohan Hovold
101521a8f5cSJohan Hovold input_sync(encoder->input);
102521a8f5cSJohan Hovold }
103521a8f5cSJohan Hovold
rotary_encoder_irq(int irq,void * dev_id)104521a8f5cSJohan Hovold static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
105521a8f5cSJohan Hovold {
106521a8f5cSJohan Hovold struct rotary_encoder *encoder = dev_id;
107d96caf8cSClifton Barnes unsigned int state;
108521a8f5cSJohan Hovold
109dee520e3STimo Teräs mutex_lock(&encoder->access_mutex);
110dee520e3STimo Teräs
11177a8f0adSDmitry Torokhov state = rotary_encoder_get_state(encoder);
112521a8f5cSJohan Hovold
113521a8f5cSJohan Hovold switch (state) {
114521a8f5cSJohan Hovold case 0x0:
115521a8f5cSJohan Hovold if (encoder->armed) {
116521a8f5cSJohan Hovold rotary_encoder_report_event(encoder);
117bd3ce655SH Hartley Sweeten encoder->armed = false;
118521a8f5cSJohan Hovold }
11973969ff0SDaniel Mack break;
12073969ff0SDaniel Mack
12173969ff0SDaniel Mack case 0x1:
1227dde4e74SUwe Kleine-König case 0x3:
12373969ff0SDaniel Mack if (encoder->armed)
1247dde4e74SUwe Kleine-König encoder->dir = 2 - state;
12573969ff0SDaniel Mack break;
12673969ff0SDaniel Mack
1277dde4e74SUwe Kleine-König case 0x2:
128bd3ce655SH Hartley Sweeten encoder->armed = true;
12973969ff0SDaniel Mack break;
13073969ff0SDaniel Mack }
13173969ff0SDaniel Mack
132dee520e3STimo Teräs mutex_unlock(&encoder->access_mutex);
133dee520e3STimo Teräs
13473969ff0SDaniel Mack return IRQ_HANDLED;
13573969ff0SDaniel Mack }
13673969ff0SDaniel Mack
rotary_encoder_half_period_irq(int irq,void * dev_id)137e70bdd41SJohan Hovold static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
138e70bdd41SJohan Hovold {
139e70bdd41SJohan Hovold struct rotary_encoder *encoder = dev_id;
1407dde4e74SUwe Kleine-König unsigned int state;
141e70bdd41SJohan Hovold
142dee520e3STimo Teräs mutex_lock(&encoder->access_mutex);
143dee520e3STimo Teräs
14477a8f0adSDmitry Torokhov state = rotary_encoder_get_state(encoder);
145e70bdd41SJohan Hovold
1467dde4e74SUwe Kleine-König if (state & 1) {
1477dde4e74SUwe Kleine-König encoder->dir = ((encoder->last_stable - state + 1) % 4) - 1;
1487dde4e74SUwe Kleine-König } else {
149e70bdd41SJohan Hovold if (state != encoder->last_stable) {
150e70bdd41SJohan Hovold rotary_encoder_report_event(encoder);
151e70bdd41SJohan Hovold encoder->last_stable = state;
152e70bdd41SJohan Hovold }
153e70bdd41SJohan Hovold }
154e70bdd41SJohan Hovold
155dee520e3STimo Teräs mutex_unlock(&encoder->access_mutex);
156dee520e3STimo Teräs
157e70bdd41SJohan Hovold return IRQ_HANDLED;
158e70bdd41SJohan Hovold }
159e70bdd41SJohan Hovold
rotary_encoder_quarter_period_irq(int irq,void * dev_id)1603a341a4cSEzequiel Garcia static irqreturn_t rotary_encoder_quarter_period_irq(int irq, void *dev_id)
1613a341a4cSEzequiel Garcia {
1623a341a4cSEzequiel Garcia struct rotary_encoder *encoder = dev_id;
1637dde4e74SUwe Kleine-König unsigned int state;
1643a341a4cSEzequiel Garcia
165dee520e3STimo Teräs mutex_lock(&encoder->access_mutex);
166dee520e3STimo Teräs
16777a8f0adSDmitry Torokhov state = rotary_encoder_get_state(encoder);
1683a341a4cSEzequiel Garcia
1697dde4e74SUwe Kleine-König if ((encoder->last_stable + 1) % 4 == state)
1707dde4e74SUwe Kleine-König encoder->dir = 1;
1717dde4e74SUwe Kleine-König else if (encoder->last_stable == (state + 1) % 4)
1727dde4e74SUwe Kleine-König encoder->dir = -1;
1737dde4e74SUwe Kleine-König else
1743a341a4cSEzequiel Garcia goto out;
1753a341a4cSEzequiel Garcia
1763a341a4cSEzequiel Garcia rotary_encoder_report_event(encoder);
1773a341a4cSEzequiel Garcia
1783a341a4cSEzequiel Garcia out:
1793a341a4cSEzequiel Garcia encoder->last_stable = state;
180dee520e3STimo Teräs mutex_unlock(&encoder->access_mutex);
181dee520e3STimo Teräs
1823a341a4cSEzequiel Garcia return IRQ_HANDLED;
1833a341a4cSEzequiel Garcia }
1843a341a4cSEzequiel Garcia
rotary_encoder_probe(struct platform_device * pdev)1855298cc4cSBill Pemberton static int rotary_encoder_probe(struct platform_device *pdev)
18673969ff0SDaniel Mack {
187ce919537SDmitry Torokhov struct device *dev = &pdev->dev;
18873969ff0SDaniel Mack struct rotary_encoder *encoder;
18973969ff0SDaniel Mack struct input_dev *input;
190e70bdd41SJohan Hovold irq_handler_t handler;
191a9e340dcSDmitry Torokhov u32 steps_per_period;
1927dde4e74SUwe Kleine-König unsigned int i;
19373969ff0SDaniel Mack int err;
19473969ff0SDaniel Mack
195d9202af2STimo Teräs encoder = devm_kzalloc(dev, sizeof(struct rotary_encoder), GFP_KERNEL);
196d9202af2STimo Teräs if (!encoder)
197d9202af2STimo Teräs return -ENOMEM;
198d9202af2STimo Teräs
19977a8f0adSDmitry Torokhov mutex_init(&encoder->access_mutex);
200a9e340dcSDmitry Torokhov
201a9e340dcSDmitry Torokhov device_property_read_u32(dev, "rotary-encoder,steps", &encoder->steps);
202a9e340dcSDmitry Torokhov
203a9e340dcSDmitry Torokhov err = device_property_read_u32(dev, "rotary-encoder,steps-per-period",
204a9e340dcSDmitry Torokhov &steps_per_period);
205a9e340dcSDmitry Torokhov if (err) {
206a9e340dcSDmitry Torokhov /*
207a9e340dcSDmitry Torokhov * The 'half-period' property has been deprecated, you must
208a9e340dcSDmitry Torokhov * use 'steps-per-period' and set an appropriate value, but
209a9e340dcSDmitry Torokhov * we still need to parse it to maintain compatibility. If
210a9e340dcSDmitry Torokhov * neither property is present we fall back to the one step
211a9e340dcSDmitry Torokhov * per period behavior.
212a9e340dcSDmitry Torokhov */
213a9e340dcSDmitry Torokhov steps_per_period = device_property_read_bool(dev,
214a9e340dcSDmitry Torokhov "rotary-encoder,half-period") ? 2 : 1;
215a9e340dcSDmitry Torokhov }
216a9e340dcSDmitry Torokhov
217a9e340dcSDmitry Torokhov encoder->rollover =
218a9e340dcSDmitry Torokhov device_property_read_bool(dev, "rotary-encoder,rollover");
219a9e340dcSDmitry Torokhov
220d205a218SUwe Kleine-König if (!device_property_present(dev, "rotary-encoder,encoding") ||
221d205a218SUwe Kleine-König !device_property_match_string(dev, "rotary-encoder,encoding",
222d205a218SUwe Kleine-König "gray")) {
223d205a218SUwe Kleine-König dev_info(dev, "gray");
224d205a218SUwe Kleine-König encoder->encoding = ROTENC_GRAY;
225d205a218SUwe Kleine-König } else if (!device_property_match_string(dev, "rotary-encoder,encoding",
226d205a218SUwe Kleine-König "binary")) {
227d205a218SUwe Kleine-König dev_info(dev, "binary");
228d205a218SUwe Kleine-König encoder->encoding = ROTENC_BINARY;
229d205a218SUwe Kleine-König } else {
230d205a218SUwe Kleine-König dev_err(dev, "unknown encoding setting\n");
231d205a218SUwe Kleine-König return -EINVAL;
232d205a218SUwe Kleine-König }
233d205a218SUwe Kleine-König
234a9e340dcSDmitry Torokhov device_property_read_u32(dev, "linux,axis", &encoder->axis);
235a9e340dcSDmitry Torokhov encoder->relative_axis =
236a9e340dcSDmitry Torokhov device_property_read_bool(dev, "rotary-encoder,relative-axis");
23777a8f0adSDmitry Torokhov
2387dde4e74SUwe Kleine-König encoder->gpios = devm_gpiod_get_array(dev, NULL, GPIOD_IN);
239*1e402a15SKrzysztof Kozlowski if (IS_ERR(encoder->gpios))
240*1e402a15SKrzysztof Kozlowski return dev_err_probe(dev, PTR_ERR(encoder->gpios), "unable to get gpios\n");
2417dde4e74SUwe Kleine-König if (encoder->gpios->ndescs < 2) {
2427dde4e74SUwe Kleine-König dev_err(dev, "not enough gpios found\n");
2437dde4e74SUwe Kleine-König return -EINVAL;
24477a8f0adSDmitry Torokhov }
24577a8f0adSDmitry Torokhov
246d9202af2STimo Teräs input = devm_input_allocate_device(dev);
247d9202af2STimo Teräs if (!input)
248d9202af2STimo Teräs return -ENOMEM;
24973969ff0SDaniel Mack
25073969ff0SDaniel Mack encoder->input = input;
25173969ff0SDaniel Mack
25273969ff0SDaniel Mack input->name = pdev->name;
25373969ff0SDaniel Mack input->id.bustype = BUS_HOST;
254bd3ce655SH Hartley Sweeten
255a9e340dcSDmitry Torokhov if (encoder->relative_axis)
256a9e340dcSDmitry Torokhov input_set_capability(input, EV_REL, encoder->axis);
2578631580fSDmitry Torokhov else
258a9e340dcSDmitry Torokhov input_set_abs_params(input,
259a9e340dcSDmitry Torokhov encoder->axis, 0, encoder->steps, 0, 1);
26073969ff0SDaniel Mack
2617dde4e74SUwe Kleine-König switch (steps_per_period >> (encoder->gpios->ndescs - 2)) {
2623a341a4cSEzequiel Garcia case 4:
2633a341a4cSEzequiel Garcia handler = &rotary_encoder_quarter_period_irq;
26477a8f0adSDmitry Torokhov encoder->last_stable = rotary_encoder_get_state(encoder);
2653a341a4cSEzequiel Garcia break;
2663a341a4cSEzequiel Garcia case 2:
267e70bdd41SJohan Hovold handler = &rotary_encoder_half_period_irq;
26877a8f0adSDmitry Torokhov encoder->last_stable = rotary_encoder_get_state(encoder);
2693a341a4cSEzequiel Garcia break;
2703a341a4cSEzequiel Garcia case 1:
271e70bdd41SJohan Hovold handler = &rotary_encoder_irq;
2723a341a4cSEzequiel Garcia break;
2733a341a4cSEzequiel Garcia default:
2743a341a4cSEzequiel Garcia dev_err(dev, "'%d' is not a valid steps-per-period value\n",
275a9e340dcSDmitry Torokhov steps_per_period);
276d9202af2STimo Teräs return -EINVAL;
277e70bdd41SJohan Hovold }
278e70bdd41SJohan Hovold
2797dde4e74SUwe Kleine-König encoder->irq =
280a86854d0SKees Cook devm_kcalloc(dev,
281a86854d0SKees Cook encoder->gpios->ndescs, sizeof(*encoder->irq),
2827dde4e74SUwe Kleine-König GFP_KERNEL);
2837dde4e74SUwe Kleine-König if (!encoder->irq)
2847dde4e74SUwe Kleine-König return -ENOMEM;
2857dde4e74SUwe Kleine-König
2867dde4e74SUwe Kleine-König for (i = 0; i < encoder->gpios->ndescs; ++i) {
2877dde4e74SUwe Kleine-König encoder->irq[i] = gpiod_to_irq(encoder->gpios->desc[i]);
2887dde4e74SUwe Kleine-König
2897dde4e74SUwe Kleine-König err = devm_request_threaded_irq(dev, encoder->irq[i],
2907dde4e74SUwe Kleine-König NULL, handler,
291dee520e3STimo Teräs IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
292dee520e3STimo Teräs IRQF_ONESHOT,
29373969ff0SDaniel Mack DRV_NAME, encoder);
29473969ff0SDaniel Mack if (err) {
2957dde4e74SUwe Kleine-König dev_err(dev, "unable to request IRQ %d (gpio#%d)\n",
2967dde4e74SUwe Kleine-König encoder->irq[i], i);
297d9202af2STimo Teräs return err;
29873969ff0SDaniel Mack }
29973969ff0SDaniel Mack }
30073969ff0SDaniel Mack
30180c99bcdSDaniel Mack err = input_register_device(input);
30280c99bcdSDaniel Mack if (err) {
30380c99bcdSDaniel Mack dev_err(dev, "failed to register input device\n");
304d9202af2STimo Teräs return err;
30580c99bcdSDaniel Mack }
30680c99bcdSDaniel Mack
307a9e340dcSDmitry Torokhov device_init_wakeup(dev,
308a9e340dcSDmitry Torokhov device_property_read_bool(dev, "wakeup-source"));
30947ec6e5aSSylvain Rochet
31073969ff0SDaniel Mack platform_set_drvdata(pdev, encoder);
31173969ff0SDaniel Mack
31273969ff0SDaniel Mack return 0;
31373969ff0SDaniel Mack }
31473969ff0SDaniel Mack
rotary_encoder_suspend(struct device * dev)3154268a06bSJonathan Cameron static int rotary_encoder_suspend(struct device *dev)
31647ec6e5aSSylvain Rochet {
31747ec6e5aSSylvain Rochet struct rotary_encoder *encoder = dev_get_drvdata(dev);
3187dde4e74SUwe Kleine-König unsigned int i;
31947ec6e5aSSylvain Rochet
32047ec6e5aSSylvain Rochet if (device_may_wakeup(dev)) {
3217dde4e74SUwe Kleine-König for (i = 0; i < encoder->gpios->ndescs; ++i)
3227dde4e74SUwe Kleine-König enable_irq_wake(encoder->irq[i]);
32347ec6e5aSSylvain Rochet }
32447ec6e5aSSylvain Rochet
32547ec6e5aSSylvain Rochet return 0;
32647ec6e5aSSylvain Rochet }
32747ec6e5aSSylvain Rochet
rotary_encoder_resume(struct device * dev)3284268a06bSJonathan Cameron static int rotary_encoder_resume(struct device *dev)
32947ec6e5aSSylvain Rochet {
33047ec6e5aSSylvain Rochet struct rotary_encoder *encoder = dev_get_drvdata(dev);
3317dde4e74SUwe Kleine-König unsigned int i;
33247ec6e5aSSylvain Rochet
33347ec6e5aSSylvain Rochet if (device_may_wakeup(dev)) {
3347dde4e74SUwe Kleine-König for (i = 0; i < encoder->gpios->ndescs; ++i)
3357dde4e74SUwe Kleine-König disable_irq_wake(encoder->irq[i]);
33647ec6e5aSSylvain Rochet }
33747ec6e5aSSylvain Rochet
33847ec6e5aSSylvain Rochet return 0;
33947ec6e5aSSylvain Rochet }
34047ec6e5aSSylvain Rochet
3414268a06bSJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(rotary_encoder_pm_ops,
34247ec6e5aSSylvain Rochet rotary_encoder_suspend, rotary_encoder_resume);
34347ec6e5aSSylvain Rochet
344a9e340dcSDmitry Torokhov #ifdef CONFIG_OF
345a9e340dcSDmitry Torokhov static const struct of_device_id rotary_encoder_of_match[] = {
346a9e340dcSDmitry Torokhov { .compatible = "rotary-encoder", },
347a9e340dcSDmitry Torokhov { },
348a9e340dcSDmitry Torokhov };
349a9e340dcSDmitry Torokhov MODULE_DEVICE_TABLE(of, rotary_encoder_of_match);
350a9e340dcSDmitry Torokhov #endif
351a9e340dcSDmitry Torokhov
35273969ff0SDaniel Mack static struct platform_driver rotary_encoder_driver = {
35373969ff0SDaniel Mack .probe = rotary_encoder_probe,
35473969ff0SDaniel Mack .driver = {
35573969ff0SDaniel Mack .name = DRV_NAME,
3564268a06bSJonathan Cameron .pm = pm_sleep_ptr(&rotary_encoder_pm_ops),
35780c99bcdSDaniel Mack .of_match_table = of_match_ptr(rotary_encoder_of_match),
35873969ff0SDaniel Mack }
35973969ff0SDaniel Mack };
360840a746bSJJ Ding module_platform_driver(rotary_encoder_driver);
36173969ff0SDaniel Mack
36273969ff0SDaniel Mack MODULE_ALIAS("platform:" DRV_NAME);
36373969ff0SDaniel Mack MODULE_DESCRIPTION("GPIO rotary encoder driver");
364e70bdd41SJohan Hovold MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>, Johan Hovold");
36573969ff0SDaniel Mack MODULE_LICENSE("GPL v2");
366