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#include <linux/greybus.h>
  17
  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 void 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
 185static struct bus_type gbphy_bus_type = {
 186        .name =         "gbphy",
 187        .match =        gbphy_dev_match,
 188        .probe =        gbphy_dev_probe,
 189        .remove =       gbphy_dev_remove,
 190        .uevent =       gbphy_dev_uevent,
 191};
 192
 193int gb_gbphy_register_driver(struct gbphy_driver *driver,
 194                             struct module *owner, const char *mod_name)
 195{
 196        int retval;
 197
 198        if (greybus_disabled())
 199                return -ENODEV;
 200
 201        driver->driver.bus = &gbphy_bus_type;
 202        driver->driver.name = driver->name;
 203        driver->driver.owner = owner;
 204        driver->driver.mod_name = mod_name;
 205
 206        retval = driver_register(&driver->driver);
 207        if (retval)
 208                return retval;
 209
 210        pr_info("registered new driver %s\n", driver->name);
 211        return 0;
 212}
 213EXPORT_SYMBOL_GPL(gb_gbphy_register_driver);
 214
 215void gb_gbphy_deregister_driver(struct gbphy_driver *driver)
 216{
 217        driver_unregister(&driver->driver);
 218}
 219EXPORT_SYMBOL_GPL(gb_gbphy_deregister_driver);
 220
 221static struct gbphy_device *gb_gbphy_create_dev(struct gb_bundle *bundle,
 222                                                struct greybus_descriptor_cport *cport_desc)
 223{
 224        struct gbphy_device *gbphy_dev;
 225        int retval;
 226        int id;
 227
 228        id = ida_simple_get(&gbphy_id, 1, 0, GFP_KERNEL);
 229        if (id < 0)
 230                return ERR_PTR(id);
 231
 232        gbphy_dev = kzalloc(sizeof(*gbphy_dev), GFP_KERNEL);
 233        if (!gbphy_dev) {
 234                ida_simple_remove(&gbphy_id, id);
 235                return ERR_PTR(-ENOMEM);
 236        }
 237
 238        gbphy_dev->id = id;
 239        gbphy_dev->bundle = bundle;
 240        gbphy_dev->cport_desc = cport_desc;
 241        gbphy_dev->dev.parent = &bundle->dev;
 242        gbphy_dev->dev.bus = &gbphy_bus_type;
 243        gbphy_dev->dev.type = &greybus_gbphy_dev_type;
 244        gbphy_dev->dev.groups = gbphy_dev_groups;
 245        gbphy_dev->dev.dma_mask = bundle->dev.dma_mask;
 246        dev_set_name(&gbphy_dev->dev, "gbphy%d", id);
 247
 248        retval = device_register(&gbphy_dev->dev);
 249        if (retval) {
 250                put_device(&gbphy_dev->dev);
 251                return ERR_PTR(retval);
 252        }
 253
 254        return gbphy_dev;
 255}
 256
 257static void gb_gbphy_disconnect(struct gb_bundle *bundle)
 258{
 259        struct gbphy_host *gbphy_host = greybus_get_drvdata(bundle);
 260        struct gbphy_device *gbphy_dev, *temp;
 261        int ret;
 262
 263        ret = gb_pm_runtime_get_sync(bundle);
 264        if (ret < 0)
 265                gb_pm_runtime_get_noresume(bundle);
 266
 267        list_for_each_entry_safe(gbphy_dev, temp, &gbphy_host->devices, list) {
 268                list_del(&gbphy_dev->list);
 269                device_unregister(&gbphy_dev->dev);
 270        }
 271
 272        kfree(gbphy_host);
 273}
 274
 275static int gb_gbphy_probe(struct gb_bundle *bundle,
 276                          const struct greybus_bundle_id *id)
 277{
 278        struct gbphy_host *gbphy_host;
 279        struct gbphy_device *gbphy_dev;
 280        int i;
 281
 282        if (bundle->num_cports == 0)
 283                return -ENODEV;
 284
 285        gbphy_host = kzalloc(sizeof(*gbphy_host), GFP_KERNEL);
 286        if (!gbphy_host)
 287                return -ENOMEM;
 288
 289        gbphy_host->bundle = bundle;
 290        INIT_LIST_HEAD(&gbphy_host->devices);
 291        greybus_set_drvdata(bundle, gbphy_host);
 292
 293        /*
 294         * Create a bunch of children devices, one per cport, and bind the
 295         * bridged phy drivers to them.
 296         */
 297        for (i = 0; i < bundle->num_cports; ++i) {
 298                gbphy_dev = gb_gbphy_create_dev(bundle, &bundle->cport_desc[i]);
 299                if (IS_ERR(gbphy_dev)) {
 300                        gb_gbphy_disconnect(bundle);
 301                        return PTR_ERR(gbphy_dev);
 302                }
 303                list_add(&gbphy_dev->list, &gbphy_host->devices);
 304        }
 305
 306        gb_pm_runtime_put_autosuspend(bundle);
 307
 308        return 0;
 309}
 310
 311static const struct greybus_bundle_id gb_gbphy_id_table[] = {
 312        { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_BRIDGED_PHY) },
 313        { },
 314};
 315MODULE_DEVICE_TABLE(greybus, gb_gbphy_id_table);
 316
 317static struct greybus_driver gb_gbphy_driver = {
 318        .name           = "gbphy",
 319        .probe          = gb_gbphy_probe,
 320        .disconnect     = gb_gbphy_disconnect,
 321        .id_table       = gb_gbphy_id_table,
 322};
 323
 324static int __init gbphy_init(void)
 325{
 326        int retval;
 327
 328        retval = bus_register(&gbphy_bus_type);
 329        if (retval) {
 330                pr_err("gbphy bus register failed (%d)\n", retval);
 331                return retval;
 332        }
 333
 334        retval = greybus_register(&gb_gbphy_driver);
 335        if (retval) {
 336                pr_err("error registering greybus driver\n");
 337                goto error_gbphy;
 338        }
 339
 340        return 0;
 341
 342error_gbphy:
 343        bus_unregister(&gbphy_bus_type);
 344        ida_destroy(&gbphy_id);
 345        return retval;
 346}
 347module_init(gbphy_init);
 348
 349static void __exit gbphy_exit(void)
 350{
 351        greybus_deregister(&gb_gbphy_driver);
 352        bus_unregister(&gbphy_bus_type);
 353        ida_destroy(&gbphy_id);
 354}
 355module_exit(gbphy_exit);
 356
 357MODULE_LICENSE("GPL v2");
 358