blob: 90f07eba3ce9e956ad333ae6deed10097c0f2b8d [file] [log] [blame]
Arve Hjønnevågeeec8b22008-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
Arve Hjønnevågeeec8b22008-10-15 18:23:47 -070016#include <linux/module.h>
17#include <linux/input.h>
18#include <linux/gpio_event.h>
19#include <linux/hrtimer.h>
20#include <linux/platform_device.h>
21#include <linux/slab.h>
22
23struct gpio_event {
24 struct gpio_event_input_devs *input_devs;
25 const struct gpio_event_platform_data *info;
Arve Hjønnevågeeec8b22008-10-15 18:23:47 -070026 void *state[0];
27};
28
29static int gpio_input_event(
30 struct input_dev *dev, unsigned int type, unsigned int code, int value)
31{
32 int i;
33 int devnr;
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 (devnr = 0; devnr < ip->input_devs->count; devnr++)
40 if (ip->input_devs->dev[devnr] == dev)
41 break;
42 if (devnr == ip->input_devs->count) {
43 pr_err("gpio_input_event: unknown device %p\n", dev);
44 return -EIO;
45 }
46
47 for (i = 0, ii = ip->info->info; i < ip->info->info_count; i++, ii++) {
48 if ((*ii)->event) {
49 tmp_ret = (*ii)->event(ip->input_devs, *ii,
50 &ip->state[i],
51 devnr, type, code, value);
52 if (tmp_ret)
53 ret = tmp_ret;
54 }
55 }
56 return ret;
57}
58
59static int gpio_event_call_all_func(struct gpio_event *ip, int func)
60{
61 int i;
62 int ret;
63 struct gpio_event_info **ii;
64
65 if (func == GPIO_EVENT_FUNC_INIT || func == GPIO_EVENT_FUNC_RESUME) {
66 ii = ip->info->info;
67 for (i = 0; i < ip->info->info_count; i++, ii++) {
68 if ((*ii)->func == NULL) {
69 ret = -ENODEV;
70 pr_err("gpio_event_probe: Incomplete pdata, "
71 "no function\n");
72 goto err_no_func;
73 }
74 if (func == GPIO_EVENT_FUNC_RESUME && (*ii)->no_suspend)
75 continue;
76 ret = (*ii)->func(ip->input_devs, *ii, &ip->state[i],
77 func);
78 if (ret) {
79 pr_err("gpio_event_probe: function failed\n");
80 goto err_func_failed;
81 }
82 }
83 return 0;
84 }
85
86 ret = 0;
87 i = ip->info->info_count;
88 ii = ip->info->info + i;
89 while (i > 0) {
90 i--;
91 ii--;
92 if ((func & ~1) == GPIO_EVENT_FUNC_SUSPEND && (*ii)->no_suspend)
93 continue;
94 (*ii)->func(ip->input_devs, *ii, &ip->state[i], func & ~1);
95err_func_failed:
96err_no_func:
97 ;
98 }
99 return ret;
100}
101
Colin Cross0ca66272012-02-01 20:26:28 -0800102static void __maybe_unused gpio_event_suspend(struct gpio_event *ip)
Arve Hjønnevågeeec8b22008-10-15 18:23:47 -0700103{
Arve Hjønnevågeeec8b22008-10-15 18:23:47 -0700104 gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_SUSPEND);
Colin Cross0ca66272012-02-01 20:26:28 -0800105 if (ip->info->power)
106 ip->info->power(ip->info, 0);
Arve Hjønnevågeeec8b22008-10-15 18:23:47 -0700107}
108
Colin Cross0ca66272012-02-01 20:26:28 -0800109static void __maybe_unused gpio_event_resume(struct gpio_event *ip)
Arve Hjønnevågeeec8b22008-10-15 18:23:47 -0700110{
Colin Cross0ca66272012-02-01 20:26:28 -0800111 if (ip->info->power)
112 ip->info->power(ip->info, 1);
Arve Hjønnevågeeec8b22008-10-15 18:23:47 -0700113 gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_RESUME);
114}
Arve Hjønnevågeeec8b22008-10-15 18:23:47 -0700115
116static int gpio_event_probe(struct platform_device *pdev)
117{
118 int err;
119 struct gpio_event *ip;
120 struct gpio_event_platform_data *event_info;
121 int dev_count = 1;
122 int i;
123 int registered = 0;
124
125 event_info = pdev->dev.platform_data;
126 if (event_info == NULL) {
127 pr_err("gpio_event_probe: No pdata\n");
128 return -ENODEV;
129 }
130 if ((!event_info->name && !event_info->names[0]) ||
131 !event_info->info || !event_info->info_count) {
132 pr_err("gpio_event_probe: Incomplete pdata\n");
133 return -ENODEV;
134 }
135 if (!event_info->name)
136 while (event_info->names[dev_count])
137 dev_count++;
138 ip = kzalloc(sizeof(*ip) +
139 sizeof(ip->state[0]) * event_info->info_count +
140 sizeof(*ip->input_devs) +
141 sizeof(ip->input_devs->dev[0]) * dev_count, GFP_KERNEL);
142 if (ip == NULL) {
143 err = -ENOMEM;
144 pr_err("gpio_event_probe: Failed to allocate private data\n");
145 goto err_kp_alloc_failed;
146 }
147 ip->input_devs = (void*)&ip->state[event_info->info_count];
148 platform_set_drvdata(pdev, ip);
149
150 for (i = 0; i < dev_count; i++) {
151 struct input_dev *input_dev = input_allocate_device();
152 if (input_dev == NULL) {
153 err = -ENOMEM;
154 pr_err("gpio_event_probe: "
155 "Failed to allocate input device\n");
156 goto err_input_dev_alloc_failed;
157 }
158 input_set_drvdata(input_dev, ip);
159 input_dev->name = event_info->name ?
160 event_info->name : event_info->names[i];
161 input_dev->event = gpio_input_event;
162 ip->input_devs->dev[i] = input_dev;
163 }
164 ip->input_devs->count = dev_count;
165 ip->info = event_info;
Colin Cross0ca66272012-02-01 20:26:28 -0800166 if (event_info->power)
Arve Hjønnevågeeec8b22008-10-15 18:23:47 -0700167 ip->info->power(ip->info, 1);
Arve Hjønnevågeeec8b22008-10-15 18:23:47 -0700168
169 err = gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_INIT);
170 if (err)
171 goto err_call_all_func_failed;
172
173 for (i = 0; i < dev_count; i++) {
174 err = input_register_device(ip->input_devs->dev[i]);
175 if (err) {
176 pr_err("gpio_event_probe: Unable to register %s "
177 "input device\n", ip->input_devs->dev[i]->name);
178 goto err_input_register_device_failed;
179 }
180 registered++;
181 }
182
183 return 0;
184
185err_input_register_device_failed:
186 gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_UNINIT);
187err_call_all_func_failed:
Colin Cross0ca66272012-02-01 20:26:28 -0800188 if (event_info->power)
Arve Hjønnevågeeec8b22008-10-15 18:23:47 -0700189 ip->info->power(ip->info, 0);
Arve Hjønnevågeeec8b22008-10-15 18:23:47 -0700190 for (i = 0; i < registered; i++)
191 input_unregister_device(ip->input_devs->dev[i]);
192 for (i = dev_count - 1; i >= registered; i--) {
193 input_free_device(ip->input_devs->dev[i]);
194err_input_dev_alloc_failed:
195 ;
196 }
197 kfree(ip);
198err_kp_alloc_failed:
199 return err;
200}
201
202static int gpio_event_remove(struct platform_device *pdev)
203{
204 struct gpio_event *ip = platform_get_drvdata(pdev);
205 int i;
206
207 gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_UNINIT);
Colin Cross0ca66272012-02-01 20:26:28 -0800208 if (ip->info->power)
Arve Hjønnevågeeec8b22008-10-15 18:23:47 -0700209 ip->info->power(ip->info, 0);
Arve Hjønnevågeeec8b22008-10-15 18:23:47 -0700210 for (i = 0; i < ip->input_devs->count; i++)
211 input_unregister_device(ip->input_devs->dev[i]);
212 kfree(ip);
213 return 0;
214}
215
216static struct platform_driver gpio_event_driver = {
217 .probe = gpio_event_probe,
218 .remove = gpio_event_remove,
219 .driver = {
220 .name = GPIO_EVENT_DEV_NAME,
221 },
222};
223
224module_platform_driver(gpio_event_driver);
225
226MODULE_DESCRIPTION("GPIO Event Driver");
227MODULE_LICENSE("GPL");
228