blob: 0e2f99df6cfa6fd49c41d71d7ba82785b9b3faa1 [file] [log] [blame]
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +08001/*
2 * Greybus "Core"
3 *
Alex Elder4441f472015-05-22 12:59:16 -05004 * Copyright 2014-2015 Google Inc.
5 * Copyright 2014-2015 Linaro Ltd.
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +08006 *
7 * Released under the GPLv2 only.
8 */
9
10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11
Bryan O'Donoghue5c8ad592015-09-18 16:38:45 +010012#define CREATE_TRACE_POINTS
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080013#include "greybus.h"
Bryan O'Donoghue5c8ad592015-09-18 16:38:45 +010014#include "greybus_trace.h"
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080015
Bryan O'Donoghue32b2b162015-09-22 18:06:38 -070016EXPORT_TRACEPOINT_SYMBOL_GPL(gb_host_device_send);
17EXPORT_TRACEPOINT_SYMBOL_GPL(gb_host_device_recv);
18
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080019/* Allow greybus to be disabled at boot if needed */
20static bool nogreybus;
21#ifdef MODULE
22module_param(nogreybus, bool, 0444);
23#else
Viresh Kumar8597e6b2014-10-20 16:45:50 +053024core_param(nogreybus, nogreybus, bool, 0444);
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080025#endif
26int greybus_disabled(void)
27{
28 return nogreybus;
29}
30EXPORT_SYMBOL_GPL(greybus_disabled);
31
Johan Hovold700001a2015-11-21 10:52:03 +010032static int greybus_match_one_id(struct gb_bundle *bundle,
33 const struct greybus_bundle_id *id)
34{
35 if ((id->match_flags & GREYBUS_ID_MATCH_VENDOR) &&
Johan Hovold9f592632015-11-25 15:58:56 +010036 (id->vendor != bundle->intf->vendor_id))
Johan Hovold700001a2015-11-21 10:52:03 +010037 return 0;
38
39 if ((id->match_flags & GREYBUS_ID_MATCH_PRODUCT) &&
Johan Hovold9f592632015-11-25 15:58:56 +010040 (id->product != bundle->intf->product_id))
Johan Hovold700001a2015-11-21 10:52:03 +010041 return 0;
42
43 if ((id->match_flags & GREYBUS_ID_MATCH_CLASS) &&
44 (id->class != bundle->class))
45 return 0;
46
47 return 1;
48}
49
50static const struct greybus_bundle_id *
51greybus_match_id(struct gb_bundle *bundle, const struct greybus_bundle_id *id)
52{
53 if (id == NULL)
54 return NULL;
55
56 for (; id->vendor || id->product || id->class || id->driver_info;
57 id++) {
58 if (greybus_match_one_id(bundle, id))
59 return id;
60 }
61
62 return NULL;
63}
64
Alex Elder778c69c2014-09-22 19:19:03 -050065static int greybus_module_match(struct device *dev, struct device_driver *drv)
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080066{
Viresh Kumar95bd99d2014-11-14 17:24:59 +053067 struct greybus_driver *driver = to_greybus_driver(drv);
Johan Hovoldb77f9322016-01-08 20:13:41 +010068 struct gb_bundle *bundle;
Viresh Kumar9f5f30e7122015-04-01 20:32:04 +053069 const struct greybus_bundle_id *id;
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080070
Johan Hovoldb77f9322016-01-08 20:13:41 +010071 if (!is_gb_bundle(dev))
72 return 0;
73
74 bundle = to_gb_bundle(dev);
75
Johan Hovold700001a2015-11-21 10:52:03 +010076 id = greybus_match_id(bundle, driver->id_table);
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080077 if (id)
78 return 1;
Viresh Kumar696e0cc2014-11-21 11:26:30 +053079 /* FIXME - Dynamic ids? */
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080080 return 0;
81}
82
83static int greybus_uevent(struct device *dev, struct kobj_uevent_env *env)
84{
Johan Hovoldf0960d02015-12-03 19:18:02 +010085 struct gb_host_device *hd;
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -080086 struct gb_interface *intf = NULL;
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050087 struct gb_bundle *bundle = NULL;
Johan Hovold88f7b962015-11-25 15:59:08 +010088 struct gb_svc *svc = NULL;
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080089
Johan Hovold2adaefb2015-11-25 15:59:02 +010090 if (is_gb_host_device(dev)) {
91 hd = to_gb_host_device(dev);
Greg Kroah-Hartmandf671552014-12-21 14:10:26 -080092 } else if (is_gb_interface(dev)) {
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -080093 intf = to_gb_interface(dev);
Johan Hovoldf0960d02015-12-03 19:18:02 +010094 hd = intf->hd;
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050095 } else if (is_gb_bundle(dev)) {
96 bundle = to_gb_bundle(dev);
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -080097 intf = bundle->intf;
Johan Hovoldf0960d02015-12-03 19:18:02 +010098 hd = intf->hd;
Johan Hovold88f7b962015-11-25 15:59:08 +010099 } else if (is_gb_svc(dev)) {
100 svc = to_gb_svc(dev);
Johan Hovoldf0960d02015-12-03 19:18:02 +0100101 hd = svc->hd;
Greg Kroah-Hartman0ac5a832014-11-15 12:12:16 -0800102 } else {
103 dev_WARN(dev, "uevent for unknown greybus device \"type\"!\n");
104 return -EINVAL;
105 }
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +0800106
Johan Hovoldf0960d02015-12-03 19:18:02 +0100107 if (add_uevent_var(env, "BUS=%u", hd->bus_id))
108 return -ENOMEM;
109
Johan Hovoldc5e6b052015-12-03 19:18:04 +0100110 if (intf) {
111 if (add_uevent_var(env, "INTERFACE=%u", intf->interface_id))
112 return -ENOMEM;
Greg Kroah-Hartmande141312016-01-11 19:24:54 -0800113 if (add_uevent_var(env, "GREYBUS_ID=%04x/%04x",
114 (u16)(intf->vendor_id & 0xffff),
115 (u16)(intf->product_id & 0xffff)))
116 return -ENOMEM;
Johan Hovoldc5e6b052015-12-03 19:18:04 +0100117 }
118
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -0500119 if (bundle) {
Greg Kroah-Hartman0ac5a832014-11-15 12:12:16 -0800120 // FIXME
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -0500121 // add a uevent that can "load" a bundle type
Greg Kroah-Hartman0ac5a832014-11-15 12:12:16 -0800122 // This is what we need to bind a driver to so use the info
123 // in gmod here as well
Johan Hovoldc29c0162015-12-04 10:44:24 +0100124
125 if (add_uevent_var(env, "BUNDLE=%u", bundle->id))
126 return -ENOMEM;
Greg Kroah-Hartman0ac5a832014-11-15 12:12:16 -0800127 }
128
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +0800129 return 0;
130}
131
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +0800132struct bus_type greybus_bus_type = {
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +0800133 .name = "greybus",
Alex Elder778c69c2014-09-22 19:19:03 -0500134 .match = greybus_module_match,
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +0800135 .uevent = greybus_uevent,
136};
137
138static int greybus_probe(struct device *dev)
139{
140 struct greybus_driver *driver = to_greybus_driver(dev->driver);
Viresh Kumar9f5f30e7122015-04-01 20:32:04 +0530141 struct gb_bundle *bundle = to_gb_bundle(dev);
142 const struct greybus_bundle_id *id;
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +0800143 int retval;
144
145 /* match id */
Johan Hovold700001a2015-11-21 10:52:03 +0100146 id = greybus_match_id(bundle, driver->id_table);
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +0800147 if (!id)
148 return -ENODEV;
149
Viresh Kumar9f5f30e7122015-04-01 20:32:04 +0530150 retval = driver->probe(bundle, id);
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +0800151 if (retval)
152 return retval;
153
154 return 0;
155}
156
157static int greybus_remove(struct device *dev)
158{
159 struct greybus_driver *driver = to_greybus_driver(dev->driver);
Viresh Kumar9f5f30e7122015-04-01 20:32:04 +0530160 struct gb_bundle *bundle = to_gb_bundle(dev);
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +0800161
Viresh Kumar9f5f30e7122015-04-01 20:32:04 +0530162 driver->disconnect(bundle);
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +0800163 return 0;
164}
165
166int greybus_register_driver(struct greybus_driver *driver, struct module *owner,
167 const char *mod_name)
168{
169 int retval;
170
171 if (greybus_disabled())
172 return -ENODEV;
173
Johan Hovold3c48d1b2016-01-08 20:13:42 +0100174 driver->driver.bus = &greybus_bus_type;
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +0800175 driver->driver.name = driver->name;
176 driver->driver.probe = greybus_probe;
177 driver->driver.remove = greybus_remove;
178 driver->driver.owner = owner;
179 driver->driver.mod_name = mod_name;
180
181 retval = driver_register(&driver->driver);
182 if (retval)
183 return retval;
184
185 pr_info("registered new driver %s\n", driver->name);
186 return 0;
187}
188EXPORT_SYMBOL_GPL(greybus_register_driver);
189
Alex Elderfd1c2e52015-06-08 12:05:13 -0500190void greybus_deregister_driver(struct greybus_driver *driver)
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +0800191{
192 driver_unregister(&driver->driver);
193}
Alex Elderfd1c2e52015-06-08 12:05:13 -0500194EXPORT_SYMBOL_GPL(greybus_deregister_driver);
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +0800195
Greg Kroah-Hartman503c1cd2014-08-30 16:21:03 -0700196static int __init gb_init(void)
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700197{
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700198 int retval;
199
Viresh Kumar337b0682015-03-20 20:29:13 +0530200 if (greybus_disabled())
201 return -ENODEV;
202
Alex Elderfb690ca2015-06-13 11:02:09 -0500203 BUILD_BUG_ON(CPORT_ID_MAX >= (long)CPORT_ID_BAD);
Alex Elder1bb3c722014-10-02 12:30:03 -0500204
Greg Kroah-Hartman48f70472015-03-27 11:38:06 +0100205 gb_debugfs_init();
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700206
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700207 retval = bus_register(&greybus_bus_type);
Greg Kroah-Hartman168db1c2014-09-13 16:15:52 -0700208 if (retval) {
Alex Elderf35ab902015-06-09 17:42:51 -0500209 pr_err("bus_register failed (%d)\n", retval);
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700210 goto error_bus;
Greg Kroah-Hartman168db1c2014-09-13 16:15:52 -0700211 }
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700212
Johan Hovold2adaefb2015-11-25 15:59:02 +0100213 retval = gb_hd_init();
214 if (retval) {
215 pr_err("gb_hd_init failed (%d)\n", retval);
216 goto error_hd;
217 }
218
Alex Elder2eb585f2014-10-16 06:35:34 -0500219 retval = gb_operation_init();
220 if (retval) {
Alex Elderf35ab902015-06-09 17:42:51 -0500221 pr_err("gb_operation_init failed (%d)\n", retval);
Alex Elder2eb585f2014-10-16 06:35:34 -0500222 goto error_operation;
223 }
224
Viresh Kumarcdee4f72015-06-22 16:42:26 +0530225 retval = gb_control_protocol_init();
226 if (retval) {
227 pr_err("gb_control_protocol_init failed\n");
228 goto error_control;
229 }
230
Viresh Kumarab69c4c2015-07-03 17:00:29 +0530231 retval = gb_svc_protocol_init();
232 if (retval) {
233 pr_err("gb_svc_protocol_init failed\n");
234 goto error_svc;
235 }
236
Viresh Kumar90f1b612015-08-12 09:19:33 +0530237 retval = gb_firmware_protocol_init();
238 if (retval) {
239 pr_err("gb_firmware_protocol_init failed\n");
240 goto error_firmware;
241 }
242
Alex Elder19d03de2014-11-05 16:12:53 -0600243 return 0; /* Success */
244
Viresh Kumar90f1b612015-08-12 09:19:33 +0530245error_firmware:
246 gb_svc_protocol_exit();
Viresh Kumarab69c4c2015-07-03 17:00:29 +0530247error_svc:
248 gb_control_protocol_exit();
Viresh Kumarcdee4f72015-06-22 16:42:26 +0530249error_control:
Alex Elderf35ab902015-06-09 17:42:51 -0500250 gb_operation_exit();
Alex Elder2eb585f2014-10-16 06:35:34 -0500251error_operation:
Johan Hovold2adaefb2015-11-25 15:59:02 +0100252 gb_hd_exit();
253error_hd:
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700254 bus_unregister(&greybus_bus_type);
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700255error_bus:
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700256 gb_debugfs_cleanup();
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700257
258 return retval;
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700259}
Viresh Kumard71aaf22015-03-19 17:02:49 +0530260module_init(gb_init);
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700261
Greg Kroah-Hartman503c1cd2014-08-30 16:21:03 -0700262static void __exit gb_exit(void)
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700263{
Viresh Kumar90f1b612015-08-12 09:19:33 +0530264 gb_firmware_protocol_exit();
Viresh Kumarab69c4c2015-07-03 17:00:29 +0530265 gb_svc_protocol_exit();
Viresh Kumarcdee4f72015-06-22 16:42:26 +0530266 gb_control_protocol_exit();
Alex Elder2eb585f2014-10-16 06:35:34 -0500267 gb_operation_exit();
Johan Hovold2adaefb2015-11-25 15:59:02 +0100268 gb_hd_exit();
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700269 bus_unregister(&greybus_bus_type);
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700270 gb_debugfs_cleanup();
Bryan O'Donoghue5c8ad592015-09-18 16:38:45 +0100271 tracepoint_synchronize_unregister();
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700272}
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700273module_exit(gb_exit);
Greg Kroah-Hartman6cf42a42015-04-13 19:51:33 +0200274MODULE_LICENSE("GPL v2");
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +0800275MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>");