Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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