173969ff0SDaniel Mack /* 273969ff0SDaniel Mack * rotary_encoder.c 373969ff0SDaniel Mack * 473969ff0SDaniel Mack * (c) 2009 Daniel Mack <daniel@caiaq.de> 5e70bdd41SJohan Hovold * Copyright (C) 2011 Johan Hovold <jhovold@gmail.com> 673969ff0SDaniel Mack * 773969ff0SDaniel Mack * state machine code inspired by code from Tim Ruetz 873969ff0SDaniel Mack * 973969ff0SDaniel Mack * A generic driver for rotary encoders connected to GPIO lines. 10395cf969SPaul Bolle * See file:Documentation/input/rotary-encoder.txt for more information 1173969ff0SDaniel Mack * 1273969ff0SDaniel Mack * This program is free software; you can redistribute it and/or modify 1373969ff0SDaniel Mack * it under the terms of the GNU General Public License version 2 as 1473969ff0SDaniel Mack * published by the Free Software Foundation. 1573969ff0SDaniel Mack */ 1673969ff0SDaniel Mack 1773969ff0SDaniel Mack #include <linux/kernel.h> 1873969ff0SDaniel Mack #include <linux/module.h> 1973969ff0SDaniel Mack #include <linux/interrupt.h> 2073969ff0SDaniel Mack #include <linux/input.h> 2173969ff0SDaniel Mack #include <linux/device.h> 2273969ff0SDaniel Mack #include <linux/platform_device.h> 2377a8f0adSDmitry Torokhov #include <linux/gpio/consumer.h> 245a0e3ad6STejun Heo #include <linux/slab.h> 252e45e539SSachin Kamat #include <linux/of.h> 2647ec6e5aSSylvain Rochet #include <linux/pm.h> 27a9e340dcSDmitry Torokhov #include <linux/property.h> 2873969ff0SDaniel Mack 2973969ff0SDaniel Mack #define DRV_NAME "rotary-encoder" 3073969ff0SDaniel Mack 3173969ff0SDaniel Mack struct rotary_encoder { 3273969ff0SDaniel Mack struct input_dev *input; 33a9e340dcSDmitry Torokhov 34dee520e3STimo Teräs struct mutex access_mutex; 35bd3ce655SH Hartley Sweeten 36a9e340dcSDmitry Torokhov u32 steps; 37a9e340dcSDmitry Torokhov u32 axis; 38a9e340dcSDmitry Torokhov bool relative_axis; 39a9e340dcSDmitry Torokhov bool rollover; 40a9e340dcSDmitry Torokhov 41bd3ce655SH Hartley Sweeten unsigned int pos; 42bd3ce655SH Hartley Sweeten 4377a8f0adSDmitry Torokhov struct gpio_desc *gpio_a; 4477a8f0adSDmitry Torokhov struct gpio_desc *gpio_b; 4577a8f0adSDmitry Torokhov 46bd3ce655SH Hartley Sweeten unsigned int irq_a; 47bd3ce655SH Hartley Sweeten unsigned int irq_b; 48bd3ce655SH Hartley Sweeten 49bd3ce655SH Hartley Sweeten bool armed; 50bd3ce655SH Hartley Sweeten unsigned char dir; /* 0 - clockwise, 1 - CCW */ 51e70bdd41SJohan Hovold 52e70bdd41SJohan Hovold char last_stable; 5373969ff0SDaniel Mack }; 5473969ff0SDaniel Mack 5577a8f0adSDmitry Torokhov static int rotary_encoder_get_state(struct rotary_encoder *encoder) 5673969ff0SDaniel Mack { 5777a8f0adSDmitry Torokhov int a = !!gpiod_get_value_cansleep(encoder->gpio_a); 5877a8f0adSDmitry Torokhov int b = !!gpiod_get_value_cansleep(encoder->gpio_b); 5973969ff0SDaniel Mack 60521a8f5cSJohan Hovold return ((a << 1) | b); 61521a8f5cSJohan Hovold } 6273969ff0SDaniel Mack 63521a8f5cSJohan Hovold static void rotary_encoder_report_event(struct rotary_encoder *encoder) 64521a8f5cSJohan Hovold { 65a9e340dcSDmitry Torokhov if (encoder->relative_axis) { 66521a8f5cSJohan Hovold input_report_rel(encoder->input, 67a9e340dcSDmitry Torokhov encoder->axis, encoder->dir ? -1 : 1); 68bd3ce655SH Hartley Sweeten } else { 69bd3ce655SH Hartley Sweeten unsigned int pos = encoder->pos; 70bd3ce655SH Hartley Sweeten 7173969ff0SDaniel Mack if (encoder->dir) { 7273969ff0SDaniel Mack /* turning counter-clockwise */ 73a9e340dcSDmitry Torokhov if (encoder->rollover) 74a9e340dcSDmitry Torokhov pos += encoder->steps; 75bd3ce655SH Hartley Sweeten if (pos) 76bd3ce655SH Hartley Sweeten pos--; 7773969ff0SDaniel Mack } else { 7873969ff0SDaniel Mack /* turning clockwise */ 79a9e340dcSDmitry Torokhov if (encoder->rollover || pos < encoder->steps) 80bd3ce655SH Hartley Sweeten pos++; 8173969ff0SDaniel Mack } 82521a8f5cSJohan Hovold 83a9e340dcSDmitry Torokhov if (encoder->rollover) 84a9e340dcSDmitry Torokhov pos %= encoder->steps; 8573969ff0SDaniel Mack 86521a8f5cSJohan Hovold encoder->pos = pos; 87a9e340dcSDmitry Torokhov input_report_abs(encoder->input, encoder->axis, encoder->pos); 88521a8f5cSJohan Hovold } 89521a8f5cSJohan Hovold 90521a8f5cSJohan Hovold input_sync(encoder->input); 91521a8f5cSJohan Hovold } 92521a8f5cSJohan Hovold 93521a8f5cSJohan Hovold static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) 94521a8f5cSJohan Hovold { 95521a8f5cSJohan Hovold struct rotary_encoder *encoder = dev_id; 96521a8f5cSJohan Hovold int state; 97521a8f5cSJohan Hovold 98dee520e3STimo Teräs mutex_lock(&encoder->access_mutex); 99dee520e3STimo Teräs 10077a8f0adSDmitry Torokhov state = rotary_encoder_get_state(encoder); 101521a8f5cSJohan Hovold 102521a8f5cSJohan Hovold switch (state) { 103521a8f5cSJohan Hovold case 0x0: 104521a8f5cSJohan Hovold if (encoder->armed) { 105521a8f5cSJohan Hovold rotary_encoder_report_event(encoder); 106bd3ce655SH Hartley Sweeten encoder->armed = false; 107521a8f5cSJohan Hovold } 10873969ff0SDaniel Mack break; 10973969ff0SDaniel Mack 11073969ff0SDaniel Mack case 0x1: 11173969ff0SDaniel Mack case 0x2: 11273969ff0SDaniel Mack if (encoder->armed) 11373969ff0SDaniel Mack encoder->dir = state - 1; 11473969ff0SDaniel Mack break; 11573969ff0SDaniel Mack 11673969ff0SDaniel Mack case 0x3: 117bd3ce655SH Hartley Sweeten encoder->armed = true; 11873969ff0SDaniel Mack break; 11973969ff0SDaniel Mack } 12073969ff0SDaniel Mack 121dee520e3STimo Teräs mutex_unlock(&encoder->access_mutex); 122dee520e3STimo Teräs 12373969ff0SDaniel Mack return IRQ_HANDLED; 12473969ff0SDaniel Mack } 12573969ff0SDaniel Mack 126e70bdd41SJohan Hovold static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id) 127e70bdd41SJohan Hovold { 128e70bdd41SJohan Hovold struct rotary_encoder *encoder = dev_id; 129e70bdd41SJohan Hovold int state; 130e70bdd41SJohan Hovold 131dee520e3STimo Teräs mutex_lock(&encoder->access_mutex); 132dee520e3STimo Teräs 13377a8f0adSDmitry Torokhov state = rotary_encoder_get_state(encoder); 134e70bdd41SJohan Hovold 135e70bdd41SJohan Hovold switch (state) { 136e70bdd41SJohan Hovold case 0x00: 137e70bdd41SJohan Hovold case 0x03: 138e70bdd41SJohan Hovold if (state != encoder->last_stable) { 139e70bdd41SJohan Hovold rotary_encoder_report_event(encoder); 140e70bdd41SJohan Hovold encoder->last_stable = state; 141e70bdd41SJohan Hovold } 142e70bdd41SJohan Hovold break; 143e70bdd41SJohan Hovold 144e70bdd41SJohan Hovold case 0x01: 145e70bdd41SJohan Hovold case 0x02: 146e70bdd41SJohan Hovold encoder->dir = (encoder->last_stable + state) & 0x01; 147e70bdd41SJohan Hovold break; 148e70bdd41SJohan Hovold } 149e70bdd41SJohan Hovold 150dee520e3STimo Teräs mutex_unlock(&encoder->access_mutex); 151dee520e3STimo Teräs 152e70bdd41SJohan Hovold return IRQ_HANDLED; 153e70bdd41SJohan Hovold } 154e70bdd41SJohan Hovold 1553a341a4cSEzequiel Garcia static irqreturn_t rotary_encoder_quarter_period_irq(int irq, void *dev_id) 1563a341a4cSEzequiel Garcia { 1573a341a4cSEzequiel Garcia struct rotary_encoder *encoder = dev_id; 1583a341a4cSEzequiel Garcia unsigned char sum; 1593a341a4cSEzequiel Garcia int state; 1603a341a4cSEzequiel Garcia 161dee520e3STimo Teräs mutex_lock(&encoder->access_mutex); 162dee520e3STimo Teräs 16377a8f0adSDmitry Torokhov state = rotary_encoder_get_state(encoder); 1643a341a4cSEzequiel Garcia 1653a341a4cSEzequiel Garcia /* 1663a341a4cSEzequiel Garcia * We encode the previous and the current state using a byte. 1673a341a4cSEzequiel Garcia * The previous state in the MSB nibble, the current state in the LSB 1683a341a4cSEzequiel Garcia * nibble. Then use a table to decide the direction of the turn. 1693a341a4cSEzequiel Garcia */ 1703a341a4cSEzequiel Garcia sum = (encoder->last_stable << 4) + state; 1713a341a4cSEzequiel Garcia switch (sum) { 1723a341a4cSEzequiel Garcia case 0x31: 1733a341a4cSEzequiel Garcia case 0x10: 1743a341a4cSEzequiel Garcia case 0x02: 1753a341a4cSEzequiel Garcia case 0x23: 1763a341a4cSEzequiel Garcia encoder->dir = 0; /* clockwise */ 1773a341a4cSEzequiel Garcia break; 1783a341a4cSEzequiel Garcia 1793a341a4cSEzequiel Garcia case 0x13: 1803a341a4cSEzequiel Garcia case 0x01: 1813a341a4cSEzequiel Garcia case 0x20: 1823a341a4cSEzequiel Garcia case 0x32: 1833a341a4cSEzequiel Garcia encoder->dir = 1; /* counter-clockwise */ 1843a341a4cSEzequiel Garcia break; 1853a341a4cSEzequiel Garcia 1863a341a4cSEzequiel Garcia default: 1873a341a4cSEzequiel Garcia /* 1883a341a4cSEzequiel Garcia * Ignore all other values. This covers the case when the 1893a341a4cSEzequiel Garcia * state didn't change (a spurious interrupt) and the 1903a341a4cSEzequiel Garcia * cases where the state changed by two steps, making it 1913a341a4cSEzequiel Garcia * impossible to tell the direction. 1923a341a4cSEzequiel Garcia * 1933a341a4cSEzequiel Garcia * In either case, don't report any event and save the 1943a341a4cSEzequiel Garcia * state for later. 1953a341a4cSEzequiel Garcia */ 1963a341a4cSEzequiel Garcia goto out; 1973a341a4cSEzequiel Garcia } 1983a341a4cSEzequiel Garcia 1993a341a4cSEzequiel Garcia rotary_encoder_report_event(encoder); 2003a341a4cSEzequiel Garcia 2013a341a4cSEzequiel Garcia out: 2023a341a4cSEzequiel Garcia encoder->last_stable = state; 203dee520e3STimo Teräs mutex_unlock(&encoder->access_mutex); 204dee520e3STimo Teräs 2053a341a4cSEzequiel Garcia return IRQ_HANDLED; 2063a341a4cSEzequiel Garcia } 2073a341a4cSEzequiel Garcia 2085298cc4cSBill Pemberton static int rotary_encoder_probe(struct platform_device *pdev) 20973969ff0SDaniel Mack { 210ce919537SDmitry Torokhov struct device *dev = &pdev->dev; 21173969ff0SDaniel Mack struct rotary_encoder *encoder; 21273969ff0SDaniel Mack struct input_dev *input; 213e70bdd41SJohan Hovold irq_handler_t handler; 214a9e340dcSDmitry Torokhov u32 steps_per_period; 21573969ff0SDaniel Mack int err; 21673969ff0SDaniel Mack 217d9202af2STimo Teräs encoder = devm_kzalloc(dev, sizeof(struct rotary_encoder), GFP_KERNEL); 218d9202af2STimo Teräs if (!encoder) 219d9202af2STimo Teräs return -ENOMEM; 220d9202af2STimo Teräs 22177a8f0adSDmitry Torokhov mutex_init(&encoder->access_mutex); 222a9e340dcSDmitry Torokhov 223a9e340dcSDmitry Torokhov device_property_read_u32(dev, "rotary-encoder,steps", &encoder->steps); 224a9e340dcSDmitry Torokhov 225a9e340dcSDmitry Torokhov err = device_property_read_u32(dev, "rotary-encoder,steps-per-period", 226a9e340dcSDmitry Torokhov &steps_per_period); 227a9e340dcSDmitry Torokhov if (err) { 228a9e340dcSDmitry Torokhov /* 229a9e340dcSDmitry Torokhov * The 'half-period' property has been deprecated, you must 230a9e340dcSDmitry Torokhov * use 'steps-per-period' and set an appropriate value, but 231a9e340dcSDmitry Torokhov * we still need to parse it to maintain compatibility. If 232a9e340dcSDmitry Torokhov * neither property is present we fall back to the one step 233a9e340dcSDmitry Torokhov * per period behavior. 234a9e340dcSDmitry Torokhov */ 235a9e340dcSDmitry Torokhov steps_per_period = device_property_read_bool(dev, 236a9e340dcSDmitry Torokhov "rotary-encoder,half-period") ? 2 : 1; 237a9e340dcSDmitry Torokhov } 238a9e340dcSDmitry Torokhov 239a9e340dcSDmitry Torokhov encoder->rollover = 240a9e340dcSDmitry Torokhov device_property_read_bool(dev, "rotary-encoder,rollover"); 241a9e340dcSDmitry Torokhov 242a9e340dcSDmitry Torokhov device_property_read_u32(dev, "linux,axis", &encoder->axis); 243a9e340dcSDmitry Torokhov encoder->relative_axis = 244a9e340dcSDmitry Torokhov device_property_read_bool(dev, "rotary-encoder,relative-axis"); 24577a8f0adSDmitry Torokhov 24677a8f0adSDmitry Torokhov encoder->gpio_a = devm_gpiod_get_index(dev, NULL, 0, GPIOD_IN); 24777a8f0adSDmitry Torokhov if (IS_ERR(encoder->gpio_a)) { 24877a8f0adSDmitry Torokhov err = PTR_ERR(encoder->gpio_a); 24977a8f0adSDmitry Torokhov dev_err(dev, "unable to get GPIO at index 0: %d\n", err); 25077a8f0adSDmitry Torokhov return err; 25177a8f0adSDmitry Torokhov } 25277a8f0adSDmitry Torokhov 25377a8f0adSDmitry Torokhov encoder->irq_a = gpiod_to_irq(encoder->gpio_a); 25477a8f0adSDmitry Torokhov 25577a8f0adSDmitry Torokhov encoder->gpio_b = devm_gpiod_get_index(dev, NULL, 1, GPIOD_IN); 25677a8f0adSDmitry Torokhov if (IS_ERR(encoder->gpio_b)) { 25777a8f0adSDmitry Torokhov err = PTR_ERR(encoder->gpio_b); 25877a8f0adSDmitry Torokhov dev_err(dev, "unable to get GPIO at index 1: %d\n", err); 25977a8f0adSDmitry Torokhov return err; 26077a8f0adSDmitry Torokhov } 26177a8f0adSDmitry Torokhov 26277a8f0adSDmitry Torokhov encoder->irq_b = gpiod_to_irq(encoder->gpio_b); 26377a8f0adSDmitry Torokhov 264d9202af2STimo Teräs input = devm_input_allocate_device(dev); 265d9202af2STimo Teräs if (!input) 266d9202af2STimo Teräs return -ENOMEM; 26773969ff0SDaniel Mack 26873969ff0SDaniel Mack encoder->input = input; 26973969ff0SDaniel Mack 27073969ff0SDaniel Mack input->name = pdev->name; 27173969ff0SDaniel Mack input->id.bustype = BUS_HOST; 27280c99bcdSDaniel Mack input->dev.parent = dev; 273bd3ce655SH Hartley Sweeten 274a9e340dcSDmitry Torokhov if (encoder->relative_axis) 275a9e340dcSDmitry Torokhov input_set_capability(input, EV_REL, encoder->axis); 2768631580fSDmitry Torokhov else 277a9e340dcSDmitry Torokhov input_set_abs_params(input, 278a9e340dcSDmitry Torokhov encoder->axis, 0, encoder->steps, 0, 1); 27973969ff0SDaniel Mack 280a9e340dcSDmitry Torokhov switch (steps_per_period) { 2813a341a4cSEzequiel Garcia case 4: 2823a341a4cSEzequiel Garcia handler = &rotary_encoder_quarter_period_irq; 28377a8f0adSDmitry Torokhov encoder->last_stable = rotary_encoder_get_state(encoder); 2843a341a4cSEzequiel Garcia break; 2853a341a4cSEzequiel Garcia case 2: 286e70bdd41SJohan Hovold handler = &rotary_encoder_half_period_irq; 28777a8f0adSDmitry Torokhov encoder->last_stable = rotary_encoder_get_state(encoder); 2883a341a4cSEzequiel Garcia break; 2893a341a4cSEzequiel Garcia case 1: 290e70bdd41SJohan Hovold handler = &rotary_encoder_irq; 2913a341a4cSEzequiel Garcia break; 2923a341a4cSEzequiel Garcia default: 2933a341a4cSEzequiel Garcia dev_err(dev, "'%d' is not a valid steps-per-period value\n", 294a9e340dcSDmitry Torokhov steps_per_period); 295d9202af2STimo Teräs return -EINVAL; 296e70bdd41SJohan Hovold } 297e70bdd41SJohan Hovold 298dee520e3STimo Teräs err = devm_request_threaded_irq(dev, encoder->irq_a, NULL, handler, 299dee520e3STimo Teräs IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | 300dee520e3STimo Teräs IRQF_ONESHOT, 30173969ff0SDaniel Mack DRV_NAME, encoder); 30273969ff0SDaniel Mack if (err) { 303429a34d7SDaniel Mack dev_err(dev, "unable to request IRQ %d\n", encoder->irq_a); 304d9202af2STimo Teräs return err; 30573969ff0SDaniel Mack } 30673969ff0SDaniel Mack 307dee520e3STimo Teräs err = devm_request_threaded_irq(dev, encoder->irq_b, NULL, handler, 308dee520e3STimo Teräs IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | 309dee520e3STimo Teräs IRQF_ONESHOT, 31073969ff0SDaniel Mack DRV_NAME, encoder); 31173969ff0SDaniel Mack if (err) { 312429a34d7SDaniel Mack dev_err(dev, "unable to request IRQ %d\n", encoder->irq_b); 313d9202af2STimo Teräs return err; 31473969ff0SDaniel Mack } 31573969ff0SDaniel Mack 31680c99bcdSDaniel Mack err = input_register_device(input); 31780c99bcdSDaniel Mack if (err) { 31880c99bcdSDaniel Mack dev_err(dev, "failed to register input device\n"); 319d9202af2STimo Teräs return err; 32080c99bcdSDaniel Mack } 32180c99bcdSDaniel Mack 322a9e340dcSDmitry Torokhov device_init_wakeup(dev, 323a9e340dcSDmitry Torokhov device_property_read_bool(dev, "wakeup-source")); 32447ec6e5aSSylvain Rochet 32573969ff0SDaniel Mack platform_set_drvdata(pdev, encoder); 32673969ff0SDaniel Mack 32773969ff0SDaniel Mack return 0; 32873969ff0SDaniel Mack } 32973969ff0SDaniel Mack 3306a6f70b3SDmitry Torokhov static int __maybe_unused rotary_encoder_suspend(struct device *dev) 33147ec6e5aSSylvain Rochet { 33247ec6e5aSSylvain Rochet struct rotary_encoder *encoder = dev_get_drvdata(dev); 33347ec6e5aSSylvain Rochet 33447ec6e5aSSylvain Rochet if (device_may_wakeup(dev)) { 33547ec6e5aSSylvain Rochet enable_irq_wake(encoder->irq_a); 33647ec6e5aSSylvain Rochet enable_irq_wake(encoder->irq_b); 33747ec6e5aSSylvain Rochet } 33847ec6e5aSSylvain Rochet 33947ec6e5aSSylvain Rochet return 0; 34047ec6e5aSSylvain Rochet } 34147ec6e5aSSylvain Rochet 3426a6f70b3SDmitry Torokhov static int __maybe_unused rotary_encoder_resume(struct device *dev) 34347ec6e5aSSylvain Rochet { 34447ec6e5aSSylvain Rochet struct rotary_encoder *encoder = dev_get_drvdata(dev); 34547ec6e5aSSylvain Rochet 34647ec6e5aSSylvain Rochet if (device_may_wakeup(dev)) { 34747ec6e5aSSylvain Rochet disable_irq_wake(encoder->irq_a); 34847ec6e5aSSylvain Rochet disable_irq_wake(encoder->irq_b); 34947ec6e5aSSylvain Rochet } 35047ec6e5aSSylvain Rochet 35147ec6e5aSSylvain Rochet return 0; 35247ec6e5aSSylvain Rochet } 35347ec6e5aSSylvain Rochet 35447ec6e5aSSylvain Rochet static SIMPLE_DEV_PM_OPS(rotary_encoder_pm_ops, 35547ec6e5aSSylvain Rochet rotary_encoder_suspend, rotary_encoder_resume); 35647ec6e5aSSylvain Rochet 357a9e340dcSDmitry Torokhov #ifdef CONFIG_OF 358a9e340dcSDmitry Torokhov static const struct of_device_id rotary_encoder_of_match[] = { 359a9e340dcSDmitry Torokhov { .compatible = "rotary-encoder", }, 360a9e340dcSDmitry Torokhov { }, 361a9e340dcSDmitry Torokhov }; 362a9e340dcSDmitry Torokhov MODULE_DEVICE_TABLE(of, rotary_encoder_of_match); 363a9e340dcSDmitry Torokhov #endif 364a9e340dcSDmitry Torokhov 36573969ff0SDaniel Mack static struct platform_driver rotary_encoder_driver = { 36673969ff0SDaniel Mack .probe = rotary_encoder_probe, 36773969ff0SDaniel Mack .driver = { 36873969ff0SDaniel Mack .name = DRV_NAME, 36947ec6e5aSSylvain Rochet .pm = &rotary_encoder_pm_ops, 37080c99bcdSDaniel Mack .of_match_table = of_match_ptr(rotary_encoder_of_match), 37173969ff0SDaniel Mack } 37273969ff0SDaniel Mack }; 373840a746bSJJ Ding module_platform_driver(rotary_encoder_driver); 37473969ff0SDaniel Mack 37573969ff0SDaniel Mack MODULE_ALIAS("platform:" DRV_NAME); 37673969ff0SDaniel Mack MODULE_DESCRIPTION("GPIO rotary encoder driver"); 377e70bdd41SJohan Hovold MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>, Johan Hovold"); 37873969ff0SDaniel Mack MODULE_LICENSE("GPL v2"); 379