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