blob: a13cf9f050593f76afc3ff44fe2d8c92bdbc6321 [file] [log] [blame]
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +08001/*
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>
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -070015#include <linux/slab.h>
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080016#include <linux/device.h>
17
18#include "greybus.h"
19
20/* Allow greybus to be disabled at boot if needed */
21static bool nogreybus;
22#ifdef MODULE
23module_param(nogreybus, bool, 0444);
24#else
25core_param(nogreybus, bool, 0444);
26#endif
27int greybus_disabled(void)
28{
29 return nogreybus;
30}
31EXPORT_SYMBOL_GPL(greybus_disabled);
32
33static int greybus_match_one_id(struct greybus_device *gdev,
Greg Kroah-Hartman6584c8a2014-09-01 13:31:31 -070034 const struct greybus_module_id *id)
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080035{
Greg Kroah-Hartman6dca7b92014-09-01 13:42:43 -070036 struct greybus_descriptor_module_id *module_id;
37 struct greybus_descriptor_serial_number *serial_num;
38
39 module_id = &gdev->module_id;
40 serial_num = &gdev->serial_number;
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080041
42 if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_VENDOR) &&
Greg Kroah-Hartman6dca7b92014-09-01 13:42:43 -070043 (id->vendor != le16_to_cpu(module_id->vendor)))
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080044 return 0;
45
46 if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_PRODUCT) &&
Greg Kroah-Hartman6dca7b92014-09-01 13:42:43 -070047 (id->product != le16_to_cpu(module_id->product)))
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080048 return 0;
49
50 if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_SERIAL) &&
Greg Kroah-Hartman6dca7b92014-09-01 13:42:43 -070051 (id->serial_number != le64_to_cpu(serial_num->serial_number)))
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080052 return 0;
53
54 return 1;
55}
56
Greg Kroah-Hartman6584c8a2014-09-01 13:31:31 -070057static const struct greybus_module_id *greybus_match_id(
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080058 struct greybus_device *gdev,
Greg Kroah-Hartman6584c8a2014-09-01 13:31:31 -070059 const struct greybus_module_id *id)
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080060{
61 if (id == NULL)
62 return NULL;
63
Greg Kroah-Hartman6dca7b92014-09-01 13:42:43 -070064 for (; id->vendor || id->product || id->serial_number ||
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080065 id->driver_info ; id++) {
66 if (greybus_match_one_id(gdev, id))
67 return id;
68 }
69
70 return NULL;
71}
72
73static int greybus_device_match(struct device *dev, struct device_driver *drv)
74{
75 struct greybus_driver *driver = to_greybus_driver(dev->driver);
76 struct greybus_device *gdev = to_greybus_device(dev);
Greg Kroah-Hartman6584c8a2014-09-01 13:31:31 -070077 const struct greybus_module_id *id;
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080078
79 id = greybus_match_id(gdev, driver->id_table);
80 if (id)
81 return 1;
82 /* FIXME - Dyanmic ids? */
83 return 0;
84}
85
86static int greybus_uevent(struct device *dev, struct kobj_uevent_env *env)
87{
88 /* struct greybus_device *gdev = to_greybus_device(dev); */
89
90 /* FIXME - add some uevents here... */
91 return 0;
92}
93
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -070094static struct bus_type greybus_bus_type = {
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080095 .name = "greybus",
96 .match = greybus_device_match,
97 .uevent = greybus_uevent,
98};
99
100static int greybus_probe(struct device *dev)
101{
102 struct greybus_driver *driver = to_greybus_driver(dev->driver);
103 struct greybus_device *gdev = to_greybus_device(dev);
Greg Kroah-Hartman6584c8a2014-09-01 13:31:31 -0700104 const struct greybus_module_id *id;
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +0800105 int retval;
106
107 /* match id */
108 id = greybus_match_id(gdev, driver->id_table);
109 if (!id)
110 return -ENODEV;
111
112 retval = driver->probe(gdev, id);
113 if (retval)
114 return retval;
115
116 return 0;
117}
118
119static int greybus_remove(struct device *dev)
120{
121 struct greybus_driver *driver = to_greybus_driver(dev->driver);
122 struct greybus_device *gdev = to_greybus_device(dev);
123
124 driver->disconnect(gdev);
125 return 0;
126}
127
128int greybus_register_driver(struct greybus_driver *driver, struct module *owner,
129 const char *mod_name)
130{
131 int retval;
132
133 if (greybus_disabled())
134 return -ENODEV;
135
136 driver->driver.name = driver->name;
137 driver->driver.probe = greybus_probe;
138 driver->driver.remove = greybus_remove;
139 driver->driver.owner = owner;
140 driver->driver.mod_name = mod_name;
141
142 retval = driver_register(&driver->driver);
143 if (retval)
144 return retval;
145
146 pr_info("registered new driver %s\n", driver->name);
147 return 0;
148}
149EXPORT_SYMBOL_GPL(greybus_register_driver);
150
151void greybus_deregister(struct greybus_driver *driver)
152{
153 driver_unregister(&driver->driver);
154}
155EXPORT_SYMBOL_GPL(greybus_deregister);
156
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700157
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700158static void greybus_module_release(struct device *dev)
159{
160 struct greybus_device *gdev = to_greybus_device(dev);
161 int i;
162
163 for (i = 0; i < gdev->num_strings; ++i)
164 kfree(gdev->string[i]);
165 for (i = 0; i < gdev->num_cports; ++i)
166 kfree(gdev->cport[i]);
167 kfree(gdev);
168}
169
170
Greg Kroah-Hartmane24e7252014-09-01 19:01:14 -0700171const u8 *greybus_string(struct greybus_device *gdev, int id)
172{
173 int i;
174 struct gdev_string *string;
175
176 if (!gdev)
177 return NULL;
178
179 for (i = 0; i < gdev->num_strings; ++i) {
180 string = gdev->string[i];
181 if (string->id == id)
182 return &string->string[0];
183 }
184 return NULL;
185}
186
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700187static struct device_type greybus_module_type = {
188 .name = "greybus_module",
189 .release = greybus_module_release,
190};
191
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700192static int gb_init_subdevs(struct greybus_device *gdev,
193 const struct greybus_module_id *id)
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700194{
195 int retval;
196
197 /* Allocate all of the different "sub device types" for this device */
198 retval = gb_i2c_probe(gdev, id);
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700199 if (retval)
200 goto error_i2c;
201
202 retval = gb_gpio_probe(gdev, id);
203 if (retval)
204 goto error_gpio;
205
206 retval = gb_sdio_probe(gdev, id);
207 if (retval)
208 goto error_sdio;
209
210 retval = gb_tty_probe(gdev, id);
211 if (retval)
212 goto error_tty;
Greg Kroah-Hartman33ea3a32014-09-07 15:39:34 -0700213
214 retval = gb_battery_probe(gdev, id);
215 if (retval)
216 goto error_battery;
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700217 return 0;
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700218
Greg Kroah-Hartman33ea3a32014-09-07 15:39:34 -0700219error_battery:
220 gb_tty_disconnect(gdev);
221
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700222error_tty:
223 gb_sdio_disconnect(gdev);
224
225error_sdio:
226 gb_gpio_disconnect(gdev);
227
228error_gpio:
229 gb_i2c_disconnect(gdev);
230
231error_i2c:
232 return retval;
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700233}
234
Greg Kroah-Hartman3be03d42014-09-01 19:10:06 -0700235static const struct greybus_module_id fake_gb_id = {
236 GREYBUS_DEVICE(0x42, 0x42)
237};
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700238
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700239static int create_function(struct greybus_device *gdev,
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700240 struct greybus_descriptor_function *function,
241 size_t desc_size)
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700242{
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700243 if (desc_size != sizeof(*function)) {
244 dev_err(gdev->dev.parent, "invalid function header size %zu\n",
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700245 desc_size);
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700246 return -EINVAL;
247 }
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700248 memcpy(&gdev->function, function, desc_size);
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700249 return 0;
250}
251
252static int create_module_id(struct greybus_device *gdev,
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700253 struct greybus_descriptor_module_id *module_id,
254 size_t desc_size)
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700255{
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700256 if (desc_size != sizeof(*module_id)) {
257 dev_err(gdev->dev.parent, "invalid module header size %zu\n",
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700258 desc_size);
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700259 return -EINVAL;
260 }
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700261 memcpy(&gdev->module_id, module_id, desc_size);
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700262 return 0;
263}
264
265static int create_serial_number(struct greybus_device *gdev,
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700266 struct greybus_descriptor_serial_number *serial_num,
267 size_t desc_size)
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700268{
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700269 if (desc_size != sizeof(*serial_num)) {
270 dev_err(gdev->dev.parent, "invalid serial number header size %zu\n",
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700271 desc_size);
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700272 return -EINVAL;
273 }
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700274 memcpy(&gdev->serial_number, serial_num, desc_size);
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700275 return 0;
276}
277
278static int create_string(struct greybus_device *gdev,
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700279 struct greybus_descriptor_string *string,
280 size_t desc_size)
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700281{
282 int string_size;
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700283 struct gdev_string *gdev_string;
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700284
285 if ((gdev->num_strings + 1) >= MAX_STRINGS_PER_MODULE) {
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700286 dev_err(gdev->dev.parent,
287 "too many strings for this module!\n");
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700288 return -EINVAL;
289 }
290
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700291 if (desc_size < sizeof(*string)) {
292 dev_err(gdev->dev.parent, "invalid string header size %zu\n",
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700293 desc_size);
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700294 return -EINVAL;
295 }
296
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700297 string_size = le16_to_cpu(string->length);
298 gdev_string = kzalloc(sizeof(*gdev_string) + string_size + 1, GFP_KERNEL);
299 if (!gdev_string)
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700300 return -ENOMEM;
301
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700302 gdev_string->length = string_size;
303 gdev_string->id = string->id;
304 memcpy(&gdev_string->string, &string->string, string_size);
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700305
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700306 gdev->string[gdev->num_strings] = gdev_string;
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700307 gdev->num_strings++;
308
309 return 0;
310}
311
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700312static int create_cport(struct greybus_device *gdev,
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700313 struct greybus_descriptor_cport *cport,
314 size_t desc_size)
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700315{
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700316 struct gdev_cport *gdev_cport;
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700317
318 if ((gdev->num_cports + 1) >= MAX_CPORTS_PER_MODULE) {
319 dev_err(gdev->dev.parent, "too many cports for this module!\n");
320 return -EINVAL;
321 }
322
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700323 if (desc_size != sizeof(*cport)) {
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700324 dev_err(gdev->dev.parent,
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700325 "invalid serial number header size %zu\n", desc_size);
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700326 return -EINVAL;
327 }
328
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700329 gdev_cport = kzalloc(sizeof(*gdev_cport), GFP_KERNEL);
330 if (!gdev_cport)
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700331 return -ENOMEM;
332
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700333 gdev_cport->number = le16_to_cpu(cport->number);
334 gdev_cport->size = le16_to_cpu(cport->size);
335 gdev_cport->speed = cport->speed;
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700336
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700337 gdev->cport[gdev->num_cports] = gdev_cport;
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700338 gdev->num_cports++;
339
340 return 0;
341}
342
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700343/**
Alex Elder05ad1892014-09-09 13:55:03 -0500344 * greybus_new_module:
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700345 *
Alex Elder05ad1892014-09-09 13:55:03 -0500346 * Pass in a buffer that _should_ contain a Greybus module manifest
347 * and spit out a greybus device structure.
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700348 */
Alex Elder05ad1892014-09-09 13:55:03 -0500349struct greybus_device *greybus_new_module(struct device *parent,
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700350 int module_number, u8 *data, int size)
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700351{
352 struct greybus_device *gdev;
Alex Elderbadad682014-09-09 13:55:04 -0500353 struct greybus_manifest *manifest;
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700354 int retval;
355 int overall_size;
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700356 u8 version_major;
357 u8 version_minor;
358
Alex Elder05ad1892014-09-09 13:55:03 -0500359 /* we have to have at _least_ the manifest header */
Alex Elderbadad682014-09-09 13:55:04 -0500360 if (size <= sizeof(manifest->header))
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700361 return NULL;
362
363 gdev = kzalloc(sizeof(*gdev), GFP_KERNEL);
364 if (!gdev)
365 return NULL;
366
367 gdev->module_number = module_number;
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700368 gdev->dev.parent = parent;
369 gdev->dev.driver = NULL;
370 gdev->dev.bus = &greybus_bus_type;
371 gdev->dev.type = &greybus_module_type;
372 gdev->dev.groups = greybus_module_groups;
373 gdev->dev.dma_mask = parent->dma_mask;
374 device_initialize(&gdev->dev);
375 dev_set_name(&gdev->dev, "%d", module_number);
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700376
Alex Elderbadad682014-09-09 13:55:04 -0500377 manifest = (struct greybus_manifest *)data;
378 overall_size = le16_to_cpu(manifest->header.size);
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700379 if (overall_size != size) {
Alex Elder05ad1892014-09-09 13:55:03 -0500380 dev_err(parent, "size != manifest header size, %d != %d\n",
381 size, overall_size);
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700382 goto error;
383 }
384
Alex Elderbadad682014-09-09 13:55:04 -0500385 version_major = manifest->header.version_major;
386 version_minor = manifest->header.version_minor;
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700387
Greg Kroah-Hartmana1dc62b2014-09-13 17:28:19 -0700388 /* Validate major/minor number */
389 if ((version_major != GREYBUS_VERSION_MAJOR) ||
390 (version_minor != GREYBUS_VERSION_MINOR)) {
391 dev_err(parent,
392 "Invalid greybus versions, expected %d.%d, got %d.%d\n",
393 GREYBUS_VERSION_MAJOR, GREYBUS_VERSION_MINOR,
394 version_major, version_minor);
395 goto error;
396 }
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700397
Alex Elderbadad682014-09-09 13:55:04 -0500398 size -= sizeof(manifest->header);
399 data += sizeof(manifest->header);
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700400 while (size > 0) {
Alex Eldere82bef42014-09-09 13:55:09 -0500401 struct greybus_descriptor *desc;
402 u16 desc_size;
403 size_t data_size;
404
Alex Elder57fc0a12014-09-09 13:55:08 -0500405 if (size < sizeof(desc->header)) {
406 dev_err(parent, "remaining size %d too small\n", size);
407 goto error;
408 }
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700409 desc = (struct greybus_descriptor *)data;
410 desc_size = le16_to_cpu(desc->header.size);
Alex Elder57fc0a12014-09-09 13:55:08 -0500411 if (size < desc_size) {
412 dev_err(parent, "descriptor size %d too big\n",
413 desc_size);
414 goto error;
415 }
Alex Eldere82bef42014-09-09 13:55:09 -0500416 data_size = (size_t)desc_size - sizeof(desc->header);
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700417
Alex Eldera22e15a2014-09-09 13:55:07 -0500418 switch (le16_to_cpu(desc->header.type)) {
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700419 case GREYBUS_TYPE_FUNCTION:
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700420 retval = create_function(gdev, &desc->function,
421 data_size);
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700422 break;
423
424 case GREYBUS_TYPE_MODULE_ID:
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700425 retval = create_module_id(gdev, &desc->module_id,
426 data_size);
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700427 break;
428
429 case GREYBUS_TYPE_SERIAL_NUMBER:
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700430 retval = create_serial_number(gdev,
431 &desc->serial_number,
432 data_size);
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700433 break;
434
435 case GREYBUS_TYPE_STRING:
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700436 retval = create_string(gdev, &desc->string, data_size);
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700437 break;
438
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700439 case GREYBUS_TYPE_CPORT:
Greg Kroah-Hartman3d545322014-09-09 17:16:54 -0700440 retval = create_cport(gdev, &desc->cport, data_size);
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700441 break;
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700442
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700443 case GREYBUS_TYPE_INVALID:
444 default:
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700445 dev_err(parent, "invalid descriptor type %d\n",
446 desc->header.type);
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700447 goto error;
448 }
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700449 if (retval)
450 goto error;
451 size -= desc_size;
452 data += desc_size;
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700453 }
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700454
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700455 retval = gb_init_subdevs(gdev, &fake_gb_id);
456 if (retval)
457 goto error;
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700458
459 // FIXME device_add(&gdev->dev);
460
461
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700462 return gdev;
463error:
Alex Eldera5808ad2014-09-09 13:55:06 -0500464 put_device(&gdev->dev);
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700465 greybus_module_release(&gdev->dev);
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700466 return NULL;
467}
468
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700469void greybus_remove_device(struct greybus_device *gdev)
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700470{
471 /* tear down all of the "sub device types" for this device */
472 gb_i2c_disconnect(gdev);
473 gb_gpio_disconnect(gdev);
474 gb_sdio_disconnect(gdev);
475 gb_tty_disconnect(gdev);
Greg Kroah-Hartman33ea3a32014-09-07 15:39:34 -0700476 gb_battery_disconnect(gdev);
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700477
478 // FIXME - device_remove(&gdev->dev);
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700479}
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700480
Greg Kroah-Hartman68f1fc42014-09-07 13:12:11 -0700481static DEFINE_MUTEX(hd_mutex);
482
483static void free_hd(struct kref *kref)
484{
485 struct greybus_host_device *hd;
486
487 hd = container_of(kref, struct greybus_host_device, kref);
488
489 kfree(hd);
490}
491
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -0700492struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver,
493 struct device *parent)
494{
495 struct greybus_host_device *hd;
496
497 hd = kzalloc(sizeof(*hd) + driver->hd_priv_size, GFP_KERNEL);
498 if (!hd)
499 return NULL;
500
501 kref_init(&hd->kref);
Greg Kroah-Hartman772149b2014-09-14 12:27:28 -0700502 hd->parent = parent;
503 hd->driver = driver;
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -0700504
505 return hd;
506}
507EXPORT_SYMBOL_GPL(greybus_create_hd);
508
Greg Kroah-Hartman68f1fc42014-09-07 13:12:11 -0700509void greybus_remove_hd(struct greybus_host_device *hd)
510{
511 kref_put_mutex(&hd->kref, free_hd, &hd_mutex);
512}
513EXPORT_SYMBOL_GPL(greybus_remove_hd);
514
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -0700515
Greg Kroah-Hartman503c1cd2014-08-30 16:21:03 -0700516static int __init gb_init(void)
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700517{
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700518 int retval;
519
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700520 retval = gb_debugfs_init();
Greg Kroah-Hartman168db1c2014-09-13 16:15:52 -0700521 if (retval) {
522 pr_err("debugfs failed\n");
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700523 return retval;
Greg Kroah-Hartman168db1c2014-09-13 16:15:52 -0700524 }
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700525
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700526 retval = bus_register(&greybus_bus_type);
Greg Kroah-Hartman168db1c2014-09-13 16:15:52 -0700527 if (retval) {
528 pr_err("bus_register failed\n");
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700529 goto error_bus;
Greg Kroah-Hartman168db1c2014-09-13 16:15:52 -0700530 }
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700531
Greg Kroah-Hartman45f36782014-09-14 11:40:35 -0700532 retval = gb_ap_init();
Greg Kroah-Hartman168db1c2014-09-13 16:15:52 -0700533 if (retval) {
Greg Kroah-Hartman45f36782014-09-14 11:40:35 -0700534 pr_err("gb_ap_init failed\n");
535 goto error_ap;
Greg Kroah-Hartman168db1c2014-09-13 16:15:52 -0700536 }
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700537
Greg Kroah-Hartman45f36782014-09-14 11:40:35 -0700538 retval = gb_gbuf_init();
539 if (retval) {
540 pr_err("gb_gbuf_init failed\n");
541 goto error_gbuf;
542 }
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700543
544 retval = gb_tty_init();
Greg Kroah-Hartman168db1c2014-09-13 16:15:52 -0700545 if (retval) {
546 pr_err("gb_tty_init failed\n");
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700547 goto error_tty;
Greg Kroah-Hartman168db1c2014-09-13 16:15:52 -0700548 }
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700549
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700550 return 0;
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700551
552error_tty:
Greg Kroah-Hartman45f36782014-09-14 11:40:35 -0700553 gb_gbuf_exit();
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700554
Greg Kroah-Hartman45f36782014-09-14 11:40:35 -0700555error_gbuf:
556 gb_ap_exit();
557
558error_ap:
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700559 bus_unregister(&greybus_bus_type);
560
561error_bus:
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700562 gb_debugfs_cleanup();
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700563
564 return retval;
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700565}
566
Greg Kroah-Hartman503c1cd2014-08-30 16:21:03 -0700567static void __exit gb_exit(void)
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700568{
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700569 gb_tty_exit();
Greg Kroah-Hartman45f36782014-09-14 11:40:35 -0700570 gb_gbuf_exit();
571 gb_ap_exit();
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700572 bus_unregister(&greybus_bus_type);
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700573 gb_debugfs_cleanup();
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700574}
575
576module_init(gb_init);
577module_exit(gb_exit);
578
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +0800579MODULE_LICENSE("GPL");
580MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>");