diff options
Diffstat (limited to 'drivers/input/touchscreen/rmi4/rmi_bus.c')
-rw-r--r-- | drivers/input/touchscreen/rmi4/rmi_bus.c | 315 |
1 files changed, 315 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/rmi4/rmi_bus.c b/drivers/input/touchscreen/rmi4/rmi_bus.c new file mode 100644 index 00000000000..6a269df4ff3 --- /dev/null +++ b/drivers/input/touchscreen/rmi4/rmi_bus.c | |||
@@ -0,0 +1,315 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011 Synaptics Incorporated | ||
3 | * Copyright (c) 2011 Unixphere | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | */ | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/device.h> | ||
21 | #include <linux/pm.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/list.h> | ||
24 | #include <linux/rmi.h> | ||
25 | |||
26 | static struct rmi_function_list { | ||
27 | struct list_head list; | ||
28 | struct rmi_function_handler *fh; | ||
29 | } rmi_supported_functions; | ||
30 | |||
31 | static int rmi_bus_match(struct device *dev, struct device_driver *driver) | ||
32 | { | ||
33 | struct rmi_driver *rmi_driver; | ||
34 | struct rmi_device *rmi_dev; | ||
35 | struct rmi_device_platform_data *pdata; | ||
36 | |||
37 | pr_info("in function ____%s____ \n", __func__); | ||
38 | rmi_driver = to_rmi_driver(driver); | ||
39 | rmi_dev = to_rmi_device(dev); | ||
40 | pdata = to_rmi_platform_data(rmi_dev); | ||
41 | |||
42 | pr_info(" rmi_driver->driver.name = %s\n", rmi_driver->driver.name); | ||
43 | pr_info(" device:rmi_device = 0x%x \n", rmi_dev); | ||
44 | pr_info(" device:rmi_device:rmi_device_platform_data:driver_name = %s \n", pdata->driver_name); | ||
45 | pr_info(" rmi_device:driver = 0x%x \n", rmi_dev->driver); | ||
46 | |||
47 | if (!strcmp(pdata->driver_name, rmi_driver->driver.name)) { | ||
48 | rmi_dev->driver = rmi_driver; | ||
49 | pr_info(" names match, so now rmi_device:driver = 0x%x \n",rmi_dev->driver); | ||
50 | return 1; | ||
51 | } | ||
52 | pr_info(" names DO NOT match, so return nothing \n"); | ||
53 | |||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | #ifdef CONFIG_PM | ||
58 | static int rmi_bus_suspend(struct device *dev) | ||
59 | { | ||
60 | #ifdef GENERIC_SUBSYS_PM_OPS | ||
61 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | ||
62 | |||
63 | if (pm && pm->suspend) | ||
64 | return pm->suspend(dev); | ||
65 | #endif | ||
66 | |||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | static int rmi_bus_resume(struct device *dev) | ||
71 | { | ||
72 | #ifdef GENERIC_SUBSYS_PM_OPS | ||
73 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | ||
74 | pr_info("in function ____%s____ \n", __func__); | ||
75 | |||
76 | if (pm && pm->resume) | ||
77 | return pm->resume(dev); | ||
78 | #endif | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | #endif | ||
83 | |||
84 | static int rmi_bus_probe(struct device *dev) | ||
85 | { | ||
86 | struct rmi_driver *driver; | ||
87 | struct rmi_device *rmi_dev = to_rmi_device(dev); | ||
88 | |||
89 | pr_info("in function ____%s____ \n", __func__); | ||
90 | driver = rmi_dev->driver; | ||
91 | if (driver && driver->probe) | ||
92 | return driver->probe(rmi_dev); | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static int rmi_bus_remove(struct device *dev) | ||
98 | { | ||
99 | struct rmi_driver *driver; | ||
100 | struct rmi_device *rmi_dev = to_rmi_device(dev); | ||
101 | |||
102 | pr_info("in function ____%s____ \n", __func__); | ||
103 | driver = rmi_dev->driver; | ||
104 | if (driver && driver->remove) | ||
105 | return driver->remove(rmi_dev); | ||
106 | |||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static void rmi_bus_shutdown(struct device *dev) | ||
111 | { | ||
112 | struct rmi_driver *driver; | ||
113 | struct rmi_device *rmi_dev = to_rmi_device(dev); | ||
114 | |||
115 | driver = rmi_dev->driver; | ||
116 | if (driver && driver->shutdown) | ||
117 | driver->shutdown(rmi_dev); | ||
118 | } | ||
119 | |||
120 | static SIMPLE_DEV_PM_OPS(rmi_bus_pm_ops, | ||
121 | rmi_bus_suspend, rmi_bus_resume); | ||
122 | |||
123 | struct bus_type rmi_bus_type = { | ||
124 | .name = "rmi", | ||
125 | .match = rmi_bus_match, | ||
126 | .probe = rmi_bus_probe, | ||
127 | .remove = rmi_bus_remove, | ||
128 | .shutdown = rmi_bus_shutdown, | ||
129 | .pm = &rmi_bus_pm_ops | ||
130 | }; | ||
131 | |||
132 | int rmi_register_phys_device(struct rmi_phys_device *phys) | ||
133 | { | ||
134 | static int phys_device_num; | ||
135 | struct rmi_device_platform_data *pdata = phys->dev->platform_data; | ||
136 | struct rmi_device *rmi_dev; | ||
137 | |||
138 | pr_info("in function ____%s____ \n", __func__); | ||
139 | |||
140 | if (!pdata) { | ||
141 | dev_err(phys->dev, "no platform data!\n"); | ||
142 | return -EINVAL; | ||
143 | } | ||
144 | |||
145 | rmi_dev = kzalloc(sizeof(struct rmi_device), GFP_KERNEL); | ||
146 | if (!rmi_dev) | ||
147 | return -ENOMEM; | ||
148 | |||
149 | rmi_dev->phys = phys; | ||
150 | rmi_dev->dev.bus = &rmi_bus_type; | ||
151 | dev_set_name(&rmi_dev->dev, "sensor%02d", phys_device_num++); | ||
152 | |||
153 | phys->rmi_dev = rmi_dev; | ||
154 | pr_info(" registering physical device:\n"); | ||
155 | pr_info(" dev.init_name = \n", rmi_dev->dev.init_name); | ||
156 | pr_info(" dev.bus->name = \n", rmi_dev->dev.bus->name); | ||
157 | return device_register(&rmi_dev->dev); | ||
158 | } | ||
159 | EXPORT_SYMBOL(rmi_register_phys_device); | ||
160 | |||
161 | void rmi_unregister_phys_device(struct rmi_phys_device *phys) | ||
162 | { | ||
163 | struct rmi_device *rmi_dev = phys->rmi_dev; | ||
164 | pr_info("in function ____%s____ \n", __func__); | ||
165 | |||
166 | device_unregister(&rmi_dev->dev); | ||
167 | kfree(rmi_dev); | ||
168 | } | ||
169 | EXPORT_SYMBOL(rmi_unregister_phys_device); | ||
170 | |||
171 | int rmi_register_driver(struct rmi_driver *driver) | ||
172 | { | ||
173 | pr_info("in function ____%s____ \n", __func__); | ||
174 | driver->driver.bus = &rmi_bus_type; | ||
175 | return driver_register(&driver->driver); | ||
176 | } | ||
177 | EXPORT_SYMBOL(rmi_register_driver); | ||
178 | |||
179 | static int __rmi_driver_remove(struct device *dev, void *data) | ||
180 | { | ||
181 | struct rmi_driver *driver = data; | ||
182 | struct rmi_device *rmi_dev = to_rmi_device(dev); | ||
183 | |||
184 | if (rmi_dev->driver == driver) | ||
185 | rmi_dev->driver = NULL; | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | void rmi_unregister_driver(struct rmi_driver *driver) | ||
191 | { | ||
192 | bus_for_each_dev(&rmi_bus_type, NULL, driver, __rmi_driver_remove); | ||
193 | driver_unregister(&driver->driver); | ||
194 | } | ||
195 | EXPORT_SYMBOL(rmi_unregister_driver); | ||
196 | |||
197 | static int __rmi_bus_fh_add(struct device *dev, void *data) | ||
198 | { | ||
199 | struct rmi_driver *driver; | ||
200 | struct rmi_device *rmi_dev = to_rmi_device(dev); | ||
201 | pr_info("in function ____%s____ \n", __func__); | ||
202 | |||
203 | driver = rmi_dev->driver; | ||
204 | if (driver && driver->fh_add) | ||
205 | driver->fh_add(rmi_dev, data); | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | int rmi_register_function_driver(struct rmi_function_handler *fh) | ||
211 | { | ||
212 | struct rmi_function_list *entry; | ||
213 | struct rmi_function_handler *fh_dup; | ||
214 | |||
215 | fh_dup = rmi_get_function_handler(fh->func); | ||
216 | if (fh_dup) { | ||
217 | pr_err("%s: function f%.2x already registered!\n", __func__, | ||
218 | fh->func); | ||
219 | return -EINVAL; | ||
220 | } | ||
221 | |||
222 | entry = kzalloc(sizeof(struct rmi_function_list), GFP_KERNEL); | ||
223 | if (!entry) | ||
224 | return -ENOMEM; | ||
225 | |||
226 | entry->fh = fh; | ||
227 | list_add_tail(&entry->list, &rmi_supported_functions.list); | ||
228 | |||
229 | /* notify devices of the new function handler */ | ||
230 | bus_for_each_dev(&rmi_bus_type, NULL, fh, __rmi_bus_fh_add); | ||
231 | |||
232 | return 0; | ||
233 | } | ||
234 | EXPORT_SYMBOL(rmi_register_function_driver); | ||
235 | |||
236 | static int __rmi_bus_fh_remove(struct device *dev, void *data) | ||
237 | { | ||
238 | struct rmi_driver *driver; | ||
239 | struct rmi_device *rmi_dev = to_rmi_device(dev); | ||
240 | |||
241 | pr_info("in function ____%s____ \n", __func__); | ||
242 | driver = rmi_dev->driver; | ||
243 | if (driver && driver->fh_remove) | ||
244 | driver->fh_remove(rmi_dev, data); | ||
245 | |||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | void rmi_unregister_function_driver(struct rmi_function_handler *fh) | ||
250 | { | ||
251 | struct rmi_function_list *entry, *n; | ||
252 | pr_info("in function ____%s____ \n", __func__); | ||
253 | |||
254 | /* notify devices of the removal of the function handler */ | ||
255 | bus_for_each_dev(&rmi_bus_type, NULL, fh, __rmi_bus_fh_remove); | ||
256 | |||
257 | list_for_each_entry_safe(entry, n, &rmi_supported_functions.list, list) | ||
258 | if (entry->fh->func == fh->func) { | ||
259 | list_del(&entry->list); | ||
260 | kfree(entry); | ||
261 | } | ||
262 | } | ||
263 | EXPORT_SYMBOL(rmi_unregister_function_driver); | ||
264 | |||
265 | struct rmi_function_handler *rmi_get_function_handler(int id) | ||
266 | { | ||
267 | struct rmi_function_list *entry; | ||
268 | pr_info("in function ____%s____ \n", __func__); | ||
269 | |||
270 | list_for_each_entry(entry, &rmi_supported_functions.list, list) | ||
271 | if (entry->fh->func == id) | ||
272 | return entry->fh; | ||
273 | |||
274 | return NULL; | ||
275 | } | ||
276 | EXPORT_SYMBOL(rmi_get_function_handler); | ||
277 | |||
278 | static int __init rmi_bus_init(void) | ||
279 | { | ||
280 | int error; | ||
281 | |||
282 | pr_info("in function ____%s____ \n", __func__); | ||
283 | INIT_LIST_HEAD(&rmi_supported_functions.list); | ||
284 | |||
285 | error = bus_register(&rmi_bus_type); | ||
286 | if (error < 0) { | ||
287 | pr_err("%s: error registering the RMI bus: %d\n", __func__, | ||
288 | error); | ||
289 | return error; | ||
290 | } | ||
291 | pr_info("%s: successfully registered RMI bus.\n", __func__); | ||
292 | |||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | static void __exit rmi_bus_exit(void) | ||
297 | { | ||
298 | struct rmi_function_list *entry, *n; | ||
299 | pr_info("in function ____%s____ \n", __func__); | ||
300 | |||
301 | list_for_each_entry_safe(entry, n, &rmi_supported_functions.list, | ||
302 | list) { | ||
303 | list_del(&entry->list); | ||
304 | kfree(entry); | ||
305 | } | ||
306 | |||
307 | bus_unregister(&rmi_bus_type); | ||
308 | } | ||
309 | |||
310 | module_init(rmi_bus_init); | ||
311 | module_exit(rmi_bus_exit); | ||
312 | |||
313 | MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>"); | ||
314 | MODULE_DESCRIPTION("RMI bus"); | ||
315 | MODULE_LICENSE("GPL"); | ||