source: trunk/target/linux/s3c24xx/files-2.6.30/drivers/input/keyboard/gta02kbd.c @ 17069

Last change on this file since 17069 was 17069, checked in by lars, 7 years ago

[s3c24xx] Move headset detection to the sound driver using the jack framework.

File size: 6.0 KB
Line 
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
25#include <mach/gpio.h>
26#include <asm/mach-types.h>
27
28#ifdef CONFIG_PM
29extern int global_inside_suspend;
30#else
31#define global_inside_suspend 0
32#endif
33
34struct gta02kbd {
35        struct platform_device *pdev;
36        struct input_dev *input;
37        int aux_state;
38};
39
40enum keys {
41        GTA02_KEY_AUX,
42        GTA02_KEY_HOLD,
43};
44
45struct gta02kbd_key {
46        const char * name;
47        irqreturn_t (*isr)(int irq, void *dev_id);
48        int irq;
49        int input_key;
50};
51
52static irqreturn_t gta02kbd_aux_irq(int irq, void *dev_id);
53static irqreturn_t gta02kbd_default_key_irq(int irq, void *dev_id);
54
55
56static struct gta02kbd_key keys[] = {
57        [GTA02_KEY_AUX] = {
58                .name = "GTA02 AUX button",
59                .isr = gta02kbd_aux_irq,
60                .input_key = KEY_PHONE,
61        },
62        [GTA02_KEY_HOLD] = {
63                .name = "GTA02 HOLD button",
64                .isr = gta02kbd_default_key_irq,
65                .input_key = KEY_PAUSE,
66        },
67};
68
69/* This timer section filters AUX button IRQ bouncing */
70
71static void aux_key_timer_f(unsigned long data);
72
73static struct timer_list aux_key_timer =
74                TIMER_INITIALIZER(aux_key_timer_f, 0, 0);
75
76#define AUX_TIMER_TIMEOUT (HZ >> 7)
77#define AUX_TIMER_ALLOWED_NOOP 2
78#define AUX_TIMER_CONSECUTIVE_EVENTS 5
79
80struct gta02kbd *timer_kbd;
81
82static void aux_key_timer_f(unsigned long data)
83{
84        static int noop_counter;
85        static int last_key = -1;
86        static int last_count;
87        int key_pressed;
88
89        key_pressed =
90                gpio_get_value(timer_kbd->pdev->resource[GTA02_KEY_AUX].start);
91
92        if (likely(key_pressed == last_key))
93                last_count++;
94        else {
95                last_count = 1;
96                last_key = key_pressed;
97        }
98
99        if (unlikely(last_count >= AUX_TIMER_CONSECUTIVE_EVENTS)) {
100                if (timer_kbd->aux_state != last_key) {
101                        input_report_key(timer_kbd->input, KEY_PHONE, last_key);
102                        input_sync(timer_kbd->input);
103
104                        timer_kbd->aux_state = last_key;
105                        noop_counter = 0;
106                }
107                last_count = 0;
108                if (unlikely(++noop_counter > AUX_TIMER_ALLOWED_NOOP)) {
109                        noop_counter = 0;
110                        return;
111                }
112        }
113
114        mod_timer(&aux_key_timer, jiffies + AUX_TIMER_TIMEOUT);
115}
116
117static irqreturn_t gta02kbd_aux_irq(int irq, void *dev)
118{
119        mod_timer(&aux_key_timer, jiffies + AUX_TIMER_TIMEOUT);
120
121        return IRQ_HANDLED;
122}
123
124static irqreturn_t gta02kbd_default_key_irq(int irq, void *dev_id)
125{
126        struct gta02kbd *kbd = dev_id;
127        int n;
128
129        for (n = 0; n < ARRAY_SIZE(keys); n++) {
130
131                if (irq != keys[n].irq)
132                        continue;
133
134                input_report_key(kbd->input, keys[n].input_key,
135                                  gpio_get_value(kbd->pdev->resource[n].start));
136                input_sync(kbd->input);
137        }
138
139        return IRQ_HANDLED;
140}
141
142#ifdef CONFIG_PM
143static int gta02kbd_suspend(struct platform_device *dev, pm_message_t state)
144{
145        disable_irq(keys[GTA02_KEY_AUX].irq);
146        del_timer_sync(&aux_key_timer);
147        return 0;
148}
149
150static int gta02kbd_resume(struct platform_device *dev)
151{
152        enable_irq(keys[GTA02_KEY_AUX].irq);
153        return 0;
154}
155#else
156#define gta02kbd_suspend        NULL
157#define gta02kbd_resume NULL
158#endif
159
160static int gta02kbd_probe(struct platform_device *pdev)
161{
162        struct gta02kbd *gta02kbd;
163        struct input_dev *input_dev;
164        int rc;
165        int irq;
166        int n;
167
168        if (pdev->resource[0].flags != 0)
169                return -EINVAL;
170
171        gta02kbd = kzalloc(sizeof(struct gta02kbd), GFP_KERNEL);
172        input_dev = input_allocate_device();
173        if (!gta02kbd || !input_dev) {
174                kfree(gta02kbd);
175                input_free_device(input_dev);
176                return -ENOMEM;
177        }
178
179        gta02kbd->pdev = pdev;
180        timer_kbd = gta02kbd;
181
182        platform_set_drvdata(pdev, gta02kbd);
183
184        gta02kbd->input = input_dev;
185
186        input_dev->name = "GTA02 Buttons";
187        input_dev->phys = "gta02kbd/input0";
188        input_dev->id.bustype = BUS_HOST;
189        input_dev->id.vendor = 0x0001;
190        input_dev->id.product = 0x0001;
191        input_dev->id.version = 0x0100;
192        input_dev->dev.parent = &pdev->dev;
193
194        input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_SW);
195        set_bit(KEY_PHONE, input_dev->keybit);
196        set_bit(KEY_PAUSE, input_dev->keybit);
197
198        rc = input_register_device(gta02kbd->input);
199        if (rc)
200                goto out_register;
201
202        /* register GPIO IRQs */
203        for(n = 0; n < min(pdev->num_resources, ARRAY_SIZE(keys)); n++) {
204
205                if (!pdev->resource[0].start)
206                        continue;
207
208                irq = gpio_to_irq(pdev->resource[n].start);
209                if (irq < 0)
210                        continue;
211
212                if (request_irq(irq, keys[n].isr, IRQF_DISABLED |
213                                IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
214                                keys[n].name, gta02kbd)) {
215                        dev_err(&pdev->dev, "Can't get IRQ %u\n", irq);
216
217                        /* unwind any irq registrations and fail */
218
219                        while (n > 0) {
220                                n--;
221                                free_irq(gpio_to_irq(pdev->resource[n].start),
222                                                                    gta02kbd);
223                        }
224                        goto out_device_create;
225                }
226
227                keys[n].irq = irq;
228        }
229
230
231        return 0;
232
233out_device_create:
234        input_unregister_device(gta02kbd->input);
235out_register:
236        input_free_device(gta02kbd->input);
237        platform_set_drvdata(pdev, NULL);
238        kfree(gta02kbd);
239
240        return -ENODEV;
241}
242
243static int gta02kbd_remove(struct platform_device *pdev)
244{
245        struct gta02kbd *gta02kbd = platform_get_drvdata(pdev);
246
247        free_irq(gpio_to_irq(pdev->resource[1].start), gta02kbd);
248        free_irq(gpio_to_irq(pdev->resource[0].start), gta02kbd);
249
250        input_unregister_device(gta02kbd->input);
251        input_free_device(gta02kbd->input);
252        platform_set_drvdata(pdev, NULL);
253        kfree(gta02kbd);
254
255        return 0;
256}
257
258static struct platform_driver gta02kbd_driver = {
259        .probe          = gta02kbd_probe,
260        .remove         = gta02kbd_remove,
261        .suspend        = gta02kbd_suspend,
262        .resume         = gta02kbd_resume,
263        .driver         = {
264                .name   = "gta02-button",
265        },
266};
267
268static int __devinit gta02kbd_init(void)
269{
270        return platform_driver_register(&gta02kbd_driver);
271}
272
273static void __exit gta02kbd_exit(void)
274{
275        platform_driver_unregister(&gta02kbd_driver);
276}
277
278module_init(gta02kbd_init);
279module_exit(gta02kbd_exit);
280
281MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
282MODULE_DESCRIPTION("Openmoko Freerunner buttons input driver");
283MODULE_LICENSE("GPL");
Note: See TracBrowser for help on using the repository browser.