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:
committed by
Dmitry Torokhov
parent
521a8f5cb7
commit
e70bdd41bd
@@ -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:
|
|||||||
|<-------->|
|
|<-------->|
|
||||||
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
|
|||||||
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 = {
|
|||||||
.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 @@
|
|||||||
* 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 {
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 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)
|
|||||||
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);
|
|||||||
|
|
||||||
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 {
|
|||||||
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__ */
|
||||||
|
Reference in New Issue
Block a user