aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hovold <jhovold@gmail.com>2011-05-11 19:35:30 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2011-05-12 11:28:47 -0400
commite70bdd41bd0ead91b4a43e9d656ac1569d7c8779 (patch)
tree9518f22417dde4f2b2d2ed3a25af8bc8f4e3814c
parent521a8f5cb79d1017d00d26143227159674e3b79d (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.txt13
-rw-r--r--drivers/input/misc/rotary_encoder.c42
-rw-r--r--include/linux/rotary_encoder.h1
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
9and by triggering on falling and rising edges, the turn direction can 9and by triggering on falling and rising edges, the turn direction can
10be determined. 10be determined.
11 11
12Some encoders have both outputs low in stable states, whereas others also have
13a stable state with both outputs high (half-period mode).
14
12The phase diagram of these two outputs look like this: 15The 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
30For more information, please see 35For 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
341. Events / state machine 391. Events / state machine
35------------------------- 40-------------------------
36 41
42In half-period mode, state a) and c) above are used to determine the
43rotational direction based on the last stable state. Events are reported in
44states 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
47Otherwise, the following apply:
48
37a) Rising edge on channel A, channel B in low state 49a) 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
101static struct platform_device rotary_encoder_device = { 114static 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
43static int rotary_encoder_get_state(struct rotary_encoder_platform_data *pdata) 46static 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
118static 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
115static int __devinit rotary_encoder_probe(struct platform_device *pdev) 143static 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
265MODULE_ALIAS("platform:" DRV_NAME); 301MODULE_ALIAS("platform:" DRV_NAME);
266MODULE_DESCRIPTION("GPIO rotary encoder driver"); 302MODULE_DESCRIPTION("GPIO rotary encoder driver");
267MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); 303MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>, Johan Hovold");
268MODULE_LICENSE("GPL v2"); 304MODULE_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__ */