]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/staging/greybus/core.c
greybus: es1-ap-usb: more init framework added.
[mirror_ubuntu-artful-kernel.git] / drivers / staging / greybus / core.c
CommitLineData
c8a797a9
GKH
1/*
2 * Greybus "Core"
3 *
4 * Copyright 2014 Google Inc.
5 *
6 * Released under the GPLv2 only.
7 */
8
9#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10
11#include <linux/types.h>
12#include <linux/module.h>
13#include <linux/moduleparam.h>
14#include <linux/kernel.h>
15#include <linux/device.h>
16
17#include "greybus.h"
18
19/* Allow greybus to be disabled at boot if needed */
20static bool nogreybus;
21#ifdef MODULE
22module_param(nogreybus, bool, 0444);
23#else
24core_param(nogreybus, bool, 0444);
25#endif
26int greybus_disabled(void)
27{
28 return nogreybus;
29}
30EXPORT_SYMBOL_GPL(greybus_disabled);
31
32static int greybus_match_one_id(struct greybus_device *gdev,
33 const struct greybus_device_id *id)
34{
35 struct greybus_descriptor *des = &gdev->descriptor;
36
37 if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_VENDOR) &&
38 (des->wVendor != id->wVendor))
39 return 0;
40
41 if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_PRODUCT) &&
42 (des->wProduct != id->wProduct))
43 return 0;
44
45 if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_SERIAL) &&
46 (des->lSerialNumber != id->lSerialNumber))
47 return 0;
48
49 return 1;
50}
51
52static const struct greybus_device_id *greybus_match_id(
53 struct greybus_device *gdev,
54 const struct greybus_device_id *id)
55{
56 if (id == NULL)
57 return NULL;
58
59 for (; id->wVendor || id->wProduct || id->lSerialNumber ||
60 id->driver_info ; id++) {
61 if (greybus_match_one_id(gdev, id))
62 return id;
63 }
64
65 return NULL;
66}
67
68static int greybus_device_match(struct device *dev, struct device_driver *drv)
69{
70 struct greybus_driver *driver = to_greybus_driver(dev->driver);
71 struct greybus_device *gdev = to_greybus_device(dev);
72 const struct greybus_device_id *id;
73
74 id = greybus_match_id(gdev, driver->id_table);
75 if (id)
76 return 1;
77 /* FIXME - Dyanmic ids? */
78 return 0;
79}
80
81static int greybus_uevent(struct device *dev, struct kobj_uevent_env *env)
82{
83 /* struct greybus_device *gdev = to_greybus_device(dev); */
84
85 /* FIXME - add some uevents here... */
86 return 0;
87}
88
89struct bus_type greybus_bus_type = {
90 .name = "greybus",
91 .match = greybus_device_match,
92 .uevent = greybus_uevent,
93};
94
95static int greybus_probe(struct device *dev)
96{
97 struct greybus_driver *driver = to_greybus_driver(dev->driver);
98 struct greybus_device *gdev = to_greybus_device(dev);
99 const struct greybus_device_id *id;
100 int retval;
101
102 /* match id */
103 id = greybus_match_id(gdev, driver->id_table);
104 if (!id)
105 return -ENODEV;
106
107 retval = driver->probe(gdev, id);
108 if (retval)
109 return retval;
110
111 return 0;
112}
113
114static int greybus_remove(struct device *dev)
115{
116 struct greybus_driver *driver = to_greybus_driver(dev->driver);
117 struct greybus_device *gdev = to_greybus_device(dev);
118
119 driver->disconnect(gdev);
120 return 0;
121}
122
123int greybus_register_driver(struct greybus_driver *driver, struct module *owner,
124 const char *mod_name)
125{
126 int retval;
127
128 if (greybus_disabled())
129 return -ENODEV;
130
131 driver->driver.name = driver->name;
132 driver->driver.probe = greybus_probe;
133 driver->driver.remove = greybus_remove;
134 driver->driver.owner = owner;
135 driver->driver.mod_name = mod_name;
136
137 retval = driver_register(&driver->driver);
138 if (retval)
139 return retval;
140
141 pr_info("registered new driver %s\n", driver->name);
142 return 0;
143}
144EXPORT_SYMBOL_GPL(greybus_register_driver);
145
146void greybus_deregister(struct greybus_driver *driver)
147{
148 driver_unregister(&driver->driver);
149}
150EXPORT_SYMBOL_GPL(greybus_deregister);
151
199d68d4
GKH
152
153static int new_device(struct greybus_device *gdev,
154 const struct greybus_device_id *id)
155{
156 int retval;
157
158 /* Allocate all of the different "sub device types" for this device */
159 retval = gb_i2c_probe(gdev, id);
db6e1fd2
GKH
160 if (retval)
161 goto error_i2c;
162
163 retval = gb_gpio_probe(gdev, id);
164 if (retval)
165 goto error_gpio;
166
167 retval = gb_sdio_probe(gdev, id);
168 if (retval)
169 goto error_sdio;
170
171 retval = gb_tty_probe(gdev, id);
172 if (retval)
173 goto error_tty;
199d68d4 174 return 0;
db6e1fd2
GKH
175
176error_tty:
177 gb_sdio_disconnect(gdev);
178
179error_sdio:
180 gb_gpio_disconnect(gdev);
181
182error_gpio:
183 gb_i2c_disconnect(gdev);
184
185error_i2c:
186 return retval;
199d68d4
GKH
187}
188
db6e1fd2
GKH
189static void remove_device(struct greybus_device *gdev)
190{
191 /* tear down all of the "sub device types" for this device */
192 gb_i2c_disconnect(gdev);
193 gb_gpio_disconnect(gdev);
194 gb_sdio_disconnect(gdev);
195 gb_tty_disconnect(gdev);
196}
199d68d4 197
503c1cdb 198static int __init gb_init(void)
199d68d4 199{
db6e1fd2
GKH
200 int retval;
201
202 retval = gb_tty_init();
203 if (retval)
204 return retval;
205
199d68d4
GKH
206 return 0;
207}
208
503c1cdb 209static void __exit gb_exit(void)
199d68d4 210{
db6e1fd2 211 gb_tty_exit();
199d68d4
GKH
212}
213
214module_init(gb_init);
215module_exit(gb_exit);
216
c8a797a9
GKH
217MODULE_LICENSE("GPL");
218MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>");