blob: 7c701f398a4dcfafa9b71ba763bb72de1a78fc5c [file] [log] [blame]
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +08001/*
2 * Greybus "Core"
3 *
4 * Copyright 2014 Google Inc.
Alex Eldera46e9672014-12-12 12:08:42 -06005 * Copyright 2014 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
12#include <linux/types.h>
13#include <linux/module.h>
14#include <linux/moduleparam.h>
15#include <linux/kernel.h>
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -070016#include <linux/slab.h>
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080017#include <linux/device.h>
18
19#include "greybus.h"
20
21/* Allow greybus to be disabled at boot if needed */
22static bool nogreybus;
23#ifdef MODULE
24module_param(nogreybus, bool, 0444);
25#else
Viresh Kumar8597e6b2014-10-20 16:45:50 +053026core_param(nogreybus, nogreybus, bool, 0444);
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080027#endif
28int greybus_disabled(void)
29{
30 return nogreybus;
31}
32EXPORT_SYMBOL_GPL(greybus_disabled);
33
Alex Elder778c69c2014-09-22 19:19:03 -050034static int greybus_module_match(struct device *dev, struct device_driver *drv)
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080035{
Viresh Kumar95bd99d2014-11-14 17:24:59 +053036 struct greybus_driver *driver = to_greybus_driver(drv);
Viresh Kumar9f5f30e7122015-04-01 20:32:04 +053037 struct gb_bundle *bundle = to_gb_bundle(dev);
38 const struct greybus_bundle_id *id;
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080039
Viresh Kumar9f5f30e7122015-04-01 20:32:04 +053040 id = gb_bundle_match_id(bundle, driver->id_table);
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080041 if (id)
42 return 1;
Viresh Kumar696e0cc2014-11-21 11:26:30 +053043 /* FIXME - Dynamic ids? */
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080044 return 0;
45}
46
47static int greybus_uevent(struct device *dev, struct kobj_uevent_env *env)
48{
Greg Kroah-Hartmandf671552014-12-21 14:10:26 -080049 struct gb_module *module = NULL;
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -080050 struct gb_interface *intf = NULL;
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050051 struct gb_bundle *bundle = NULL;
Greg Kroah-Hartman0ac5a832014-11-15 12:12:16 -080052 struct gb_connection *connection = NULL;
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080053
Greg Kroah-Hartman0f035ac2015-04-07 20:26:53 +020054 if (is_gb_endo(dev)) {
55 /*
56 * Not much to do for an endo, just fall through, as the
57 * "default" attributes are good enough for us.
58 */
59 return 0;
60 }
61
Greg Kroah-Hartmandf671552014-12-21 14:10:26 -080062 if (is_gb_module(dev)) {
63 module = to_gb_module(dev);
64 } else if (is_gb_interface(dev)) {
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -080065 intf = to_gb_interface(dev);
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050066 } else if (is_gb_bundle(dev)) {
67 bundle = to_gb_bundle(dev);
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -080068 intf = bundle->intf;
Greg Kroah-Hartman0ac5a832014-11-15 12:12:16 -080069 } else if (is_gb_connection(dev)) {
70 connection = to_gb_connection(dev);
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050071 bundle = connection->bundle;
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -080072 intf = bundle->intf;
Greg Kroah-Hartman0ac5a832014-11-15 12:12:16 -080073 } else {
74 dev_WARN(dev, "uevent for unknown greybus device \"type\"!\n");
75 return -EINVAL;
76 }
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +080077
Greg Kroah-Hartman0ac5a832014-11-15 12:12:16 -080078 if (connection) {
79 // FIXME
80 // add a uevent that can "load" a connection type
81 return 0;
82 }
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +080083
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050084 if (bundle) {
Greg Kroah-Hartman0ac5a832014-11-15 12:12:16 -080085 // FIXME
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050086 // add a uevent that can "load" a bundle type
Greg Kroah-Hartman0ac5a832014-11-15 12:12:16 -080087 // This is what we need to bind a driver to so use the info
88 // in gmod here as well
89 return 0;
90 }
91
92 // FIXME
93 // "just" a module, be vague here, nothing binds to a module except
94 // the greybus core, so there's not much, if anything, we need to
95 // advertise.
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080096 return 0;
97}
98
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +080099struct bus_type greybus_bus_type = {
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +0800100 .name = "greybus",
Alex Elder778c69c2014-09-22 19:19:03 -0500101 .match = greybus_module_match,
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +0800102 .uevent = greybus_uevent,
103};
104
105static int greybus_probe(struct device *dev)
106{
107 struct greybus_driver *driver = to_greybus_driver(dev->driver);
Viresh Kumar9f5f30e7122015-04-01 20:32:04 +0530108 struct gb_bundle *bundle = to_gb_bundle(dev);
109 const struct greybus_bundle_id *id;
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +0800110 int retval;
111
112 /* match id */
Viresh Kumar9f5f30e7122015-04-01 20:32:04 +0530113 id = gb_bundle_match_id(bundle, driver->id_table);
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +0800114 if (!id)
115 return -ENODEV;
116
Viresh Kumar9f5f30e7122015-04-01 20:32:04 +0530117 retval = driver->probe(bundle, id);
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +0800118 if (retval)
119 return retval;
120
121 return 0;
122}
123
124static int greybus_remove(struct device *dev)
125{
126 struct greybus_driver *driver = to_greybus_driver(dev->driver);
Viresh Kumar9f5f30e7122015-04-01 20:32:04 +0530127 struct gb_bundle *bundle = to_gb_bundle(dev);
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +0800128
Viresh Kumar9f5f30e7122015-04-01 20:32:04 +0530129 driver->disconnect(bundle);
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +0800130 return 0;
131}
132
133int greybus_register_driver(struct greybus_driver *driver, struct module *owner,
134 const char *mod_name)
135{
136 int retval;
137
138 if (greybus_disabled())
139 return -ENODEV;
140
141 driver->driver.name = driver->name;
142 driver->driver.probe = greybus_probe;
143 driver->driver.remove = greybus_remove;
144 driver->driver.owner = owner;
145 driver->driver.mod_name = mod_name;
146
147 retval = driver_register(&driver->driver);
148 if (retval)
149 return retval;
150
151 pr_info("registered new driver %s\n", driver->name);
152 return 0;
153}
154EXPORT_SYMBOL_GPL(greybus_register_driver);
155
156void greybus_deregister(struct greybus_driver *driver)
157{
158 driver_unregister(&driver->driver);
159}
160EXPORT_SYMBOL_GPL(greybus_deregister);
161
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700162
Greg Kroah-Hartman68f1fc42014-09-07 13:12:11 -0700163static DEFINE_MUTEX(hd_mutex);
164
165static void free_hd(struct kref *kref)
166{
167 struct greybus_host_device *hd;
168
169 hd = container_of(kref, struct greybus_host_device, kref);
170
171 kfree(hd);
Alex Eldera06df4b2014-10-16 06:35:26 -0500172 mutex_unlock(&hd_mutex);
Greg Kroah-Hartman68f1fc42014-09-07 13:12:11 -0700173}
174
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -0700175struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver,
176 struct device *parent)
177{
178 struct greybus_host_device *hd;
179
Greg Kroah-Hartman724b6192014-10-27 13:32:27 +0800180 /*
181 * Validate that the driver implements all of the callbacks
182 * so that we don't have to every time we make them.
183 */
Johan Hovold7cf7bca2015-04-07 11:27:16 +0200184 if ((!driver->message_send) || (!driver->message_cancel) ||
Alex Eldera9163b22014-11-18 13:26:44 -0600185 (!driver->submit_svc)) {
Greg Kroah-Hartman724b6192014-10-27 13:32:27 +0800186 pr_err("Must implement all greybus_host_driver callbacks!\n");
187 return NULL;
188 }
189
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -0700190 hd = kzalloc(sizeof(*hd) + driver->hd_priv_size, GFP_KERNEL);
191 if (!hd)
192 return NULL;
193
194 kref_init(&hd->kref);
Greg Kroah-Hartman772149b2014-09-14 12:27:28 -0700195 hd->parent = parent;
196 hd->driver = driver;
Greg Kroah-Hartman1cd56a82014-12-19 14:56:36 -0800197 INIT_LIST_HEAD(&hd->interfaces);
Alex Elder2c43ce42014-11-17 08:08:44 -0600198 INIT_LIST_HEAD(&hd->connections);
Alex Elder177404b2014-10-03 14:14:24 -0500199 ida_init(&hd->cport_id_map);
Alex Elder1bb3c722014-10-02 12:30:03 -0500200
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -0700201 return hd;
202}
203EXPORT_SYMBOL_GPL(greybus_create_hd);
204
Greg Kroah-Hartman68f1fc42014-09-07 13:12:11 -0700205void greybus_remove_hd(struct greybus_host_device *hd)
206{
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +0800207 /* Tear down all modules that happen to be associated with this host
208 * controller */
Greg Kroah-Hartman13e6aac2014-12-19 14:56:35 -0800209 gb_remove_interfaces(hd);
Greg Kroah-Hartman68f1fc42014-09-07 13:12:11 -0700210 kref_put_mutex(&hd->kref, free_hd, &hd_mutex);
211}
212EXPORT_SYMBOL_GPL(greybus_remove_hd);
213
Greg Kroah-Hartman503c1cd2014-08-30 16:21:03 -0700214static int __init gb_init(void)
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700215{
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700216 int retval;
217
Viresh Kumar337b0682015-03-20 20:29:13 +0530218 if (greybus_disabled())
219 return -ENODEV;
220
Alex Elder1bb3c722014-10-02 12:30:03 -0500221 BUILD_BUG_ON(HOST_DEV_CPORT_ID_MAX >= (long)CPORT_ID_BAD);
Alex Elder1bb3c722014-10-02 12:30:03 -0500222
Greg Kroah-Hartman48f70472015-03-27 11:38:06 +0100223 gb_debugfs_init();
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700224
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700225 retval = bus_register(&greybus_bus_type);
Greg Kroah-Hartman168db1c2014-09-13 16:15:52 -0700226 if (retval) {
227 pr_err("bus_register failed\n");
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700228 goto error_bus;
Greg Kroah-Hartman168db1c2014-09-13 16:15:52 -0700229 }
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700230
Greg Kroah-Hartman45f36782014-09-14 11:40:35 -0700231 retval = gb_ap_init();
Greg Kroah-Hartman168db1c2014-09-13 16:15:52 -0700232 if (retval) {
Greg Kroah-Hartman45f36782014-09-14 11:40:35 -0700233 pr_err("gb_ap_init failed\n");
234 goto error_ap;
Greg Kroah-Hartman168db1c2014-09-13 16:15:52 -0700235 }
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700236
Alex Elder2eb585f2014-10-16 06:35:34 -0500237 retval = gb_operation_init();
238 if (retval) {
239 pr_err("gb_operation_init failed\n");
240 goto error_operation;
241 }
242
Alex Elder19d03de2014-11-05 16:12:53 -0600243 return 0; /* Success */
244
Alex Elder2eb585f2014-10-16 06:35:34 -0500245error_operation:
Greg Kroah-Hartman45f36782014-09-14 11:40:35 -0700246 gb_ap_exit();
Greg Kroah-Hartman45f36782014-09-14 11:40:35 -0700247error_ap:
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700248 bus_unregister(&greybus_bus_type);
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700249error_bus:
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700250 gb_debugfs_cleanup();
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700251
252 return retval;
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700253}
Viresh Kumard71aaf22015-03-19 17:02:49 +0530254module_init(gb_init);
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700255
Greg Kroah-Hartman503c1cd2014-08-30 16:21:03 -0700256static void __exit gb_exit(void)
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700257{
Alex Elder2eb585f2014-10-16 06:35:34 -0500258 gb_operation_exit();
Greg Kroah-Hartman45f36782014-09-14 11:40:35 -0700259 gb_ap_exit();
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700260 bus_unregister(&greybus_bus_type);
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700261 gb_debugfs_cleanup();
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700262}
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700263module_exit(gb_exit);
264
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +0800265MODULE_LICENSE("GPL");
266MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>");