]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/staging/dream/gpio_event.c
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel...
[net-next-2.6.git] / drivers / staging / dream / gpio_event.c
CommitLineData
420818f9
AH
1/* 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
ace9e791 16
5a0e3ad6 17#include <linux/slab.h>
420818f9
AH
18#include <linux/module.h>
19#include <linux/input.h>
20#include <linux/gpio_event.h>
21#include <linux/hrtimer.h>
22#include <linux/platform_device.h>
23
24struct gpio_event {
25 struct input_dev *input_dev;
26 const struct gpio_event_platform_data *info;
420818f9
AH
27 void *state[0];
28};
29
30static int gpio_input_event(
31 struct input_dev *dev, unsigned int type, unsigned int code, int value)
32{
33 int i;
34 int ret = 0;
35 int tmp_ret;
36 struct gpio_event_info **ii;
37 struct gpio_event *ip = input_get_drvdata(dev);
38
39 for (i = 0, ii = ip->info->info; i < ip->info->info_count; i++, ii++) {
40 if ((*ii)->event) {
41 tmp_ret = (*ii)->event(ip->input_dev, *ii,
42 &ip->state[i], type, code, value);
43 if (tmp_ret)
44 ret = tmp_ret;
45 }
46 }
47 return ret;
48}
49
50static int gpio_event_call_all_func(struct gpio_event *ip, int func)
51{
52 int i;
53 int ret;
54 struct gpio_event_info **ii;
55
56 if (func == GPIO_EVENT_FUNC_INIT || func == GPIO_EVENT_FUNC_RESUME) {
57 ii = ip->info->info;
58 for (i = 0; i < ip->info->info_count; i++, ii++) {
59 if ((*ii)->func == NULL) {
60 ret = -ENODEV;
61 pr_err("gpio_event_probe: Incomplete pdata, "
62 "no function\n");
63 goto err_no_func;
64 }
65 ret = (*ii)->func(ip->input_dev, *ii, &ip->state[i],
66 func);
67 if (ret) {
68 pr_err("gpio_event_probe: function failed\n");
69 goto err_func_failed;
70 }
71 }
72 return 0;
73 }
74
75 ret = 0;
76 i = ip->info->info_count;
77 ii = ip->info->info + i;
78 while (i > 0) {
79 i--;
80 ii--;
81 (*ii)->func(ip->input_dev, *ii, &ip->state[i], func & ~1);
82err_func_failed:
83err_no_func:
84 ;
85 }
86 return ret;
87}
88
89#ifdef CONFIG_HAS_EARLYSUSPEND
90void gpio_event_suspend(struct early_suspend *h)
91{
92 struct gpio_event *ip;
93 ip = container_of(h, struct gpio_event, early_suspend);
94 gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_SUSPEND);
95 ip->info->power(ip->info, 0);
96}
97
98void gpio_event_resume(struct early_suspend *h)
99{
100 struct gpio_event *ip;
101 ip = container_of(h, struct gpio_event, early_suspend);
102 ip->info->power(ip->info, 1);
103 gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_RESUME);
104}
105#endif
106
107static int __init gpio_event_probe(struct platform_device *pdev)
108{
109 int err;
110 struct gpio_event *ip;
111 struct input_dev *input_dev;
112 struct gpio_event_platform_data *event_info;
113
114 event_info = pdev->dev.platform_data;
115 if (event_info == NULL) {
116 pr_err("gpio_event_probe: No pdata\n");
117 return -ENODEV;
118 }
119 if (event_info->name == NULL ||
120 event_info->info == NULL ||
121 event_info->info_count == 0) {
122 pr_err("gpio_event_probe: Incomplete pdata\n");
123 return -ENODEV;
124 }
125 ip = kzalloc(sizeof(*ip) +
126 sizeof(ip->state[0]) * event_info->info_count, GFP_KERNEL);
127 if (ip == NULL) {
128 err = -ENOMEM;
129 pr_err("gpio_event_probe: Failed to allocate private data\n");
130 goto err_kp_alloc_failed;
131 }
132 platform_set_drvdata(pdev, ip);
133
134 input_dev = input_allocate_device();
135 if (input_dev == NULL) {
136 err = -ENOMEM;
137 pr_err("gpio_event_probe: Failed to allocate input device\n");
138 goto err_input_dev_alloc_failed;
139 }
140 input_set_drvdata(input_dev, ip);
141 ip->input_dev = input_dev;
142 ip->info = event_info;
143 if (event_info->power) {
144#ifdef CONFIG_HAS_EARLYSUSPEND
145 ip->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
146 ip->early_suspend.suspend = gpio_event_suspend;
147 ip->early_suspend.resume = gpio_event_resume;
148 register_early_suspend(&ip->early_suspend);
149#endif
150 ip->info->power(ip->info, 1);
151 }
152
153 input_dev->name = ip->info->name;
154 input_dev->event = gpio_input_event;
155
156 err = gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_INIT);
157 if (err)
158 goto err_call_all_func_failed;
159
160 err = input_register_device(input_dev);
161 if (err) {
162 pr_err("gpio_event_probe: Unable to register %s input device\n",
163 input_dev->name);
164 goto err_input_register_device_failed;
165 }
166
167 return 0;
168
169err_input_register_device_failed:
170 gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_UNINIT);
171err_call_all_func_failed:
172 if (event_info->power) {
173#ifdef CONFIG_HAS_EARLYSUSPEND
174 unregister_early_suspend(&ip->early_suspend);
175#endif
176 ip->info->power(ip->info, 0);
177 }
178 input_free_device(input_dev);
179err_input_dev_alloc_failed:
180 kfree(ip);
181err_kp_alloc_failed:
182 return err;
183}
184
185static int gpio_event_remove(struct platform_device *pdev)
186{
187 struct gpio_event *ip = platform_get_drvdata(pdev);
188
189 gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_UNINIT);
190 if (ip->info->power) {
191#ifdef CONFIG_HAS_EARLYSUSPEND
192 unregister_early_suspend(&ip->early_suspend);
193#endif
194 ip->info->power(ip->info, 0);
195 }
196 input_unregister_device(ip->input_dev);
197 kfree(ip);
198 return 0;
199}
200
201static struct platform_driver gpio_event_driver = {
202 .probe = gpio_event_probe,
203 .remove = gpio_event_remove,
204 .driver = {
205 .name = GPIO_EVENT_DEV_NAME,
206 },
207};
208
209static int __devinit gpio_event_init(void)
210{
211 return platform_driver_register(&gpio_event_driver);
212}
213
214static void __exit gpio_event_exit(void)
215{
216 platform_driver_unregister(&gpio_event_driver);
217}
218
219module_init(gpio_event_init);
220module_exit(gpio_event_exit);
221
222MODULE_DESCRIPTION("GPIO Event Driver");
223MODULE_LICENSE("GPL");
224