linux/drivers/bcma/main.c
<<
>>
Prefs
   1/*
   2 * Broadcom specific AMBA
   3 * Bus subsystem
   4 *
   5 * Licensed under the GNU/GPL. See COPYING for details.
   6 */
   7
   8#include "bcma_private.h"
   9#include <linux/module.h>
  10#include <linux/bcma/bcma.h>
  11#include <linux/slab.h>
  12
  13MODULE_DESCRIPTION("Broadcom's specific AMBA driver");
  14MODULE_LICENSE("GPL");
  15
  16static int bcma_bus_match(struct device *dev, struct device_driver *drv);
  17static int bcma_device_probe(struct device *dev);
  18static int bcma_device_remove(struct device *dev);
  19static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env);
  20
  21static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf)
  22{
  23        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
  24        return sprintf(buf, "0x%03X\n", core->id.manuf);
  25}
  26static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf)
  27{
  28        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
  29        return sprintf(buf, "0x%03X\n", core->id.id);
  30}
  31static ssize_t rev_show(struct device *dev, struct device_attribute *attr, char *buf)
  32{
  33        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
  34        return sprintf(buf, "0x%02X\n", core->id.rev);
  35}
  36static ssize_t class_show(struct device *dev, struct device_attribute *attr, char *buf)
  37{
  38        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
  39        return sprintf(buf, "0x%X\n", core->id.class);
  40}
  41static struct device_attribute bcma_device_attrs[] = {
  42        __ATTR_RO(manuf),
  43        __ATTR_RO(id),
  44        __ATTR_RO(rev),
  45        __ATTR_RO(class),
  46        __ATTR_NULL,
  47};
  48
  49static struct bus_type bcma_bus_type = {
  50        .name           = "bcma",
  51        .match          = bcma_bus_match,
  52        .probe          = bcma_device_probe,
  53        .remove         = bcma_device_remove,
  54        .uevent         = bcma_device_uevent,
  55        .dev_attrs      = bcma_device_attrs,
  56};
  57
  58static struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid)
  59{
  60        struct bcma_device *core;
  61
  62        list_for_each_entry(core, &bus->cores, list) {
  63                if (core->id.id == coreid)
  64                        return core;
  65        }
  66        return NULL;
  67}
  68
  69static void bcma_release_core_dev(struct device *dev)
  70{
  71        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
  72        if (core->io_addr)
  73                iounmap(core->io_addr);
  74        if (core->io_wrap)
  75                iounmap(core->io_wrap);
  76        kfree(core);
  77}
  78
  79static int bcma_register_cores(struct bcma_bus *bus)
  80{
  81        struct bcma_device *core;
  82        int err, dev_id = 0;
  83
  84        list_for_each_entry(core, &bus->cores, list) {
  85                /* We support that cores ourself */
  86                switch (core->id.id) {
  87                case BCMA_CORE_CHIPCOMMON:
  88                case BCMA_CORE_PCI:
  89                case BCMA_CORE_PCIE:
  90                case BCMA_CORE_MIPS_74K:
  91                        continue;
  92                }
  93
  94                core->dev.release = bcma_release_core_dev;
  95                core->dev.bus = &bcma_bus_type;
  96                dev_set_name(&core->dev, "bcma%d:%d", 0/*bus->num*/, dev_id);
  97
  98                switch (bus->hosttype) {
  99                case BCMA_HOSTTYPE_PCI:
 100                        core->dev.parent = &bus->host_pci->dev;
 101                        core->dma_dev = &bus->host_pci->dev;
 102                        core->irq = bus->host_pci->irq;
 103                        break;
 104                case BCMA_HOSTTYPE_SOC:
 105                        core->dev.dma_mask = &core->dev.coherent_dma_mask;
 106                        core->dma_dev = &core->dev;
 107                        break;
 108                case BCMA_HOSTTYPE_SDIO:
 109                        break;
 110                }
 111
 112                err = device_register(&core->dev);
 113                if (err) {
 114                        pr_err("Could not register dev for core 0x%03X\n",
 115                               core->id.id);
 116                        continue;
 117                }
 118                core->dev_registered = true;
 119                dev_id++;
 120        }
 121
 122        return 0;
 123}
 124
 125static void bcma_unregister_cores(struct bcma_bus *bus)
 126{
 127        struct bcma_device *core;
 128
 129        list_for_each_entry(core, &bus->cores, list) {
 130                if (core->dev_registered)
 131                        device_unregister(&core->dev);
 132        }
 133}
 134
 135int bcma_bus_register(struct bcma_bus *bus)
 136{
 137        int err;
 138        struct bcma_device *core;
 139
 140        /* Scan for devices (cores) */
 141        err = bcma_bus_scan(bus);
 142        if (err) {
 143                pr_err("Failed to scan: %d\n", err);
 144                return -1;
 145        }
 146
 147        /* Init CC core */
 148        core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
 149        if (core) {
 150                bus->drv_cc.core = core;
 151                bcma_core_chipcommon_init(&bus->drv_cc);
 152        }
 153
 154        /* Init MIPS core */
 155        core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
 156        if (core) {
 157                bus->drv_mips.core = core;
 158                bcma_core_mips_init(&bus->drv_mips);
 159        }
 160
 161        /* Init PCIE core */
 162        core = bcma_find_core(bus, BCMA_CORE_PCIE);
 163        if (core) {
 164                bus->drv_pci.core = core;
 165                bcma_core_pci_init(&bus->drv_pci);
 166        }
 167
 168        /* Try to get SPROM */
 169        err = bcma_sprom_get(bus);
 170        if (err == -ENOENT) {
 171                pr_err("No SPROM available\n");
 172        } else if (err)
 173                pr_err("Failed to get SPROM: %d\n", err);
 174
 175        /* Register found cores */
 176        bcma_register_cores(bus);
 177
 178        pr_info("Bus registered\n");
 179
 180        return 0;
 181}
 182
 183void bcma_bus_unregister(struct bcma_bus *bus)
 184{
 185        bcma_unregister_cores(bus);
 186}
 187
 188int __init bcma_bus_early_register(struct bcma_bus *bus,
 189                                   struct bcma_device *core_cc,
 190                                   struct bcma_device *core_mips)
 191{
 192        int err;
 193        struct bcma_device *core;
 194        struct bcma_device_id match;
 195
 196        bcma_init_bus(bus);
 197
 198        match.manuf = BCMA_MANUF_BCM;
 199        match.id = BCMA_CORE_CHIPCOMMON;
 200        match.class = BCMA_CL_SIM;
 201        match.rev = BCMA_ANY_REV;
 202
 203        /* Scan for chip common core */
 204        err = bcma_bus_scan_early(bus, &match, core_cc);
 205        if (err) {
 206                pr_err("Failed to scan for common core: %d\n", err);
 207                return -1;
 208        }
 209
 210        match.manuf = BCMA_MANUF_MIPS;
 211        match.id = BCMA_CORE_MIPS_74K;
 212        match.class = BCMA_CL_SIM;
 213        match.rev = BCMA_ANY_REV;
 214
 215        /* Scan for mips core */
 216        err = bcma_bus_scan_early(bus, &match, core_mips);
 217        if (err) {
 218                pr_err("Failed to scan for mips core: %d\n", err);
 219                return -1;
 220        }
 221
 222        /* Init CC core */
 223        core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
 224        if (core) {
 225                bus->drv_cc.core = core;
 226                bcma_core_chipcommon_init(&bus->drv_cc);
 227        }
 228
 229        /* Init MIPS core */
 230        core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
 231        if (core) {
 232                bus->drv_mips.core = core;
 233                bcma_core_mips_init(&bus->drv_mips);
 234        }
 235
 236        pr_info("Early bus registered\n");
 237
 238        return 0;
 239}
 240
 241#ifdef CONFIG_PM
 242int bcma_bus_suspend(struct bcma_bus *bus)
 243{
 244        struct bcma_device *core;
 245
 246        list_for_each_entry(core, &bus->cores, list) {
 247                struct device_driver *drv = core->dev.driver;
 248                if (drv) {
 249                        struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv);
 250                        if (adrv->suspend)
 251                                adrv->suspend(core);
 252                }
 253        }
 254        return 0;
 255}
 256
 257int bcma_bus_resume(struct bcma_bus *bus)
 258{
 259        struct bcma_device *core;
 260
 261        /* Init CC core */
 262        core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
 263        if (core) {
 264                bus->drv_cc.setup_done = false;
 265                bcma_core_chipcommon_init(&bus->drv_cc);
 266        }
 267
 268        list_for_each_entry(core, &bus->cores, list) {
 269                struct device_driver *drv = core->dev.driver;
 270                if (drv) {
 271                        struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv);
 272                        if (adrv->resume)
 273                                adrv->resume(core);
 274                }
 275        }
 276
 277        return 0;
 278}
 279#endif
 280
 281int __bcma_driver_register(struct bcma_driver *drv, struct module *owner)
 282{
 283        drv->drv.name = drv->name;
 284        drv->drv.bus = &bcma_bus_type;
 285        drv->drv.owner = owner;
 286
 287        return driver_register(&drv->drv);
 288}
 289EXPORT_SYMBOL_GPL(__bcma_driver_register);
 290
 291void bcma_driver_unregister(struct bcma_driver *drv)
 292{
 293        driver_unregister(&drv->drv);
 294}
 295EXPORT_SYMBOL_GPL(bcma_driver_unregister);
 296
 297static int bcma_bus_match(struct device *dev, struct device_driver *drv)
 298{
 299        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
 300        struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv);
 301        const struct bcma_device_id *cid = &core->id;
 302        const struct bcma_device_id *did;
 303
 304        for (did = adrv->id_table; did->manuf || did->id || did->rev; did++) {
 305            if ((did->manuf == cid->manuf || did->manuf == BCMA_ANY_MANUF) &&
 306                (did->id == cid->id || did->id == BCMA_ANY_ID) &&
 307                (did->rev == cid->rev || did->rev == BCMA_ANY_REV) &&
 308                (did->class == cid->class || did->class == BCMA_ANY_CLASS))
 309                        return 1;
 310        }
 311        return 0;
 312}
 313
 314static int bcma_device_probe(struct device *dev)
 315{
 316        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
 317        struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver,
 318                                               drv);
 319        int err = 0;
 320
 321        if (adrv->probe)
 322                err = adrv->probe(core);
 323
 324        return err;
 325}
 326
 327static int bcma_device_remove(struct device *dev)
 328{
 329        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
 330        struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver,
 331                                               drv);
 332
 333        if (adrv->remove)
 334                adrv->remove(core);
 335
 336        return 0;
 337}
 338
 339static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env)
 340{
 341        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
 342
 343        return add_uevent_var(env,
 344                              "MODALIAS=bcma:m%04Xid%04Xrev%02Xcl%02X",
 345                              core->id.manuf, core->id.id,
 346                              core->id.rev, core->id.class);
 347}
 348
 349static int __init bcma_modinit(void)
 350{
 351        int err;
 352
 353        err = bus_register(&bcma_bus_type);
 354        if (err)
 355                return err;
 356
 357#ifdef CONFIG_BCMA_HOST_PCI
 358        err = bcma_host_pci_init();
 359        if (err) {
 360                pr_err("PCI host initialization failed\n");
 361                err = 0;
 362        }
 363#endif
 364
 365        return err;
 366}
 367fs_initcall(bcma_modinit);
 368
 369static void __exit bcma_modexit(void)
 370{
 371#ifdef CONFIG_BCMA_HOST_PCI
 372        bcma_host_pci_exit();
 373#endif
 374        bus_unregister(&bcma_bus_type);
 375}
 376module_exit(bcma_modexit)
 377