Skip to content

Commit

Permalink
Input: rotary-encoder - add support for half-period encoders
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Johan Hovold authored and Dmitry Torokhov committed May 12, 2011
1 parent 521a8f5 commit e70bdd4
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 3 deletions.
13 changes: 13 additions & 0 deletions Documentation/input/rotary-encoder.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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:

_____ _____ _____
Expand All @@ -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
Expand All @@ -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

Expand Down Expand Up @@ -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 = {
Expand Down
42 changes: 39 additions & 3 deletions drivers/input/misc/rotary_encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand All @@ -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) {
Expand Down Expand Up @@ -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");
1 change: 1 addition & 0 deletions include/linux/rotary_encoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__ */

0 comments on commit e70bdd4

Please sign in to comment.