]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/staging/dream/gpio_matrix.c
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel...
[net-next-2.6.git] / drivers / staging / dream / gpio_matrix.c
CommitLineData
420818f9
AH
1/* 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>
5a0e3ad6 17#include <linux/slab.h>
420818f9
AH
18#include <linux/gpio.h>
19#include <linux/gpio_event.h>
20#include <linux/hrtimer.h>
21#include <linux/interrupt.h>
420818f9
AH
22
23struct gpio_kp {
24 struct input_dev *input_dev;
25 struct gpio_event_matrix_info *keypad_info;
26 struct hrtimer timer;
420818f9
AH
27 int current_output;
28 unsigned int use_irq:1;
29 unsigned int key_state_changed:1;
30 unsigned int last_key_state_changed:1;
31 unsigned int some_keys_pressed:2;
32 unsigned long keys_pressed[0];
33};
34
35static void clear_phantom_key(struct gpio_kp *kp, int out, int in)
36{
37 struct gpio_event_matrix_info *mi = kp->keypad_info;
38 int key_index = out * mi->ninputs + in;
39 unsigned short keycode = mi->keymap[key_index];;
40
41 if (!test_bit(keycode, kp->input_dev->key)) {
42 if (mi->flags & GPIOKPF_PRINT_PHANTOM_KEYS)
43 pr_info("gpiomatrix: phantom key %x, %d-%d (%d-%d) "
44 "cleared\n", keycode, out, in,
45 mi->output_gpios[out], mi->input_gpios[in]);
46 __clear_bit(key_index, kp->keys_pressed);
47 } else {
48 if (mi->flags & GPIOKPF_PRINT_PHANTOM_KEYS)
49 pr_info("gpiomatrix: phantom key %x, %d-%d (%d-%d) "
50 "not cleared\n", keycode, out, in,
51 mi->output_gpios[out], mi->input_gpios[in]);
52 }
53}
54
55static int restore_keys_for_input(struct gpio_kp *kp, int out, int in)
56{
57 int rv = 0;
58 int key_index;
59
60 key_index = out * kp->keypad_info->ninputs + in;
61 while (out < kp->keypad_info->noutputs) {
62 if (test_bit(key_index, kp->keys_pressed)) {
63 rv = 1;
64 clear_phantom_key(kp, out, in);
65 }
66 key_index += kp->keypad_info->ninputs;
67 out++;
68 }
69 return rv;
70}
71
72static void remove_phantom_keys(struct gpio_kp *kp)
73{
74 int out, in, inp;
75 int key_index;
76
77 if (kp->some_keys_pressed < 3)
78 return;
79
80 for (out = 0; out < kp->keypad_info->noutputs; out++) {
81 inp = -1;
82 key_index = out * kp->keypad_info->ninputs;
83 for (in = 0; in < kp->keypad_info->ninputs; in++, key_index++) {
84 if (test_bit(key_index, kp->keys_pressed)) {
85 if (inp == -1) {
86 inp = in;
87 continue;
88 }
89 if (inp >= 0) {
90 if (!restore_keys_for_input(kp, out + 1,
91 inp))
92 break;
93 clear_phantom_key(kp, out, inp);
94 inp = -2;
95 }
96 restore_keys_for_input(kp, out, in);
97 }
98 }
99 }
100}
101
102static void report_key(struct gpio_kp *kp, int key_index, int out, int in)
103{
104 struct gpio_event_matrix_info *mi = kp->keypad_info;
105 int pressed = test_bit(key_index, kp->keys_pressed);
106 unsigned short keycode = mi->keymap[key_index];
107 if (pressed != test_bit(keycode, kp->input_dev->key)) {
108 if (keycode == KEY_RESERVED) {
109 if (mi->flags & GPIOKPF_PRINT_UNMAPPED_KEYS)
110 pr_info("gpiomatrix: unmapped key, %d-%d "
111 "(%d-%d) changed to %d\n",
112 out, in, mi->output_gpios[out],
113 mi->input_gpios[in], pressed);
114 } else {
115 if (mi->flags & GPIOKPF_PRINT_MAPPED_KEYS)
116 pr_info("gpiomatrix: key %x, %d-%d (%d-%d) "
117 "changed to %d\n", keycode,
118 out, in, mi->output_gpios[out],
119 mi->input_gpios[in], pressed);
120 input_report_key(kp->input_dev, keycode, pressed);
121 }
122 }
123}
124
125static enum hrtimer_restart gpio_keypad_timer_func(struct hrtimer *timer)
126{
127 int out, in;
128 int key_index;
129 int gpio;
130 struct gpio_kp *kp = container_of(timer, struct gpio_kp, timer);
131 struct gpio_event_matrix_info *mi = kp->keypad_info;
132 unsigned gpio_keypad_flags = mi->flags;
133 unsigned polarity = !!(gpio_keypad_flags & GPIOKPF_ACTIVE_HIGH);
134
135 out = kp->current_output;
136 if (out == mi->noutputs) {
137 out = 0;
138 kp->last_key_state_changed = kp->key_state_changed;
139 kp->key_state_changed = 0;
140 kp->some_keys_pressed = 0;
141 } else {
142 key_index = out * mi->ninputs;
143 for (in = 0; in < mi->ninputs; in++, key_index++) {
144 gpio = mi->input_gpios[in];
145 if (gpio_get_value(gpio) ^ !polarity) {
146 if (kp->some_keys_pressed < 3)
147 kp->some_keys_pressed++;
148 kp->key_state_changed |= !__test_and_set_bit(
149 key_index, kp->keys_pressed);
150 } else
151 kp->key_state_changed |= __test_and_clear_bit(
152 key_index, kp->keys_pressed);
153 }
154 gpio = mi->output_gpios[out];
155 if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE)
156 gpio_set_value(gpio, !polarity);
157 else
158 gpio_direction_input(gpio);
159 out++;
160 }
161 kp->current_output = out;
162 if (out < mi->noutputs) {
163 gpio = mi->output_gpios[out];
164 if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE)
165 gpio_set_value(gpio, polarity);
166 else
167 gpio_direction_output(gpio, polarity);
168 hrtimer_start(timer, mi->settle_time, HRTIMER_MODE_REL);
169 return HRTIMER_NORESTART;
170 }
171 if (gpio_keypad_flags & GPIOKPF_DEBOUNCE) {
172 if (kp->key_state_changed) {
173 hrtimer_start(&kp->timer, mi->debounce_delay,
174 HRTIMER_MODE_REL);
175 return HRTIMER_NORESTART;
176 }
177 kp->key_state_changed = kp->last_key_state_changed;
178 }
179 if (kp->key_state_changed) {
180 if (gpio_keypad_flags & GPIOKPF_REMOVE_SOME_PHANTOM_KEYS)
181 remove_phantom_keys(kp);
182 key_index = 0;
183 for (out = 0; out < mi->noutputs; out++)
184 for (in = 0; in < mi->ninputs; in++, key_index++)
185 report_key(kp, key_index, out, in);
186 }
187 if (!kp->use_irq || kp->some_keys_pressed) {
188 hrtimer_start(timer, mi->poll_time, HRTIMER_MODE_REL);
189 return HRTIMER_NORESTART;
190 }
191
192 /* No keys are pressed, reenable interrupt */
193 for (out = 0; out < mi->noutputs; out++) {
194 if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE)
195 gpio_set_value(mi->output_gpios[out], polarity);
196 else
197 gpio_direction_output(mi->output_gpios[out], polarity);
198 }
199 for (in = 0; in < mi->ninputs; in++)
200 enable_irq(gpio_to_irq(mi->input_gpios[in]));
420818f9
AH
201 return HRTIMER_NORESTART;
202}
203
204static irqreturn_t gpio_keypad_irq_handler(int irq_in, void *dev_id)
205{
206 int i;
207 struct gpio_kp *kp = dev_id;
208 struct gpio_event_matrix_info *mi = kp->keypad_info;
209 unsigned gpio_keypad_flags = mi->flags;
210
211 if (!kp->use_irq) /* ignore interrupt while registering the handler */
212 return IRQ_HANDLED;
213
214 for (i = 0; i < mi->ninputs; i++)
215 disable_irq(gpio_to_irq(mi->input_gpios[i]));
216 for (i = 0; i < mi->noutputs; i++) {
217 if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE)
218 gpio_set_value(mi->output_gpios[i],
219 !(gpio_keypad_flags & GPIOKPF_ACTIVE_HIGH));
220 else
221 gpio_direction_input(mi->output_gpios[i]);
222 }
420818f9
AH
223 hrtimer_start(&kp->timer, ktime_set(0, 0), HRTIMER_MODE_REL);
224 return IRQ_HANDLED;
225}
226
227static int gpio_keypad_request_irqs(struct gpio_kp *kp)
228{
229 int i;
230 int err;
231 unsigned int irq;
232 unsigned long request_flags;
233 struct gpio_event_matrix_info *mi = kp->keypad_info;
234
235 switch (mi->flags & (GPIOKPF_ACTIVE_HIGH|GPIOKPF_LEVEL_TRIGGERED_IRQ)) {
236 default:
237 request_flags = IRQF_TRIGGER_FALLING;
238 break;
239 case GPIOKPF_ACTIVE_HIGH:
240 request_flags = IRQF_TRIGGER_RISING;
241 break;
242 case GPIOKPF_LEVEL_TRIGGERED_IRQ:
243 request_flags = IRQF_TRIGGER_LOW;
244 break;
245 case GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_ACTIVE_HIGH:
246 request_flags = IRQF_TRIGGER_HIGH;
247 break;
248 }
249
250 for (i = 0; i < mi->ninputs; i++) {
251 err = irq = gpio_to_irq(mi->input_gpios[i]);
252 if (err < 0)
253 goto err_gpio_get_irq_num_failed;
254 err = request_irq(irq, gpio_keypad_irq_handler, request_flags,
255 "gpio_kp", kp);
256 if (err) {
257 pr_err("gpiomatrix: request_irq failed for input %d, "
258 "irq %d\n", mi->input_gpios[i], irq);
259 goto err_request_irq_failed;
260 }
261 err = set_irq_wake(irq, 1);
262 if (err) {
263 pr_err("gpiomatrix: set_irq_wake failed for input %d, "
264 "irq %d\n", mi->input_gpios[i], irq);
265 }
266 disable_irq(irq);
267 }
268 return 0;
269
270 for (i = mi->noutputs - 1; i >= 0; i--) {
271 free_irq(gpio_to_irq(mi->input_gpios[i]), kp);
272err_request_irq_failed:
273err_gpio_get_irq_num_failed:
274 ;
275 }
276 return err;
277}
278
279int gpio_event_matrix_func(struct input_dev *input_dev,
280 struct gpio_event_info *info, void **data, int func)
281{
282 int i;
283 int err;
284 int key_count;
285 struct gpio_kp *kp;
286 struct gpio_event_matrix_info *mi;
287
288 mi = container_of(info, struct gpio_event_matrix_info, info);
289 if (func == GPIO_EVENT_FUNC_SUSPEND || func == GPIO_EVENT_FUNC_RESUME) {
290 /* TODO: disable scanning */
291 return 0;
292 }
293
294 if (func == GPIO_EVENT_FUNC_INIT) {
295 if (mi->keymap == NULL ||
296 mi->input_gpios == NULL ||
297 mi->output_gpios == NULL) {
298 err = -ENODEV;
299 pr_err("gpiomatrix: Incomplete pdata\n");
300 goto err_invalid_platform_data;
301 }
302 key_count = mi->ninputs * mi->noutputs;
303
304 *data = kp = kzalloc(sizeof(*kp) + sizeof(kp->keys_pressed[0]) *
305 BITS_TO_LONGS(key_count), GFP_KERNEL);
306 if (kp == NULL) {
307 err = -ENOMEM;
308 pr_err("gpiomatrix: Failed to allocate private data\n");
309 goto err_kp_alloc_failed;
310 }
311 kp->input_dev = input_dev;
312 kp->keypad_info = mi;
313 set_bit(EV_KEY, input_dev->evbit);
314 for (i = 0; i < key_count; i++) {
315 if (mi->keymap[i])
316 set_bit(mi->keymap[i] & KEY_MAX,
317 input_dev->keybit);
318 }
319
320 for (i = 0; i < mi->noutputs; i++) {
321 if (gpio_cansleep(mi->output_gpios[i])) {
322 pr_err("gpiomatrix: unsupported output gpio %d,"
323 " can sleep\n", mi->output_gpios[i]);
324 err = -EINVAL;
325 goto err_request_output_gpio_failed;
326 }
327 err = gpio_request(mi->output_gpios[i], "gpio_kp_out");
328 if (err) {
329 pr_err("gpiomatrix: gpio_request failed for "
330 "output %d\n", mi->output_gpios[i]);
331 goto err_request_output_gpio_failed;
332 }
333 if (mi->flags & GPIOKPF_DRIVE_INACTIVE)
334 err = gpio_direction_output(mi->output_gpios[i],
335 !(mi->flags & GPIOKPF_ACTIVE_HIGH));
336 else
337 err = gpio_direction_input(mi->output_gpios[i]);
338 if (err) {
339 pr_err("gpiomatrix: gpio_configure failed for "
340 "output %d\n", mi->output_gpios[i]);
341 goto err_output_gpio_configure_failed;
342 }
343 }
344 for (i = 0; i < mi->ninputs; i++) {
345 err = gpio_request(mi->input_gpios[i], "gpio_kp_in");
346 if (err) {
347 pr_err("gpiomatrix: gpio_request failed for "
348 "input %d\n", mi->input_gpios[i]);
349 goto err_request_input_gpio_failed;
350 }
351 err = gpio_direction_input(mi->input_gpios[i]);
352 if (err) {
353 pr_err("gpiomatrix: gpio_direction_input failed"
354 " for input %d\n", mi->input_gpios[i]);
355 goto err_gpio_direction_input_failed;
356 }
357 }
358 kp->current_output = mi->noutputs;
359 kp->key_state_changed = 1;
360
361 hrtimer_init(&kp->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
362 kp->timer.function = gpio_keypad_timer_func;
420818f9
AH
363 err = gpio_keypad_request_irqs(kp);
364 kp->use_irq = err == 0;
365
366 pr_info("GPIO Matrix Keypad Driver: Start keypad matrix for %s "
367 "in %s mode\n", input_dev->name,
368 kp->use_irq ? "interrupt" : "polling");
369
420818f9
AH
370 hrtimer_start(&kp->timer, ktime_set(0, 0), HRTIMER_MODE_REL);
371
372 return 0;
373 }
374
375 err = 0;
376 kp = *data;
377
378 if (kp->use_irq)
379 for (i = mi->noutputs - 1; i >= 0; i--)
380 free_irq(gpio_to_irq(mi->input_gpios[i]), kp);
381
382 hrtimer_cancel(&kp->timer);
420818f9
AH
383 for (i = mi->noutputs - 1; i >= 0; i--) {
384err_gpio_direction_input_failed:
385 gpio_free(mi->input_gpios[i]);
386err_request_input_gpio_failed:
387 ;
388 }
389 for (i = mi->noutputs - 1; i >= 0; i--) {
390err_output_gpio_configure_failed:
391 gpio_free(mi->output_gpios[i]);
392err_request_output_gpio_failed:
393 ;
394 }
395 kfree(kp);
396err_kp_alloc_failed:
397err_invalid_platform_data:
398 return err;
399}