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/init.h> 2073969ff0SDaniel Mack #include <linux/interrupt.h> 2173969ff0SDaniel Mack #include <linux/input.h> 2273969ff0SDaniel Mack #include <linux/device.h> 2373969ff0SDaniel Mack #include <linux/platform_device.h> 2473969ff0SDaniel Mack #include <linux/gpio.h> 2573969ff0SDaniel Mack #include <linux/rotary_encoder.h> 265a0e3ad6STejun Heo #include <linux/slab.h> 2773969ff0SDaniel Mack 2873969ff0SDaniel Mack #define DRV_NAME "rotary-encoder" 2973969ff0SDaniel Mack 3073969ff0SDaniel Mack struct rotary_encoder { 3173969ff0SDaniel Mack struct input_dev *input; 32ce919537SDmitry Torokhov const struct rotary_encoder_platform_data *pdata; 33bd3ce655SH Hartley Sweeten 34bd3ce655SH Hartley Sweeten unsigned int axis; 35bd3ce655SH Hartley Sweeten unsigned int pos; 36bd3ce655SH Hartley Sweeten 37bd3ce655SH Hartley Sweeten unsigned int irq_a; 38bd3ce655SH Hartley Sweeten unsigned int irq_b; 39bd3ce655SH Hartley Sweeten 40bd3ce655SH Hartley Sweeten bool armed; 41bd3ce655SH Hartley Sweeten unsigned char dir; /* 0 - clockwise, 1 - CCW */ 42e70bdd41SJohan Hovold 43e70bdd41SJohan Hovold char last_stable; 4473969ff0SDaniel Mack }; 4573969ff0SDaniel Mack 46ce919537SDmitry Torokhov static int rotary_encoder_get_state(const struct rotary_encoder_platform_data *pdata) 4773969ff0SDaniel Mack { 4873969ff0SDaniel Mack int a = !!gpio_get_value(pdata->gpio_a); 4973969ff0SDaniel Mack int b = !!gpio_get_value(pdata->gpio_b); 5073969ff0SDaniel Mack 5173969ff0SDaniel Mack a ^= pdata->inverted_a; 5273969ff0SDaniel Mack b ^= pdata->inverted_b; 5373969ff0SDaniel Mack 54521a8f5cSJohan Hovold return ((a << 1) | b); 55521a8f5cSJohan Hovold } 5673969ff0SDaniel Mack 57521a8f5cSJohan Hovold static void rotary_encoder_report_event(struct rotary_encoder *encoder) 58521a8f5cSJohan Hovold { 59ce919537SDmitry Torokhov const struct rotary_encoder_platform_data *pdata = encoder->pdata; 6073969ff0SDaniel Mack 61bd3ce655SH Hartley Sweeten if (pdata->relative_axis) { 62521a8f5cSJohan Hovold input_report_rel(encoder->input, 63521a8f5cSJohan Hovold pdata->axis, encoder->dir ? -1 : 1); 64bd3ce655SH Hartley Sweeten } else { 65bd3ce655SH Hartley Sweeten unsigned int pos = encoder->pos; 66bd3ce655SH Hartley Sweeten 6773969ff0SDaniel Mack if (encoder->dir) { 6873969ff0SDaniel Mack /* turning counter-clockwise */ 69bd3ce655SH Hartley Sweeten if (pdata->rollover) 70bd3ce655SH Hartley Sweeten pos += pdata->steps; 71bd3ce655SH Hartley Sweeten if (pos) 72bd3ce655SH Hartley Sweeten pos--; 7373969ff0SDaniel Mack } else { 7473969ff0SDaniel Mack /* turning clockwise */ 75bd3ce655SH Hartley Sweeten if (pdata->rollover || pos < pdata->steps) 76bd3ce655SH Hartley Sweeten pos++; 7773969ff0SDaniel Mack } 78521a8f5cSJohan Hovold 79bd3ce655SH Hartley Sweeten if (pdata->rollover) 80bd3ce655SH Hartley Sweeten pos %= pdata->steps; 8173969ff0SDaniel Mack 82521a8f5cSJohan Hovold encoder->pos = pos; 83521a8f5cSJohan Hovold input_report_abs(encoder->input, pdata->axis, encoder->pos); 84521a8f5cSJohan Hovold } 85521a8f5cSJohan Hovold 86521a8f5cSJohan Hovold input_sync(encoder->input); 87521a8f5cSJohan Hovold } 88521a8f5cSJohan Hovold 89521a8f5cSJohan Hovold static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) 90521a8f5cSJohan Hovold { 91521a8f5cSJohan Hovold struct rotary_encoder *encoder = dev_id; 92521a8f5cSJohan Hovold int state; 93521a8f5cSJohan Hovold 94521a8f5cSJohan Hovold state = rotary_encoder_get_state(encoder->pdata); 95521a8f5cSJohan Hovold 96521a8f5cSJohan Hovold switch (state) { 97521a8f5cSJohan Hovold case 0x0: 98521a8f5cSJohan Hovold if (encoder->armed) { 99521a8f5cSJohan Hovold rotary_encoder_report_event(encoder); 100bd3ce655SH Hartley Sweeten encoder->armed = false; 101521a8f5cSJohan Hovold } 10273969ff0SDaniel Mack break; 10373969ff0SDaniel Mack 10473969ff0SDaniel Mack case 0x1: 10573969ff0SDaniel Mack case 0x2: 10673969ff0SDaniel Mack if (encoder->armed) 10773969ff0SDaniel Mack encoder->dir = state - 1; 10873969ff0SDaniel Mack break; 10973969ff0SDaniel Mack 11073969ff0SDaniel Mack case 0x3: 111bd3ce655SH Hartley Sweeten encoder->armed = true; 11273969ff0SDaniel Mack break; 11373969ff0SDaniel Mack } 11473969ff0SDaniel Mack 11573969ff0SDaniel Mack return IRQ_HANDLED; 11673969ff0SDaniel Mack } 11773969ff0SDaniel Mack 118e70bdd41SJohan Hovold static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id) 119e70bdd41SJohan Hovold { 120e70bdd41SJohan Hovold struct rotary_encoder *encoder = dev_id; 121e70bdd41SJohan Hovold int state; 122e70bdd41SJohan Hovold 123e70bdd41SJohan Hovold state = rotary_encoder_get_state(encoder->pdata); 124e70bdd41SJohan Hovold 125e70bdd41SJohan Hovold switch (state) { 126e70bdd41SJohan Hovold case 0x00: 127e70bdd41SJohan Hovold case 0x03: 128e70bdd41SJohan Hovold if (state != encoder->last_stable) { 129e70bdd41SJohan Hovold rotary_encoder_report_event(encoder); 130e70bdd41SJohan Hovold encoder->last_stable = state; 131e70bdd41SJohan Hovold } 132e70bdd41SJohan Hovold break; 133e70bdd41SJohan Hovold 134e70bdd41SJohan Hovold case 0x01: 135e70bdd41SJohan Hovold case 0x02: 136e70bdd41SJohan Hovold encoder->dir = (encoder->last_stable + state) & 0x01; 137e70bdd41SJohan Hovold break; 138e70bdd41SJohan Hovold } 139e70bdd41SJohan Hovold 140e70bdd41SJohan Hovold return IRQ_HANDLED; 141e70bdd41SJohan Hovold } 142e70bdd41SJohan Hovold 14373969ff0SDaniel Mack static int __devinit rotary_encoder_probe(struct platform_device *pdev) 14473969ff0SDaniel Mack { 145ce919537SDmitry Torokhov struct device *dev = &pdev->dev; 146ce919537SDmitry Torokhov const struct rotary_encoder_platform_data *pdata = dev_get_platdata(dev); 14773969ff0SDaniel Mack struct rotary_encoder *encoder; 14873969ff0SDaniel Mack struct input_dev *input; 149e70bdd41SJohan Hovold irq_handler_t handler; 15073969ff0SDaniel Mack int err; 15173969ff0SDaniel Mack 15206ee3d3cSH Hartley Sweeten if (!pdata) { 15306ee3d3cSH Hartley Sweeten dev_err(&pdev->dev, "missing platform data\n"); 15473969ff0SDaniel Mack return -ENOENT; 15573969ff0SDaniel Mack } 15673969ff0SDaniel Mack 15773969ff0SDaniel Mack encoder = kzalloc(sizeof(struct rotary_encoder), GFP_KERNEL); 15873969ff0SDaniel Mack input = input_allocate_device(); 15973969ff0SDaniel Mack if (!encoder || !input) { 16073969ff0SDaniel Mack dev_err(&pdev->dev, "failed to allocate memory for device\n"); 16173969ff0SDaniel Mack err = -ENOMEM; 16273969ff0SDaniel Mack goto exit_free_mem; 16373969ff0SDaniel Mack } 16473969ff0SDaniel Mack 16573969ff0SDaniel Mack encoder->input = input; 16673969ff0SDaniel Mack encoder->pdata = pdata; 16773969ff0SDaniel Mack 16873969ff0SDaniel Mack /* create and register the input driver */ 16973969ff0SDaniel Mack input->name = pdev->name; 17073969ff0SDaniel Mack input->id.bustype = BUS_HOST; 17173969ff0SDaniel Mack input->dev.parent = &pdev->dev; 172bd3ce655SH Hartley Sweeten 173bd3ce655SH Hartley Sweeten if (pdata->relative_axis) { 174bd3ce655SH Hartley Sweeten input->evbit[0] = BIT_MASK(EV_REL); 175bd3ce655SH Hartley Sweeten input->relbit[0] = BIT_MASK(pdata->axis); 176bd3ce655SH Hartley Sweeten } else { 17773969ff0SDaniel Mack input->evbit[0] = BIT_MASK(EV_ABS); 17873969ff0SDaniel Mack input_set_abs_params(encoder->input, 17973969ff0SDaniel Mack pdata->axis, 0, pdata->steps, 0, 1); 180bd3ce655SH Hartley Sweeten } 18173969ff0SDaniel Mack 18273969ff0SDaniel Mack err = input_register_device(input); 18373969ff0SDaniel Mack if (err) { 184429a34d7SDaniel Mack dev_err(dev, "failed to register input device\n"); 18573969ff0SDaniel Mack goto exit_free_mem; 18673969ff0SDaniel Mack } 18773969ff0SDaniel Mack 18873969ff0SDaniel Mack /* request the GPIOs */ 189429a34d7SDaniel Mack err = gpio_request_one(pdata->gpio_a, GPIOF_IN, dev_name(dev)); 19073969ff0SDaniel Mack if (err) { 191429a34d7SDaniel Mack dev_err(dev, "unable to request GPIO %d\n", pdata->gpio_a); 19273969ff0SDaniel Mack goto exit_unregister_input; 19373969ff0SDaniel Mack } 19473969ff0SDaniel Mack 195429a34d7SDaniel Mack err = gpio_request_one(pdata->gpio_b, GPIOF_IN, dev_name(dev)); 1965deeac99SAndrew Clayton if (err) { 197429a34d7SDaniel Mack dev_err(dev, "unable to request GPIO %d\n", pdata->gpio_b); 1985deeac99SAndrew Clayton goto exit_free_gpio_a; 1995deeac99SAndrew Clayton } 2005deeac99SAndrew Clayton 201a78769b8SDaniel Mack encoder->irq_a = gpio_to_irq(pdata->gpio_a); 202a78769b8SDaniel Mack encoder->irq_b = gpio_to_irq(pdata->gpio_b); 203a78769b8SDaniel Mack 20473969ff0SDaniel Mack /* request the IRQs */ 205e70bdd41SJohan Hovold if (pdata->half_period) { 206e70bdd41SJohan Hovold handler = &rotary_encoder_half_period_irq; 207e70bdd41SJohan Hovold encoder->last_stable = rotary_encoder_get_state(pdata); 208e70bdd41SJohan Hovold } else { 209e70bdd41SJohan Hovold handler = &rotary_encoder_irq; 210e70bdd41SJohan Hovold } 211e70bdd41SJohan Hovold 212e70bdd41SJohan Hovold err = request_irq(encoder->irq_a, handler, 213e0d5f4c3SAlexander Stein IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 21473969ff0SDaniel Mack DRV_NAME, encoder); 21573969ff0SDaniel Mack if (err) { 216429a34d7SDaniel Mack dev_err(dev, "unable to request IRQ %d\n", encoder->irq_a); 21773969ff0SDaniel Mack goto exit_free_gpio_b; 21873969ff0SDaniel Mack } 21973969ff0SDaniel Mack 220e70bdd41SJohan Hovold err = request_irq(encoder->irq_b, handler, 221e0d5f4c3SAlexander Stein IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 22273969ff0SDaniel Mack DRV_NAME, encoder); 22373969ff0SDaniel Mack if (err) { 224429a34d7SDaniel Mack dev_err(dev, "unable to request IRQ %d\n", encoder->irq_b); 22573969ff0SDaniel Mack goto exit_free_irq_a; 22673969ff0SDaniel Mack } 22773969ff0SDaniel Mack 22873969ff0SDaniel Mack platform_set_drvdata(pdev, encoder); 22973969ff0SDaniel Mack 23073969ff0SDaniel Mack return 0; 23173969ff0SDaniel Mack 23273969ff0SDaniel Mack exit_free_irq_a: 23373969ff0SDaniel Mack free_irq(encoder->irq_a, encoder); 23473969ff0SDaniel Mack exit_free_gpio_b: 23573969ff0SDaniel Mack gpio_free(pdata->gpio_b); 23673969ff0SDaniel Mack exit_free_gpio_a: 23773969ff0SDaniel Mack gpio_free(pdata->gpio_a); 23873969ff0SDaniel Mack exit_unregister_input: 23973969ff0SDaniel Mack input_unregister_device(input); 24073969ff0SDaniel Mack input = NULL; /* so we don't try to free it */ 24173969ff0SDaniel Mack exit_free_mem: 24273969ff0SDaniel Mack input_free_device(input); 24373969ff0SDaniel Mack kfree(encoder); 24473969ff0SDaniel Mack return err; 24573969ff0SDaniel Mack } 24673969ff0SDaniel Mack 24773969ff0SDaniel Mack static int __devexit rotary_encoder_remove(struct platform_device *pdev) 24873969ff0SDaniel Mack { 24973969ff0SDaniel Mack struct rotary_encoder *encoder = platform_get_drvdata(pdev); 250ce919537SDmitry Torokhov const struct rotary_encoder_platform_data *pdata = encoder->pdata; 25173969ff0SDaniel Mack 25273969ff0SDaniel Mack free_irq(encoder->irq_a, encoder); 25373969ff0SDaniel Mack free_irq(encoder->irq_b, encoder); 25473969ff0SDaniel Mack gpio_free(pdata->gpio_a); 25573969ff0SDaniel Mack gpio_free(pdata->gpio_b); 25673969ff0SDaniel Mack input_unregister_device(encoder->input); 25773969ff0SDaniel Mack platform_set_drvdata(pdev, NULL); 25873969ff0SDaniel Mack kfree(encoder); 25973969ff0SDaniel Mack 26073969ff0SDaniel Mack return 0; 26173969ff0SDaniel Mack } 26273969ff0SDaniel Mack 26373969ff0SDaniel Mack static struct platform_driver rotary_encoder_driver = { 26473969ff0SDaniel Mack .probe = rotary_encoder_probe, 26573969ff0SDaniel Mack .remove = __devexit_p(rotary_encoder_remove), 26673969ff0SDaniel Mack .driver = { 26773969ff0SDaniel Mack .name = DRV_NAME, 26873969ff0SDaniel Mack .owner = THIS_MODULE, 26973969ff0SDaniel Mack } 27073969ff0SDaniel Mack }; 271840a746bSJJ Ding module_platform_driver(rotary_encoder_driver); 27273969ff0SDaniel Mack 27373969ff0SDaniel Mack MODULE_ALIAS("platform:" DRV_NAME); 27473969ff0SDaniel Mack MODULE_DESCRIPTION("GPIO rotary encoder driver"); 275e70bdd41SJohan Hovold MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>, Johan Hovold"); 27673969ff0SDaniel Mack MODULE_LICENSE("GPL v2"); 277