aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/misc/rotary_encoder.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/misc/rotary_encoder.c')
-rw-r--r--drivers/input/misc/rotary_encoder.c119
1 files changed, 83 insertions, 36 deletions
diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c
index 7e64d01da2be..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,52 +39,66 @@ 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 irqreturn_t rotary_encoder_irq(int irq, void *dev_id) 46static int rotary_encoder_get_state(struct rotary_encoder_platform_data *pdata)
44{ 47{
45 struct rotary_encoder *encoder = dev_id;
46 struct rotary_encoder_platform_data *pdata = encoder->pdata;
47 int a = !!gpio_get_value(pdata->gpio_a); 48 int a = !!gpio_get_value(pdata->gpio_a);
48 int b = !!gpio_get_value(pdata->gpio_b); 49 int b = !!gpio_get_value(pdata->gpio_b);
49 int state;
50 50
51 a ^= pdata->inverted_a; 51 a ^= pdata->inverted_a;
52 b ^= pdata->inverted_b; 52 b ^= pdata->inverted_b;
53 state = (a << 1) | b;
54 53
55 switch (state) { 54 return ((a << 1) | b);
55}
56 56
57 case 0x0: 57static void rotary_encoder_report_event(struct rotary_encoder *encoder)
58 if (!encoder->armed) 58{
59 break; 59 struct rotary_encoder_platform_data *pdata = encoder->pdata;
60 60
61 if (pdata->relative_axis) { 61 if (pdata->relative_axis) {
62 input_report_rel(encoder->input, pdata->axis, 62 input_report_rel(encoder->input,
63 encoder->dir ? -1 : 1); 63 pdata->axis, encoder->dir ? -1 : 1);
64 } else { 64 } else {
65 unsigned int pos = encoder->pos; 65 unsigned int pos = encoder->pos;
66 66
67 if (encoder->dir) { 67 if (encoder->dir) {
68 /* turning counter-clockwise */ 68 /* turning counter-clockwise */
69 if (pdata->rollover)
70 pos += pdata->steps;
71 if (pos)
72 pos--;
73 } else {
74 /* turning clockwise */
75 if (pdata->rollover || pos < pdata->steps)
76 pos++;
77 }
78 if (pdata->rollover) 69 if (pdata->rollover)
79 pos %= pdata->steps; 70 pos += pdata->steps;
80 encoder->pos = pos; 71 if (pos)
81 input_report_abs(encoder->input, pdata->axis, 72 pos--;
82 encoder->pos); 73 } else {
74 /* turning clockwise */
75 if (pdata->rollover || pos < pdata->steps)
76 pos++;
83 } 77 }
84 input_sync(encoder->input);
85 78
86 encoder->armed = false; 79 if (pdata->rollover)
80 pos %= pdata->steps;
81
82 encoder->pos = pos;
83 input_report_abs(encoder->input, pdata->axis, encoder->pos);
84 }
85
86 input_sync(encoder->input);
87}
88
89static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
90{
91 struct rotary_encoder *encoder = dev_id;
92 int state;
93
94 state = rotary_encoder_get_state(encoder->pdata);
95
96 switch (state) {
97 case 0x0:
98 if (encoder->armed) {
99 rotary_encoder_report_event(encoder);
100 encoder->armed = false;
101 }
87 break; 102 break;
88 103
89 case 0x1: 104 case 0x1:
@@ -100,11 +115,37 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
100 return IRQ_HANDLED; 115 return IRQ_HANDLED;
101} 116}
102 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
103static int __devinit rotary_encoder_probe(struct platform_device *pdev) 143static int __devinit rotary_encoder_probe(struct platform_device *pdev)
104{ 144{
105 struct rotary_encoder_platform_data *pdata = pdev->dev.platform_data; 145 struct rotary_encoder_platform_data *pdata = pdev->dev.platform_data;
106 struct rotary_encoder *encoder; 146 struct rotary_encoder *encoder;
107 struct input_dev *input; 147 struct input_dev *input;
148 irq_handler_t handler;
108 int err; 149 int err;
109 150
110 if (!pdata) { 151 if (!pdata) {
@@ -175,7 +216,14 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
175 } 216 }
176 217
177 /* request the IRQs */ 218 /* request the IRQs */
178 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,
179 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 227 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
180 DRV_NAME, encoder); 228 DRV_NAME, encoder);
181 if (err) { 229 if (err) {
@@ -184,7 +232,7 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
184 goto exit_free_gpio_b; 232 goto exit_free_gpio_b;
185 } 233 }
186 234
187 err = request_irq(encoder->irq_b, &rotary_encoder_irq, 235 err = request_irq(encoder->irq_b, handler,
188 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 236 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
189 DRV_NAME, encoder); 237 DRV_NAME, encoder);
190 if (err) { 238 if (err) {
@@ -252,6 +300,5 @@ module_exit(rotary_encoder_exit);
252 300
253MODULE_ALIAS("platform:" DRV_NAME); 301MODULE_ALIAS("platform:" DRV_NAME);
254MODULE_DESCRIPTION("GPIO rotary encoder driver"); 302MODULE_DESCRIPTION("GPIO rotary encoder driver");
255MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); 303MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>, Johan Hovold");
256MODULE_LICENSE("GPL v2"); 304MODULE_LICENSE("GPL v2");
257