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 22af5dc7f8SDavid Lin #define GB_GBPHY_AUTOSUSPEND_MS 3000 23af5dc7f8SDavid Lin 24e54b106dSSandeep Patil struct gbphy_host { 25e54b106dSSandeep Patil struct gb_bundle *bundle; 26e54b106dSSandeep Patil struct list_head devices; 27e54b106dSSandeep Patil }; 28e54b106dSSandeep Patil 29e54b106dSSandeep Patil static DEFINE_IDA(gbphy_id); 30e54b106dSSandeep Patil 31e54b106dSSandeep Patil static ssize_t protocol_id_show(struct device *dev, 32e54b106dSSandeep Patil struct device_attribute *attr, char *buf) 33e54b106dSSandeep Patil { 34e54b106dSSandeep Patil struct gbphy_device *gbphy_dev = to_gbphy_dev(dev); 35e54b106dSSandeep Patil 36e54b106dSSandeep Patil return sprintf(buf, "0x%02x\n", gbphy_dev->cport_desc->protocol_id); 37e54b106dSSandeep Patil } 38e54b106dSSandeep Patil static DEVICE_ATTR_RO(protocol_id); 39e54b106dSSandeep Patil 40e54b106dSSandeep Patil static struct attribute *gbphy_dev_attrs[] = { 41e54b106dSSandeep Patil &dev_attr_protocol_id.attr, 42e54b106dSSandeep Patil NULL, 43e54b106dSSandeep Patil }; 44e54b106dSSandeep Patil 45e54b106dSSandeep Patil ATTRIBUTE_GROUPS(gbphy_dev); 46e54b106dSSandeep Patil 47e54b106dSSandeep Patil static void gbphy_dev_release(struct device *dev) 48e54b106dSSandeep Patil { 49e54b106dSSandeep Patil struct gbphy_device *gbphy_dev = to_gbphy_dev(dev); 50e54b106dSSandeep Patil 51e54b106dSSandeep Patil ida_simple_remove(&gbphy_id, gbphy_dev->id); 52e54b106dSSandeep Patil kfree(gbphy_dev); 53e54b106dSSandeep Patil } 54e54b106dSSandeep Patil 55948c6227SGreg Kroah-Hartman #ifdef CONFIG_PM 56af5dc7f8SDavid Lin static int gb_gbphy_idle(struct device *dev) 57af5dc7f8SDavid Lin { 58af5dc7f8SDavid Lin pm_runtime_mark_last_busy(dev); 59af5dc7f8SDavid Lin pm_request_autosuspend(dev); 60af5dc7f8SDavid Lin return 0; 61af5dc7f8SDavid Lin } 62af5dc7f8SDavid Lin #endif 63af5dc7f8SDavid Lin 64af5dc7f8SDavid Lin static const struct dev_pm_ops gb_gbphy_pm_ops = { 65af5dc7f8SDavid Lin SET_RUNTIME_PM_OPS(pm_generic_runtime_suspend, 66af5dc7f8SDavid Lin pm_generic_runtime_resume, 67af5dc7f8SDavid Lin gb_gbphy_idle) 68af5dc7f8SDavid Lin }; 69af5dc7f8SDavid Lin 70e54b106dSSandeep Patil static struct device_type greybus_gbphy_dev_type = { 71e54b106dSSandeep Patil .name = "gbphy_device", 72e54b106dSSandeep Patil .release = gbphy_dev_release, 73af5dc7f8SDavid Lin .pm = &gb_gbphy_pm_ops, 74e54b106dSSandeep Patil }; 75e54b106dSSandeep Patil 76e54b106dSSandeep Patil static int gbphy_dev_uevent(struct device *dev, struct kobj_uevent_env *env) 77e54b106dSSandeep Patil { 78e54b106dSSandeep Patil struct gbphy_device *gbphy_dev = to_gbphy_dev(dev); 79e54b106dSSandeep Patil struct greybus_descriptor_cport *cport_desc = gbphy_dev->cport_desc; 80e54b106dSSandeep Patil struct gb_bundle *bundle = gbphy_dev->bundle; 81e54b106dSSandeep Patil struct gb_interface *intf = bundle->intf; 82e54b106dSSandeep Patil struct gb_module *module = intf->module; 83e54b106dSSandeep Patil struct gb_host_device *hd = intf->hd; 84e54b106dSSandeep Patil 85e54b106dSSandeep Patil if (add_uevent_var(env, "BUS=%u", hd->bus_id)) 86e54b106dSSandeep Patil return -ENOMEM; 87e54b106dSSandeep Patil if (add_uevent_var(env, "MODULE=%u", module->module_id)) 88e54b106dSSandeep Patil return -ENOMEM; 89e54b106dSSandeep Patil if (add_uevent_var(env, "INTERFACE=%u", intf->interface_id)) 90e54b106dSSandeep Patil return -ENOMEM; 91e54b106dSSandeep Patil if (add_uevent_var(env, "GREYBUS_ID=%08x/%08x", 92e54b106dSSandeep Patil intf->vendor_id, intf->product_id)) 93e54b106dSSandeep Patil return -ENOMEM; 94e54b106dSSandeep Patil if (add_uevent_var(env, "BUNDLE=%u", gbphy_dev->bundle->id)) 95e54b106dSSandeep Patil return -ENOMEM; 96e54b106dSSandeep Patil if (add_uevent_var(env, "BUNDLE_CLASS=%02x", bundle->class)) 97e54b106dSSandeep Patil return -ENOMEM; 98e54b106dSSandeep Patil if (add_uevent_var(env, "GBPHY=%u", gbphy_dev->id)) 99e54b106dSSandeep Patil return -ENOMEM; 100e54b106dSSandeep Patil if (add_uevent_var(env, "PROTOCOL_ID=%02x", cport_desc->protocol_id)) 101e54b106dSSandeep Patil return -ENOMEM; 102e54b106dSSandeep Patil 103e54b106dSSandeep Patil return 0; 104e54b106dSSandeep Patil } 105e54b106dSSandeep Patil 106e54b106dSSandeep Patil static const struct gbphy_device_id * 107e54b106dSSandeep Patil gbphy_dev_match_id(struct gbphy_device *gbphy_dev, struct gbphy_driver *gbphy_drv) 108e54b106dSSandeep Patil { 109e54b106dSSandeep Patil const struct gbphy_device_id *id = gbphy_drv->id_table; 110e54b106dSSandeep Patil 111e54b106dSSandeep Patil if (!id) 112e54b106dSSandeep Patil return NULL; 113e54b106dSSandeep Patil 114e54b106dSSandeep Patil for (; id->protocol_id; id++) 115e54b106dSSandeep Patil if (id->protocol_id == gbphy_dev->cport_desc->protocol_id) 116e54b106dSSandeep Patil return id; 117e54b106dSSandeep Patil 118e54b106dSSandeep Patil return NULL; 119e54b106dSSandeep Patil } 120e54b106dSSandeep Patil 121e54b106dSSandeep Patil static int gbphy_dev_match(struct device *dev, struct device_driver *drv) 122e54b106dSSandeep Patil { 123e54b106dSSandeep Patil struct gbphy_driver *gbphy_drv = to_gbphy_driver(drv); 124e54b106dSSandeep Patil struct gbphy_device *gbphy_dev = to_gbphy_dev(dev); 125e54b106dSSandeep Patil const struct gbphy_device_id *id; 126e54b106dSSandeep Patil 127e54b106dSSandeep Patil id = gbphy_dev_match_id(gbphy_dev, gbphy_drv); 128e54b106dSSandeep Patil if (id) 129e54b106dSSandeep Patil return 1; 130e54b106dSSandeep Patil 131e54b106dSSandeep Patil return 0; 132e54b106dSSandeep Patil } 133e54b106dSSandeep Patil 134e54b106dSSandeep Patil static int gbphy_dev_probe(struct device *dev) 135e54b106dSSandeep Patil { 136e54b106dSSandeep Patil struct gbphy_driver *gbphy_drv = to_gbphy_driver(dev->driver); 137e54b106dSSandeep Patil struct gbphy_device *gbphy_dev = to_gbphy_dev(dev); 138e54b106dSSandeep Patil const struct gbphy_device_id *id; 139af5dc7f8SDavid Lin int ret; 140e54b106dSSandeep Patil 141e54b106dSSandeep Patil id = gbphy_dev_match_id(gbphy_dev, gbphy_drv); 142e54b106dSSandeep Patil if (!id) 143e54b106dSSandeep Patil return -ENODEV; 144e54b106dSSandeep Patil 145af5dc7f8SDavid Lin /* for old kernels we need get_sync to resume parent devices */ 146af5dc7f8SDavid Lin ret = gb_pm_runtime_get_sync(gbphy_dev->bundle); 147af5dc7f8SDavid Lin if (ret < 0) 148af5dc7f8SDavid Lin return ret; 149af5dc7f8SDavid Lin 150af5dc7f8SDavid Lin pm_runtime_set_autosuspend_delay(dev, GB_GBPHY_AUTOSUSPEND_MS); 151af5dc7f8SDavid Lin pm_runtime_use_autosuspend(dev); 152af5dc7f8SDavid Lin pm_runtime_get_noresume(dev); 153af5dc7f8SDavid Lin pm_runtime_set_active(dev); 154af5dc7f8SDavid Lin pm_runtime_enable(dev); 155af5dc7f8SDavid Lin 156af5dc7f8SDavid Lin /* 157af5dc7f8SDavid Lin * Drivers should call put on the gbphy dev before returning 158af5dc7f8SDavid Lin * from probe if they support runtime pm. 159af5dc7f8SDavid Lin */ 160af5dc7f8SDavid Lin ret = gbphy_drv->probe(gbphy_dev, id); 161af5dc7f8SDavid Lin if (ret) { 162af5dc7f8SDavid Lin pm_runtime_disable(dev); 163af5dc7f8SDavid Lin pm_runtime_set_suspended(dev); 164af5dc7f8SDavid Lin pm_runtime_put_noidle(dev); 165af5dc7f8SDavid Lin pm_runtime_dont_use_autosuspend(dev); 166af5dc7f8SDavid Lin } 167af5dc7f8SDavid Lin 168af5dc7f8SDavid Lin gb_pm_runtime_put_autosuspend(gbphy_dev->bundle); 169af5dc7f8SDavid Lin 170af5dc7f8SDavid Lin return ret; 171e54b106dSSandeep Patil } 172e54b106dSSandeep Patil 173e54b106dSSandeep Patil static int gbphy_dev_remove(struct device *dev) 174e54b106dSSandeep Patil { 175e54b106dSSandeep Patil struct gbphy_driver *gbphy_drv = to_gbphy_driver(dev->driver); 176e54b106dSSandeep Patil struct gbphy_device *gbphy_dev = to_gbphy_dev(dev); 177e54b106dSSandeep Patil 178e54b106dSSandeep Patil gbphy_drv->remove(gbphy_dev); 179af5dc7f8SDavid Lin 180af5dc7f8SDavid Lin pm_runtime_disable(dev); 181af5dc7f8SDavid Lin pm_runtime_set_suspended(dev); 182af5dc7f8SDavid Lin pm_runtime_put_noidle(dev); 183af5dc7f8SDavid Lin pm_runtime_dont_use_autosuspend(dev); 184af5dc7f8SDavid Lin 185e54b106dSSandeep Patil return 0; 186e54b106dSSandeep Patil } 187e54b106dSSandeep Patil 188e54b106dSSandeep Patil static struct bus_type gbphy_bus_type = { 189e54b106dSSandeep Patil .name = "gbphy", 190e54b106dSSandeep Patil .match = gbphy_dev_match, 191e54b106dSSandeep Patil .probe = gbphy_dev_probe, 192e54b106dSSandeep Patil .remove = gbphy_dev_remove, 193e54b106dSSandeep Patil .uevent = gbphy_dev_uevent, 194e54b106dSSandeep Patil }; 195e54b106dSSandeep Patil 196e54b106dSSandeep Patil int gb_gbphy_register_driver(struct gbphy_driver *driver, 197e54b106dSSandeep Patil struct module *owner, const char *mod_name) 198e54b106dSSandeep Patil { 199e54b106dSSandeep Patil int retval; 200e54b106dSSandeep Patil 201e54b106dSSandeep Patil if (greybus_disabled()) 202e54b106dSSandeep Patil return -ENODEV; 203e54b106dSSandeep Patil 204e54b106dSSandeep Patil driver->driver.bus = &gbphy_bus_type; 205e54b106dSSandeep Patil driver->driver.name = driver->name; 206e54b106dSSandeep Patil driver->driver.owner = owner; 207e54b106dSSandeep Patil driver->driver.mod_name = mod_name; 208e54b106dSSandeep Patil 209e54b106dSSandeep Patil retval = driver_register(&driver->driver); 210e54b106dSSandeep Patil if (retval) 211e54b106dSSandeep Patil return retval; 212e54b106dSSandeep Patil 213e54b106dSSandeep Patil pr_info("registered new driver %s\n", driver->name); 214e54b106dSSandeep Patil return 0; 215e54b106dSSandeep Patil } 216e54b106dSSandeep Patil EXPORT_SYMBOL_GPL(gb_gbphy_register_driver); 217e54b106dSSandeep Patil 218e54b106dSSandeep Patil void gb_gbphy_deregister_driver(struct gbphy_driver *driver) 219e54b106dSSandeep Patil { 220e54b106dSSandeep Patil driver_unregister(&driver->driver); 221e54b106dSSandeep Patil } 222e54b106dSSandeep Patil EXPORT_SYMBOL_GPL(gb_gbphy_deregister_driver); 223e54b106dSSandeep Patil 224e54b106dSSandeep Patil static struct gbphy_device *gb_gbphy_create_dev(struct gb_bundle *bundle, 225e54b106dSSandeep Patil struct greybus_descriptor_cport *cport_desc) 226e54b106dSSandeep Patil { 227e54b106dSSandeep Patil struct gbphy_device *gbphy_dev; 228e54b106dSSandeep Patil int retval; 229e54b106dSSandeep Patil int id; 230e54b106dSSandeep Patil 231e54b106dSSandeep Patil id = ida_simple_get(&gbphy_id, 1, 0, GFP_KERNEL); 232e54b106dSSandeep Patil if (id < 0) 233e54b106dSSandeep Patil return ERR_PTR(id); 234e54b106dSSandeep Patil 235e54b106dSSandeep Patil gbphy_dev = kzalloc(sizeof(*gbphy_dev), GFP_KERNEL); 236e54b106dSSandeep Patil if (!gbphy_dev) { 237e54b106dSSandeep Patil ida_simple_remove(&gbphy_id, id); 238e54b106dSSandeep Patil return ERR_PTR(-ENOMEM); 239e54b106dSSandeep Patil } 240e54b106dSSandeep Patil 241e54b106dSSandeep Patil gbphy_dev->id = id; 242e54b106dSSandeep Patil gbphy_dev->bundle = bundle; 243e54b106dSSandeep Patil gbphy_dev->cport_desc = cport_desc; 244e54b106dSSandeep Patil gbphy_dev->dev.parent = &bundle->dev; 245e54b106dSSandeep Patil gbphy_dev->dev.bus = &gbphy_bus_type; 246e54b106dSSandeep Patil gbphy_dev->dev.type = &greybus_gbphy_dev_type; 247e54b106dSSandeep Patil gbphy_dev->dev.groups = gbphy_dev_groups; 248e54b106dSSandeep Patil gbphy_dev->dev.dma_mask = bundle->dev.dma_mask; 249e54b106dSSandeep Patil dev_set_name(&gbphy_dev->dev, "gbphy%d", id); 250e54b106dSSandeep Patil 251e54b106dSSandeep Patil retval = device_register(&gbphy_dev->dev); 252e54b106dSSandeep Patil if (retval) { 253e54b106dSSandeep Patil put_device(&gbphy_dev->dev); 254e54b106dSSandeep Patil return ERR_PTR(retval); 255e54b106dSSandeep Patil } 256e54b106dSSandeep Patil 257e54b106dSSandeep Patil return gbphy_dev; 258e54b106dSSandeep Patil } 259e54b106dSSandeep Patil 260e54b106dSSandeep Patil static void gb_gbphy_disconnect(struct gb_bundle *bundle) 261e54b106dSSandeep Patil { 262e54b106dSSandeep Patil struct gbphy_host *gbphy_host = greybus_get_drvdata(bundle); 263e54b106dSSandeep Patil struct gbphy_device *gbphy_dev, *temp; 264af5dc7f8SDavid Lin int ret; 265af5dc7f8SDavid Lin 266af5dc7f8SDavid Lin ret = gb_pm_runtime_get_sync(bundle); 267af5dc7f8SDavid Lin if (ret < 0) 268af5dc7f8SDavid Lin gb_pm_runtime_get_noresume(bundle); 269e54b106dSSandeep Patil 270e54b106dSSandeep Patil list_for_each_entry_safe(gbphy_dev, temp, &gbphy_host->devices, list) { 271e54b106dSSandeep Patil list_del(&gbphy_dev->list); 272e54b106dSSandeep Patil device_unregister(&gbphy_dev->dev); 273e54b106dSSandeep Patil } 274e54b106dSSandeep Patil 275e54b106dSSandeep Patil kfree(gbphy_host); 276e54b106dSSandeep Patil } 277e54b106dSSandeep Patil 278e54b106dSSandeep Patil static int gb_gbphy_probe(struct gb_bundle *bundle, 279e54b106dSSandeep Patil const struct greybus_bundle_id *id) 280e54b106dSSandeep Patil { 281e54b106dSSandeep Patil struct gbphy_host *gbphy_host; 282e54b106dSSandeep Patil struct gbphy_device *gbphy_dev; 283e54b106dSSandeep Patil int i; 284e54b106dSSandeep Patil 285e54b106dSSandeep Patil if (bundle->num_cports == 0) 286e54b106dSSandeep Patil return -ENODEV; 287e54b106dSSandeep Patil 288e54b106dSSandeep Patil gbphy_host = kzalloc(sizeof(*gbphy_host), GFP_KERNEL); 289e54b106dSSandeep Patil if (!gbphy_host) 290e54b106dSSandeep Patil return -ENOMEM; 291e54b106dSSandeep Patil 292e54b106dSSandeep Patil gbphy_host->bundle = bundle; 293e54b106dSSandeep Patil INIT_LIST_HEAD(&gbphy_host->devices); 294e54b106dSSandeep Patil greybus_set_drvdata(bundle, gbphy_host); 295e54b106dSSandeep Patil 296e54b106dSSandeep Patil /* 297e54b106dSSandeep Patil * Create a bunch of children devices, one per cport, and bind the 298e54b106dSSandeep Patil * bridged phy drivers to them. 299e54b106dSSandeep Patil */ 300e54b106dSSandeep Patil for (i = 0; i < bundle->num_cports; ++i) { 301e54b106dSSandeep Patil gbphy_dev = gb_gbphy_create_dev(bundle, &bundle->cport_desc[i]); 302e54b106dSSandeep Patil if (IS_ERR(gbphy_dev)) { 303e54b106dSSandeep Patil gb_gbphy_disconnect(bundle); 304e54b106dSSandeep Patil return PTR_ERR(gbphy_dev); 305e54b106dSSandeep Patil } 306e54b106dSSandeep Patil list_add(&gbphy_dev->list, &gbphy_host->devices); 307e54b106dSSandeep Patil } 308e54b106dSSandeep Patil 309af5dc7f8SDavid Lin gb_pm_runtime_put_autosuspend(bundle); 310af5dc7f8SDavid Lin 311e54b106dSSandeep Patil return 0; 312e54b106dSSandeep Patil } 313e54b106dSSandeep Patil 314e54b106dSSandeep Patil static const struct greybus_bundle_id gb_gbphy_id_table[] = { 315e54b106dSSandeep Patil { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_BRIDGED_PHY) }, 316e54b106dSSandeep Patil { }, 317e54b106dSSandeep Patil }; 318e54b106dSSandeep Patil MODULE_DEVICE_TABLE(greybus, gb_gbphy_id_table); 319e54b106dSSandeep Patil 320e54b106dSSandeep Patil static struct greybus_driver gb_gbphy_driver = { 321e54b106dSSandeep Patil .name = "gbphy", 322e54b106dSSandeep Patil .probe = gb_gbphy_probe, 323e54b106dSSandeep Patil .disconnect = gb_gbphy_disconnect, 324e54b106dSSandeep Patil .id_table = gb_gbphy_id_table, 325e54b106dSSandeep Patil }; 326e54b106dSSandeep Patil 327e54b106dSSandeep Patil static int __init gbphy_init(void) 328e54b106dSSandeep Patil { 329e54b106dSSandeep Patil int retval; 330e54b106dSSandeep Patil 331e54b106dSSandeep Patil retval = bus_register(&gbphy_bus_type); 332e54b106dSSandeep Patil if (retval) { 333e54b106dSSandeep Patil pr_err("gbphy bus register failed (%d)\n", retval); 334e54b106dSSandeep Patil return retval; 335e54b106dSSandeep Patil } 336e54b106dSSandeep Patil 337e54b106dSSandeep Patil retval = greybus_register(&gb_gbphy_driver); 338e54b106dSSandeep Patil if (retval) { 339e54b106dSSandeep Patil pr_err("error registering greybus driver\n"); 340e54b106dSSandeep Patil goto error_gbphy; 341e54b106dSSandeep Patil } 342e54b106dSSandeep Patil 343e54b106dSSandeep Patil return 0; 344e54b106dSSandeep Patil 345e54b106dSSandeep Patil error_gbphy: 346e54b106dSSandeep Patil bus_unregister(&gbphy_bus_type); 347e54b106dSSandeep Patil ida_destroy(&gbphy_id); 348e54b106dSSandeep Patil return retval; 349e54b106dSSandeep Patil } 350e54b106dSSandeep Patil module_init(gbphy_init); 351e54b106dSSandeep Patil 352e54b106dSSandeep Patil static void __exit gbphy_exit(void) 353e54b106dSSandeep Patil { 354e54b106dSSandeep Patil greybus_deregister(&gb_gbphy_driver); 355e54b106dSSandeep Patil bus_unregister(&gbphy_bus_type); 356e54b106dSSandeep Patil ida_destroy(&gbphy_id); 357e54b106dSSandeep Patil } 358e54b106dSSandeep Patil module_exit(gbphy_exit); 359e54b106dSSandeep Patil 360e54b106dSSandeep Patil MODULE_LICENSE("GPL v2"); 361