1 #include <linux/module.h>
2 #include <linux/device.h>
3 #include <linux/platform_device.h>
4 #include <linux/gpio_event.h>
7 /* hardware debounce: (value + 1) * 31us */
8 #define GPIO_DEBOUNCE_TIME 0x1
10 #define PREFIX "debounce: "
12 static unsigned old_flags
= 0;
13 ktime_t old_debounce_delay
;
14 ktime_t old_settle_time
;
15 ktime_t old_poll_time
;
16 static struct gpio_event_matrix_info
*gpio_evmi
= NULL
;
18 static int find_ms2_dev(struct device
*dev
, void *data
)
20 if (!strncmp((char*)data
, dev_name(dev
), strlen((char*)data
))) {
21 printk(KERN_INFO PREFIX
"Found it\n");
27 static ssize_t
show_debounce_delay(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
32 return snprintf(buf
, PAGE_SIZE
, "%ld\n", (gpio_evmi
->debounce_delay
.tv
.nsec
/ NSEC_PER_MSEC
));
35 static void set_debounce_delay(long delay
)
37 if (gpio_evmi
->debounce_delay
.tv
.nsec
!= delay
* NSEC_PER_MSEC
) {
38 printk(KERN_INFO PREFIX
"Changing debounce_delay\n");
39 gpio_evmi
->debounce_delay
.tv
.nsec
= delay
* NSEC_PER_MSEC
;
40 printk(KERN_INFO PREFIX
"debounce_delay: %u\n", gpio_evmi
->debounce_delay
.tv
.nsec
);
44 if (gpio_evmi
->debounce_delay
.tv
.nsec
!= 0) {
45 if (!(gpio_evmi
->flags
& GPIOKPF_DEBOUNCE
)) {
46 printk(KERN_INFO PREFIX
"Activating debounce\n");
47 gpio_evmi
->flags
|= GPIOKPF_DEBOUNCE
;
50 if (gpio_evmi
->flags
& GPIOKPF_DEBOUNCE
) {
51 printk(KERN_INFO PREFIX
"Deactivating debounce\n");
52 gpio_evmi
->flags
&= ~GPIOKPF_DEBOUNCE
;
58 static ssize_t
store_debounce_delay(struct device
*dev
, struct device_attribute
*attr
, const char *buf
, size_t count
)
65 sscanf(buf
, "%ld", &delay
);
66 set_debounce_delay(delay
);
71 static ssize_t
show_settle_time(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
76 return snprintf(buf
, PAGE_SIZE
, "%ld\n", (gpio_evmi
->settle_time
.tv
.nsec
/ NSEC_PER_USEC
));
79 static ssize_t
store_settle_time(struct device
*dev
, struct device_attribute
*attr
, const char *buf
, size_t count
)
86 sscanf(buf
, "%ld", &delay
);
87 gpio_evmi
->settle_time
.tv
.nsec
= delay
* NSEC_PER_USEC
;
92 static ssize_t
show_poll_time(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
97 return snprintf(buf
, PAGE_SIZE
, "%ld\n", (gpio_evmi
->poll_time
.tv
.nsec
/ NSEC_PER_MSEC
));
100 static ssize_t
store_poll_time(struct device
*dev
, struct device_attribute
*attr
, const char *buf
, size_t count
)
107 sscanf(buf
, "%ld", &delay
);
108 gpio_evmi
->poll_time
.tv
.nsec
= delay
* NSEC_PER_MSEC
;
113 static ssize_t
show_flags(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
118 return snprintf(buf
, PAGE_SIZE
, "0x%x\n", gpio_evmi
->flags
);
121 static ssize_t
store_flags(struct device
*dev
, struct device_attribute
*attr
, const char *buf
, size_t count
)
128 sscanf(buf
, "0x%x", &flags
);
130 printk(KERN_INFO PREFIX
"flags: 0x%x\n", flags
);
132 gpio_evmi
->flags
= flags
;
137 static ssize_t
show_debounce_flag(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
142 return snprintf(buf
, PAGE_SIZE
, "%u\n", (gpio_evmi
->flags
& GPIOKPF_DEBOUNCE
) ? 1 : 0);
145 static ssize_t
store_debounce_flag(struct device
*dev
, struct device_attribute
*attr
, const char *buf
, size_t count
)
152 sscanf(buf
, "%u", &flag
);
155 gpio_evmi
->flags
|= GPIOKPF_DEBOUNCE
;
157 gpio_evmi
->flags
&= ~GPIOKPF_DEBOUNCE
;
163 static ssize_t
show_remove_some_phantom_keys_flag(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
168 return snprintf(buf
, PAGE_SIZE
, "%u\n", (gpio_evmi
->flags
& GPIOKPF_REMOVE_SOME_PHANTOM_KEYS
) ? 1 : 0);
171 static ssize_t
store_remove_some_phantom_keys_flag(struct device
*dev
, struct device_attribute
*attr
, const char *buf
, size_t count
)
178 sscanf(buf
, "%u", &flag
);
181 gpio_evmi
->flags
|= GPIOKPF_REMOVE_SOME_PHANTOM_KEYS
;
183 gpio_evmi
->flags
&= ~GPIOKPF_REMOVE_SOME_PHANTOM_KEYS
;
189 static ssize_t
show_print_unmapped_keys_flag(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
194 return snprintf(buf
, PAGE_SIZE
, "%u\n", (gpio_evmi
->flags
& GPIOKPF_PRINT_UNMAPPED_KEYS
) ? 1 : 0);
197 static ssize_t
store_print_unmapped_keys_flag(struct device
*dev
, struct device_attribute
*attr
, const char *buf
, size_t count
)
204 sscanf(buf
, "%u", &flag
);
207 gpio_evmi
->flags
|= GPIOKPF_PRINT_UNMAPPED_KEYS
;
209 gpio_evmi
->flags
&= ~GPIOKPF_PRINT_UNMAPPED_KEYS
;
215 static ssize_t
show_print_mapped_keys_flag(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
220 return snprintf(buf
, PAGE_SIZE
, "%u\n", (gpio_evmi
->flags
& GPIOKPF_PRINT_MAPPED_KEYS
) ? 1 : 0);
223 static ssize_t
store_print_mapped_keys_flag(struct device
*dev
, struct device_attribute
*attr
, const char *buf
, size_t count
)
230 sscanf(buf
, "%u", &flag
);
233 gpio_evmi
->flags
|= GPIOKPF_PRINT_MAPPED_KEYS
;
235 gpio_evmi
->flags
&= ~GPIOKPF_PRINT_MAPPED_KEYS
;
241 static ssize_t
show_print_phantom_keys_flag(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
246 return snprintf(buf
, PAGE_SIZE
, "%u\n", (gpio_evmi
->flags
& GPIOKPF_PRINT_PHANTOM_KEYS
) ? 1 : 0);
249 static ssize_t
store_print_phantom_keys_flag(struct device
*dev
, struct device_attribute
*attr
, const char *buf
, size_t count
)
256 sscanf(buf
, "%u", &flag
);
259 gpio_evmi
->flags
|= GPIOKPF_PRINT_PHANTOM_KEYS
;
261 gpio_evmi
->flags
&= ~GPIOKPF_PRINT_PHANTOM_KEYS
;
267 static ssize_t
show_active_high_flag(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
272 return snprintf(buf
, PAGE_SIZE
, "%u\n", (gpio_evmi
->flags
& GPIOKPF_ACTIVE_HIGH
) ? 1 : 0);
275 static ssize_t
store_active_high_flag(struct device
*dev
, struct device_attribute
*attr
, const char *buf
, size_t count
)
282 sscanf(buf
, "%u", &flag
);
285 gpio_evmi
->flags
|= GPIOKPF_ACTIVE_HIGH
;
287 gpio_evmi
->flags
&= ~GPIOKPF_ACTIVE_HIGH
;
293 static ssize_t
show_drive_inactive_flag(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
298 return snprintf(buf
, PAGE_SIZE
, "%u\n", (gpio_evmi
->flags
& GPIOKPF_DRIVE_INACTIVE
) ? 1 : 0);
301 static ssize_t
store_drive_inactive_flag(struct device
*dev
, struct device_attribute
*attr
, const char *buf
, size_t count
)
308 sscanf(buf
, "%u", &flag
);
311 gpio_evmi
->flags
|= GPIOKPF_DRIVE_INACTIVE
;
313 gpio_evmi
->flags
&= ~GPIOKPF_DRIVE_INACTIVE
;
319 static DEVICE_ATTR(debounce_delay
, (S_IRUGO
| S_IWUGO
), show_debounce_delay
, store_debounce_delay
);
320 static DEVICE_ATTR(settle_time
, (S_IRUGO
| S_IWUGO
), show_settle_time
, store_settle_time
);
321 static DEVICE_ATTR(poll_time
, (S_IRUGO
| S_IWUGO
), show_poll_time
, store_poll_time
);
322 static DEVICE_ATTR(flags
, (S_IRUGO
), show_flags
, store_flags
);
323 static DEVICE_ATTR(debounce_flag
, (S_IRUGO
| S_IWUGO
), show_debounce_flag
, store_debounce_flag
);
324 static DEVICE_ATTR(remove_some_phantom_keys_flag
, (S_IRUGO
| S_IWUGO
), show_remove_some_phantom_keys_flag
, store_remove_some_phantom_keys_flag
);
325 static DEVICE_ATTR(print_unmapped_keys_flag
, (S_IRUGO
| S_IWUGO
), show_print_unmapped_keys_flag
, store_print_unmapped_keys_flag
);
326 static DEVICE_ATTR(print_mapped_keys_flag
, (S_IRUGO
| S_IWUGO
), show_print_mapped_keys_flag
, store_print_mapped_keys_flag
);
327 static DEVICE_ATTR(print_phantom_keys_flag
, (S_IRUGO
| S_IWUGO
), show_print_phantom_keys_flag
, store_print_phantom_keys_flag
);
328 static DEVICE_ATTR(active_high_flag
, (S_IRUGO
), show_active_high_flag
, store_active_high_flag
);
329 static DEVICE_ATTR(drive_inactive_flag
, (S_IRUGO
| S_IWUGO
), show_drive_inactive_flag
, store_drive_inactive_flag
);
331 static void debounce_release(struct device
*dev
)
335 static struct device debounce_device
= {
336 .init_name
= "debounce",
337 .release
= debounce_release
,
340 static unsigned int mapphone_col_gpios
[] = { 43, 53, 54, 55, 56, 57, 58, 63 };
341 static unsigned int mapphone_row_gpios
[] = { 34, 35, 36, 37, 38, 39, 40, 41 };
343 static void hw_debounce_pin(int gpio
, int enable
) {
344 printk(KERN_INFO PREFIX
"%sabling hardware debounce for GPIO %d\n", (enable
?"En":"Dis"), gpio
);
346 omap_set_gpio_debounce_time(gpio
, GPIO_DEBOUNCE_TIME
);
347 omap_set_gpio_debounce(gpio
, enable
);
350 static void hw_debounce(int enable
) {
353 for (i
= 0; i
< (sizeof(mapphone_col_gpios
) / sizeof(mapphone_col_gpios
[0])); i
++) {
354 hw_debounce_pin(mapphone_col_gpios
[i
], enable
);
357 for (i
= 0; i
< (sizeof(mapphone_row_gpios
) / sizeof(mapphone_row_gpios
[0])); i
++) {
358 hw_debounce_pin(mapphone_row_gpios
[i
], enable
);
362 static int __init
debounce_init(void)
364 struct device
*event_dev
= NULL
;
365 struct gpio_event_platform_data
*gpio_epd
;
366 struct gpio_event_info
*gpio_ei
;
369 printk(KERN_INFO PREFIX
"Searching for " GPIO_EVENT_DEV_NAME
"...\n");
371 event_dev
= device_find_child(&platform_bus
, GPIO_EVENT_DEV_NAME
, find_ms2_dev
);
372 if (event_dev
== NULL
)
375 gpio_epd
= (struct gpio_event_platform_data
*)event_dev
->platform_data
;
376 printk(KERN_INFO PREFIX
"And there is a %s connected...\n", gpio_epd
->name
);
377 if (strcmp(gpio_epd
->name
, "sholes-keypad"))
380 gpio_ei
= (struct gpio_event_info
*)gpio_epd
->info
[0];
381 gpio_evmi
= container_of(gpio_ei
, struct gpio_event_matrix_info
, info
);
383 err
= device_register(&debounce_device
);
390 err
= device_create_file(&debounce_device
, &dev_attr_debounce_delay
);
391 err
= device_create_file(&debounce_device
, &dev_attr_settle_time
);
392 err
= device_create_file(&debounce_device
, &dev_attr_poll_time
);
393 err
= device_create_file(&debounce_device
, &dev_attr_flags
);
394 err
= device_create_file(&debounce_device
, &dev_attr_debounce_flag
);
395 err
= device_create_file(&debounce_device
, &dev_attr_remove_some_phantom_keys_flag
);
396 err
= device_create_file(&debounce_device
, &dev_attr_print_unmapped_keys_flag
);
397 err
= device_create_file(&debounce_device
, &dev_attr_print_mapped_keys_flag
);
398 err
= device_create_file(&debounce_device
, &dev_attr_print_phantom_keys_flag
);
399 err
= device_create_file(&debounce_device
, &dev_attr_active_high_flag
);
400 err
= device_create_file(&debounce_device
, &dev_attr_drive_inactive_flag
);
402 printk(KERN_INFO PREFIX
"settle_time: %u\n", gpio_evmi
->settle_time
.tv
.nsec
);
403 printk(KERN_INFO PREFIX
"poll_time: %u\n", gpio_evmi
->poll_time
.tv
.nsec
);
404 printk(KERN_INFO PREFIX
"debounce_delay: %u\n", gpio_evmi
->debounce_delay
.tv
.nsec
);
405 printk(KERN_INFO PREFIX
"flags: 0x%x\n", gpio_evmi
->flags
);
407 old_debounce_delay
= gpio_evmi
->debounce_delay
;
408 old_settle_time
= gpio_evmi
->settle_time
;
409 old_poll_time
= gpio_evmi
->poll_time
;
410 old_flags
= gpio_evmi
->flags
;
412 printk(KERN_INFO PREFIX
"flags: 0x%x\n", gpio_evmi
->flags
);
417 static void __exit
debounce_exit(void)
420 if (gpio_evmi
->debounce_delay
.tv
.nsec
!= old_debounce_delay
.tv
.nsec
) {
421 printk(KERN_INFO PREFIX
"Restoring debounce_delay\n");
422 gpio_evmi
->debounce_delay
= old_debounce_delay
;
423 printk(KERN_INFO PREFIX
"debounce_delay: %u\n", gpio_evmi
->debounce_delay
.tv
.nsec
);
425 if (gpio_evmi
->flags
!= old_flags
) {
426 printk(KERN_INFO PREFIX
"Restoring flags\n");
427 gpio_evmi
->flags
= old_flags
;
428 printk(KERN_INFO PREFIX
"flags: 0x%x\n", gpio_evmi
->flags
);
430 gpio_evmi
->settle_time
= old_settle_time
;
431 gpio_evmi
->poll_time
= old_poll_time
;
434 device_remove_file(&debounce_device
, &dev_attr_debounce_delay
);
435 device_remove_file(&debounce_device
, &dev_attr_settle_time
);
436 device_remove_file(&debounce_device
, &dev_attr_poll_time
);
437 device_remove_file(&debounce_device
, &dev_attr_flags
);
438 device_remove_file(&debounce_device
, &dev_attr_debounce_flag
);
439 device_remove_file(&debounce_device
, &dev_attr_remove_some_phantom_keys_flag
);
440 device_remove_file(&debounce_device
, &dev_attr_print_unmapped_keys_flag
);
441 device_remove_file(&debounce_device
, &dev_attr_print_mapped_keys_flag
);
442 device_remove_file(&debounce_device
, &dev_attr_print_phantom_keys_flag
);
443 device_remove_file(&debounce_device
, &dev_attr_active_high_flag
);
444 device_remove_file(&debounce_device
, &dev_attr_drive_inactive_flag
);
445 device_unregister(&debounce_device
);
448 module_init(debounce_init
);
449 module_exit(debounce_exit
);
451 MODULE_LICENSE("GPL");
452 MODULE_AUTHOR("Michael Gernoth <michael@gernoth.net>");