blob: 56e91fdc35e365092d47ac61b82f16b231ce0985 [file] [log] [blame]
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -07001/* drivers/input/misc/gpio_matrix.c
2 *
3 * Copyright (C) 2007 Google, Inc.
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 */
15
16#include <linux/kernel.h>
17#include <linux/gpio.h>
18#include <linux/gpio_event.h>
19#include <linux/hrtimer.h>
20#include <linux/interrupt.h>
21#include <linux/slab.h>
22#include <linux/wakelock.h>
23
24struct gpio_kp {
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -070025 struct gpio_event_input_devs *input_devs;
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -070026 struct gpio_event_matrix_info *keypad_info;
27 struct hrtimer timer;
28 struct wake_lock wake_lock;
29 int current_output;
30 unsigned int use_irq:1;
31 unsigned int key_state_changed:1;
32 unsigned int last_key_state_changed:1;
33 unsigned int some_keys_pressed:2;
Dima Zavin23119372010-04-09 23:26:09 -070034 unsigned int disabled_irq:1;
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -070035 unsigned long keys_pressed[0];
36};
37
38static void clear_phantom_key(struct gpio_kp *kp, int out, int in)
39{
40 struct gpio_event_matrix_info *mi = kp->keypad_info;
41 int key_index = out * mi->ninputs + in;
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -070042 unsigned short keyentry = mi->keymap[key_index];
43 unsigned short keycode = keyentry & MATRIX_KEY_MASK;
44 unsigned short dev = keyentry >> MATRIX_CODE_BITS;
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -070045
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -070046 if (!test_bit(keycode, kp->input_devs->dev[dev]->key)) {
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -070047 if (mi->flags & GPIOKPF_PRINT_PHANTOM_KEYS)
48 pr_info("gpiomatrix: phantom key %x, %d-%d (%d-%d) "
49 "cleared\n", keycode, out, in,
50 mi->output_gpios[out], mi->input_gpios[in]);
51 __clear_bit(key_index, kp->keys_pressed);
52 } else {
53 if (mi->flags & GPIOKPF_PRINT_PHANTOM_KEYS)
54 pr_info("gpiomatrix: phantom key %x, %d-%d (%d-%d) "
55 "not cleared\n", keycode, out, in,
56 mi->output_gpios[out], mi->input_gpios[in]);
57 }
58}
59
60static int restore_keys_for_input(struct gpio_kp *kp, int out, int in)
61{
62 int rv = 0;
63 int key_index;
64
65 key_index = out * kp->keypad_info->ninputs + in;
66 while (out < kp->keypad_info->noutputs) {
67 if (test_bit(key_index, kp->keys_pressed)) {
68 rv = 1;
69 clear_phantom_key(kp, out, in);
70 }
71 key_index += kp->keypad_info->ninputs;
72 out++;
73 }
74 return rv;
75}
76
77static void remove_phantom_keys(struct gpio_kp *kp)
78{
79 int out, in, inp;
80 int key_index;
81
82 if (kp->some_keys_pressed < 3)
83 return;
84
85 for (out = 0; out < kp->keypad_info->noutputs; out++) {
86 inp = -1;
87 key_index = out * kp->keypad_info->ninputs;
88 for (in = 0; in < kp->keypad_info->ninputs; in++, key_index++) {
89 if (test_bit(key_index, kp->keys_pressed)) {
90 if (inp == -1) {
91 inp = in;
92 continue;
93 }
94 if (inp >= 0) {
95 if (!restore_keys_for_input(kp, out + 1,
96 inp))
97 break;
98 clear_phantom_key(kp, out, inp);
99 inp = -2;
100 }
101 restore_keys_for_input(kp, out, in);
102 }
103 }
104 }
105}
106
107static void report_key(struct gpio_kp *kp, int key_index, int out, int in)
108{
109 struct gpio_event_matrix_info *mi = kp->keypad_info;
110 int pressed = test_bit(key_index, kp->keys_pressed);
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -0700111 unsigned short keyentry = mi->keymap[key_index];
112 unsigned short keycode = keyentry & MATRIX_KEY_MASK;
113 unsigned short dev = keyentry >> MATRIX_CODE_BITS;
114
115 if (pressed != test_bit(keycode, kp->input_devs->dev[dev]->key)) {
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700116 if (keycode == KEY_RESERVED) {
117 if (mi->flags & GPIOKPF_PRINT_UNMAPPED_KEYS)
118 pr_info("gpiomatrix: unmapped key, %d-%d "
119 "(%d-%d) changed to %d\n",
120 out, in, mi->output_gpios[out],
121 mi->input_gpios[in], pressed);
122 } else {
123 if (mi->flags & GPIOKPF_PRINT_MAPPED_KEYS)
124 pr_info("gpiomatrix: key %x, %d-%d (%d-%d) "
125 "changed to %d\n", keycode,
126 out, in, mi->output_gpios[out],
127 mi->input_gpios[in], pressed);
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -0700128 input_report_key(kp->input_devs->dev[dev], keycode, pressed);
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700129 }
130 }
131}
132
Jeff Brownbe4cb212011-03-18 14:10:23 -0700133static void report_sync(struct gpio_kp *kp)
134{
135 int i;
136
137 for (i = 0; i < kp->input_devs->count; i++)
138 input_sync(kp->input_devs->dev[i]);
139}
140
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700141static enum hrtimer_restart gpio_keypad_timer_func(struct hrtimer *timer)
142{
143 int out, in;
144 int key_index;
145 int gpio;
146 struct gpio_kp *kp = container_of(timer, struct gpio_kp, timer);
147 struct gpio_event_matrix_info *mi = kp->keypad_info;
148 unsigned gpio_keypad_flags = mi->flags;
149 unsigned polarity = !!(gpio_keypad_flags & GPIOKPF_ACTIVE_HIGH);
150
151 out = kp->current_output;
152 if (out == mi->noutputs) {
153 out = 0;
154 kp->last_key_state_changed = kp->key_state_changed;
155 kp->key_state_changed = 0;
156 kp->some_keys_pressed = 0;
157 } else {
158 key_index = out * mi->ninputs;
159 for (in = 0; in < mi->ninputs; in++, key_index++) {
160 gpio = mi->input_gpios[in];
161 if (gpio_get_value(gpio) ^ !polarity) {
162 if (kp->some_keys_pressed < 3)
163 kp->some_keys_pressed++;
164 kp->key_state_changed |= !__test_and_set_bit(
165 key_index, kp->keys_pressed);
166 } else
167 kp->key_state_changed |= __test_and_clear_bit(
168 key_index, kp->keys_pressed);
169 }
170 gpio = mi->output_gpios[out];
171 if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE)
172 gpio_set_value(gpio, !polarity);
173 else
174 gpio_direction_input(gpio);
175 out++;
176 }
177 kp->current_output = out;
178 if (out < mi->noutputs) {
179 gpio = mi->output_gpios[out];
180 if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE)
181 gpio_set_value(gpio, polarity);
182 else
183 gpio_direction_output(gpio, polarity);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700184 hrtimer_start(timer, timespec_to_ktime(mi->settle_time),
185 HRTIMER_MODE_REL);
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700186 return HRTIMER_NORESTART;
187 }
188 if (gpio_keypad_flags & GPIOKPF_DEBOUNCE) {
189 if (kp->key_state_changed) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700190 hrtimer_start(&kp->timer,
191 timespec_to_ktime(mi->debounce_delay),
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700192 HRTIMER_MODE_REL);
193 return HRTIMER_NORESTART;
194 }
195 kp->key_state_changed = kp->last_key_state_changed;
196 }
197 if (kp->key_state_changed) {
198 if (gpio_keypad_flags & GPIOKPF_REMOVE_SOME_PHANTOM_KEYS)
199 remove_phantom_keys(kp);
200 key_index = 0;
201 for (out = 0; out < mi->noutputs; out++)
202 for (in = 0; in < mi->ninputs; in++, key_index++)
203 report_key(kp, key_index, out, in);
Jeff Brownbe4cb212011-03-18 14:10:23 -0700204 report_sync(kp);
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700205 }
206 if (!kp->use_irq || kp->some_keys_pressed) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700207 hrtimer_start(timer, timespec_to_ktime(mi->poll_time),
208 HRTIMER_MODE_REL);
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700209 return HRTIMER_NORESTART;
210 }
211
212 /* No keys are pressed, reenable interrupt */
213 for (out = 0; out < mi->noutputs; out++) {
214 if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE)
215 gpio_set_value(mi->output_gpios[out], polarity);
216 else
217 gpio_direction_output(mi->output_gpios[out], polarity);
218 }
219 for (in = 0; in < mi->ninputs; in++)
220 enable_irq(gpio_to_irq(mi->input_gpios[in]));
221 wake_unlock(&kp->wake_lock);
222 return HRTIMER_NORESTART;
223}
224
225static irqreturn_t gpio_keypad_irq_handler(int irq_in, void *dev_id)
226{
227 int i;
228 struct gpio_kp *kp = dev_id;
229 struct gpio_event_matrix_info *mi = kp->keypad_info;
230 unsigned gpio_keypad_flags = mi->flags;
231
Dima Zavin23119372010-04-09 23:26:09 -0700232 if (!kp->use_irq) {
233 /* ignore interrupt while registering the handler */
234 kp->disabled_irq = 1;
235 disable_irq_nosync(irq_in);
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700236 return IRQ_HANDLED;
Dima Zavin23119372010-04-09 23:26:09 -0700237 }
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700238
239 for (i = 0; i < mi->ninputs; i++)
Arve Hjønnevåg9be7b632009-04-17 18:24:59 -0700240 disable_irq_nosync(gpio_to_irq(mi->input_gpios[i]));
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700241 for (i = 0; i < mi->noutputs; i++) {
242 if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE)
243 gpio_set_value(mi->output_gpios[i],
244 !(gpio_keypad_flags & GPIOKPF_ACTIVE_HIGH));
245 else
246 gpio_direction_input(mi->output_gpios[i]);
247 }
248 wake_lock(&kp->wake_lock);
249 hrtimer_start(&kp->timer, ktime_set(0, 0), HRTIMER_MODE_REL);
250 return IRQ_HANDLED;
251}
252
253static int gpio_keypad_request_irqs(struct gpio_kp *kp)
254{
255 int i;
256 int err;
257 unsigned int irq;
258 unsigned long request_flags;
259 struct gpio_event_matrix_info *mi = kp->keypad_info;
260
261 switch (mi->flags & (GPIOKPF_ACTIVE_HIGH|GPIOKPF_LEVEL_TRIGGERED_IRQ)) {
262 default:
263 request_flags = IRQF_TRIGGER_FALLING;
264 break;
265 case GPIOKPF_ACTIVE_HIGH:
266 request_flags = IRQF_TRIGGER_RISING;
267 break;
268 case GPIOKPF_LEVEL_TRIGGERED_IRQ:
269 request_flags = IRQF_TRIGGER_LOW;
270 break;
271 case GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_ACTIVE_HIGH:
272 request_flags = IRQF_TRIGGER_HIGH;
273 break;
274 }
275
276 for (i = 0; i < mi->ninputs; i++) {
277 err = irq = gpio_to_irq(mi->input_gpios[i]);
278 if (err < 0)
279 goto err_gpio_get_irq_num_failed;
280 err = request_irq(irq, gpio_keypad_irq_handler, request_flags,
281 "gpio_kp", kp);
282 if (err) {
283 pr_err("gpiomatrix: request_irq failed for input %d, "
284 "irq %d\n", mi->input_gpios[i], irq);
285 goto err_request_irq_failed;
286 }
Colin Cross6e890512011-04-08 19:18:42 -0700287 err = enable_irq_wake(irq);
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700288 if (err) {
289 pr_err("gpiomatrix: set_irq_wake failed for input %d, "
290 "irq %d\n", mi->input_gpios[i], irq);
291 }
292 disable_irq(irq);
Dima Zavin23119372010-04-09 23:26:09 -0700293 if (kp->disabled_irq) {
294 kp->disabled_irq = 0;
295 enable_irq(irq);
296 }
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700297 }
298 return 0;
299
300 for (i = mi->noutputs - 1; i >= 0; i--) {
301 free_irq(gpio_to_irq(mi->input_gpios[i]), kp);
302err_request_irq_failed:
303err_gpio_get_irq_num_failed:
304 ;
305 }
306 return err;
307}
308
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -0700309int gpio_event_matrix_func(struct gpio_event_input_devs *input_devs,
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700310 struct gpio_event_info *info, void **data, int func)
311{
312 int i;
313 int err;
314 int key_count;
315 struct gpio_kp *kp;
316 struct gpio_event_matrix_info *mi;
317
318 mi = container_of(info, struct gpio_event_matrix_info, info);
319 if (func == GPIO_EVENT_FUNC_SUSPEND || func == GPIO_EVENT_FUNC_RESUME) {
320 /* TODO: disable scanning */
321 return 0;
322 }
323
324 if (func == GPIO_EVENT_FUNC_INIT) {
325 if (mi->keymap == NULL ||
326 mi->input_gpios == NULL ||
327 mi->output_gpios == NULL) {
328 err = -ENODEV;
329 pr_err("gpiomatrix: Incomplete pdata\n");
330 goto err_invalid_platform_data;
331 }
332 key_count = mi->ninputs * mi->noutputs;
333
334 *data = kp = kzalloc(sizeof(*kp) + sizeof(kp->keys_pressed[0]) *
335 BITS_TO_LONGS(key_count), GFP_KERNEL);
336 if (kp == NULL) {
337 err = -ENOMEM;
338 pr_err("gpiomatrix: Failed to allocate private data\n");
339 goto err_kp_alloc_failed;
340 }
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -0700341 kp->input_devs = input_devs;
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700342 kp->keypad_info = mi;
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700343 for (i = 0; i < key_count; i++) {
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -0700344 unsigned short keyentry = mi->keymap[i];
345 unsigned short keycode = keyentry & MATRIX_KEY_MASK;
346 unsigned short dev = keyentry >> MATRIX_CODE_BITS;
347 if (dev >= input_devs->count) {
348 pr_err("gpiomatrix: bad device index %d >= "
349 "%d for key code %d\n",
350 dev, input_devs->count, keycode);
351 err = -EINVAL;
352 goto err_bad_keymap;
353 }
354 if (keycode && keycode <= KEY_MAX)
355 input_set_capability(input_devs->dev[dev],
356 EV_KEY, keycode);
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700357 }
358
359 for (i = 0; i < mi->noutputs; i++) {
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700360 err = gpio_request(mi->output_gpios[i], "gpio_kp_out");
361 if (err) {
362 pr_err("gpiomatrix: gpio_request failed for "
363 "output %d\n", mi->output_gpios[i]);
364 goto err_request_output_gpio_failed;
365 }
Arve Hjønnevåge7b269e2010-04-01 19:52:27 -0700366 if (gpio_cansleep(mi->output_gpios[i])) {
367 pr_err("gpiomatrix: unsupported output gpio %d,"
368 " can sleep\n", mi->output_gpios[i]);
369 err = -EINVAL;
370 goto err_output_gpio_configure_failed;
371 }
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700372 if (mi->flags & GPIOKPF_DRIVE_INACTIVE)
373 err = gpio_direction_output(mi->output_gpios[i],
374 !(mi->flags & GPIOKPF_ACTIVE_HIGH));
375 else
376 err = gpio_direction_input(mi->output_gpios[i]);
377 if (err) {
378 pr_err("gpiomatrix: gpio_configure failed for "
379 "output %d\n", mi->output_gpios[i]);
380 goto err_output_gpio_configure_failed;
381 }
382 }
383 for (i = 0; i < mi->ninputs; i++) {
384 err = gpio_request(mi->input_gpios[i], "gpio_kp_in");
385 if (err) {
386 pr_err("gpiomatrix: gpio_request failed for "
387 "input %d\n", mi->input_gpios[i]);
388 goto err_request_input_gpio_failed;
389 }
390 err = gpio_direction_input(mi->input_gpios[i]);
391 if (err) {
392 pr_err("gpiomatrix: gpio_direction_input failed"
393 " for input %d\n", mi->input_gpios[i]);
394 goto err_gpio_direction_input_failed;
395 }
396 }
397 kp->current_output = mi->noutputs;
398 kp->key_state_changed = 1;
399
400 hrtimer_init(&kp->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
401 kp->timer.function = gpio_keypad_timer_func;
402 wake_lock_init(&kp->wake_lock, WAKE_LOCK_SUSPEND, "gpio_kp");
403 err = gpio_keypad_request_irqs(kp);
404 kp->use_irq = err == 0;
405
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -0700406 pr_info("GPIO Matrix Keypad Driver: Start keypad matrix for "
407 "%s%s in %s mode\n", input_devs->dev[0]->name,
408 (input_devs->count > 1) ? "..." : "",
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700409 kp->use_irq ? "interrupt" : "polling");
410
411 if (kp->use_irq)
412 wake_lock(&kp->wake_lock);
413 hrtimer_start(&kp->timer, ktime_set(0, 0), HRTIMER_MODE_REL);
414
415 return 0;
416 }
417
418 err = 0;
419 kp = *data;
420
421 if (kp->use_irq)
422 for (i = mi->noutputs - 1; i >= 0; i--)
423 free_irq(gpio_to_irq(mi->input_gpios[i]), kp);
424
425 hrtimer_cancel(&kp->timer);
426 wake_lock_destroy(&kp->wake_lock);
427 for (i = mi->noutputs - 1; i >= 0; i--) {
428err_gpio_direction_input_failed:
429 gpio_free(mi->input_gpios[i]);
430err_request_input_gpio_failed:
431 ;
432 }
433 for (i = mi->noutputs - 1; i >= 0; i--) {
434err_output_gpio_configure_failed:
435 gpio_free(mi->output_gpios[i]);
436err_request_output_gpio_failed:
437 ;
438 }
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -0700439err_bad_keymap:
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700440 kfree(kp);
441err_kp_alloc_failed:
442err_invalid_platform_data:
443 return err;
444}