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