diff options
Diffstat (limited to 'drivers/input/keyboard/gpio_keys.c')
-rw-r--r-- | drivers/input/keyboard/gpio_keys.c | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c new file mode 100644 index 000000000000..3a8f1b427a7f --- /dev/null +++ b/drivers/input/keyboard/gpio_keys.c | |||
@@ -0,0 +1,147 @@ | |||
1 | /* | ||
2 | * Driver for keys on GPIO lines capable of generating interrupts. | ||
3 | * | ||
4 | * Copyright 2005 Phil Blundell | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/version.h> | ||
13 | |||
14 | #include <linux/init.h> | ||
15 | #include <linux/fs.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/irq.h> | ||
18 | #include <linux/sched.h> | ||
19 | #include <linux/pm.h> | ||
20 | #include <linux/sysctl.h> | ||
21 | #include <linux/proc_fs.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/input.h> | ||
25 | #include <linux/irq.h> | ||
26 | |||
27 | #include <asm/arch/pxa-regs.h> | ||
28 | #include <asm/arch/hardware.h> | ||
29 | |||
30 | #include <asm/hardware/gpio_keys.h> | ||
31 | |||
32 | static irqreturn_t gpio_keys_isr(int irq, void *dev_id) | ||
33 | { | ||
34 | int i; | ||
35 | struct platform_device *pdev = dev_id; | ||
36 | struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; | ||
37 | struct input_dev *input = platform_get_drvdata(pdev); | ||
38 | |||
39 | for (i = 0; i < pdata->nbuttons; i++) { | ||
40 | int gpio = pdata->buttons[i].gpio; | ||
41 | if (irq == IRQ_GPIO(gpio)) { | ||
42 | int state = ((GPLR(gpio) & GPIO_bit(gpio)) ? 1 : 0) ^ (pdata->buttons[i].active_low); | ||
43 | |||
44 | input_report_key(input, pdata->buttons[i].keycode, state); | ||
45 | input_sync(input); | ||
46 | } | ||
47 | } | ||
48 | |||
49 | return IRQ_HANDLED; | ||
50 | } | ||
51 | |||
52 | static int __devinit gpio_keys_probe(struct platform_device *pdev) | ||
53 | { | ||
54 | struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; | ||
55 | struct input_dev *input; | ||
56 | int i, error; | ||
57 | |||
58 | input = input_allocate_device(); | ||
59 | if (!input) | ||
60 | return -ENOMEM; | ||
61 | |||
62 | platform_set_drvdata(pdev, input); | ||
63 | |||
64 | input->evbit[0] = BIT(EV_KEY); | ||
65 | |||
66 | input->name = pdev->name; | ||
67 | input->phys = "gpio-keys/input0"; | ||
68 | input->cdev.dev = &pdev->dev; | ||
69 | input->private = pdata; | ||
70 | |||
71 | input->id.bustype = BUS_HOST; | ||
72 | input->id.vendor = 0x0001; | ||
73 | input->id.product = 0x0001; | ||
74 | input->id.version = 0x0100; | ||
75 | |||
76 | for (i = 0; i < pdata->nbuttons; i++) { | ||
77 | int code = pdata->buttons[i].keycode; | ||
78 | int irq = IRQ_GPIO(pdata->buttons[i].gpio); | ||
79 | |||
80 | set_irq_type(irq, IRQ_TYPE_EDGE_BOTH); | ||
81 | error = request_irq(irq, gpio_keys_isr, SA_SAMPLE_RANDOM, | ||
82 | pdata->buttons[i].desc ? pdata->buttons[i].desc : "gpio_keys", | ||
83 | pdev); | ||
84 | if (error) { | ||
85 | printk(KERN_ERR "gpio-keys: unable to claim irq %d; error %d\n", irq, ret); | ||
86 | goto fail; | ||
87 | } | ||
88 | set_bit(code, input->keybit); | ||
89 | } | ||
90 | |||
91 | error = input_register_device(input); | ||
92 | if (error) { | ||
93 | printk(KERN_ERR "Unable to register gpio-keys input device\n"); | ||
94 | goto fail; | ||
95 | } | ||
96 | |||
97 | return 0; | ||
98 | |||
99 | fail: | ||
100 | for (i = i - 1; i >= 0; i--) | ||
101 | free_irq(IRQ_GPIO(pdata->buttons[i].gpio), pdev); | ||
102 | |||
103 | input_free_device(input); | ||
104 | |||
105 | return error; | ||
106 | } | ||
107 | |||
108 | static int __devexit gpio_keys_remove(struct platform_device *pdev) | ||
109 | { | ||
110 | struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; | ||
111 | struct input_dev *input = platform_get_drvdata(pdev); | ||
112 | int i; | ||
113 | |||
114 | for (i = 0; i < pdata->nbuttons; i++) { | ||
115 | int irq = IRQ_GPIO(pdata->buttons[i].gpio); | ||
116 | free_irq(irq, pdev); | ||
117 | } | ||
118 | |||
119 | input_unregister_device(input); | ||
120 | |||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | struct platform_driver gpio_keys_device_driver = { | ||
125 | .probe = gpio_keys_probe, | ||
126 | .remove = __devexit_p(gpio_keys_remove), | ||
127 | .driver = { | ||
128 | .name = "gpio-keys", | ||
129 | } | ||
130 | }; | ||
131 | |||
132 | static int __init gpio_keys_init(void) | ||
133 | { | ||
134 | return platform_driver_register(&gpio_keys_device_driver); | ||
135 | } | ||
136 | |||
137 | static void __exit gpio_keys_exit(void) | ||
138 | { | ||
139 | platform_driver_unregister(&gpio_keys_device_driver); | ||
140 | } | ||
141 | |||
142 | module_init(gpio_keys_init); | ||
143 | module_exit(gpio_keys_exit); | ||
144 | |||
145 | MODULE_LICENSE("GPL"); | ||
146 | MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>"); | ||
147 | MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs"); | ||