Input: rotary_encoder - move away from platform data structure
[deliverable/linux.git] / drivers / input / misc / rotary_encoder.c
CommitLineData
73969ff0
DM
1/*
2 * rotary_encoder.c
3 *
4 * (c) 2009 Daniel Mack <daniel@caiaq.de>
e70bdd41 5 * Copyright (C) 2011 Johan Hovold <jhovold@gmail.com>
73969ff0
DM
6 *
7 * state machine code inspired by code from Tim Ruetz
8 *
9 * A generic driver for rotary encoders connected to GPIO lines.
395cf969 10 * See file:Documentation/input/rotary-encoder.txt for more information
73969ff0
DM
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 */
16
17#include <linux/kernel.h>
18#include <linux/module.h>
73969ff0
DM
19#include <linux/interrupt.h>
20#include <linux/input.h>
21#include <linux/device.h>
22#include <linux/platform_device.h>
77a8f0ad 23#include <linux/gpio/consumer.h>
5a0e3ad6 24#include <linux/slab.h>
2e45e539 25#include <linux/of.h>
47ec6e5a 26#include <linux/pm.h>
a9e340dc 27#include <linux/property.h>
73969ff0
DM
28
29#define DRV_NAME "rotary-encoder"
30
31struct rotary_encoder {
73969ff0 32 struct input_dev *input;
a9e340dc 33
dee520e3 34 struct mutex access_mutex;
bd3ce655 35
a9e340dc
DT
36 u32 steps;
37 u32 axis;
38 bool relative_axis;
39 bool rollover;
40
bd3ce655
HS
41 unsigned int pos;
42
77a8f0ad
DT
43 struct gpio_desc *gpio_a;
44 struct gpio_desc *gpio_b;
45
bd3ce655
HS
46 unsigned int irq_a;
47 unsigned int irq_b;
48
49 bool armed;
50 unsigned char dir; /* 0 - clockwise, 1 - CCW */
e70bdd41
JH
51
52 char last_stable;
73969ff0
DM
53};
54
77a8f0ad 55static int rotary_encoder_get_state(struct rotary_encoder *encoder)
73969ff0 56{
77a8f0ad
DT
57 int a = !!gpiod_get_value_cansleep(encoder->gpio_a);
58 int b = !!gpiod_get_value_cansleep(encoder->gpio_b);
73969ff0 59
521a8f5c
JH
60 return ((a << 1) | b);
61}
73969ff0 62
521a8f5c
JH
63static void rotary_encoder_report_event(struct rotary_encoder *encoder)
64{
a9e340dc 65 if (encoder->relative_axis) {
521a8f5c 66 input_report_rel(encoder->input,
a9e340dc 67 encoder->axis, encoder->dir ? -1 : 1);
521a8f5c
JH
68 } else {
69 unsigned int pos = encoder->pos;
70
71 if (encoder->dir) {
72 /* turning counter-clockwise */
a9e340dc
DT
73 if (encoder->rollover)
74 pos += encoder->steps;
521a8f5c
JH
75 if (pos)
76 pos--;
77 } else {
78 /* turning clockwise */
a9e340dc 79 if (encoder->rollover || pos < encoder->steps)
521a8f5c 80 pos++;
73969ff0 81 }
73969ff0 82
a9e340dc
DT
83 if (encoder->rollover)
84 pos %= encoder->steps;
521a8f5c
JH
85
86 encoder->pos = pos;
a9e340dc 87 input_report_abs(encoder->input, encoder->axis, encoder->pos);
521a8f5c
JH
88 }
89
90 input_sync(encoder->input);
91}
92
93static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
94{
95 struct rotary_encoder *encoder = dev_id;
96 int state;
97
dee520e3
TT
98 mutex_lock(&encoder->access_mutex);
99
77a8f0ad 100 state = rotary_encoder_get_state(encoder);
521a8f5c
JH
101
102 switch (state) {
103 case 0x0:
104 if (encoder->armed) {
105 rotary_encoder_report_event(encoder);
106 encoder->armed = false;
107 }
73969ff0
DM
108 break;
109
110 case 0x1:
111 case 0x2:
112 if (encoder->armed)
113 encoder->dir = state - 1;
114 break;
115
116 case 0x3:
bd3ce655 117 encoder->armed = true;
73969ff0
DM
118 break;
119 }
120
dee520e3
TT
121 mutex_unlock(&encoder->access_mutex);
122
73969ff0
DM
123 return IRQ_HANDLED;
124}
125
e70bdd41
JH
126static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
127{
128 struct rotary_encoder *encoder = dev_id;
129 int state;
130
dee520e3
TT
131 mutex_lock(&encoder->access_mutex);
132
77a8f0ad 133 state = rotary_encoder_get_state(encoder);
e70bdd41
JH
134
135 switch (state) {
136 case 0x00:
137 case 0x03:
138 if (state != encoder->last_stable) {
139 rotary_encoder_report_event(encoder);
140 encoder->last_stable = state;
141 }
142 break;
143
144 case 0x01:
145 case 0x02:
146 encoder->dir = (encoder->last_stable + state) & 0x01;
147 break;
148 }
149
dee520e3
TT
150 mutex_unlock(&encoder->access_mutex);
151
e70bdd41
JH
152 return IRQ_HANDLED;
153}
154
3a341a4c
EG
155static irqreturn_t rotary_encoder_quarter_period_irq(int irq, void *dev_id)
156{
157 struct rotary_encoder *encoder = dev_id;
158 unsigned char sum;
159 int state;
160
dee520e3
TT
161 mutex_lock(&encoder->access_mutex);
162
77a8f0ad 163 state = rotary_encoder_get_state(encoder);
3a341a4c
EG
164
165 /*
166 * We encode the previous and the current state using a byte.
167 * The previous state in the MSB nibble, the current state in the LSB
168 * nibble. Then use a table to decide the direction of the turn.
169 */
170 sum = (encoder->last_stable << 4) + state;
171 switch (sum) {
172 case 0x31:
173 case 0x10:
174 case 0x02:
175 case 0x23:
176 encoder->dir = 0; /* clockwise */
177 break;
178
179 case 0x13:
180 case 0x01:
181 case 0x20:
182 case 0x32:
183 encoder->dir = 1; /* counter-clockwise */
184 break;
185
186 default:
187 /*
188 * Ignore all other values. This covers the case when the
189 * state didn't change (a spurious interrupt) and the
190 * cases where the state changed by two steps, making it
191 * impossible to tell the direction.
192 *
193 * In either case, don't report any event and save the
194 * state for later.
195 */
196 goto out;
197 }
198
199 rotary_encoder_report_event(encoder);
200
201out:
202 encoder->last_stable = state;
dee520e3
TT
203 mutex_unlock(&encoder->access_mutex);
204
3a341a4c
EG
205 return IRQ_HANDLED;
206}
207
5298cc4c 208static int rotary_encoder_probe(struct platform_device *pdev)
73969ff0 209{
ce919537 210 struct device *dev = &pdev->dev;
73969ff0
DM
211 struct rotary_encoder *encoder;
212 struct input_dev *input;
e70bdd41 213 irq_handler_t handler;
a9e340dc 214 u32 steps_per_period;
73969ff0
DM
215 int err;
216
d9202af2
TT
217 encoder = devm_kzalloc(dev, sizeof(struct rotary_encoder), GFP_KERNEL);
218 if (!encoder)
219 return -ENOMEM;
220
77a8f0ad 221 mutex_init(&encoder->access_mutex);
a9e340dc
DT
222
223 device_property_read_u32(dev, "rotary-encoder,steps", &encoder->steps);
224
225 err = device_property_read_u32(dev, "rotary-encoder,steps-per-period",
226 &steps_per_period);
227 if (err) {
228 /*
229 * The 'half-period' property has been deprecated, you must
230 * use 'steps-per-period' and set an appropriate value, but
231 * we still need to parse it to maintain compatibility. If
232 * neither property is present we fall back to the one step
233 * per period behavior.
234 */
235 steps_per_period = device_property_read_bool(dev,
236 "rotary-encoder,half-period") ? 2 : 1;
237 }
238
239 encoder->rollover =
240 device_property_read_bool(dev, "rotary-encoder,rollover");
241
242 device_property_read_u32(dev, "linux,axis", &encoder->axis);
243 encoder->relative_axis =
244 device_property_read_bool(dev, "rotary-encoder,relative-axis");
77a8f0ad
DT
245
246 encoder->gpio_a = devm_gpiod_get_index(dev, NULL, 0, GPIOD_IN);
247 if (IS_ERR(encoder->gpio_a)) {
248 err = PTR_ERR(encoder->gpio_a);
249 dev_err(dev, "unable to get GPIO at index 0: %d\n", err);
250 return err;
251 }
252
253 encoder->irq_a = gpiod_to_irq(encoder->gpio_a);
254
255 encoder->gpio_b = devm_gpiod_get_index(dev, NULL, 1, GPIOD_IN);
256 if (IS_ERR(encoder->gpio_b)) {
257 err = PTR_ERR(encoder->gpio_b);
258 dev_err(dev, "unable to get GPIO at index 1: %d\n", err);
259 return err;
260 }
261
262 encoder->irq_b = gpiod_to_irq(encoder->gpio_b);
263
d9202af2
TT
264 input = devm_input_allocate_device(dev);
265 if (!input)
266 return -ENOMEM;
73969ff0
DM
267
268 encoder->input = input;
73969ff0 269
73969ff0
DM
270 input->name = pdev->name;
271 input->id.bustype = BUS_HOST;
80c99bcd 272 input->dev.parent = dev;
bd3ce655 273
a9e340dc
DT
274 if (encoder->relative_axis)
275 input_set_capability(input, EV_REL, encoder->axis);
8631580f 276 else
a9e340dc
DT
277 input_set_abs_params(input,
278 encoder->axis, 0, encoder->steps, 0, 1);
73969ff0 279
a9e340dc 280 switch (steps_per_period) {
3a341a4c
EG
281 case 4:
282 handler = &rotary_encoder_quarter_period_irq;
77a8f0ad 283 encoder->last_stable = rotary_encoder_get_state(encoder);
3a341a4c
EG
284 break;
285 case 2:
e70bdd41 286 handler = &rotary_encoder_half_period_irq;
77a8f0ad 287 encoder->last_stable = rotary_encoder_get_state(encoder);
3a341a4c
EG
288 break;
289 case 1:
e70bdd41 290 handler = &rotary_encoder_irq;
3a341a4c
EG
291 break;
292 default:
293 dev_err(dev, "'%d' is not a valid steps-per-period value\n",
a9e340dc 294 steps_per_period);
d9202af2 295 return -EINVAL;
e70bdd41
JH
296 }
297
dee520e3
TT
298 err = devm_request_threaded_irq(dev, encoder->irq_a, NULL, handler,
299 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
300 IRQF_ONESHOT,
301 DRV_NAME, encoder);
73969ff0 302 if (err) {
429a34d7 303 dev_err(dev, "unable to request IRQ %d\n", encoder->irq_a);
d9202af2 304 return err;
73969ff0
DM
305 }
306
dee520e3
TT
307 err = devm_request_threaded_irq(dev, encoder->irq_b, NULL, handler,
308 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
309 IRQF_ONESHOT,
310 DRV_NAME, encoder);
73969ff0 311 if (err) {
429a34d7 312 dev_err(dev, "unable to request IRQ %d\n", encoder->irq_b);
d9202af2 313 return err;
73969ff0
DM
314 }
315
80c99bcd
DM
316 err = input_register_device(input);
317 if (err) {
318 dev_err(dev, "failed to register input device\n");
d9202af2 319 return err;
80c99bcd
DM
320 }
321
a9e340dc
DT
322 device_init_wakeup(dev,
323 device_property_read_bool(dev, "wakeup-source"));
47ec6e5a 324
73969ff0
DM
325 platform_set_drvdata(pdev, encoder);
326
327 return 0;
73969ff0
DM
328}
329
6a6f70b3 330static int __maybe_unused rotary_encoder_suspend(struct device *dev)
47ec6e5a
SR
331{
332 struct rotary_encoder *encoder = dev_get_drvdata(dev);
333
334 if (device_may_wakeup(dev)) {
335 enable_irq_wake(encoder->irq_a);
336 enable_irq_wake(encoder->irq_b);
337 }
338
339 return 0;
340}
341
6a6f70b3 342static int __maybe_unused rotary_encoder_resume(struct device *dev)
47ec6e5a
SR
343{
344 struct rotary_encoder *encoder = dev_get_drvdata(dev);
345
346 if (device_may_wakeup(dev)) {
347 disable_irq_wake(encoder->irq_a);
348 disable_irq_wake(encoder->irq_b);
349 }
350
351 return 0;
352}
47ec6e5a
SR
353
354static SIMPLE_DEV_PM_OPS(rotary_encoder_pm_ops,
6a6f70b3 355 rotary_encoder_suspend, rotary_encoder_resume);
47ec6e5a 356
a9e340dc
DT
357#ifdef CONFIG_OF
358static const struct of_device_id rotary_encoder_of_match[] = {
359 { .compatible = "rotary-encoder", },
360 { },
361};
362MODULE_DEVICE_TABLE(of, rotary_encoder_of_match);
363#endif
364
73969ff0
DM
365static struct platform_driver rotary_encoder_driver = {
366 .probe = rotary_encoder_probe,
73969ff0
DM
367 .driver = {
368 .name = DRV_NAME,
47ec6e5a 369 .pm = &rotary_encoder_pm_ops,
80c99bcd 370 .of_match_table = of_match_ptr(rotary_encoder_of_match),
73969ff0
DM
371 }
372};
840a746b 373module_platform_driver(rotary_encoder_driver);
73969ff0
DM
374
375MODULE_ALIAS("platform:" DRV_NAME);
376MODULE_DESCRIPTION("GPIO rotary encoder driver");
e70bdd41 377MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>, Johan Hovold");
73969ff0 378MODULE_LICENSE("GPL v2");
This page took 0.27647 seconds and 5 git commands to generate.