diff options
author | Johan Hovold <jhovold@gmail.com> | 2011-05-11 19:35:30 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2011-05-12 11:28:47 -0400 |
commit | e70bdd41bd0ead91b4a43e9d656ac1569d7c8779 (patch) | |
tree | 9518f22417dde4f2b2d2ed3a25af8bc8f4e3814c | |
parent | 521a8f5cb79d1017d00d26143227159674e3b79d (diff) |
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>
-rw-r--r-- | Documentation/input/rotary-encoder.txt | 13 | ||||
-rw-r--r-- | drivers/input/misc/rotary_encoder.c | 42 | ||||
-rw-r--r-- | include/linux/rotary_encoder.h | 1 |
3 files changed, 53 insertions, 3 deletions
diff --git a/Documentation/input/rotary-encoder.txt b/Documentation/input/rotary-encoder.txt index 943e8f6f2b15..92e68bce13a4 100644 --- a/Documentation/input/rotary-encoder.txt +++ b/Documentation/input/rotary-encoder.txt | |||
@@ -9,6 +9,9 @@ peripherals with two wires. The outputs are phase-shifted by 90 degrees | |||
9 | and by triggering on falling and rising edges, the turn direction can | 9 | and by triggering on falling and rising edges, the turn direction can |
10 | be determined. | 10 | be determined. |
11 | 11 | ||
12 | Some encoders have both outputs low in stable states, whereas others also have | ||
13 | a stable state with both outputs high (half-period mode). | ||
14 | |||
12 | The phase diagram of these two outputs look like this: | 15 | The phase diagram of these two outputs look like this: |
13 | 16 | ||
14 | _____ _____ _____ | 17 | _____ _____ _____ |
@@ -26,6 +29,8 @@ The phase diagram of these two outputs look like this: | |||
26 | |<-------->| | 29 | |<-------->| |
27 | one step | 30 | one step |
28 | 31 | ||
32 | |<-->| | ||
33 | one step (half-period mode) | ||
29 | 34 | ||
30 | For more information, please see | 35 | For more information, please see |
31 | http://en.wikipedia.org/wiki/Rotary_encoder | 36 | http://en.wikipedia.org/wiki/Rotary_encoder |
@@ -34,6 +39,13 @@ For more information, please see | |||
34 | 1. Events / state machine | 39 | 1. Events / state machine |
35 | ------------------------- | 40 | ------------------------- |
36 | 41 | ||
42 | In half-period mode, state a) and c) above are used to determine the | ||
43 | rotational direction based on the last stable state. Events are reported in | ||
44 | states b) and d) given that the new stable state is different from the last | ||
45 | (i.e. the rotation was not reversed half-way). | ||
46 | |||
47 | Otherwise, the following apply: | ||
48 | |||
37 | a) Rising edge on channel A, channel B in low state | 49 | a) Rising edge on channel A, channel B in low state |
38 | This state is used to recognize a clockwise turn | 50 | This state is used to recognize a clockwise turn |
39 | 51 | ||
@@ -96,6 +108,7 @@ static struct rotary_encoder_platform_data my_rotary_encoder_info = { | |||
96 | .gpio_b = GPIO_ROTARY_B, | 108 | .gpio_b = GPIO_ROTARY_B, |
97 | .inverted_a = 0, | 109 | .inverted_a = 0, |
98 | .inverted_b = 0, | 110 | .inverted_b = 0, |
111 | .half_period = false, | ||
99 | }; | 112 | }; |
100 | 113 | ||
101 | static struct platform_device rotary_encoder_device = { | 114 | static struct platform_device rotary_encoder_device = { |
diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index 077b80bdca69..2c8b84dd9dac 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * rotary_encoder.c | 2 | * rotary_encoder.c |
3 | * | 3 | * |
4 | * (c) 2009 Daniel Mack <daniel@caiaq.de> | 4 | * (c) 2009 Daniel Mack <daniel@caiaq.de> |
5 | * Copyright (C) 2011 Johan Hovold <jhovold@gmail.com> | ||
5 | * | 6 | * |
6 | * state machine code inspired by code from Tim Ruetz | 7 | * state machine code inspired by code from Tim Ruetz |
7 | * | 8 | * |
@@ -38,6 +39,8 @@ struct rotary_encoder { | |||
38 | 39 | ||
39 | bool armed; | 40 | bool armed; |
40 | unsigned char dir; /* 0 - clockwise, 1 - CCW */ | 41 | unsigned char dir; /* 0 - clockwise, 1 - CCW */ |
42 | |||
43 | char last_stable; | ||
41 | }; | 44 | }; |
42 | 45 | ||
43 | static int rotary_encoder_get_state(struct rotary_encoder_platform_data *pdata) | 46 | 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 | return IRQ_HANDLED; | 115 | return IRQ_HANDLED; |
113 | } | 116 | } |
114 | 117 | ||
118 | static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id) | ||
119 | { | ||
120 | struct rotary_encoder *encoder = dev_id; | ||
121 | int state; | ||
122 | |||
123 | state = rotary_encoder_get_state(encoder->pdata); | ||
124 | |||
125 | switch (state) { | ||
126 | case 0x00: | ||
127 | case 0x03: | ||
128 | if (state != encoder->last_stable) { | ||
129 | rotary_encoder_report_event(encoder); | ||
130 | encoder->last_stable = state; | ||
131 | } | ||
132 | break; | ||
133 | |||
134 | case 0x01: | ||
135 | case 0x02: | ||
136 | encoder->dir = (encoder->last_stable + state) & 0x01; | ||
137 | break; | ||
138 | } | ||
139 | |||
140 | return IRQ_HANDLED; | ||
141 | } | ||
142 | |||
115 | static int __devinit rotary_encoder_probe(struct platform_device *pdev) | 143 | static int __devinit rotary_encoder_probe(struct platform_device *pdev) |
116 | { | 144 | { |
117 | struct rotary_encoder_platform_data *pdata = pdev->dev.platform_data; | 145 | struct rotary_encoder_platform_data *pdata = pdev->dev.platform_data; |
118 | struct rotary_encoder *encoder; | 146 | struct rotary_encoder *encoder; |
119 | struct input_dev *input; | 147 | struct input_dev *input; |
148 | irq_handler_t handler; | ||
120 | int err; | 149 | int err; |
121 | 150 | ||
122 | if (!pdata) { | 151 | if (!pdata) { |
@@ -187,7 +216,14 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev) | |||
187 | } | 216 | } |
188 | 217 | ||
189 | /* request the IRQs */ | 218 | /* request the IRQs */ |
190 | err = request_irq(encoder->irq_a, &rotary_encoder_irq, | 219 | if (pdata->half_period) { |
220 | handler = &rotary_encoder_half_period_irq; | ||
221 | encoder->last_stable = rotary_encoder_get_state(pdata); | ||
222 | } else { | ||
223 | handler = &rotary_encoder_irq; | ||
224 | } | ||
225 | |||
226 | err = request_irq(encoder->irq_a, handler, | ||
191 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, | 227 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, |
192 | DRV_NAME, encoder); | 228 | DRV_NAME, encoder); |
193 | if (err) { | 229 | if (err) { |
@@ -196,7 +232,7 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev) | |||
196 | goto exit_free_gpio_b; | 232 | goto exit_free_gpio_b; |
197 | } | 233 | } |
198 | 234 | ||
199 | err = request_irq(encoder->irq_b, &rotary_encoder_irq, | 235 | err = request_irq(encoder->irq_b, handler, |
200 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, | 236 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, |
201 | DRV_NAME, encoder); | 237 | DRV_NAME, encoder); |
202 | if (err) { | 238 | if (err) { |
@@ -264,5 +300,5 @@ module_exit(rotary_encoder_exit); | |||
264 | 300 | ||
265 | MODULE_ALIAS("platform:" DRV_NAME); | 301 | MODULE_ALIAS("platform:" DRV_NAME); |
266 | MODULE_DESCRIPTION("GPIO rotary encoder driver"); | 302 | MODULE_DESCRIPTION("GPIO rotary encoder driver"); |
267 | MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); | 303 | MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>, Johan Hovold"); |
268 | MODULE_LICENSE("GPL v2"); | 304 | MODULE_LICENSE("GPL v2"); |
diff --git a/include/linux/rotary_encoder.h b/include/linux/rotary_encoder.h index 215278b8df2a..3f594dce5716 100644 --- a/include/linux/rotary_encoder.h +++ b/include/linux/rotary_encoder.h | |||
@@ -10,6 +10,7 @@ struct rotary_encoder_platform_data { | |||
10 | unsigned int inverted_b; | 10 | unsigned int inverted_b; |
11 | bool relative_axis; | 11 | bool relative_axis; |
12 | bool rollover; | 12 | bool rollover; |
13 | bool half_period; | ||
13 | }; | 14 | }; |
14 | 15 | ||
15 | #endif /* __ROTARY_ENCODER_H__ */ | 16 | #endif /* __ROTARY_ENCODER_H__ */ |