better hw debounce time
[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>
62a453fc
MG
5#include <mach/gpio.h>
6
7/* hardware debounce: (value + 1) * 31us */
f556e8c9 8#define GPIO_DEBOUNCE_TIME 0x3
d1ff9643 9
ab5ed215
MG
10#define PREFIX "debounce: "
11
a4838b14 12static unsigned old_flags = 0;
bb65757a
MG
13ktime_t old_debounce_delay;
14ktime_t old_settle_time;
15ktime_t old_poll_time;
1e65c113
MG
16static struct gpio_event_matrix_info *gpio_evmi = NULL;
17
ab5ed215 18static int find_ms2_dev(struct device *dev, void *data)
d1ff9643
MG
19{
20 if (!strncmp((char*)data, dev_name(dev), strlen((char*)data))) {
ab5ed215 21 printk(KERN_INFO PREFIX "Found it\n");
d1ff9643
MG
22 return 1;
23 }
24 return 0;
25}
b422e333 26
f7cb07b2
MG
27static ssize_t show_debounce_delay(struct device *dev, struct device_attribute *attr, char *buf)
28{
29 if (!gpio_evmi)
30 return -ENODEV;
31
32 return snprintf(buf, PAGE_SIZE, "%ld\n", (gpio_evmi->debounce_delay.tv.nsec / NSEC_PER_MSEC));
33}
34
35static void set_debounce_delay(long delay)
36{
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;
f7cb07b2
MG
40 printk(KERN_INFO PREFIX "debounce_delay: %u\n", gpio_evmi->debounce_delay.tv.nsec);
41 }
42
fc215caa 43#if 0
f7cb07b2
MG
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;
48 }
49 } else {
50 if (gpio_evmi->flags & GPIOKPF_DEBOUNCE) {
51 printk(KERN_INFO PREFIX "Deactivating debounce\n");
52 gpio_evmi->flags &= ~GPIOKPF_DEBOUNCE;
53 }
54 }
fc215caa 55#endif
f7cb07b2
MG
56}
57
58static ssize_t store_debounce_delay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
59{
60 long int delay;
61
62 if (!gpio_evmi)
63 return -ENODEV;
64
65 sscanf(buf, "%ld", &delay);
66 set_debounce_delay(delay);
67
fc215caa 68 return count;
f7cb07b2
MG
69}
70
71static ssize_t show_settle_time(struct device *dev, struct device_attribute *attr, char *buf)
72{
73 if (!gpio_evmi)
74 return -ENODEV;
75
76 return snprintf(buf, PAGE_SIZE, "%ld\n", (gpio_evmi->settle_time.tv.nsec / NSEC_PER_USEC));
77}
78
79static ssize_t store_settle_time(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
80{
81 long int delay;
82
83 if (!gpio_evmi)
84 return -ENODEV;
85
86 sscanf(buf, "%ld", &delay);
87 gpio_evmi->settle_time.tv.nsec = delay * NSEC_PER_USEC;
88
fc215caa 89 return count;
f7cb07b2
MG
90}
91
92static ssize_t show_poll_time(struct device *dev, struct device_attribute *attr, char *buf)
93{
94 if (!gpio_evmi)
95 return -ENODEV;
96
97 return snprintf(buf, PAGE_SIZE, "%ld\n", (gpio_evmi->poll_time.tv.nsec / NSEC_PER_MSEC));
98}
99
100static ssize_t store_poll_time(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
101{
102 long int delay;
103
104 if (!gpio_evmi)
105 return -ENODEV;
106
107 sscanf(buf, "%ld", &delay);
108 gpio_evmi->poll_time.tv.nsec = delay * NSEC_PER_MSEC;
109
fc215caa 110 return count;
f7cb07b2
MG
111}
112
113static ssize_t show_flags(struct device *dev, struct device_attribute *attr, char *buf)
114{
115 if (!gpio_evmi)
116 return -ENODEV;
117
118 return snprintf(buf, PAGE_SIZE, "0x%x\n", gpio_evmi->flags);
119}
120
121static ssize_t store_flags(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
122{
123 unsigned flags;
124
125 if (!gpio_evmi)
126 return -ENODEV;
127
128 sscanf(buf, "0x%x", &flags);
fc215caa
MG
129
130 printk(KERN_INFO PREFIX "flags: 0x%x\n", flags);
131
f7cb07b2
MG
132 gpio_evmi->flags = flags;
133
fc215caa
MG
134 return count;
135}
136
137static ssize_t show_debounce_flag(struct device *dev, struct device_attribute *attr, char *buf)
138{
139 if (!gpio_evmi)
140 return -ENODEV;
141
142 return snprintf(buf, PAGE_SIZE, "%u\n", (gpio_evmi->flags & GPIOKPF_DEBOUNCE) ? 1 : 0);
f7cb07b2
MG
143}
144
fc215caa
MG
145static ssize_t store_debounce_flag(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
146{
147 unsigned flag;
148
149 if (!gpio_evmi)
150 return -ENODEV;
151
152 sscanf(buf, "%u", &flag);
153
154 if (flag) {
155 gpio_evmi->flags |= GPIOKPF_DEBOUNCE;
156 } else {
157 gpio_evmi->flags &= ~GPIOKPF_DEBOUNCE;
158 }
159
160 return count;
161}
162
163static ssize_t show_remove_some_phantom_keys_flag(struct device *dev, struct device_attribute *attr, char *buf)
164{
165 if (!gpio_evmi)
166 return -ENODEV;
167
168 return snprintf(buf, PAGE_SIZE, "%u\n", (gpio_evmi->flags & GPIOKPF_REMOVE_SOME_PHANTOM_KEYS) ? 1 : 0);
169}
170
171static ssize_t store_remove_some_phantom_keys_flag(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
172{
173 unsigned flag;
174
175 if (!gpio_evmi)
176 return -ENODEV;
177
178 sscanf(buf, "%u", &flag);
179
180 if (flag) {
181 gpio_evmi->flags |= GPIOKPF_REMOVE_SOME_PHANTOM_KEYS;
182 } else {
183 gpio_evmi->flags &= ~GPIOKPF_REMOVE_SOME_PHANTOM_KEYS;
184 }
185
186 return count;
187}
188
189static ssize_t show_print_unmapped_keys_flag(struct device *dev, struct device_attribute *attr, char *buf)
190{
191 if (!gpio_evmi)
192 return -ENODEV;
193
194 return snprintf(buf, PAGE_SIZE, "%u\n", (gpio_evmi->flags & GPIOKPF_PRINT_UNMAPPED_KEYS) ? 1 : 0);
195}
196
197static ssize_t store_print_unmapped_keys_flag(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
198{
199 unsigned flag;
200
201 if (!gpio_evmi)
202 return -ENODEV;
203
204 sscanf(buf, "%u", &flag);
205
206 if (flag) {
207 gpio_evmi->flags |= GPIOKPF_PRINT_UNMAPPED_KEYS;
208 } else {
209 gpio_evmi->flags &= ~GPIOKPF_PRINT_UNMAPPED_KEYS;
210 }
211
212 return count;
213}
214
215static ssize_t show_print_mapped_keys_flag(struct device *dev, struct device_attribute *attr, char *buf)
216{
217 if (!gpio_evmi)
218 return -ENODEV;
219
220 return snprintf(buf, PAGE_SIZE, "%u\n", (gpio_evmi->flags & GPIOKPF_PRINT_MAPPED_KEYS) ? 1 : 0);
221}
222
223static ssize_t store_print_mapped_keys_flag(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
224{
225 unsigned flag;
226
227 if (!gpio_evmi)
228 return -ENODEV;
229
230 sscanf(buf, "%u", &flag);
231
232 if (flag) {
233 gpio_evmi->flags |= GPIOKPF_PRINT_MAPPED_KEYS;
234 } else {
235 gpio_evmi->flags &= ~GPIOKPF_PRINT_MAPPED_KEYS;
236 }
237
238 return count;
239}
240
241static ssize_t show_print_phantom_keys_flag(struct device *dev, struct device_attribute *attr, char *buf)
242{
243 if (!gpio_evmi)
244 return -ENODEV;
245
246 return snprintf(buf, PAGE_SIZE, "%u\n", (gpio_evmi->flags & GPIOKPF_PRINT_PHANTOM_KEYS) ? 1 : 0);
247}
248
249static ssize_t store_print_phantom_keys_flag(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
250{
251 unsigned flag;
252
253 if (!gpio_evmi)
254 return -ENODEV;
255
256 sscanf(buf, "%u", &flag);
257
258 if (flag) {
259 gpio_evmi->flags |= GPIOKPF_PRINT_PHANTOM_KEYS;
260 } else {
261 gpio_evmi->flags &= ~GPIOKPF_PRINT_PHANTOM_KEYS;
262 }
263
264 return count;
265}
266
a2485674
MG
267static ssize_t show_active_high_flag(struct device *dev, struct device_attribute *attr, char *buf)
268{
269 if (!gpio_evmi)
270 return -ENODEV;
271
272 return snprintf(buf, PAGE_SIZE, "%u\n", (gpio_evmi->flags & GPIOKPF_ACTIVE_HIGH) ? 1 : 0);
273}
274
275static ssize_t store_active_high_flag(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
276{
277 unsigned flag;
278
279 if (!gpio_evmi)
280 return -ENODEV;
281
282 sscanf(buf, "%u", &flag);
283
284 if (flag) {
285 gpio_evmi->flags |= GPIOKPF_ACTIVE_HIGH;
286 } else {
287 gpio_evmi->flags &= ~GPIOKPF_ACTIVE_HIGH;
288 }
289
290 return count;
291}
292
293static ssize_t show_drive_inactive_flag(struct device *dev, struct device_attribute *attr, char *buf)
294{
295 if (!gpio_evmi)
296 return -ENODEV;
297
298 return snprintf(buf, PAGE_SIZE, "%u\n", (gpio_evmi->flags & GPIOKPF_DRIVE_INACTIVE) ? 1 : 0);
299}
300
301static ssize_t store_drive_inactive_flag(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
302{
303 unsigned flag;
304
305 if (!gpio_evmi)
306 return -ENODEV;
307
308 sscanf(buf, "%u", &flag);
309
310 if (flag) {
311 gpio_evmi->flags |= GPIOKPF_DRIVE_INACTIVE;
312 } else {
313 gpio_evmi->flags &= ~GPIOKPF_DRIVE_INACTIVE;
314 }
315
316 return count;
317}
318
fc215caa
MG
319static DEVICE_ATTR(debounce_delay, (S_IRUGO | S_IWUGO), show_debounce_delay, store_debounce_delay);
320static DEVICE_ATTR(settle_time, (S_IRUGO | S_IWUGO), show_settle_time, store_settle_time);
321static DEVICE_ATTR(poll_time, (S_IRUGO | S_IWUGO), show_poll_time, store_poll_time);
322static DEVICE_ATTR(flags, (S_IRUGO), show_flags, store_flags);
323static DEVICE_ATTR(debounce_flag, (S_IRUGO | S_IWUGO), show_debounce_flag, store_debounce_flag);
324static DEVICE_ATTR(remove_some_phantom_keys_flag, (S_IRUGO | S_IWUGO), show_remove_some_phantom_keys_flag, store_remove_some_phantom_keys_flag);
325static DEVICE_ATTR(print_unmapped_keys_flag, (S_IRUGO | S_IWUGO), show_print_unmapped_keys_flag, store_print_unmapped_keys_flag);
326static DEVICE_ATTR(print_mapped_keys_flag, (S_IRUGO | S_IWUGO), show_print_mapped_keys_flag, store_print_mapped_keys_flag);
327static DEVICE_ATTR(print_phantom_keys_flag, (S_IRUGO | S_IWUGO), show_print_phantom_keys_flag, store_print_phantom_keys_flag);
a2485674
MG
328static DEVICE_ATTR(active_high_flag, (S_IRUGO), show_active_high_flag, store_active_high_flag);
329static DEVICE_ATTR(drive_inactive_flag, (S_IRUGO | S_IWUGO), show_drive_inactive_flag, store_drive_inactive_flag);
f7cb07b2
MG
330
331static void debounce_release(struct device *dev)
332{
333}
334
335static struct device debounce_device = {
336 .init_name = "debounce",
337 .release = debounce_release,
338};
339
62a453fc
MG
340static unsigned int mapphone_col_gpios[] = { 43, 53, 54, 55, 56, 57, 58, 63 };
341static unsigned int mapphone_row_gpios[] = { 34, 35, 36, 37, 38, 39, 40, 41 };
342
343static void hw_debounce_pin(int gpio, int enable) {
344 printk(KERN_INFO PREFIX "%sabling hardware debounce for GPIO %d\n", (enable?"En":"Dis"), gpio);
345 if (enable)
346 omap_set_gpio_debounce_time(gpio, GPIO_DEBOUNCE_TIME);
347 omap_set_gpio_debounce(gpio, enable);
348}
349
350static void hw_debounce(int enable) {
351 int i;
352
353 for (i = 0; i < (sizeof(mapphone_col_gpios) / sizeof(mapphone_col_gpios[0])); i++) {
354 hw_debounce_pin(mapphone_col_gpios[i], enable);
355 }
356
357 for (i = 0; i < (sizeof(mapphone_row_gpios) / sizeof(mapphone_row_gpios[0])); i++) {
358 hw_debounce_pin(mapphone_row_gpios[i], enable);
359 }
360}
361
b422e333
MG
362static int __init debounce_init(void)
363{
d1ff9643
MG
364 struct device *event_dev = NULL;
365 struct gpio_event_platform_data *gpio_epd;
366 struct gpio_event_info *gpio_ei;
f7cb07b2 367 int err = 0;
d1ff9643 368
ab5ed215 369 printk(KERN_INFO PREFIX "Searching for " GPIO_EVENT_DEV_NAME "...\n");
d1ff9643
MG
370
371 event_dev = device_find_child(&platform_bus, GPIO_EVENT_DEV_NAME, find_ms2_dev);
372 if (event_dev == NULL)
373 return -ENODEV;
374
375 gpio_epd = (struct gpio_event_platform_data*)event_dev->platform_data;
ab5ed215 376 printk(KERN_INFO PREFIX "And there is a %s connected...\n", gpio_epd->name);
d1ff9643
MG
377 if (strcmp(gpio_epd->name, "sholes-keypad"))
378 return -ENODEV;
379
380 gpio_ei = (struct gpio_event_info*)gpio_epd->info[0];
381 gpio_evmi = container_of(gpio_ei, struct gpio_event_matrix_info, info);
382
f7cb07b2
MG
383 err = device_register(&debounce_device);
384 if (err) {
385 return err;
386 }
387
62a453fc
MG
388 hw_debounce(1);
389
f7cb07b2
MG
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);
fc215caa
MG
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);
a2485674
MG
399 err = device_create_file(&debounce_device, &dev_attr_active_high_flag);
400 err = device_create_file(&debounce_device, &dev_attr_drive_inactive_flag);
f7cb07b2 401
ab5ed215
MG
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);
20bf1c9e 406
bb65757a
MG
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;
1e65c113 411
a4838b14
MG
412 printk(KERN_INFO PREFIX "flags: 0x%x\n", gpio_evmi->flags);
413
b422e333
MG
414 return 0;
415}
416
417static void __exit debounce_exit(void)
418{
1e65c113 419 if (gpio_evmi) {
bb65757a 420 if (gpio_evmi->debounce_delay.tv.nsec != old_debounce_delay.tv.nsec) {
1e65c113 421 printk(KERN_INFO PREFIX "Restoring debounce_delay\n");
bb65757a 422 gpio_evmi->debounce_delay = old_debounce_delay;
1e65c113
MG
423 printk(KERN_INFO PREFIX "debounce_delay: %u\n", gpio_evmi->debounce_delay.tv.nsec);
424 }
a4838b14
MG
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);
429 }
bb65757a
MG
430 gpio_evmi->settle_time = old_settle_time;
431 gpio_evmi->poll_time = old_poll_time;
1e65c113 432 }
62a453fc 433 hw_debounce(0);
f7cb07b2
MG
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);
fc215caa
MG
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);
a2485674
MG
443 device_remove_file(&debounce_device, &dev_attr_active_high_flag);
444 device_remove_file(&debounce_device, &dev_attr_drive_inactive_flag);
f7cb07b2 445 device_unregister(&debounce_device);
b422e333
MG
446}
447
448module_init(debounce_init);
449module_exit(debounce_exit);
450
451MODULE_LICENSE("GPL");
452MODULE_AUTHOR("Michael Gernoth <michael@gernoth.net>");
Impressum, Datenschutz