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