Commit e70bdd41 authored by Johan Hovold's avatar Johan Hovold Committed by Dmitry Torokhov

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

Add support for encoders that have two detents per input signal period.
Signed-off-by: default avatarJohan Hovold <jhovold@gmail.com>
Acked-by: default avatarDaniel Mack <zonque@gmail.com>
Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
parent 521a8f5c
...@@ -9,6 +9,9 @@ peripherals with two wires. The outputs are phase-shifted by 90 degrees ...@@ -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 and by triggering on falling and rising edges, the turn direction can
be determined. 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: The phase diagram of these two outputs look like this:
_____ _____ _____ _____ _____ _____
...@@ -26,6 +29,8 @@ 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
|<-->|
one step (half-period mode)
For more information, please see For more information, please see
http://en.wikipedia.org/wiki/Rotary_encoder http://en.wikipedia.org/wiki/Rotary_encoder
...@@ -34,6 +39,13 @@ For more information, please see ...@@ -34,6 +39,13 @@ For more information, please see
1. Events / state machine 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 a) Rising edge on channel A, channel B in low state
This state is used to recognize a clockwise turn This state is used to recognize a clockwise turn
...@@ -96,6 +108,7 @@ static struct rotary_encoder_platform_data my_rotary_encoder_info = { ...@@ -96,6 +108,7 @@ static struct rotary_encoder_platform_data my_rotary_encoder_info = {
.gpio_b = GPIO_ROTARY_B, .gpio_b = GPIO_ROTARY_B,
.inverted_a = 0, .inverted_a = 0,
.inverted_b = 0, .inverted_b = 0,
.half_period = false,
}; };
static struct platform_device rotary_encoder_device = { static struct platform_device rotary_encoder_device = {
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* rotary_encoder.c * rotary_encoder.c
* *
* (c) 2009 Daniel Mack <daniel@caiaq.de> * (c) 2009 Daniel Mack <daniel@caiaq.de>
* Copyright (C) 2011 Johan Hovold <jhovold@gmail.com>
* *
* state machine code inspired by code from Tim Ruetz * state machine code inspired by code from Tim Ruetz
* *
...@@ -38,6 +39,8 @@ struct rotary_encoder { ...@@ -38,6 +39,8 @@ struct rotary_encoder {
bool armed; bool armed;
unsigned char dir; /* 0 - clockwise, 1 - CCW */ unsigned char dir; /* 0 - clockwise, 1 - CCW */
char last_stable;
}; };
static int rotary_encoder_get_state(struct rotary_encoder_platform_data *pdata) 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) ...@@ -112,11 +115,37 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
return IRQ_HANDLED; 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) static int __devinit rotary_encoder_probe(struct platform_device *pdev)
{ {
struct rotary_encoder_platform_data *pdata = pdev->dev.platform_data; struct rotary_encoder_platform_data *pdata = pdev->dev.platform_data;
struct rotary_encoder *encoder; struct rotary_encoder *encoder;
struct input_dev *input; struct input_dev *input;
irq_handler_t handler;
int err; int err;
if (!pdata) { if (!pdata) {
...@@ -187,7 +216,14 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev) ...@@ -187,7 +216,14 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
} }
/* request the IRQs */ /* 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, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
DRV_NAME, encoder); DRV_NAME, encoder);
if (err) { if (err) {
...@@ -196,7 +232,7 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev) ...@@ -196,7 +232,7 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
goto exit_free_gpio_b; 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, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
DRV_NAME, encoder); DRV_NAME, encoder);
if (err) { if (err) {
...@@ -264,5 +300,5 @@ module_exit(rotary_encoder_exit); ...@@ -264,5 +300,5 @@ module_exit(rotary_encoder_exit);
MODULE_ALIAS("platform:" DRV_NAME); MODULE_ALIAS("platform:" DRV_NAME);
MODULE_DESCRIPTION("GPIO rotary encoder driver"); 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"); MODULE_LICENSE("GPL v2");
...@@ -10,6 +10,7 @@ struct rotary_encoder_platform_data { ...@@ -10,6 +10,7 @@ struct rotary_encoder_platform_data {
unsigned int inverted_b; unsigned int inverted_b;
bool relative_axis; bool relative_axis;
bool rollover; bool rollover;
bool half_period;
}; };
#endif /* __ROTARY_ENCODER_H__ */ #endif /* __ROTARY_ENCODER_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment