[s3c24xx] bump to 2.6.30-rc6
[openwrt.git] / target / linux / s3c24xx / files-2.6.30 / drivers / input / keyboard / gta02kbd.c
1 /*
2  * Keyboard driver for Openmoko Freerunner GSM phone
3  *
4  * (C) 2006-2007 by Openmoko, Inc.
5  * Author: Harald Welte <laforge@openmoko.org>
6  * All rights reserved.
7  *
8  * inspired by corkgbd.c by Richard Purdie
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  *
14  */
15
16 #include <linux/delay.h>
17 #include <linux/platform_device.h>
18 #include <linux/init.h>
19 #include <linux/input.h>
20 #include <linux/interrupt.h>
21 #include <linux/jiffies.h>
22 #include <linux/module.h>
23 #include <linux/slab.h>
24 #include <linux/workqueue.h>
25
26 #include <mach/gpio.h>
27 #include <asm/mach-types.h>
28
29 #ifdef CONFIG_PM
30 extern int global_inside_suspend;
31 #else
32 #define global_inside_suspend 0
33 #endif
34
35 struct gta02kbd {
36         struct platform_device *pdev;
37         struct input_dev *input;
38         struct device *cdev;
39         struct work_struct work;
40         int aux_state;
41         int work_in_progress;
42         int hp_irq_count_in_work;
43         int hp_irq_count;
44         int jack_irq;
45 };
46
47 static struct class *gta02kbd_switch_class;
48
49 enum keys {
50         GTA02_KEY_AUX,
51         GTA02_KEY_HOLD,
52         GTA02_KEY_JACK,
53 };
54
55 struct gta02kbd_key {
56         const char * name;
57         irqreturn_t (*isr)(int irq, void *dev_id);
58         int irq;
59         int input_key;
60 };
61
62 static irqreturn_t gta02kbd_aux_irq(int irq, void *dev_id);
63 static irqreturn_t gta02kbd_headphone_irq(int irq, void *dev_id);
64 static irqreturn_t gta02kbd_default_key_irq(int irq, void *dev_id);
65
66
67 static struct gta02kbd_key keys[] = {
68         [GTA02_KEY_AUX] = {
69                 .name = "GTA02 AUX button",
70                 .isr = gta02kbd_aux_irq,
71                 .input_key = KEY_PHONE,
72         },
73         [GTA02_KEY_HOLD] = {
74                 .name = "GTA02 HOLD button",
75                 .isr = gta02kbd_default_key_irq,
76                 .input_key = KEY_PAUSE,
77         },
78         [GTA02_KEY_JACK] = {
79                 .name = "GTA02 Headphone jack",
80                 .isr = gta02kbd_headphone_irq,
81         },
82 };
83
84 /* This timer section filters AUX button IRQ bouncing */
85
86 static void aux_key_timer_f(unsigned long data);
87
88 static struct timer_list aux_key_timer =
89                 TIMER_INITIALIZER(aux_key_timer_f, 0, 0);
90
91 #define AUX_TIMER_TIMEOUT (HZ >> 7)
92 #define AUX_TIMER_ALLOWED_NOOP 2
93 #define AUX_TIMER_CONSECUTIVE_EVENTS 5
94
95 struct gta02kbd *timer_kbd;
96
97 static void aux_key_timer_f(unsigned long data)
98 {
99         static int noop_counter;
100         static int last_key = -1;
101         static int last_count;
102         int key_pressed;
103
104         key_pressed =
105                 gpio_get_value(timer_kbd->pdev->resource[GTA02_KEY_AUX].start);
106
107         if (likely(key_pressed == last_key))
108                 last_count++;
109         else {
110                 last_count = 1;
111                 last_key = key_pressed;
112         }
113
114         if (unlikely(last_count >= AUX_TIMER_CONSECUTIVE_EVENTS)) {
115                 if (timer_kbd->aux_state != last_key) {
116                         input_report_key(timer_kbd->input, KEY_PHONE, last_key);
117                         input_sync(timer_kbd->input);
118
119                         timer_kbd->aux_state = last_key;
120                         noop_counter = 0;
121                 }
122                 last_count = 0;
123                 if (unlikely(++noop_counter > AUX_TIMER_ALLOWED_NOOP)) {
124                         noop_counter = 0;
125                         return;
126                 }
127         }
128
129         mod_timer(&aux_key_timer, jiffies + AUX_TIMER_TIMEOUT);
130 }
131
132 static irqreturn_t gta02kbd_aux_irq(int irq, void *dev)
133 {
134         mod_timer(&aux_key_timer, jiffies + AUX_TIMER_TIMEOUT);
135
136         return IRQ_HANDLED;
137 }
138
139 static irqreturn_t gta02kbd_default_key_irq(int irq, void *dev_id)
140 {
141         struct gta02kbd *kbd = dev_id;
142         int n;
143
144         for (n = 0; n < ARRAY_SIZE(keys); n++) {
145
146                 if (irq != keys[n].irq)
147                         continue;
148
149                 input_report_key(kbd->input, keys[n].input_key,
150                                   gpio_get_value(kbd->pdev->resource[n].start));
151                 input_sync(kbd->input);
152         }
153
154         return IRQ_HANDLED;
155 }
156
157
158 static const char *event_array_jack[2][4] = {
159         [0] = {
160                 "SWITCH_NAME=headset",
161                 "SWITCH_STATE=0",
162                 "EVENT=remove",
163                 NULL
164         },
165         [1] = {
166                 "SWITCH_NAME=headset",
167                 "SWITCH_STATE=1",
168                 "EVENT=insert",
169                 NULL
170         },
171 };
172
173 static void gta02kbd_jack_event(struct device *dev, int num)
174 {
175         kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, (char **)event_array_jack[!!num]);
176 }
177
178
179 static void gta02kbd_debounce_jack(struct work_struct *work)
180 {
181         struct gta02kbd *kbd = container_of(work, struct gta02kbd, work);
182         unsigned long flags;
183         int loop = 0;
184         int level;
185
186         do {
187                 /*
188                  * we wait out any multiple interrupt
189                  * stuttering in 100ms lumps
190                  */
191                 do {
192                         kbd->hp_irq_count_in_work = kbd->hp_irq_count;
193                         msleep(100);
194                 } while (kbd->hp_irq_count != kbd->hp_irq_count_in_work);
195                 /*
196                  * no new interrupts on jack for 100ms...
197                  * ok we will report it
198                  */
199                 level = gpio_get_value(kbd->pdev->resource[GTA02_KEY_JACK].start);
200                 input_report_switch(kbd->input, SW_HEADPHONE_INSERT, level);
201                 input_sync(kbd->input);
202                 gta02kbd_jack_event(kbd->cdev, level);
203                 /*
204                  * we go around the outer loop again if we detect that more
205                  * interrupts came while we are servicing here.  But we have
206                  * to sequence it carefully with interrupts off
207                  */
208                 local_save_flags(flags);
209                 /* no interrupts during this work means we can exit the work */
210                 loop = !!(kbd->hp_irq_count != kbd->hp_irq_count_in_work);
211                 if (!loop)
212                         kbd->work_in_progress = 0;
213                 local_irq_restore(flags);
214                 /*
215                  * interrupt that comes here will either queue a new work action
216                  * since work_in_progress is cleared now, or be dealt with
217                  * when we loop.
218                  */
219         } while (loop);
220 }
221
222
223 static irqreturn_t gta02kbd_headphone_irq(int irq, void *dev_id)
224 {
225         struct gta02kbd *gta02kbd_data = dev_id;
226
227         /*
228          * this interrupt is prone to bouncing and userspace doesn't like
229          * to have to deal with that kind of thing.  So we do not accept
230          * that a jack interrupt is equal to a jack event.  Instead we fire
231          * some work on the first interrupt, and it hangs about in 100ms units
232          * until no more interrupts come.  Then it accepts the state it finds
233          * for jack insert and reports it once
234          */
235
236         gta02kbd_data->hp_irq_count++;
237         /*
238          * the first interrupt we see for a while, we fire the work item
239          * and record the interrupt count when we did that.  If more interrupts
240          * come in the meanwhile, we can tell by the difference in that
241          * stored count and hp_irq_count which increments every interrupt
242          */
243         if (!gta02kbd_data->work_in_progress) {
244                 gta02kbd_data->jack_irq = irq;
245                 gta02kbd_data->hp_irq_count_in_work =
246                                                 gta02kbd_data->hp_irq_count;
247                 if (!schedule_work(&gta02kbd_data->work))
248                         printk(KERN_ERR
249                                 "Unable to schedule headphone debounce\n");
250                 else
251                         gta02kbd_data->work_in_progress = 1;
252         }
253
254         return IRQ_HANDLED;
255 }
256
257 #ifdef CONFIG_PM
258 static int gta02kbd_suspend(struct platform_device *dev, pm_message_t state)
259 {
260         disable_irq(keys[GTA02_KEY_AUX].irq);
261         del_timer_sync(&aux_key_timer);
262         return 0;
263 }
264
265 static int gta02kbd_resume(struct platform_device *dev)
266 {
267         enable_irq(keys[GTA02_KEY_AUX].irq);
268         return 0;
269 }
270 #else
271 #define gta02kbd_suspend        NULL
272 #define gta02kbd_resume NULL
273 #endif
274
275 static ssize_t gta02kbd_switch_name_show(struct device *dev,
276                         struct device_attribute *attr, char *buf)
277 {
278         return sprintf(buf, "%s\n", "gta02 Headset Jack");
279 }
280
281 static ssize_t gta02kbd_switch_state_show(struct device *dev,
282                         struct device_attribute *attr, char *buf)
283 {
284         struct gta02kbd *kbd = dev_get_drvdata(dev);
285         return sprintf(buf, "%d\n",
286                    gpio_get_value(kbd->pdev->resource[GTA02_KEY_JACK].start));
287 }
288
289 static DEVICE_ATTR(name, S_IRUGO , gta02kbd_switch_name_show, NULL);
290 static DEVICE_ATTR(state, S_IRUGO , gta02kbd_switch_state_show, NULL);
291
292 static int gta02kbd_probe(struct platform_device *pdev)
293 {
294         struct gta02kbd *gta02kbd;
295         struct input_dev *input_dev;
296         int rc;
297         int irq;
298         int n;
299
300         gta02kbd = kzalloc(sizeof(struct gta02kbd), GFP_KERNEL);
301         input_dev = input_allocate_device();
302         if (!gta02kbd || !input_dev) {
303                 kfree(gta02kbd);
304                 input_free_device(input_dev);
305                 return -ENOMEM;
306         }
307
308         gta02kbd->pdev = pdev;
309         timer_kbd = gta02kbd;
310
311         if (pdev->resource[0].flags != 0)
312                 return -EINVAL;
313
314         platform_set_drvdata(pdev, gta02kbd);
315
316         gta02kbd->input = input_dev;
317
318         INIT_WORK(&gta02kbd->work, gta02kbd_debounce_jack);
319
320         input_dev->name = "GTA02 Buttons";
321         input_dev->phys = "gta02kbd/input0";
322         input_dev->id.bustype = BUS_HOST;
323         input_dev->id.vendor = 0x0001;
324         input_dev->id.product = 0x0001;
325         input_dev->id.version = 0x0100;
326         input_dev->dev.parent = &pdev->dev;
327
328         input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_SW);
329         set_bit(SW_HEADPHONE_INSERT, input_dev->swbit);
330         set_bit(KEY_PHONE, input_dev->keybit);
331         set_bit(KEY_PAUSE, input_dev->keybit);
332
333         rc = input_register_device(gta02kbd->input);
334         if (rc)
335                 goto out_register;
336
337         gta02kbd->cdev = device_create(gta02kbd_switch_class,
338                                           &pdev->dev, 0, gta02kbd, "headset");
339         if (unlikely(IS_ERR(gta02kbd->cdev))) {
340                 rc = PTR_ERR(gta02kbd->cdev);
341                 goto out_device_create;
342         }
343
344         rc = device_create_file(gta02kbd->cdev, &dev_attr_name);
345         if(rc)
346                 goto out_device_create_file;
347
348         rc = device_create_file(gta02kbd->cdev, &dev_attr_state);
349         if(rc)
350                 goto out_device_create_file;
351
352         /* register GPIO IRQs */
353         for(n = 0; n < min(pdev->num_resources, ARRAY_SIZE(keys)); n++) {
354
355                 if (!pdev->resource[0].start)
356                         continue;
357
358                 irq = gpio_to_irq(pdev->resource[n].start);
359                 if (irq < 0)
360                         continue;
361
362                 if (request_irq(irq, keys[n].isr, IRQF_DISABLED |
363                                 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
364                                 keys[n].name, gta02kbd)) {
365                         dev_err(&pdev->dev, "Can't get IRQ %u\n", irq);
366
367                         /* unwind any irq registrations and fail */
368
369                         while (n > 0) {
370                                 n--;
371                                 free_irq(gpio_to_irq(pdev->resource[n].start),
372                                                                     gta02kbd);
373                         }
374                         goto out_device_create_file;
375                 }
376
377                 keys[n].irq = irq;
378         }
379
380         enable_irq_wake(keys[GTA02_KEY_JACK].irq);
381
382         return 0;
383
384 out_device_create_file:
385         device_unregister(gta02kbd->cdev);
386 out_device_create:
387         input_unregister_device(gta02kbd->input);
388 out_register:
389         input_free_device(gta02kbd->input);
390         platform_set_drvdata(pdev, NULL);
391         kfree(gta02kbd);
392
393         return -ENODEV;
394 }
395
396 static int gta02kbd_remove(struct platform_device *pdev)
397 {
398         struct gta02kbd *gta02kbd = platform_get_drvdata(pdev);
399
400         free_irq(gpio_to_irq(pdev->resource[2].start), gta02kbd);
401         free_irq(gpio_to_irq(pdev->resource[1].start), gta02kbd);
402         free_irq(gpio_to_irq(pdev->resource[0].start), gta02kbd);
403
404         device_unregister(gta02kbd->cdev);
405         input_unregister_device(gta02kbd->input);
406         input_free_device(gta02kbd->input);
407         platform_set_drvdata(pdev, NULL);
408         kfree(gta02kbd);
409
410         return 0;
411 }
412
413 static struct platform_driver gta02kbd_driver = {
414         .probe          = gta02kbd_probe,
415         .remove         = gta02kbd_remove,
416         .suspend        = gta02kbd_suspend,
417         .resume         = gta02kbd_resume,
418         .driver         = {
419                 .name   = "gta02-button",
420         },
421 };
422
423 static int __devinit gta02kbd_init(void)
424 {
425         gta02kbd_switch_class = class_create(THIS_MODULE, "switch");
426         if (IS_ERR(gta02kbd_switch_class))
427                 return PTR_ERR(gta02kbd_switch_class);
428         return platform_driver_register(&gta02kbd_driver);
429 }
430
431 static void __exit gta02kbd_exit(void)
432 {
433         platform_driver_unregister(&gta02kbd_driver);
434         class_destroy(gta02kbd_switch_class);
435 }
436
437 module_init(gta02kbd_init);
438 module_exit(gta02kbd_exit);
439
440 MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
441 MODULE_DESCRIPTION("Openmoko Freerunner buttons input driver");
442 MODULE_LICENSE("GPL");