]>
Commit | Line | Data |
---|---|---|
b422e333 | 1 | #include <linux/module.h> |
d1ff9643 MG |
2 | #include <linux/device.h> |
3 | #include <linux/platform_device.h> | |
4 | #include <linux/gpio_event.h> | |
f4286301 MG |
5 | #include <linux/interrupt.h> |
6 | #include <linux/irq.h> | |
62a453fc | 7 | #include <mach/gpio.h> |
e2cecc6a MG |
8 | #include <linux/earlysuspend.h> |
9 | #include <linux/wakelock.h> | |
62a453fc | 10 | |
ab5ed215 MG |
11 | #define PREFIX "debounce: " |
12 | ||
a4838b14 | 13 | static unsigned old_flags = 0; |
29bad272 MG |
14 | static ktime_t old_debounce_delay; |
15 | static ktime_t old_settle_time; | |
16 | static ktime_t old_poll_time; | |
e063f9d5 | 17 | static int (*old_sw_fixup)(int index); |
1e65c113 | 18 | static struct gpio_event_matrix_info *gpio_evmi = NULL; |
29bad272 MG |
19 | static int hw_debounce = 0; |
20 | static int hw_debounce_time = 0; | |
1e65c113 | 21 | |
e2cecc6a MG |
22 | struct gpio_event { |
23 | struct gpio_event_input_devs *input_devs; | |
24 | const struct gpio_event_platform_data *info; | |
25 | struct early_suspend early_suspend; | |
26 | void *state[0]; | |
27 | }; | |
28 | ||
29 | struct gpio_kp { | |
30 | struct gpio_event_input_devs *input_devs; | |
31 | struct gpio_event_matrix_info *keypad_info; | |
32 | struct hrtimer timer; | |
33 | struct wake_lock wake_lock; | |
34 | int current_output; | |
35 | unsigned int use_irq:1; | |
36 | unsigned int key_state_changed:1; | |
37 | unsigned int last_key_state_changed:1; | |
38 | unsigned int some_keys_pressed:2; | |
39 | unsigned long keys_pressed[0]; | |
40 | }; | |
41 | ||
42 | static struct gpio_kp *gpio_kp_state = NULL; | |
43 | ||
ab5ed215 | 44 | static int find_ms2_dev(struct device *dev, void *data) |
d1ff9643 MG |
45 | { |
46 | if (!strncmp((char*)data, dev_name(dev), strlen((char*)data))) { | |
ab5ed215 | 47 | printk(KERN_INFO PREFIX "Found it\n"); |
d1ff9643 MG |
48 | return 1; |
49 | } | |
50 | return 0; | |
51 | } | |
b422e333 | 52 | |
29bad272 MG |
53 | /* hardware debounce: (time + 1) * 31us */ |
54 | static void hw_debounce_set(int enable, int time) { | |
55 | int i; | |
56 | ||
57 | if (gpio_evmi == NULL) | |
58 | return; | |
59 | ||
60 | for (i = 0; i < gpio_evmi->ninputs; i++) { | |
61 | int gpio = gpio_evmi->input_gpios[i]; | |
62 | ||
308fc1a5 | 63 | if ((time != -1) && (time != hw_debounce_time) && hw_debounce) { |
5df3a8e0 | 64 | printk(KERN_INFO PREFIX "Setting hardware debounce time for GPIO %d to %d (%dus)\n", gpio, time, (time+1)*31); |
29bad272 MG |
65 | omap_set_gpio_debounce_time(gpio, time); |
66 | } | |
308fc1a5 MG |
67 | |
68 | if ((enable != -1) && (enable != hw_debounce)) { | |
69 | printk(KERN_INFO PREFIX "%sabling hardware debounce for GPIO %d\n", (enable?"En":"Dis"), gpio); | |
70 | omap_set_gpio_debounce(gpio, enable); | |
71 | } | |
29bad272 MG |
72 | } |
73 | } | |
74 | ||
f4286301 MG |
75 | static void set_irq_types(void) { |
76 | int err; | |
77 | unsigned int irq; | |
78 | unsigned long type; | |
79 | int i; | |
80 | ||
81 | if (gpio_evmi == NULL) | |
82 | return; | |
83 | ||
84 | switch (gpio_evmi->flags & (GPIOKPF_ACTIVE_HIGH|GPIOKPF_LEVEL_TRIGGERED_IRQ)) { | |
85 | default: | |
86 | type = IRQ_TYPE_EDGE_FALLING; | |
87 | break; | |
88 | case GPIOKPF_ACTIVE_HIGH: | |
89 | type = IRQ_TYPE_EDGE_RISING; | |
90 | break; | |
91 | case GPIOKPF_LEVEL_TRIGGERED_IRQ: | |
92 | type = IRQ_TYPE_LEVEL_LOW; | |
93 | break; | |
94 | case GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_ACTIVE_HIGH: | |
95 | type = IRQ_TYPE_LEVEL_HIGH; | |
96 | break; | |
97 | } | |
98 | ||
99 | printk(KERN_INFO PREFIX "Settinhg IRQ type to 0x%lx\n", type); | |
100 | ||
101 | for (i = 0; i < gpio_evmi->ninputs; i++) { | |
102 | ||
103 | err = irq = gpio_to_irq(gpio_evmi->input_gpios[i]); | |
104 | ||
105 | if (err < 0) | |
106 | return; | |
107 | ||
108 | err = set_irq_type(irq, type); | |
109 | } | |
110 | } | |
29bad272 | 111 | |
f7cb07b2 MG |
112 | static ssize_t show_debounce_delay(struct device *dev, struct device_attribute *attr, char *buf) |
113 | { | |
114 | if (!gpio_evmi) | |
115 | return -ENODEV; | |
116 | ||
117 | return snprintf(buf, PAGE_SIZE, "%ld\n", (gpio_evmi->debounce_delay.tv.nsec / NSEC_PER_MSEC)); | |
118 | } | |
119 | ||
120 | static void set_debounce_delay(long delay) | |
121 | { | |
122 | if (gpio_evmi->debounce_delay.tv.nsec != delay * NSEC_PER_MSEC) { | |
123 | printk(KERN_INFO PREFIX "Changing debounce_delay\n"); | |
124 | gpio_evmi->debounce_delay.tv.nsec = delay * NSEC_PER_MSEC; | |
f7cb07b2 MG |
125 | printk(KERN_INFO PREFIX "debounce_delay: %u\n", gpio_evmi->debounce_delay.tv.nsec); |
126 | } | |
127 | ||
fc215caa | 128 | #if 0 |
f7cb07b2 MG |
129 | if (gpio_evmi->debounce_delay.tv.nsec != 0) { |
130 | if (!(gpio_evmi->flags & GPIOKPF_DEBOUNCE)) { | |
131 | printk(KERN_INFO PREFIX "Activating debounce\n"); | |
132 | gpio_evmi->flags |= GPIOKPF_DEBOUNCE; | |
133 | } | |
134 | } else { | |
135 | if (gpio_evmi->flags & GPIOKPF_DEBOUNCE) { | |
136 | printk(KERN_INFO PREFIX "Deactivating debounce\n"); | |
137 | gpio_evmi->flags &= ~GPIOKPF_DEBOUNCE; | |
138 | } | |
139 | } | |
fc215caa | 140 | #endif |
f7cb07b2 MG |
141 | } |
142 | ||
143 | static ssize_t store_debounce_delay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | |
144 | { | |
145 | long int delay; | |
146 | ||
147 | if (!gpio_evmi) | |
148 | return -ENODEV; | |
149 | ||
150 | sscanf(buf, "%ld", &delay); | |
151 | set_debounce_delay(delay); | |
152 | ||
fc215caa | 153 | return count; |
f7cb07b2 MG |
154 | } |
155 | ||
156 | static ssize_t show_settle_time(struct device *dev, struct device_attribute *attr, char *buf) | |
157 | { | |
158 | if (!gpio_evmi) | |
159 | return -ENODEV; | |
160 | ||
161 | return snprintf(buf, PAGE_SIZE, "%ld\n", (gpio_evmi->settle_time.tv.nsec / NSEC_PER_USEC)); | |
162 | } | |
163 | ||
164 | static ssize_t store_settle_time(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | |
165 | { | |
166 | long int delay; | |
167 | ||
168 | if (!gpio_evmi) | |
169 | return -ENODEV; | |
170 | ||
171 | sscanf(buf, "%ld", &delay); | |
172 | gpio_evmi->settle_time.tv.nsec = delay * NSEC_PER_USEC; | |
173 | ||
fc215caa | 174 | return count; |
f7cb07b2 MG |
175 | } |
176 | ||
177 | static ssize_t show_poll_time(struct device *dev, struct device_attribute *attr, char *buf) | |
178 | { | |
179 | if (!gpio_evmi) | |
180 | return -ENODEV; | |
181 | ||
182 | return snprintf(buf, PAGE_SIZE, "%ld\n", (gpio_evmi->poll_time.tv.nsec / NSEC_PER_MSEC)); | |
183 | } | |
184 | ||
185 | static ssize_t store_poll_time(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | |
186 | { | |
187 | long int delay; | |
188 | ||
189 | if (!gpio_evmi) | |
190 | return -ENODEV; | |
191 | ||
192 | sscanf(buf, "%ld", &delay); | |
193 | gpio_evmi->poll_time.tv.nsec = delay * NSEC_PER_MSEC; | |
194 | ||
fc215caa | 195 | return count; |
f7cb07b2 MG |
196 | } |
197 | ||
198 | static ssize_t show_flags(struct device *dev, struct device_attribute *attr, char *buf) | |
199 | { | |
200 | if (!gpio_evmi) | |
201 | return -ENODEV; | |
202 | ||
203 | return snprintf(buf, PAGE_SIZE, "0x%x\n", gpio_evmi->flags); | |
204 | } | |
205 | ||
206 | static ssize_t store_flags(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | |
207 | { | |
208 | unsigned flags; | |
209 | ||
210 | if (!gpio_evmi) | |
211 | return -ENODEV; | |
212 | ||
213 | sscanf(buf, "0x%x", &flags); | |
fc215caa MG |
214 | |
215 | printk(KERN_INFO PREFIX "flags: 0x%x\n", flags); | |
216 | ||
f7cb07b2 MG |
217 | gpio_evmi->flags = flags; |
218 | ||
fc215caa MG |
219 | return count; |
220 | } | |
221 | ||
222 | static ssize_t show_debounce_flag(struct device *dev, struct device_attribute *attr, char *buf) | |
223 | { | |
224 | if (!gpio_evmi) | |
225 | return -ENODEV; | |
226 | ||
227 | return snprintf(buf, PAGE_SIZE, "%u\n", (gpio_evmi->flags & GPIOKPF_DEBOUNCE) ? 1 : 0); | |
f7cb07b2 MG |
228 | } |
229 | ||
fc215caa MG |
230 | static ssize_t store_debounce_flag(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
231 | { | |
232 | unsigned flag; | |
233 | ||
234 | if (!gpio_evmi) | |
235 | return -ENODEV; | |
236 | ||
237 | sscanf(buf, "%u", &flag); | |
238 | ||
239 | if (flag) { | |
240 | gpio_evmi->flags |= GPIOKPF_DEBOUNCE; | |
241 | } else { | |
242 | gpio_evmi->flags &= ~GPIOKPF_DEBOUNCE; | |
243 | } | |
244 | ||
245 | return count; | |
246 | } | |
247 | ||
248 | static ssize_t show_remove_some_phantom_keys_flag(struct device *dev, struct device_attribute *attr, char *buf) | |
249 | { | |
250 | if (!gpio_evmi) | |
251 | return -ENODEV; | |
252 | ||
253 | return snprintf(buf, PAGE_SIZE, "%u\n", (gpio_evmi->flags & GPIOKPF_REMOVE_SOME_PHANTOM_KEYS) ? 1 : 0); | |
254 | } | |
255 | ||
256 | static ssize_t store_remove_some_phantom_keys_flag(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | |
257 | { | |
258 | unsigned flag; | |
259 | ||
260 | if (!gpio_evmi) | |
261 | return -ENODEV; | |
262 | ||
263 | sscanf(buf, "%u", &flag); | |
264 | ||
265 | if (flag) { | |
266 | gpio_evmi->flags |= GPIOKPF_REMOVE_SOME_PHANTOM_KEYS; | |
267 | } else { | |
268 | gpio_evmi->flags &= ~GPIOKPF_REMOVE_SOME_PHANTOM_KEYS; | |
269 | } | |
270 | ||
271 | return count; | |
272 | } | |
273 | ||
274 | static ssize_t show_print_unmapped_keys_flag(struct device *dev, struct device_attribute *attr, char *buf) | |
275 | { | |
276 | if (!gpio_evmi) | |
277 | return -ENODEV; | |
278 | ||
279 | return snprintf(buf, PAGE_SIZE, "%u\n", (gpio_evmi->flags & GPIOKPF_PRINT_UNMAPPED_KEYS) ? 1 : 0); | |
280 | } | |
281 | ||
282 | static ssize_t store_print_unmapped_keys_flag(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | |
283 | { | |
284 | unsigned flag; | |
285 | ||
286 | if (!gpio_evmi) | |
287 | return -ENODEV; | |
288 | ||
289 | sscanf(buf, "%u", &flag); | |
290 | ||
291 | if (flag) { | |
292 | gpio_evmi->flags |= GPIOKPF_PRINT_UNMAPPED_KEYS; | |
293 | } else { | |
294 | gpio_evmi->flags &= ~GPIOKPF_PRINT_UNMAPPED_KEYS; | |
295 | } | |
296 | ||
297 | return count; | |
298 | } | |
299 | ||
300 | static ssize_t show_print_mapped_keys_flag(struct device *dev, struct device_attribute *attr, char *buf) | |
301 | { | |
302 | if (!gpio_evmi) | |
303 | return -ENODEV; | |
304 | ||
305 | return snprintf(buf, PAGE_SIZE, "%u\n", (gpio_evmi->flags & GPIOKPF_PRINT_MAPPED_KEYS) ? 1 : 0); | |
306 | } | |
307 | ||
308 | static ssize_t store_print_mapped_keys_flag(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | |
309 | { | |
310 | unsigned flag; | |
311 | ||
312 | if (!gpio_evmi) | |
313 | return -ENODEV; | |
314 | ||
315 | sscanf(buf, "%u", &flag); | |
316 | ||
317 | if (flag) { | |
318 | gpio_evmi->flags |= GPIOKPF_PRINT_MAPPED_KEYS; | |
319 | } else { | |
320 | gpio_evmi->flags &= ~GPIOKPF_PRINT_MAPPED_KEYS; | |
321 | } | |
322 | ||
323 | return count; | |
324 | } | |
325 | ||
326 | static ssize_t show_print_phantom_keys_flag(struct device *dev, struct device_attribute *attr, char *buf) | |
327 | { | |
328 | if (!gpio_evmi) | |
329 | return -ENODEV; | |
330 | ||
331 | return snprintf(buf, PAGE_SIZE, "%u\n", (gpio_evmi->flags & GPIOKPF_PRINT_PHANTOM_KEYS) ? 1 : 0); | |
332 | } | |
333 | ||
334 | static ssize_t store_print_phantom_keys_flag(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | |
335 | { | |
336 | unsigned flag; | |
337 | ||
338 | if (!gpio_evmi) | |
339 | return -ENODEV; | |
340 | ||
341 | sscanf(buf, "%u", &flag); | |
342 | ||
343 | if (flag) { | |
344 | gpio_evmi->flags |= GPIOKPF_PRINT_PHANTOM_KEYS; | |
345 | } else { | |
346 | gpio_evmi->flags &= ~GPIOKPF_PRINT_PHANTOM_KEYS; | |
347 | } | |
348 | ||
349 | return count; | |
350 | } | |
351 | ||
a2485674 MG |
352 | static ssize_t show_active_high_flag(struct device *dev, struct device_attribute *attr, char *buf) |
353 | { | |
354 | if (!gpio_evmi) | |
355 | return -ENODEV; | |
356 | ||
357 | return snprintf(buf, PAGE_SIZE, "%u\n", (gpio_evmi->flags & GPIOKPF_ACTIVE_HIGH) ? 1 : 0); | |
358 | } | |
359 | ||
360 | static ssize_t store_active_high_flag(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | |
361 | { | |
362 | unsigned flag; | |
363 | ||
364 | if (!gpio_evmi) | |
365 | return -ENODEV; | |
366 | ||
367 | sscanf(buf, "%u", &flag); | |
368 | ||
369 | if (flag) { | |
370 | gpio_evmi->flags |= GPIOKPF_ACTIVE_HIGH; | |
371 | } else { | |
372 | gpio_evmi->flags &= ~GPIOKPF_ACTIVE_HIGH; | |
373 | } | |
374 | ||
f4286301 MG |
375 | set_irq_types(); |
376 | ||
377 | return count; | |
378 | } | |
379 | ||
380 | static ssize_t show_level_triggered_irq_flag(struct device *dev, struct device_attribute *attr, char *buf) | |
381 | { | |
382 | if (!gpio_evmi) | |
383 | return -ENODEV; | |
384 | ||
385 | return snprintf(buf, PAGE_SIZE, "%u\n", (gpio_evmi->flags & GPIOKPF_LEVEL_TRIGGERED_IRQ) ? 1 : 0); | |
386 | } | |
387 | ||
388 | static ssize_t store_level_triggered_irq_flag(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | |
389 | { | |
390 | unsigned flag; | |
391 | ||
392 | if (!gpio_evmi) | |
393 | return -ENODEV; | |
394 | ||
395 | sscanf(buf, "%u", &flag); | |
396 | ||
397 | if (flag) { | |
398 | gpio_evmi->flags |= GPIOKPF_LEVEL_TRIGGERED_IRQ; | |
399 | } else { | |
400 | gpio_evmi->flags &= ~GPIOKPF_LEVEL_TRIGGERED_IRQ; | |
401 | } | |
402 | ||
403 | set_irq_types(); | |
404 | ||
a2485674 MG |
405 | return count; |
406 | } | |
407 | ||
408 | static ssize_t show_drive_inactive_flag(struct device *dev, struct device_attribute *attr, char *buf) | |
409 | { | |
410 | if (!gpio_evmi) | |
411 | return -ENODEV; | |
412 | ||
413 | return snprintf(buf, PAGE_SIZE, "%u\n", (gpio_evmi->flags & GPIOKPF_DRIVE_INACTIVE) ? 1 : 0); | |
414 | } | |
415 | ||
416 | static ssize_t store_drive_inactive_flag(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | |
417 | { | |
418 | unsigned flag; | |
419 | ||
420 | if (!gpio_evmi) | |
421 | return -ENODEV; | |
422 | ||
423 | sscanf(buf, "%u", &flag); | |
424 | ||
425 | if (flag) { | |
426 | gpio_evmi->flags |= GPIOKPF_DRIVE_INACTIVE; | |
427 | } else { | |
428 | gpio_evmi->flags &= ~GPIOKPF_DRIVE_INACTIVE; | |
429 | } | |
430 | ||
431 | return count; | |
432 | } | |
433 | ||
29bad272 MG |
434 | static ssize_t show_hw_debounce(struct device *dev, struct device_attribute *attr, char *buf) |
435 | { | |
436 | return snprintf(buf, PAGE_SIZE, "%d\n", hw_debounce); | |
437 | } | |
438 | ||
439 | static ssize_t store_hw_debounce(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | |
440 | { | |
441 | int enable; | |
442 | ||
443 | sscanf(buf, "%d", &enable); | |
444 | ||
445 | if (enable) { | |
446 | hw_debounce_set(1, -1); | |
447 | hw_debounce = 1; | |
448 | } | |
449 | else { | |
c0cd650e | 450 | hw_debounce_set(-1, 0); |
29bad272 MG |
451 | hw_debounce_set(0, -1); |
452 | hw_debounce = 0; | |
c0cd650e | 453 | hw_debounce_time = 0; |
29bad272 MG |
454 | } |
455 | ||
456 | return count; | |
457 | } | |
458 | ||
459 | static ssize_t show_hw_debounce_time(struct device *dev, struct device_attribute *attr, char *buf) | |
460 | { | |
461 | return snprintf(buf, PAGE_SIZE, "%d\n", hw_debounce_time); | |
462 | } | |
463 | ||
464 | static ssize_t store_hw_debounce_time(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | |
465 | { | |
466 | int time; | |
467 | ||
468 | sscanf(buf, "%d", &time); | |
469 | ||
470 | if ((time < 0) || (time > 0xff)) | |
471 | return count; | |
472 | ||
8440ec7c MG |
473 | if (!hw_debounce) |
474 | return count; | |
475 | ||
29bad272 MG |
476 | hw_debounce_set(-1, time); |
477 | hw_debounce_time = time; | |
478 | ||
479 | return count; | |
480 | } | |
481 | ||
fc215caa MG |
482 | static DEVICE_ATTR(debounce_delay, (S_IRUGO | S_IWUGO), show_debounce_delay, store_debounce_delay); |
483 | static DEVICE_ATTR(settle_time, (S_IRUGO | S_IWUGO), show_settle_time, store_settle_time); | |
484 | static DEVICE_ATTR(poll_time, (S_IRUGO | S_IWUGO), show_poll_time, store_poll_time); | |
485 | static DEVICE_ATTR(flags, (S_IRUGO), show_flags, store_flags); | |
486 | static DEVICE_ATTR(debounce_flag, (S_IRUGO | S_IWUGO), show_debounce_flag, store_debounce_flag); | |
487 | static DEVICE_ATTR(remove_some_phantom_keys_flag, (S_IRUGO | S_IWUGO), show_remove_some_phantom_keys_flag, store_remove_some_phantom_keys_flag); | |
488 | static DEVICE_ATTR(print_unmapped_keys_flag, (S_IRUGO | S_IWUGO), show_print_unmapped_keys_flag, store_print_unmapped_keys_flag); | |
489 | static DEVICE_ATTR(print_mapped_keys_flag, (S_IRUGO | S_IWUGO), show_print_mapped_keys_flag, store_print_mapped_keys_flag); | |
490 | static DEVICE_ATTR(print_phantom_keys_flag, (S_IRUGO | S_IWUGO), show_print_phantom_keys_flag, store_print_phantom_keys_flag); | |
60fe4255 | 491 | static DEVICE_ATTR(active_high_flag, (S_IRUGO | S_IWUGO), show_active_high_flag, store_active_high_flag); |
f4286301 | 492 | static DEVICE_ATTR(level_triggered_irq_flag, (S_IRUGO | S_IWUGO), show_level_triggered_irq_flag, store_level_triggered_irq_flag); |
a2485674 | 493 | static DEVICE_ATTR(drive_inactive_flag, (S_IRUGO | S_IWUGO), show_drive_inactive_flag, store_drive_inactive_flag); |
29bad272 MG |
494 | static DEVICE_ATTR(hw_debounce, (S_IRUGO | S_IWUGO), show_hw_debounce, store_hw_debounce); |
495 | static DEVICE_ATTR(hw_debounce_time, (S_IRUGO | S_IWUGO), show_hw_debounce_time, store_hw_debounce_time); | |
f7cb07b2 | 496 | |
e063f9d5 MG |
497 | #if 0 |
498 | static int debounce_fixup(int index) | |
499 | { | |
500 | int ret; | |
501 | ||
e2cecc6a MG |
502 | printk(KERN_INFO PREFIX "key_state_changed: %d, last_key_state_changed: %d, some_keys_pressed: %d\n", |
503 | gpio_kp_state->key_state_changed, | |
504 | gpio_kp_state->last_key_state_changed, | |
505 | gpio_kp_state->some_keys_pressed); | |
e063f9d5 MG |
506 | |
507 | ret = old_sw_fixup(index); | |
508 | if (!ret) | |
e2cecc6a | 509 | printk(KERN_INFO PREFIX "Index 0x%x ignored!\n", index); |
e063f9d5 MG |
510 | |
511 | return ret; | |
512 | } | |
513 | #endif | |
514 | ||
f7cb07b2 MG |
515 | static void debounce_release(struct device *dev) |
516 | { | |
517 | } | |
518 | ||
519 | static struct device debounce_device = { | |
520 | .init_name = "debounce", | |
521 | .release = debounce_release, | |
522 | }; | |
523 | ||
b422e333 MG |
524 | static int __init debounce_init(void) |
525 | { | |
d1ff9643 | 526 | struct device *event_dev = NULL; |
e2cecc6a | 527 | struct platform_device *pdev = NULL; |
d1ff9643 MG |
528 | struct gpio_event_platform_data *gpio_epd; |
529 | struct gpio_event_info *gpio_ei; | |
e2cecc6a | 530 | struct gpio_event *gpio_e; |
f7cb07b2 | 531 | int err = 0; |
e2cecc6a | 532 | int i; |
d1ff9643 | 533 | |
ab5ed215 | 534 | printk(KERN_INFO PREFIX "Searching for " GPIO_EVENT_DEV_NAME "...\n"); |
d1ff9643 MG |
535 | |
536 | event_dev = device_find_child(&platform_bus, GPIO_EVENT_DEV_NAME, find_ms2_dev); | |
537 | if (event_dev == NULL) | |
538 | return -ENODEV; | |
e2cecc6a MG |
539 | |
540 | pdev = container_of(event_dev, struct platform_device, dev); | |
541 | if (pdev == NULL) | |
542 | return -ENODEV; | |
543 | ||
d1ff9643 | 544 | gpio_epd = (struct gpio_event_platform_data*)event_dev->platform_data; |
ab5ed215 | 545 | printk(KERN_INFO PREFIX "And there is a %s connected...\n", gpio_epd->name); |
d1ff9643 MG |
546 | if (strcmp(gpio_epd->name, "sholes-keypad")) |
547 | return -ENODEV; | |
548 | ||
549 | gpio_ei = (struct gpio_event_info*)gpio_epd->info[0]; | |
550 | gpio_evmi = container_of(gpio_ei, struct gpio_event_matrix_info, info); | |
551 | ||
e2cecc6a MG |
552 | gpio_e = platform_get_drvdata(pdev); |
553 | printk(KERN_INFO PREFIX "Number of states: %d\n", gpio_e->info->info_count); | |
554 | ||
555 | /* Search for correct gpio_event state */ | |
556 | for (i = 0; i < gpio_e->info->info_count; i++) { | |
557 | if (gpio_e->info->info[i]->func == gpio_ei->func) { | |
558 | printk(KERN_INFO PREFIX "Keypad state: %d\n", i); | |
559 | gpio_kp_state = gpio_e->state[i]; | |
560 | } | |
561 | } | |
562 | ||
563 | if (!gpio_kp_state) { | |
564 | printk(KERN_ERR PREFIX "Can't determine correct keypad state!\n"); | |
565 | return -ENODEV; | |
566 | } | |
567 | ||
568 | printk(KERN_INFO PREFIX "kp_use_irq: %d\n", gpio_kp_state->use_irq); | |
569 | #if 0 | |
570 | gpio_kp_state->use_irq=0; | |
571 | hrtimer_start(&(gpio_kp_state->timer), gpio_evmi->poll_time, HRTIMER_MODE_REL); | |
572 | printk(KERN_INFO PREFIX "kp_use_irq: %d\n", gpio_kp_state->use_irq); | |
573 | #endif | |
574 | ||
f7cb07b2 MG |
575 | err = device_register(&debounce_device); |
576 | if (err) { | |
577 | return err; | |
578 | } | |
579 | ||
580 | err = device_create_file(&debounce_device, &dev_attr_debounce_delay); | |
581 | err = device_create_file(&debounce_device, &dev_attr_settle_time); | |
582 | err = device_create_file(&debounce_device, &dev_attr_poll_time); | |
583 | err = device_create_file(&debounce_device, &dev_attr_flags); | |
fc215caa MG |
584 | err = device_create_file(&debounce_device, &dev_attr_debounce_flag); |
585 | err = device_create_file(&debounce_device, &dev_attr_remove_some_phantom_keys_flag); | |
586 | err = device_create_file(&debounce_device, &dev_attr_print_unmapped_keys_flag); | |
587 | err = device_create_file(&debounce_device, &dev_attr_print_mapped_keys_flag); | |
588 | err = device_create_file(&debounce_device, &dev_attr_print_phantom_keys_flag); | |
a2485674 | 589 | err = device_create_file(&debounce_device, &dev_attr_active_high_flag); |
f4286301 | 590 | err = device_create_file(&debounce_device, &dev_attr_level_triggered_irq_flag); |
a2485674 | 591 | err = device_create_file(&debounce_device, &dev_attr_drive_inactive_flag); |
29bad272 MG |
592 | err = device_create_file(&debounce_device, &dev_attr_hw_debounce); |
593 | err = device_create_file(&debounce_device, &dev_attr_hw_debounce_time); | |
f7cb07b2 | 594 | |
ab5ed215 MG |
595 | printk(KERN_INFO PREFIX "settle_time: %u\n", gpio_evmi->settle_time.tv.nsec); |
596 | printk(KERN_INFO PREFIX "poll_time: %u\n", gpio_evmi->poll_time.tv.nsec); | |
597 | printk(KERN_INFO PREFIX "debounce_delay: %u\n", gpio_evmi->debounce_delay.tv.nsec); | |
598 | printk(KERN_INFO PREFIX "flags: 0x%x\n", gpio_evmi->flags); | |
20bf1c9e | 599 | |
bb65757a MG |
600 | old_debounce_delay = gpio_evmi->debounce_delay; |
601 | old_settle_time = gpio_evmi->settle_time; | |
602 | old_poll_time = gpio_evmi->poll_time; | |
603 | old_flags = gpio_evmi->flags; | |
e063f9d5 | 604 | old_sw_fixup = gpio_evmi->sw_fixup; |
1e65c113 | 605 | |
e063f9d5 MG |
606 | #if 0 |
607 | printk(KERN_INFO PREFIX "Registering fixup handler\n"); | |
608 | gpio_evmi->sw_fixup = debounce_fixup; | |
609 | #endif | |
a4838b14 | 610 | |
b422e333 MG |
611 | return 0; |
612 | } | |
613 | ||
614 | static void __exit debounce_exit(void) | |
615 | { | |
1e65c113 | 616 | if (gpio_evmi) { |
bb65757a | 617 | if (gpio_evmi->debounce_delay.tv.nsec != old_debounce_delay.tv.nsec) { |
1e65c113 | 618 | printk(KERN_INFO PREFIX "Restoring debounce_delay\n"); |
bb65757a | 619 | gpio_evmi->debounce_delay = old_debounce_delay; |
1e65c113 MG |
620 | printk(KERN_INFO PREFIX "debounce_delay: %u\n", gpio_evmi->debounce_delay.tv.nsec); |
621 | } | |
a4838b14 MG |
622 | if (gpio_evmi->flags != old_flags) { |
623 | printk(KERN_INFO PREFIX "Restoring flags\n"); | |
624 | gpio_evmi->flags = old_flags; | |
625 | printk(KERN_INFO PREFIX "flags: 0x%x\n", gpio_evmi->flags); | |
f4286301 | 626 | set_irq_types(); |
a4838b14 | 627 | } |
bb65757a MG |
628 | gpio_evmi->settle_time = old_settle_time; |
629 | gpio_evmi->poll_time = old_poll_time; | |
e063f9d5 MG |
630 | |
631 | if (gpio_evmi->sw_fixup != old_sw_fixup) { | |
632 | printk(KERN_INFO PREFIX "Restoring fixup handler\n"); | |
633 | gpio_evmi->sw_fixup = old_sw_fixup; | |
634 | } | |
1e65c113 | 635 | } |
29bad272 | 636 | hw_debounce_set(0, 0); |
f7cb07b2 MG |
637 | device_remove_file(&debounce_device, &dev_attr_debounce_delay); |
638 | device_remove_file(&debounce_device, &dev_attr_settle_time); | |
639 | device_remove_file(&debounce_device, &dev_attr_poll_time); | |
640 | device_remove_file(&debounce_device, &dev_attr_flags); | |
fc215caa MG |
641 | device_remove_file(&debounce_device, &dev_attr_debounce_flag); |
642 | device_remove_file(&debounce_device, &dev_attr_remove_some_phantom_keys_flag); | |
643 | device_remove_file(&debounce_device, &dev_attr_print_unmapped_keys_flag); | |
644 | device_remove_file(&debounce_device, &dev_attr_print_mapped_keys_flag); | |
645 | device_remove_file(&debounce_device, &dev_attr_print_phantom_keys_flag); | |
a2485674 | 646 | device_remove_file(&debounce_device, &dev_attr_active_high_flag); |
f4286301 | 647 | device_remove_file(&debounce_device, &dev_attr_level_triggered_irq_flag); |
a2485674 | 648 | device_remove_file(&debounce_device, &dev_attr_drive_inactive_flag); |
29bad272 MG |
649 | device_remove_file(&debounce_device, &dev_attr_hw_debounce); |
650 | device_remove_file(&debounce_device, &dev_attr_hw_debounce_time); | |
f7cb07b2 | 651 | device_unregister(&debounce_device); |
b422e333 MG |
652 | } |
653 | ||
654 | module_init(debounce_init); | |
655 | module_exit(debounce_exit); | |
656 | ||
657 | MODULE_LICENSE("GPL"); | |
658 | MODULE_AUTHOR("Michael Gernoth <michael@gernoth.net>"); |