Input: rotary-encoder - add support for half-period encoders

Add support for encoders that have two detents per input signal period.

Signed-off-by: Johan Hovold <jhovold@gmail.com>
Acked-by: Daniel Mack <zonque@gmail.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
This commit is contained in:
Johan Hovold 2011-05-11 16:35:30 -07:00 committed by Dmitry Torokhov
parent 521a8f5cb7
commit e70bdd41bd
3 changed files with 53 additions and 3 deletions

View File

@ -9,6 +9,9 @@ peripherals with two wires. The outputs are phase-shifted by 90 degrees
and by triggering on falling and rising edges, the turn direction can
be determined.
Some encoders have both outputs low in stable states, whereas others also have
a stable state with both outputs high (half-period mode).
The phase diagram of these two outputs look like this:
_____ _____ _____
@ -26,6 +29,8 @@ The phase diagram of these two outputs look like this:
|<-------->|
one step
|<-->|
one step (half-period mode)
For more information, please see
http://en.wikipedia.org/wiki/Rotary_encoder
@ -34,6 +39,13 @@ For more information, please see
1. Events / state machine
-------------------------
In half-period mode, state a) and c) above are used to determine the
rotational direction based on the last stable state. Events are reported in
states b) and d) given that the new stable state is different from the last
(i.e. the rotation was not reversed half-way).
Otherwise, the following apply:
a) Rising edge on channel A, channel B in low state
This state is used to recognize a clockwise turn
@ -96,6 +108,7 @@ static struct rotary_encoder_platform_data my_rotary_encoder_info = {
.gpio_b = GPIO_ROTARY_B,
.inverted_a = 0,
.inverted_b = 0,
.half_period = false,
};
static struct platform_device rotary_encoder_device = {

View File

@ -2,6 +2,7 @@
* rotary_encoder.c
*
* (c) 2009 Daniel Mack <daniel@caiaq.de>
* Copyright (C) 2011 Johan Hovold <jhovold@gmail.com>
*
* state machine code inspired by code from Tim Ruetz
*
@ -38,6 +39,8 @@ struct rotary_encoder {
bool armed;
unsigned char dir; /* 0 - clockwise, 1 - CCW */
char last_stable;
};
static int rotary_encoder_get_state(struct rotary_encoder_platform_data *pdata)
@ -112,11 +115,37 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
{
struct rotary_encoder *encoder = dev_id;
int state;
state = rotary_encoder_get_state(encoder->pdata);
switch (state) {
case 0x00:
case 0x03:
if (state != encoder->last_stable) {
rotary_encoder_report_event(encoder);
encoder->last_stable = state;
}
break;
case 0x01:
case 0x02:
encoder->dir = (encoder->last_stable + state) & 0x01;
break;
}
return IRQ_HANDLED;
}
static int __devinit rotary_encoder_probe(struct platform_device *pdev)
{
struct rotary_encoder_platform_data *pdata = pdev->dev.platform_data;
struct rotary_encoder *encoder;
struct input_dev *input;
irq_handler_t handler;
int err;
if (!pdata) {
@ -187,7 +216,14 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
}
/* request the IRQs */
err = request_irq(encoder->irq_a, &rotary_encoder_irq,
if (pdata->half_period) {
handler = &rotary_encoder_half_period_irq;
encoder->last_stable = rotary_encoder_get_state(pdata);
} else {
handler = &rotary_encoder_irq;
}
err = request_irq(encoder->irq_a, handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
DRV_NAME, encoder);
if (err) {
@ -196,7 +232,7 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
goto exit_free_gpio_b;
}
err = request_irq(encoder->irq_b, &rotary_encoder_irq,
err = request_irq(encoder->irq_b, handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
DRV_NAME, encoder);
if (err) {
@ -264,5 +300,5 @@ module_exit(rotary_encoder_exit);
MODULE_ALIAS("platform:" DRV_NAME);
MODULE_DESCRIPTION("GPIO rotary encoder driver");
MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>, Johan Hovold");
MODULE_LICENSE("GPL v2");

View File

@ -10,6 +10,7 @@ struct rotary_encoder_platform_data {
unsigned int inverted_b;
bool relative_axis;
bool rollover;
bool half_period;
};
#endif /* __ROTARY_ENCODER_H__ */