173969ff0SDaniel Mack /* 273969ff0SDaniel Mack * rotary_encoder.c 373969ff0SDaniel Mack * 473969ff0SDaniel Mack * (c) 2009 Daniel Mack <daniel@caiaq.de> 573969ff0SDaniel Mack * 673969ff0SDaniel Mack * state machine code inspired by code from Tim Ruetz 773969ff0SDaniel Mack * 873969ff0SDaniel Mack * A generic driver for rotary encoders connected to GPIO lines. 973969ff0SDaniel Mack * See file:Documentation/input/rotary_encoder.txt for more information 1073969ff0SDaniel Mack * 1173969ff0SDaniel Mack * This program is free software; you can redistribute it and/or modify 1273969ff0SDaniel Mack * it under the terms of the GNU General Public License version 2 as 1373969ff0SDaniel Mack * published by the Free Software Foundation. 1473969ff0SDaniel Mack */ 1573969ff0SDaniel Mack 1673969ff0SDaniel Mack #include <linux/kernel.h> 1773969ff0SDaniel Mack #include <linux/module.h> 1873969ff0SDaniel Mack #include <linux/init.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> 2373969ff0SDaniel Mack #include <linux/gpio.h> 2473969ff0SDaniel Mack #include <linux/rotary_encoder.h> 255a0e3ad6STejun Heo #include <linux/slab.h> 2673969ff0SDaniel Mack 2773969ff0SDaniel Mack #define DRV_NAME "rotary-encoder" 2873969ff0SDaniel Mack 2973969ff0SDaniel Mack struct rotary_encoder { 3073969ff0SDaniel Mack struct input_dev *input; 3173969ff0SDaniel Mack struct rotary_encoder_platform_data *pdata; 32bd3ce655SH Hartley Sweeten 33bd3ce655SH Hartley Sweeten unsigned int axis; 34bd3ce655SH Hartley Sweeten unsigned int pos; 35bd3ce655SH Hartley Sweeten 36bd3ce655SH Hartley Sweeten unsigned int irq_a; 37bd3ce655SH Hartley Sweeten unsigned int irq_b; 38bd3ce655SH Hartley Sweeten 39bd3ce655SH Hartley Sweeten bool armed; 40bd3ce655SH Hartley Sweeten unsigned char dir; /* 0 - clockwise, 1 - CCW */ 4173969ff0SDaniel Mack }; 4273969ff0SDaniel Mack 43521a8f5cSJohan Hovold static int rotary_encoder_get_state(struct rotary_encoder_platform_data *pdata) 4473969ff0SDaniel Mack { 4573969ff0SDaniel Mack int a = !!gpio_get_value(pdata->gpio_a); 4673969ff0SDaniel Mack int b = !!gpio_get_value(pdata->gpio_b); 4773969ff0SDaniel Mack 4873969ff0SDaniel Mack a ^= pdata->inverted_a; 4973969ff0SDaniel Mack b ^= pdata->inverted_b; 5073969ff0SDaniel Mack 51521a8f5cSJohan Hovold return ((a << 1) | b); 52521a8f5cSJohan Hovold } 5373969ff0SDaniel Mack 54521a8f5cSJohan Hovold static void rotary_encoder_report_event(struct rotary_encoder *encoder) 55521a8f5cSJohan Hovold { 56521a8f5cSJohan Hovold struct rotary_encoder_platform_data *pdata = encoder->pdata; 5773969ff0SDaniel Mack 58bd3ce655SH Hartley Sweeten if (pdata->relative_axis) { 59521a8f5cSJohan Hovold input_report_rel(encoder->input, 60521a8f5cSJohan Hovold pdata->axis, encoder->dir ? -1 : 1); 61bd3ce655SH Hartley Sweeten } else { 62bd3ce655SH Hartley Sweeten unsigned int pos = encoder->pos; 63bd3ce655SH Hartley Sweeten 6473969ff0SDaniel Mack if (encoder->dir) { 6573969ff0SDaniel Mack /* turning counter-clockwise */ 66bd3ce655SH Hartley Sweeten if (pdata->rollover) 67bd3ce655SH Hartley Sweeten pos += pdata->steps; 68bd3ce655SH Hartley Sweeten if (pos) 69bd3ce655SH Hartley Sweeten pos--; 7073969ff0SDaniel Mack } else { 7173969ff0SDaniel Mack /* turning clockwise */ 72bd3ce655SH Hartley Sweeten if (pdata->rollover || pos < pdata->steps) 73bd3ce655SH Hartley Sweeten pos++; 7473969ff0SDaniel Mack } 75521a8f5cSJohan Hovold 76bd3ce655SH Hartley Sweeten if (pdata->rollover) 77bd3ce655SH Hartley Sweeten pos %= pdata->steps; 7873969ff0SDaniel Mack 79521a8f5cSJohan Hovold encoder->pos = pos; 80521a8f5cSJohan Hovold input_report_abs(encoder->input, pdata->axis, encoder->pos); 81521a8f5cSJohan Hovold } 82521a8f5cSJohan Hovold 83521a8f5cSJohan Hovold input_sync(encoder->input); 84521a8f5cSJohan Hovold } 85521a8f5cSJohan Hovold 86521a8f5cSJohan Hovold static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) 87521a8f5cSJohan Hovold { 88521a8f5cSJohan Hovold struct rotary_encoder *encoder = dev_id; 89521a8f5cSJohan Hovold int state; 90521a8f5cSJohan Hovold 91521a8f5cSJohan Hovold state = rotary_encoder_get_state(encoder->pdata); 92521a8f5cSJohan Hovold 93521a8f5cSJohan Hovold switch (state) { 94521a8f5cSJohan Hovold case 0x0: 95521a8f5cSJohan Hovold if (encoder->armed) { 96521a8f5cSJohan Hovold rotary_encoder_report_event(encoder); 97bd3ce655SH Hartley Sweeten encoder->armed = false; 98521a8f5cSJohan Hovold } 9973969ff0SDaniel Mack break; 10073969ff0SDaniel Mack 10173969ff0SDaniel Mack case 0x1: 10273969ff0SDaniel Mack case 0x2: 10373969ff0SDaniel Mack if (encoder->armed) 10473969ff0SDaniel Mack encoder->dir = state - 1; 10573969ff0SDaniel Mack break; 10673969ff0SDaniel Mack 10773969ff0SDaniel Mack case 0x3: 108bd3ce655SH Hartley Sweeten encoder->armed = true; 10973969ff0SDaniel Mack break; 11073969ff0SDaniel Mack } 11173969ff0SDaniel Mack 11273969ff0SDaniel Mack return IRQ_HANDLED; 11373969ff0SDaniel Mack } 11473969ff0SDaniel Mack 11573969ff0SDaniel Mack static int __devinit rotary_encoder_probe(struct platform_device *pdev) 11673969ff0SDaniel Mack { 11773969ff0SDaniel Mack struct rotary_encoder_platform_data *pdata = pdev->dev.platform_data; 11873969ff0SDaniel Mack struct rotary_encoder *encoder; 11973969ff0SDaniel Mack struct input_dev *input; 12073969ff0SDaniel Mack int err; 12173969ff0SDaniel Mack 12206ee3d3cSH Hartley Sweeten if (!pdata) { 12306ee3d3cSH Hartley Sweeten dev_err(&pdev->dev, "missing platform data\n"); 12473969ff0SDaniel Mack return -ENOENT; 12573969ff0SDaniel Mack } 12673969ff0SDaniel Mack 12773969ff0SDaniel Mack encoder = kzalloc(sizeof(struct rotary_encoder), GFP_KERNEL); 12873969ff0SDaniel Mack input = input_allocate_device(); 12973969ff0SDaniel Mack if (!encoder || !input) { 13073969ff0SDaniel Mack dev_err(&pdev->dev, "failed to allocate memory for device\n"); 13173969ff0SDaniel Mack err = -ENOMEM; 13273969ff0SDaniel Mack goto exit_free_mem; 13373969ff0SDaniel Mack } 13473969ff0SDaniel Mack 13573969ff0SDaniel Mack encoder->input = input; 13673969ff0SDaniel Mack encoder->pdata = pdata; 13773969ff0SDaniel Mack encoder->irq_a = gpio_to_irq(pdata->gpio_a); 13873969ff0SDaniel Mack encoder->irq_b = gpio_to_irq(pdata->gpio_b); 13973969ff0SDaniel Mack 14073969ff0SDaniel Mack /* create and register the input driver */ 14173969ff0SDaniel Mack input->name = pdev->name; 14273969ff0SDaniel Mack input->id.bustype = BUS_HOST; 14373969ff0SDaniel Mack input->dev.parent = &pdev->dev; 144bd3ce655SH Hartley Sweeten 145bd3ce655SH Hartley Sweeten if (pdata->relative_axis) { 146bd3ce655SH Hartley Sweeten input->evbit[0] = BIT_MASK(EV_REL); 147bd3ce655SH Hartley Sweeten input->relbit[0] = BIT_MASK(pdata->axis); 148bd3ce655SH Hartley Sweeten } else { 14973969ff0SDaniel Mack input->evbit[0] = BIT_MASK(EV_ABS); 15073969ff0SDaniel Mack input_set_abs_params(encoder->input, 15173969ff0SDaniel Mack pdata->axis, 0, pdata->steps, 0, 1); 152bd3ce655SH Hartley Sweeten } 15373969ff0SDaniel Mack 15473969ff0SDaniel Mack err = input_register_device(input); 15573969ff0SDaniel Mack if (err) { 15673969ff0SDaniel Mack dev_err(&pdev->dev, "failed to register input device\n"); 15773969ff0SDaniel Mack goto exit_free_mem; 15873969ff0SDaniel Mack } 15973969ff0SDaniel Mack 16073969ff0SDaniel Mack /* request the GPIOs */ 16173969ff0SDaniel Mack err = gpio_request(pdata->gpio_a, DRV_NAME); 16273969ff0SDaniel Mack if (err) { 16373969ff0SDaniel Mack dev_err(&pdev->dev, "unable to request GPIO %d\n", 16473969ff0SDaniel Mack pdata->gpio_a); 16573969ff0SDaniel Mack goto exit_unregister_input; 16673969ff0SDaniel Mack } 16773969ff0SDaniel Mack 1685deeac99SAndrew Clayton err = gpio_direction_input(pdata->gpio_a); 1695deeac99SAndrew Clayton if (err) { 1705deeac99SAndrew Clayton dev_err(&pdev->dev, "unable to set GPIO %d for input\n", 1715deeac99SAndrew Clayton pdata->gpio_a); 1725deeac99SAndrew Clayton goto exit_unregister_input; 1735deeac99SAndrew Clayton } 1745deeac99SAndrew Clayton 17573969ff0SDaniel Mack err = gpio_request(pdata->gpio_b, DRV_NAME); 17673969ff0SDaniel Mack if (err) { 17773969ff0SDaniel Mack dev_err(&pdev->dev, "unable to request GPIO %d\n", 17873969ff0SDaniel Mack pdata->gpio_b); 17973969ff0SDaniel Mack goto exit_free_gpio_a; 18073969ff0SDaniel Mack } 18173969ff0SDaniel Mack 1825deeac99SAndrew Clayton err = gpio_direction_input(pdata->gpio_b); 1835deeac99SAndrew Clayton if (err) { 1845deeac99SAndrew Clayton dev_err(&pdev->dev, "unable to set GPIO %d for input\n", 1855deeac99SAndrew Clayton pdata->gpio_b); 1865deeac99SAndrew Clayton goto exit_free_gpio_a; 1875deeac99SAndrew Clayton } 1885deeac99SAndrew Clayton 18973969ff0SDaniel Mack /* request the IRQs */ 19073969ff0SDaniel Mack err = request_irq(encoder->irq_a, &rotary_encoder_irq, 191e0d5f4c3SAlexander Stein IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 19273969ff0SDaniel Mack DRV_NAME, encoder); 19373969ff0SDaniel Mack if (err) { 19473969ff0SDaniel Mack dev_err(&pdev->dev, "unable to request IRQ %d\n", 19573969ff0SDaniel Mack encoder->irq_a); 19673969ff0SDaniel Mack goto exit_free_gpio_b; 19773969ff0SDaniel Mack } 19873969ff0SDaniel Mack 19973969ff0SDaniel Mack err = request_irq(encoder->irq_b, &rotary_encoder_irq, 200e0d5f4c3SAlexander Stein IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 20173969ff0SDaniel Mack DRV_NAME, encoder); 20273969ff0SDaniel Mack if (err) { 20373969ff0SDaniel Mack dev_err(&pdev->dev, "unable to request IRQ %d\n", 20473969ff0SDaniel Mack encoder->irq_b); 20573969ff0SDaniel Mack goto exit_free_irq_a; 20673969ff0SDaniel Mack } 20773969ff0SDaniel Mack 20873969ff0SDaniel Mack platform_set_drvdata(pdev, encoder); 20973969ff0SDaniel Mack 21073969ff0SDaniel Mack return 0; 21173969ff0SDaniel Mack 21273969ff0SDaniel Mack exit_free_irq_a: 21373969ff0SDaniel Mack free_irq(encoder->irq_a, encoder); 21473969ff0SDaniel Mack exit_free_gpio_b: 21573969ff0SDaniel Mack gpio_free(pdata->gpio_b); 21673969ff0SDaniel Mack exit_free_gpio_a: 21773969ff0SDaniel Mack gpio_free(pdata->gpio_a); 21873969ff0SDaniel Mack exit_unregister_input: 21973969ff0SDaniel Mack input_unregister_device(input); 22073969ff0SDaniel Mack input = NULL; /* so we don't try to free it */ 22173969ff0SDaniel Mack exit_free_mem: 22273969ff0SDaniel Mack input_free_device(input); 22373969ff0SDaniel Mack kfree(encoder); 22473969ff0SDaniel Mack return err; 22573969ff0SDaniel Mack } 22673969ff0SDaniel Mack 22773969ff0SDaniel Mack static int __devexit rotary_encoder_remove(struct platform_device *pdev) 22873969ff0SDaniel Mack { 22973969ff0SDaniel Mack struct rotary_encoder *encoder = platform_get_drvdata(pdev); 23073969ff0SDaniel Mack struct rotary_encoder_platform_data *pdata = pdev->dev.platform_data; 23173969ff0SDaniel Mack 23273969ff0SDaniel Mack free_irq(encoder->irq_a, encoder); 23373969ff0SDaniel Mack free_irq(encoder->irq_b, encoder); 23473969ff0SDaniel Mack gpio_free(pdata->gpio_a); 23573969ff0SDaniel Mack gpio_free(pdata->gpio_b); 23673969ff0SDaniel Mack input_unregister_device(encoder->input); 23773969ff0SDaniel Mack platform_set_drvdata(pdev, NULL); 23873969ff0SDaniel Mack kfree(encoder); 23973969ff0SDaniel Mack 24073969ff0SDaniel Mack return 0; 24173969ff0SDaniel Mack } 24273969ff0SDaniel Mack 24373969ff0SDaniel Mack static struct platform_driver rotary_encoder_driver = { 24473969ff0SDaniel Mack .probe = rotary_encoder_probe, 24573969ff0SDaniel Mack .remove = __devexit_p(rotary_encoder_remove), 24673969ff0SDaniel Mack .driver = { 24773969ff0SDaniel Mack .name = DRV_NAME, 24873969ff0SDaniel Mack .owner = THIS_MODULE, 24973969ff0SDaniel Mack } 25073969ff0SDaniel Mack }; 25173969ff0SDaniel Mack 25273969ff0SDaniel Mack static int __init rotary_encoder_init(void) 25373969ff0SDaniel Mack { 25473969ff0SDaniel Mack return platform_driver_register(&rotary_encoder_driver); 25573969ff0SDaniel Mack } 25673969ff0SDaniel Mack 25773969ff0SDaniel Mack static void __exit rotary_encoder_exit(void) 25873969ff0SDaniel Mack { 25973969ff0SDaniel Mack platform_driver_unregister(&rotary_encoder_driver); 26073969ff0SDaniel Mack } 26173969ff0SDaniel Mack 26273969ff0SDaniel Mack module_init(rotary_encoder_init); 26373969ff0SDaniel Mack module_exit(rotary_encoder_exit); 26473969ff0SDaniel Mack 26573969ff0SDaniel Mack MODULE_ALIAS("platform:" DRV_NAME); 26673969ff0SDaniel Mack MODULE_DESCRIPTION("GPIO rotary encoder driver"); 26773969ff0SDaniel Mack MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); 26873969ff0SDaniel Mack MODULE_LICENSE("GPL v2"); 269