1e54b106dSSandeep Patil /* 2e54b106dSSandeep Patil * Greybus Bridged-Phy Bus driver 3e54b106dSSandeep Patil * 4e54b106dSSandeep Patil * Copyright 2014 Google Inc. 5e54b106dSSandeep Patil * Copyright 2014 Linaro Ltd. 6e54b106dSSandeep Patil * 7e54b106dSSandeep Patil * Released under the GPLv2 only. 8e54b106dSSandeep Patil */ 9e54b106dSSandeep Patil 10e54b106dSSandeep Patil #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 11e54b106dSSandeep Patil 12e54b106dSSandeep Patil #include <linux/types.h> 13e54b106dSSandeep Patil #include <linux/module.h> 14e54b106dSSandeep Patil #include <linux/moduleparam.h> 15e54b106dSSandeep Patil #include <linux/kernel.h> 16e54b106dSSandeep Patil #include <linux/slab.h> 17e54b106dSSandeep Patil #include <linux/device.h> 18e54b106dSSandeep Patil 19e54b106dSSandeep Patil #include "greybus.h" 20e54b106dSSandeep Patil #include "gbphy.h" 21e54b106dSSandeep Patil 22e54b106dSSandeep Patil struct gbphy_host { 23e54b106dSSandeep Patil struct gb_bundle *bundle; 24e54b106dSSandeep Patil struct list_head devices; 25e54b106dSSandeep Patil }; 26e54b106dSSandeep Patil 27e54b106dSSandeep Patil static DEFINE_IDA(gbphy_id); 28e54b106dSSandeep Patil 29e54b106dSSandeep Patil static ssize_t protocol_id_show(struct device *dev, 30e54b106dSSandeep Patil struct device_attribute *attr, char *buf) 31e54b106dSSandeep Patil { 32e54b106dSSandeep Patil struct gbphy_device *gbphy_dev = to_gbphy_dev(dev); 33e54b106dSSandeep Patil 34e54b106dSSandeep Patil return sprintf(buf, "0x%02x\n", gbphy_dev->cport_desc->protocol_id); 35e54b106dSSandeep Patil } 36e54b106dSSandeep Patil static DEVICE_ATTR_RO(protocol_id); 37e54b106dSSandeep Patil 38e54b106dSSandeep Patil static struct attribute *gbphy_dev_attrs[] = { 39e54b106dSSandeep Patil &dev_attr_protocol_id.attr, 40e54b106dSSandeep Patil NULL, 41e54b106dSSandeep Patil }; 42e54b106dSSandeep Patil 43e54b106dSSandeep Patil ATTRIBUTE_GROUPS(gbphy_dev); 44e54b106dSSandeep Patil 45e54b106dSSandeep Patil static void gbphy_dev_release(struct device *dev) 46e54b106dSSandeep Patil { 47e54b106dSSandeep Patil struct gbphy_device *gbphy_dev = to_gbphy_dev(dev); 48e54b106dSSandeep Patil 49e54b106dSSandeep Patil ida_simple_remove(&gbphy_id, gbphy_dev->id); 50e54b106dSSandeep Patil kfree(gbphy_dev); 51e54b106dSSandeep Patil } 52e54b106dSSandeep Patil 53e54b106dSSandeep Patil static struct device_type greybus_gbphy_dev_type = { 54e54b106dSSandeep Patil .name = "gbphy_device", 55e54b106dSSandeep Patil .release = gbphy_dev_release, 56e54b106dSSandeep Patil }; 57e54b106dSSandeep Patil 58e54b106dSSandeep Patil static int gbphy_dev_uevent(struct device *dev, struct kobj_uevent_env *env) 59e54b106dSSandeep Patil { 60e54b106dSSandeep Patil struct gbphy_device *gbphy_dev = to_gbphy_dev(dev); 61e54b106dSSandeep Patil struct greybus_descriptor_cport *cport_desc = gbphy_dev->cport_desc; 62e54b106dSSandeep Patil struct gb_bundle *bundle = gbphy_dev->bundle; 63e54b106dSSandeep Patil struct gb_interface *intf = bundle->intf; 64e54b106dSSandeep Patil struct gb_module *module = intf->module; 65e54b106dSSandeep Patil struct gb_host_device *hd = intf->hd; 66e54b106dSSandeep Patil 67e54b106dSSandeep Patil if (add_uevent_var(env, "BUS=%u", hd->bus_id)) 68e54b106dSSandeep Patil return -ENOMEM; 69e54b106dSSandeep Patil if (add_uevent_var(env, "MODULE=%u", module->module_id)) 70e54b106dSSandeep Patil return -ENOMEM; 71e54b106dSSandeep Patil if (add_uevent_var(env, "INTERFACE=%u", intf->interface_id)) 72e54b106dSSandeep Patil return -ENOMEM; 73e54b106dSSandeep Patil if (add_uevent_var(env, "GREYBUS_ID=%08x/%08x", 74e54b106dSSandeep Patil intf->vendor_id, intf->product_id)) 75e54b106dSSandeep Patil return -ENOMEM; 76e54b106dSSandeep Patil if (add_uevent_var(env, "BUNDLE=%u", gbphy_dev->bundle->id)) 77e54b106dSSandeep Patil return -ENOMEM; 78e54b106dSSandeep Patil if (add_uevent_var(env, "BUNDLE_CLASS=%02x", bundle->class)) 79e54b106dSSandeep Patil return -ENOMEM; 80e54b106dSSandeep Patil if (add_uevent_var(env, "GBPHY=%u", gbphy_dev->id)) 81e54b106dSSandeep Patil return -ENOMEM; 82e54b106dSSandeep Patil if (add_uevent_var(env, "PROTOCOL_ID=%02x", cport_desc->protocol_id)) 83e54b106dSSandeep Patil return -ENOMEM; 84e54b106dSSandeep Patil 85e54b106dSSandeep Patil return 0; 86e54b106dSSandeep Patil } 87e54b106dSSandeep Patil 88e54b106dSSandeep Patil static const struct gbphy_device_id * 89e54b106dSSandeep Patil gbphy_dev_match_id(struct gbphy_device *gbphy_dev, struct gbphy_driver *gbphy_drv) 90e54b106dSSandeep Patil { 91e54b106dSSandeep Patil const struct gbphy_device_id *id = gbphy_drv->id_table; 92e54b106dSSandeep Patil 93e54b106dSSandeep Patil if (!id) 94e54b106dSSandeep Patil return NULL; 95e54b106dSSandeep Patil 96e54b106dSSandeep Patil for (; id->protocol_id; id++) 97e54b106dSSandeep Patil if (id->protocol_id == gbphy_dev->cport_desc->protocol_id) 98e54b106dSSandeep Patil return id; 99e54b106dSSandeep Patil 100e54b106dSSandeep Patil return NULL; 101e54b106dSSandeep Patil } 102e54b106dSSandeep Patil 103e54b106dSSandeep Patil static int gbphy_dev_match(struct device *dev, struct device_driver *drv) 104e54b106dSSandeep Patil { 105e54b106dSSandeep Patil struct gbphy_driver *gbphy_drv = to_gbphy_driver(drv); 106e54b106dSSandeep Patil struct gbphy_device *gbphy_dev = to_gbphy_dev(dev); 107e54b106dSSandeep Patil const struct gbphy_device_id *id; 108e54b106dSSandeep Patil 109e54b106dSSandeep Patil id = gbphy_dev_match_id(gbphy_dev, gbphy_drv); 110e54b106dSSandeep Patil if (id) 111e54b106dSSandeep Patil return 1; 112e54b106dSSandeep Patil 113e54b106dSSandeep Patil return 0; 114e54b106dSSandeep Patil } 115e54b106dSSandeep Patil 116e54b106dSSandeep Patil static int gbphy_dev_probe(struct device *dev) 117e54b106dSSandeep Patil { 118e54b106dSSandeep Patil struct gbphy_driver *gbphy_drv = to_gbphy_driver(dev->driver); 119e54b106dSSandeep Patil struct gbphy_device *gbphy_dev = to_gbphy_dev(dev); 120e54b106dSSandeep Patil const struct gbphy_device_id *id; 121e54b106dSSandeep Patil 122e54b106dSSandeep Patil id = gbphy_dev_match_id(gbphy_dev, gbphy_drv); 123e54b106dSSandeep Patil if (!id) 124e54b106dSSandeep Patil return -ENODEV; 125e54b106dSSandeep Patil 126e54b106dSSandeep Patil return gbphy_drv->probe(gbphy_dev, id); 127e54b106dSSandeep Patil } 128e54b106dSSandeep Patil 129e54b106dSSandeep Patil static int gbphy_dev_remove(struct device *dev) 130e54b106dSSandeep Patil { 131e54b106dSSandeep Patil struct gbphy_driver *gbphy_drv = to_gbphy_driver(dev->driver); 132e54b106dSSandeep Patil struct gbphy_device *gbphy_dev = to_gbphy_dev(dev); 133e54b106dSSandeep Patil 134e54b106dSSandeep Patil gbphy_drv->remove(gbphy_dev); 135e54b106dSSandeep Patil return 0; 136e54b106dSSandeep Patil } 137e54b106dSSandeep Patil 138e54b106dSSandeep Patil static struct bus_type gbphy_bus_type = { 139e54b106dSSandeep Patil .name = "gbphy", 140e54b106dSSandeep Patil .match = gbphy_dev_match, 141e54b106dSSandeep Patil .probe = gbphy_dev_probe, 142e54b106dSSandeep Patil .remove = gbphy_dev_remove, 143e54b106dSSandeep Patil .uevent = gbphy_dev_uevent, 144e54b106dSSandeep Patil }; 145e54b106dSSandeep Patil 146e54b106dSSandeep Patil int gb_gbphy_register_driver(struct gbphy_driver *driver, 147e54b106dSSandeep Patil struct module *owner, const char *mod_name) 148e54b106dSSandeep Patil { 149e54b106dSSandeep Patil int retval; 150e54b106dSSandeep Patil 151e54b106dSSandeep Patil if (greybus_disabled()) 152e54b106dSSandeep Patil return -ENODEV; 153e54b106dSSandeep Patil 154e54b106dSSandeep Patil driver->driver.bus = &gbphy_bus_type; 155e54b106dSSandeep Patil driver->driver.name = driver->name; 156e54b106dSSandeep Patil driver->driver.owner = owner; 157e54b106dSSandeep Patil driver->driver.mod_name = mod_name; 158e54b106dSSandeep Patil 159e54b106dSSandeep Patil retval = driver_register(&driver->driver); 160e54b106dSSandeep Patil if (retval) 161e54b106dSSandeep Patil return retval; 162e54b106dSSandeep Patil 163e54b106dSSandeep Patil pr_info("registered new driver %s\n", driver->name); 164e54b106dSSandeep Patil return 0; 165e54b106dSSandeep Patil } 166e54b106dSSandeep Patil EXPORT_SYMBOL_GPL(gb_gbphy_register_driver); 167e54b106dSSandeep Patil 168e54b106dSSandeep Patil void gb_gbphy_deregister_driver(struct gbphy_driver *driver) 169e54b106dSSandeep Patil { 170e54b106dSSandeep Patil driver_unregister(&driver->driver); 171e54b106dSSandeep Patil } 172e54b106dSSandeep Patil EXPORT_SYMBOL_GPL(gb_gbphy_deregister_driver); 173e54b106dSSandeep Patil 174e54b106dSSandeep Patil int gb_gbphy_get_version(struct gb_connection *connection) 175e54b106dSSandeep Patil { 176e54b106dSSandeep Patil struct gb_protocol_version_request request; 177e54b106dSSandeep Patil struct gb_protocol_version_response response; 178e54b106dSSandeep Patil int retval; 179e54b106dSSandeep Patil 180e54b106dSSandeep Patil request.major = 1; 181e54b106dSSandeep Patil request.minor = 0; 182e54b106dSSandeep Patil 183e54b106dSSandeep Patil retval = gb_operation_sync(connection, GB_REQUEST_TYPE_PROTOCOL_VERSION, 184e54b106dSSandeep Patil &request, sizeof(request), &response, 185e54b106dSSandeep Patil sizeof(response)); 186e54b106dSSandeep Patil if (retval) 187e54b106dSSandeep Patil return retval; 188e54b106dSSandeep Patil 189e54b106dSSandeep Patil /* FIXME - do proper version negotiation here someday... */ 190e54b106dSSandeep Patil 191e54b106dSSandeep Patil connection->module_major = response.major; 192e54b106dSSandeep Patil connection->module_minor = response.minor; 193e54b106dSSandeep Patil 194e54b106dSSandeep Patil dev_dbg(&connection->hd->dev, "%s: v%u.%u\n", connection->name, 195e54b106dSSandeep Patil response.major, response.minor); 196e54b106dSSandeep Patil 197e54b106dSSandeep Patil return 0; 198e54b106dSSandeep Patil } 199e54b106dSSandeep Patil EXPORT_SYMBOL_GPL(gb_gbphy_get_version); 200e54b106dSSandeep Patil 201e54b106dSSandeep Patil static struct gbphy_device *gb_gbphy_create_dev(struct gb_bundle *bundle, 202e54b106dSSandeep Patil struct greybus_descriptor_cport *cport_desc) 203e54b106dSSandeep Patil { 204e54b106dSSandeep Patil struct gbphy_device *gbphy_dev; 205e54b106dSSandeep Patil int retval; 206e54b106dSSandeep Patil int id; 207e54b106dSSandeep Patil 208e54b106dSSandeep Patil id = ida_simple_get(&gbphy_id, 1, 0, GFP_KERNEL); 209e54b106dSSandeep Patil if (id < 0) 210e54b106dSSandeep Patil return ERR_PTR(id); 211e54b106dSSandeep Patil 212e54b106dSSandeep Patil gbphy_dev = kzalloc(sizeof(*gbphy_dev), GFP_KERNEL); 213e54b106dSSandeep Patil if (!gbphy_dev) { 214e54b106dSSandeep Patil ida_simple_remove(&gbphy_id, id); 215e54b106dSSandeep Patil return ERR_PTR(-ENOMEM); 216e54b106dSSandeep Patil } 217e54b106dSSandeep Patil 218e54b106dSSandeep Patil gbphy_dev->id = id; 219e54b106dSSandeep Patil gbphy_dev->bundle = bundle; 220e54b106dSSandeep Patil gbphy_dev->cport_desc = cport_desc; 221e54b106dSSandeep Patil gbphy_dev->dev.parent = &bundle->dev; 222e54b106dSSandeep Patil gbphy_dev->dev.bus = &gbphy_bus_type; 223e54b106dSSandeep Patil gbphy_dev->dev.type = &greybus_gbphy_dev_type; 224e54b106dSSandeep Patil gbphy_dev->dev.groups = gbphy_dev_groups; 225e54b106dSSandeep Patil gbphy_dev->dev.dma_mask = bundle->dev.dma_mask; 226e54b106dSSandeep Patil dev_set_name(&gbphy_dev->dev, "gbphy%d", id); 227e54b106dSSandeep Patil 228e54b106dSSandeep Patil retval = device_register(&gbphy_dev->dev); 229e54b106dSSandeep Patil if (retval) { 230e54b106dSSandeep Patil put_device(&gbphy_dev->dev); 231e54b106dSSandeep Patil return ERR_PTR(retval); 232e54b106dSSandeep Patil } 233e54b106dSSandeep Patil 234e54b106dSSandeep Patil return gbphy_dev; 235e54b106dSSandeep Patil } 236e54b106dSSandeep Patil 237e54b106dSSandeep Patil static void gb_gbphy_disconnect(struct gb_bundle *bundle) 238e54b106dSSandeep Patil { 239e54b106dSSandeep Patil struct gbphy_host *gbphy_host = greybus_get_drvdata(bundle); 240e54b106dSSandeep Patil struct gbphy_device *gbphy_dev, *temp; 241e54b106dSSandeep Patil 242e54b106dSSandeep Patil list_for_each_entry_safe(gbphy_dev, temp, &gbphy_host->devices, list) { 243e54b106dSSandeep Patil list_del(&gbphy_dev->list); 244e54b106dSSandeep Patil device_unregister(&gbphy_dev->dev); 245e54b106dSSandeep Patil } 246e54b106dSSandeep Patil 247e54b106dSSandeep Patil kfree(gbphy_host); 248e54b106dSSandeep Patil } 249e54b106dSSandeep Patil 250e54b106dSSandeep Patil static int gb_gbphy_probe(struct gb_bundle *bundle, 251e54b106dSSandeep Patil const struct greybus_bundle_id *id) 252e54b106dSSandeep Patil { 253e54b106dSSandeep Patil struct gbphy_host *gbphy_host; 254e54b106dSSandeep Patil struct gbphy_device *gbphy_dev; 255e54b106dSSandeep Patil int i; 256e54b106dSSandeep Patil 257e54b106dSSandeep Patil if (bundle->num_cports == 0) 258e54b106dSSandeep Patil return -ENODEV; 259e54b106dSSandeep Patil 260e54b106dSSandeep Patil gbphy_host = kzalloc(sizeof(*gbphy_host), GFP_KERNEL); 261e54b106dSSandeep Patil if (!gbphy_host) 262e54b106dSSandeep Patil return -ENOMEM; 263e54b106dSSandeep Patil 264e54b106dSSandeep Patil gbphy_host->bundle = bundle; 265e54b106dSSandeep Patil INIT_LIST_HEAD(&gbphy_host->devices); 266e54b106dSSandeep Patil greybus_set_drvdata(bundle, gbphy_host); 267e54b106dSSandeep Patil 268e54b106dSSandeep Patil /* 269e54b106dSSandeep Patil * Create a bunch of children devices, one per cport, and bind the 270e54b106dSSandeep Patil * bridged phy drivers to them. 271e54b106dSSandeep Patil */ 272e54b106dSSandeep Patil for (i = 0; i < bundle->num_cports; ++i) { 273e54b106dSSandeep Patil gbphy_dev = gb_gbphy_create_dev(bundle, &bundle->cport_desc[i]); 274e54b106dSSandeep Patil if (IS_ERR(gbphy_dev)) { 275e54b106dSSandeep Patil gb_gbphy_disconnect(bundle); 276e54b106dSSandeep Patil return PTR_ERR(gbphy_dev); 277e54b106dSSandeep Patil } 278e54b106dSSandeep Patil list_add(&gbphy_dev->list, &gbphy_host->devices); 279e54b106dSSandeep Patil } 280e54b106dSSandeep Patil 281e54b106dSSandeep Patil return 0; 282e54b106dSSandeep Patil } 283e54b106dSSandeep Patil 284e54b106dSSandeep Patil static const struct greybus_bundle_id gb_gbphy_id_table[] = { 285e54b106dSSandeep Patil { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_BRIDGED_PHY) }, 286e54b106dSSandeep Patil { }, 287e54b106dSSandeep Patil }; 288e54b106dSSandeep Patil MODULE_DEVICE_TABLE(greybus, gb_gbphy_id_table); 289e54b106dSSandeep Patil 290e54b106dSSandeep Patil static struct greybus_driver gb_gbphy_driver = { 291e54b106dSSandeep Patil .name = "gbphy", 292e54b106dSSandeep Patil .probe = gb_gbphy_probe, 293e54b106dSSandeep Patil .disconnect = gb_gbphy_disconnect, 294e54b106dSSandeep Patil .id_table = gb_gbphy_id_table, 295e54b106dSSandeep Patil }; 296e54b106dSSandeep Patil 297e54b106dSSandeep Patil static int __init gbphy_init(void) 298e54b106dSSandeep Patil { 299e54b106dSSandeep Patil int retval; 300e54b106dSSandeep Patil 301e54b106dSSandeep Patil retval = bus_register(&gbphy_bus_type); 302e54b106dSSandeep Patil if (retval) { 303e54b106dSSandeep Patil pr_err("gbphy bus register failed (%d)\n", retval); 304e54b106dSSandeep Patil return retval; 305e54b106dSSandeep Patil } 306e54b106dSSandeep Patil 307e54b106dSSandeep Patil retval = greybus_register(&gb_gbphy_driver); 308e54b106dSSandeep Patil if (retval) { 309e54b106dSSandeep Patil pr_err("error registering greybus driver\n"); 310e54b106dSSandeep Patil goto error_gbphy; 311e54b106dSSandeep Patil } 312e54b106dSSandeep Patil 313e54b106dSSandeep Patil return 0; 314e54b106dSSandeep Patil 315e54b106dSSandeep Patil error_gbphy: 316e54b106dSSandeep Patil bus_unregister(&gbphy_bus_type); 317e54b106dSSandeep Patil ida_destroy(&gbphy_id); 318e54b106dSSandeep Patil return retval; 319e54b106dSSandeep Patil } 320e54b106dSSandeep Patil module_init(gbphy_init); 321e54b106dSSandeep Patil 322e54b106dSSandeep Patil static void __exit gbphy_exit(void) 323e54b106dSSandeep Patil { 324e54b106dSSandeep Patil greybus_deregister(&gb_gbphy_driver); 325e54b106dSSandeep Patil bus_unregister(&gbphy_bus_type); 326e54b106dSSandeep Patil ida_destroy(&gbphy_id); 327e54b106dSSandeep Patil } 328e54b106dSSandeep Patil module_exit(gbphy_exit); 329e54b106dSSandeep Patil 330e54b106dSSandeep Patil MODULE_LICENSE("GPL v2"); 331