blob: a98be67d1ab0d530b110573d5d688bc970dc7330 [file] [log] [blame]
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -07001/* drivers/input/misc/gpio_event.c
2 *
3 * Copyright (C) 2007 Google, Inc.
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 */
15
16#include <linux/earlysuspend.h>
17#include <linux/module.h>
18#include <linux/input.h>
19#include <linux/gpio_event.h>
20#include <linux/hrtimer.h>
21#include <linux/platform_device.h>
22#include <linux/slab.h>
23
24struct gpio_event {
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -070025 struct gpio_event_input_devs *input_devs;
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -070026 const struct gpio_event_platform_data *info;
27 struct early_suspend early_suspend;
28 void *state[0];
29};
30
31static int gpio_input_event(
32 struct input_dev *dev, unsigned int type, unsigned int code, int value)
33{
34 int i;
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -070035 int devnr;
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -070036 int ret = 0;
37 int tmp_ret;
38 struct gpio_event_info **ii;
39 struct gpio_event *ip = input_get_drvdata(dev);
40
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -070041 for (devnr = 0; devnr < ip->input_devs->count; devnr++)
42 if (ip->input_devs->dev[devnr] == dev)
43 break;
44 if (devnr == ip->input_devs->count) {
45 pr_err("gpio_input_event: unknown device %p\n", dev);
46 return -EIO;
47 }
48
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -070049 for (i = 0, ii = ip->info->info; i < ip->info->info_count; i++, ii++) {
50 if ((*ii)->event) {
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -070051 tmp_ret = (*ii)->event(ip->input_devs, *ii,
52 &ip->state[i],
53 devnr, type, code, value);
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -070054 if (tmp_ret)
55 ret = tmp_ret;
56 }
57 }
58 return ret;
59}
60
61static int gpio_event_call_all_func(struct gpio_event *ip, int func)
62{
63 int i;
64 int ret;
65 struct gpio_event_info **ii;
66
67 if (func == GPIO_EVENT_FUNC_INIT || func == GPIO_EVENT_FUNC_RESUME) {
68 ii = ip->info->info;
69 for (i = 0; i < ip->info->info_count; i++, ii++) {
70 if ((*ii)->func == NULL) {
71 ret = -ENODEV;
72 pr_err("gpio_event_probe: Incomplete pdata, "
73 "no function\n");
74 goto err_no_func;
75 }
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -070076 if (func == GPIO_EVENT_FUNC_RESUME && (*ii)->no_suspend)
77 continue;
78 ret = (*ii)->func(ip->input_devs, *ii, &ip->state[i],
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -070079 func);
80 if (ret) {
81 pr_err("gpio_event_probe: function failed\n");
82 goto err_func_failed;
83 }
84 }
85 return 0;
86 }
87
88 ret = 0;
89 i = ip->info->info_count;
90 ii = ip->info->info + i;
91 while (i > 0) {
92 i--;
93 ii--;
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -070094 if ((func & ~1) == GPIO_EVENT_FUNC_SUSPEND && (*ii)->no_suspend)
95 continue;
96 (*ii)->func(ip->input_devs, *ii, &ip->state[i], func & ~1);
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -070097err_func_failed:
98err_no_func:
99 ;
100 }
101 return ret;
102}
103
104#ifdef CONFIG_HAS_EARLYSUSPEND
105void gpio_event_suspend(struct early_suspend *h)
106{
107 struct gpio_event *ip;
108 ip = container_of(h, struct gpio_event, early_suspend);
109 gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_SUSPEND);
110 ip->info->power(ip->info, 0);
111}
112
113void gpio_event_resume(struct early_suspend *h)
114{
115 struct gpio_event *ip;
116 ip = container_of(h, struct gpio_event, early_suspend);
117 ip->info->power(ip->info, 1);
118 gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_RESUME);
119}
120#endif
121
Dmitry Shmidt2921bbb2010-07-02 12:48:48 -0700122static int gpio_event_probe(struct platform_device *pdev)
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700123{
124 int err;
125 struct gpio_event *ip;
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700126 struct gpio_event_platform_data *event_info;
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -0700127 int dev_count = 1;
128 int i;
129 int registered = 0;
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700130
131 event_info = pdev->dev.platform_data;
132 if (event_info == NULL) {
133 pr_err("gpio_event_probe: No pdata\n");
134 return -ENODEV;
135 }
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -0700136 if ((!event_info->name && !event_info->names[0]) ||
137 !event_info->info || !event_info->info_count) {
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700138 pr_err("gpio_event_probe: Incomplete pdata\n");
139 return -ENODEV;
140 }
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -0700141 if (!event_info->name)
142 while (event_info->names[dev_count])
143 dev_count++;
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700144 ip = kzalloc(sizeof(*ip) +
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -0700145 sizeof(ip->state[0]) * event_info->info_count +
146 sizeof(*ip->input_devs) +
147 sizeof(ip->input_devs->dev[0]) * dev_count, GFP_KERNEL);
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700148 if (ip == NULL) {
149 err = -ENOMEM;
150 pr_err("gpio_event_probe: Failed to allocate private data\n");
151 goto err_kp_alloc_failed;
152 }
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -0700153 ip->input_devs = (void*)&ip->state[event_info->info_count];
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700154 platform_set_drvdata(pdev, ip);
155
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -0700156 for (i = 0; i < dev_count; i++) {
157 struct input_dev *input_dev = input_allocate_device();
158 if (input_dev == NULL) {
159 err = -ENOMEM;
160 pr_err("gpio_event_probe: "
161 "Failed to allocate input device\n");
162 goto err_input_dev_alloc_failed;
163 }
164 input_set_drvdata(input_dev, ip);
165 input_dev->name = event_info->name ?
166 event_info->name : event_info->names[i];
167 input_dev->event = gpio_input_event;
168 ip->input_devs->dev[i] = input_dev;
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700169 }
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -0700170 ip->input_devs->count = dev_count;
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700171 ip->info = event_info;
172 if (event_info->power) {
173#ifdef CONFIG_HAS_EARLYSUSPEND
174 ip->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
175 ip->early_suspend.suspend = gpio_event_suspend;
176 ip->early_suspend.resume = gpio_event_resume;
177 register_early_suspend(&ip->early_suspend);
178#endif
179 ip->info->power(ip->info, 1);
180 }
181
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700182 err = gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_INIT);
183 if (err)
184 goto err_call_all_func_failed;
185
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -0700186 for (i = 0; i < dev_count; i++) {
187 err = input_register_device(ip->input_devs->dev[i]);
188 if (err) {
189 pr_err("gpio_event_probe: Unable to register %s "
190 "input device\n", ip->input_devs->dev[i]->name);
191 goto err_input_register_device_failed;
192 }
193 registered++;
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700194 }
195
196 return 0;
197
198err_input_register_device_failed:
199 gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_UNINIT);
200err_call_all_func_failed:
201 if (event_info->power) {
202#ifdef CONFIG_HAS_EARLYSUSPEND
203 unregister_early_suspend(&ip->early_suspend);
204#endif
205 ip->info->power(ip->info, 0);
206 }
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -0700207 for (i = 0; i < registered; i++)
208 input_unregister_device(ip->input_devs->dev[i]);
209 for (i = dev_count - 1; i >= registered; i--) {
210 input_free_device(ip->input_devs->dev[i]);
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700211err_input_dev_alloc_failed:
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -0700212 ;
213 }
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700214 kfree(ip);
215err_kp_alloc_failed:
216 return err;
217}
218
219static int gpio_event_remove(struct platform_device *pdev)
220{
221 struct gpio_event *ip = platform_get_drvdata(pdev);
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -0700222 int i;
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700223
224 gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_UNINIT);
225 if (ip->info->power) {
226#ifdef CONFIG_HAS_EARLYSUSPEND
227 unregister_early_suspend(&ip->early_suspend);
228#endif
229 ip->info->power(ip->info, 0);
230 }
Arve Hjønnevåg0da26bf2009-07-24 15:19:56 -0700231 for (i = 0; i < ip->input_devs->count; i++)
232 input_unregister_device(ip->input_devs->dev[i]);
Arve Hjønnevåg72fc6242008-10-15 18:23:47 -0700233 kfree(ip);
234 return 0;
235}
236
237static struct platform_driver gpio_event_driver = {
238 .probe = gpio_event_probe,
239 .remove = gpio_event_remove,
240 .driver = {
241 .name = GPIO_EVENT_DEV_NAME,
242 },
243};
244
245static int __devinit gpio_event_init(void)
246{
247 return platform_driver_register(&gpio_event_driver);
248}
249
250static void __exit gpio_event_exit(void)
251{
252 platform_driver_unregister(&gpio_event_driver);
253}
254
255module_init(gpio_event_init);
256module_exit(gpio_event_exit);
257
258MODULE_DESCRIPTION("GPIO Event Driver");
259MODULE_LICENSE("GPL");
260