| 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/mmc/sdio_func.h>
|
| 11 | #include <linux/platform_device.h>
|
| 12 | #include <linux/pci.h>
|
| 13 | #include <linux/bcma/bcma.h>
|
| 14 | #include <linux/slab.h>
|
| 15 | #include <linux/of_address.h>
|
| 16 | #include <linux/of_irq.h>
|
| 17 | #include <linux/of_device.h>
|
| 18 | #include <linux/of_platform.h>
|
| 19 |
|
| 20 | MODULE_DESCRIPTION("Broadcom's specific AMBA driver");
|
| 21 | MODULE_LICENSE("GPL");
|
| 22 |
|
| 23 |
|
| 24 | static unsigned int bcma_bus_next_num;
|
| 25 |
|
| 26 |
|
| 27 | static DEFINE_MUTEX(bcma_buses_mutex);
|
| 28 |
|
| 29 | static int bcma_bus_match(struct device *dev, const struct device_driver *drv);
|
| 30 | static int bcma_device_probe(struct device *dev);
|
| 31 | static void bcma_device_remove(struct device *dev);
|
| 32 | static int bcma_device_uevent(const struct device *dev, struct kobj_uevent_env *env);
|
| 33 |
|
| 34 | static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf)
|
| 35 | {
|
| 36 | struct bcma_device *core = container_of(dev, struct bcma_device, dev);
|
| 37 | return sprintf(buf, "0x%03X\n", core->id.manuf);
|
| 38 | }
|
| 39 | static DEVICE_ATTR_RO(manuf);
|
| 40 |
|
| 41 | static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf)
|
| 42 | {
|
| 43 | struct bcma_device *core = container_of(dev, struct bcma_device, dev);
|
| 44 | return sprintf(buf, "0x%03X\n", core->id.id);
|
| 45 | }
|
| 46 | static DEVICE_ATTR_RO(id);
|
| 47 |
|
| 48 | static ssize_t rev_show(struct device *dev, struct device_attribute *attr, char *buf)
|
| 49 | {
|
| 50 | struct bcma_device *core = container_of(dev, struct bcma_device, dev);
|
| 51 | return sprintf(buf, "0x%02X\n", core->id.rev);
|
| 52 | }
|
| 53 | static DEVICE_ATTR_RO(rev);
|
| 54 |
|
| 55 | static ssize_t class_show(struct device *dev, struct device_attribute *attr, char *buf)
|
| 56 | {
|
| 57 | struct bcma_device *core = container_of(dev, struct bcma_device, dev);
|
| 58 | return sprintf(buf, "0x%X\n", core->id.class);
|
| 59 | }
|
| 60 | static DEVICE_ATTR_RO(class);
|
| 61 |
|
| 62 | static struct attribute *bcma_device_attrs[] = {
|
| 63 | &dev_attr_manuf.attr,
|
| 64 | &dev_attr_id.attr,
|
| 65 | &dev_attr_rev.attr,
|
| 66 | &dev_attr_class.attr,
|
| 67 | NULL,
|
| 68 | };
|
| 69 | ATTRIBUTE_GROUPS(bcma_device);
|
| 70 |
|
| 71 | static const struct bus_type bcma_bus_type = {
|
| 72 | .name = "bcma",
|
| 73 | .match = bcma_bus_match,
|
| 74 | .probe = bcma_device_probe,
|
| 75 | .remove = bcma_device_remove,
|
| 76 | .uevent = bcma_device_uevent,
|
| 77 | .dev_groups = bcma_device_groups,
|
| 78 | };
|
| 79 |
|
| 80 | static u16 bcma_cc_core_id(struct bcma_bus *bus)
|
| 81 | {
|
| 82 | if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706)
|
| 83 | return BCMA_CORE_4706_CHIPCOMMON;
|
| 84 | return BCMA_CORE_CHIPCOMMON;
|
| 85 | }
|
| 86 |
|
| 87 | struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid,
|
| 88 | u8 unit)
|
| 89 | {
|
| 90 | struct bcma_device *core;
|
| 91 |
|
| 92 | list_for_each_entry(core, &bus->cores, list) {
|
| 93 | if (core->id.id == coreid && core->core_unit == unit)
|
| 94 | return core;
|
| 95 | }
|
| 96 | return NULL;
|
| 97 | }
|
| 98 | EXPORT_SYMBOL_GPL(bcma_find_core_unit);
|
| 99 |
|
| 100 | bool bcma_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value,
|
| 101 | int timeout)
|
| 102 | {
|
| 103 | unsigned long deadline = jiffies + timeout;
|
| 104 | u32 val;
|
| 105 |
|
| 106 | do {
|
| 107 | val = bcma_read32(core, reg);
|
| 108 | if ((val & mask) == value)
|
| 109 | return true;
|
| 110 | cpu_relax();
|
| 111 | udelay(10);
|
| 112 | } while (!time_after_eq(jiffies, deadline));
|
| 113 |
|
| 114 | bcma_warn(core->bus, "Timeout waiting for register 0x%04X!\n", reg);
|
| 115 |
|
| 116 | return false;
|
| 117 | }
|
| 118 |
|
| 119 | static void bcma_release_core_dev(struct device *dev)
|
| 120 | {
|
| 121 | struct bcma_device *core = container_of(dev, struct bcma_device, dev);
|
| 122 | if (core->io_addr)
|
| 123 | iounmap(core->io_addr);
|
| 124 | if (core->io_wrap)
|
| 125 | iounmap(core->io_wrap);
|
| 126 | kfree(core);
|
| 127 | }
|
| 128 |
|
| 129 | static bool bcma_is_core_needed_early(u16 core_id)
|
| 130 | {
|
| 131 | switch (core_id) {
|
| 132 | case BCMA_CORE_NS_NAND:
|
| 133 | case BCMA_CORE_NS_QSPI:
|
| 134 | return true;
|
| 135 | }
|
| 136 |
|
| 137 | return false;
|
| 138 | }
|
| 139 |
|
| 140 | static struct device_node *bcma_of_find_child_device(struct device *parent,
|
| 141 | struct bcma_device *core)
|
| 142 | {
|
| 143 | struct device_node *node;
|
| 144 | int ret;
|
| 145 |
|
| 146 | if (!parent->of_node)
|
| 147 | return NULL;
|
| 148 |
|
| 149 | for_each_child_of_node(parent->of_node, node) {
|
| 150 | struct resource res;
|
| 151 | ret = of_address_to_resource(node, 0, &res);
|
| 152 | if (ret)
|
| 153 | continue;
|
| 154 | if (res.start == core->addr)
|
| 155 | return node;
|
| 156 | }
|
| 157 | return NULL;
|
| 158 | }
|
| 159 |
|
| 160 | static int bcma_of_irq_parse(struct device *parent,
|
| 161 | struct bcma_device *core,
|
| 162 | struct of_phandle_args *out_irq, int num)
|
| 163 | {
|
| 164 | __be32 laddr[1];
|
| 165 | int rc;
|
| 166 |
|
| 167 | if (core->dev.of_node) {
|
| 168 | rc = of_irq_parse_one(core->dev.of_node, num, out_irq);
|
| 169 | if (!rc)
|
| 170 | return rc;
|
| 171 | }
|
| 172 |
|
| 173 | out_irq->np = parent->of_node;
|
| 174 | out_irq->args_count = 1;
|
| 175 | out_irq->args[0] = num;
|
| 176 |
|
| 177 | laddr[0] = cpu_to_be32(core->addr);
|
| 178 | return of_irq_parse_raw(laddr, out_irq);
|
| 179 | }
|
| 180 |
|
| 181 | static unsigned int bcma_of_get_irq(struct device *parent,
|
| 182 | struct bcma_device *core, int num)
|
| 183 | {
|
| 184 | struct of_phandle_args out_irq;
|
| 185 | int ret;
|
| 186 |
|
| 187 | if (!IS_ENABLED(CONFIG_OF_IRQ) || !parent->of_node)
|
| 188 | return 0;
|
| 189 |
|
| 190 | ret = bcma_of_irq_parse(parent, core, &out_irq, num);
|
| 191 | if (ret) {
|
| 192 | bcma_debug(core->bus, "bcma_of_get_irq() failed with rc=%d\n",
|
| 193 | ret);
|
| 194 | return 0;
|
| 195 | }
|
| 196 |
|
| 197 | return irq_create_of_mapping(&out_irq);
|
| 198 | }
|
| 199 |
|
| 200 | static void bcma_of_fill_device(struct device *parent,
|
| 201 | struct bcma_device *core)
|
| 202 | {
|
| 203 | struct device_node *node;
|
| 204 |
|
| 205 | node = bcma_of_find_child_device(parent, core);
|
| 206 | if (node)
|
| 207 | core->dev.of_node = node;
|
| 208 |
|
| 209 | core->irq = bcma_of_get_irq(parent, core, 0);
|
| 210 |
|
| 211 | of_dma_configure(&core->dev, node, false);
|
| 212 | }
|
| 213 |
|
| 214 | unsigned int bcma_core_irq(struct bcma_device *core, int num)
|
| 215 | {
|
| 216 | struct bcma_bus *bus = core->bus;
|
| 217 | unsigned int mips_irq;
|
| 218 |
|
| 219 | switch (bus->hosttype) {
|
| 220 | case BCMA_HOSTTYPE_PCI:
|
| 221 | return bus->host_pci->irq;
|
| 222 | case BCMA_HOSTTYPE_SOC:
|
| 223 | if (bus->drv_mips.core && num == 0) {
|
| 224 | mips_irq = bcma_core_mips_irq(core);
|
| 225 | return mips_irq <= 4 ? mips_irq + 2 : 0;
|
| 226 | }
|
| 227 | if (bus->dev)
|
| 228 | return bcma_of_get_irq(bus->dev, core, num);
|
| 229 | return 0;
|
| 230 | case BCMA_HOSTTYPE_SDIO:
|
| 231 | return 0;
|
| 232 | }
|
| 233 |
|
| 234 | return 0;
|
| 235 | }
|
| 236 | EXPORT_SYMBOL(bcma_core_irq);
|
| 237 |
|
| 238 | void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core)
|
| 239 | {
|
| 240 | device_initialize(&core->dev);
|
| 241 | core->dev.release = bcma_release_core_dev;
|
| 242 | core->dev.bus = &bcma_bus_type;
|
| 243 | dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index);
|
| 244 | core->dev.parent = bus->dev;
|
| 245 | if (bus->dev)
|
| 246 | bcma_of_fill_device(bus->dev, core);
|
| 247 |
|
| 248 | switch (bus->hosttype) {
|
| 249 | case BCMA_HOSTTYPE_PCI:
|
| 250 | core->dma_dev = bus->dev;
|
| 251 | core->irq = bus->host_pci->irq;
|
| 252 | break;
|
| 253 | case BCMA_HOSTTYPE_SOC:
|
| 254 | if (IS_ENABLED(CONFIG_OF) && bus->dev) {
|
| 255 | core->dma_dev = bus->dev;
|
| 256 | } else {
|
| 257 | core->dev.dma_mask = &core->dev.coherent_dma_mask;
|
| 258 | core->dma_dev = &core->dev;
|
| 259 | }
|
| 260 | break;
|
| 261 | case BCMA_HOSTTYPE_SDIO:
|
| 262 | break;
|
| 263 | }
|
| 264 | }
|
| 265 |
|
| 266 | void bcma_init_bus(struct bcma_bus *bus)
|
| 267 | {
|
| 268 | mutex_lock(&bcma_buses_mutex);
|
| 269 | bus->num = bcma_bus_next_num++;
|
| 270 | mutex_unlock(&bcma_buses_mutex);
|
| 271 |
|
| 272 | INIT_LIST_HEAD(&bus->cores);
|
| 273 | bus->nr_cores = 0;
|
| 274 |
|
| 275 | bcma_detect_chip(bus);
|
| 276 | }
|
| 277 |
|
| 278 | static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core)
|
| 279 | {
|
| 280 | int err;
|
| 281 |
|
| 282 | err = device_add(&core->dev);
|
| 283 | if (err) {
|
| 284 | bcma_err(bus, "Could not register dev for core 0x%03X\n",
|
| 285 | core->id.id);
|
| 286 | return;
|
| 287 | }
|
| 288 | core->dev_registered = true;
|
| 289 | }
|
| 290 |
|
| 291 | static int bcma_register_devices(struct bcma_bus *bus)
|
| 292 | {
|
| 293 | struct bcma_device *core;
|
| 294 | int err;
|
| 295 |
|
| 296 | list_for_each_entry(core, &bus->cores, list) {
|
| 297 | struct device_node *np;
|
| 298 |
|
| 299 |
|
| 300 | switch (core->id.id) {
|
| 301 | case BCMA_CORE_4706_CHIPCOMMON:
|
| 302 | case BCMA_CORE_CHIPCOMMON:
|
| 303 | case BCMA_CORE_NS_CHIPCOMMON_B:
|
| 304 | case BCMA_CORE_PCI:
|
| 305 | case BCMA_CORE_PCIE:
|
| 306 | case BCMA_CORE_PCIE2:
|
| 307 | case BCMA_CORE_MIPS_74K:
|
| 308 | case BCMA_CORE_4706_MAC_GBIT_COMMON:
|
| 309 | continue;
|
| 310 | }
|
| 311 |
|
| 312 |
|
| 313 | if (bcma_is_core_needed_early(core->id.id))
|
| 314 | continue;
|
| 315 |
|
| 316 | np = core->dev.of_node;
|
| 317 | if (np && !of_device_is_available(np))
|
| 318 | continue;
|
| 319 |
|
| 320 |
|
| 321 | if (core->id.id == BCMA_CORE_4706_MAC_GBIT &&
|
| 322 | core->core_unit > 0)
|
| 323 | continue;
|
| 324 |
|
| 325 | bcma_register_core(bus, core);
|
| 326 | }
|
| 327 |
|
| 328 | #ifdef CONFIG_BCMA_PFLASH
|
| 329 | if (bus->drv_cc.pflash.present) {
|
| 330 | err = platform_device_register(&bcma_pflash_dev);
|
| 331 | if (err)
|
| 332 | bcma_err(bus, "Error registering parallel flash\n");
|
| 333 | }
|
| 334 | #endif
|
| 335 |
|
| 336 | #ifdef CONFIG_BCMA_SFLASH
|
| 337 | if (bus->drv_cc.sflash.present) {
|
| 338 | err = platform_device_register(&bcma_sflash_dev);
|
| 339 | if (err)
|
| 340 | bcma_err(bus, "Error registering serial flash\n");
|
| 341 | }
|
| 342 | #endif
|
| 343 |
|
| 344 | #ifdef CONFIG_BCMA_NFLASH
|
| 345 | if (bus->drv_cc.nflash.present) {
|
| 346 | err = platform_device_register(&bcma_nflash_dev);
|
| 347 | if (err)
|
| 348 | bcma_err(bus, "Error registering NAND flash\n");
|
| 349 | }
|
| 350 | #endif
|
| 351 | err = bcma_gpio_init(&bus->drv_cc);
|
| 352 | if (err == -ENOTSUPP)
|
| 353 | bcma_debug(bus, "GPIO driver not activated\n");
|
| 354 | else if (err) {
|
| 355 | bcma_err(bus, "Error registering GPIO driver: %i\n", err);
|
| 356 | return err;
|
| 357 | }
|
| 358 |
|
| 359 | if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
|
| 360 | err = bcma_chipco_watchdog_register(&bus->drv_cc);
|
| 361 | if (err)
|
| 362 | bcma_err(bus, "Error registering watchdog driver\n");
|
| 363 | }
|
| 364 |
|
| 365 | return 0;
|
| 366 | }
|
| 367 |
|
| 368 | void bcma_unregister_cores(struct bcma_bus *bus)
|
| 369 | {
|
| 370 | struct bcma_device *core, *tmp;
|
| 371 |
|
| 372 | list_for_each_entry_safe(core, tmp, &bus->cores, list) {
|
| 373 | if (!core->dev_registered)
|
| 374 | continue;
|
| 375 | list_del(&core->list);
|
| 376 | device_unregister(&core->dev);
|
| 377 | }
|
| 378 | if (bus->hosttype == BCMA_HOSTTYPE_SOC)
|
| 379 | platform_device_unregister(bus->drv_cc.watchdog);
|
| 380 |
|
| 381 |
|
| 382 | list_for_each_entry_safe(core, tmp, &bus->cores, list) {
|
| 383 | list_del(&core->list);
|
| 384 | put_device(&core->dev);
|
| 385 | }
|
| 386 | }
|
| 387 |
|
| 388 | int bcma_bus_register(struct bcma_bus *bus)
|
| 389 | {
|
| 390 | int err;
|
| 391 | struct bcma_device *core;
|
| 392 |
|
| 393 |
|
| 394 | err = bcma_bus_scan(bus);
|
| 395 | if (err) {
|
| 396 | bcma_err(bus, "Failed to scan: %d\n", err);
|
| 397 | return err;
|
| 398 | }
|
| 399 |
|
| 400 |
|
| 401 | core = bcma_find_core(bus, bcma_cc_core_id(bus));
|
| 402 | if (core) {
|
| 403 | bus->drv_cc.core = core;
|
| 404 | bcma_core_chipcommon_early_init(&bus->drv_cc);
|
| 405 | }
|
| 406 |
|
| 407 |
|
| 408 | core = bcma_find_core(bus, BCMA_CORE_PCIE);
|
| 409 | if (core) {
|
| 410 | bus->drv_pci[0].core = core;
|
| 411 | bcma_core_pci_early_init(&bus->drv_pci[0]);
|
| 412 | }
|
| 413 |
|
| 414 | if (bus->dev)
|
| 415 | of_platform_default_populate(bus->dev->of_node, NULL, bus->dev);
|
| 416 |
|
| 417 |
|
| 418 | list_for_each_entry(core, &bus->cores, list) {
|
| 419 | if (bcma_is_core_needed_early(core->id.id))
|
| 420 | bcma_register_core(bus, core);
|
| 421 | }
|
| 422 |
|
| 423 |
|
| 424 | err = bcma_sprom_get(bus);
|
| 425 | if (err == -ENOENT) {
|
| 426 | bcma_err(bus, "No SPROM available\n");
|
| 427 | } else if (err)
|
| 428 | bcma_err(bus, "Failed to get SPROM: %d\n", err);
|
| 429 |
|
| 430 |
|
| 431 | core = bcma_find_core(bus, bcma_cc_core_id(bus));
|
| 432 | if (core) {
|
| 433 | bus->drv_cc.core = core;
|
| 434 | bcma_core_chipcommon_init(&bus->drv_cc);
|
| 435 | }
|
| 436 |
|
| 437 |
|
| 438 | core = bcma_find_core(bus, BCMA_CORE_NS_CHIPCOMMON_B);
|
| 439 | if (core) {
|
| 440 | bus->drv_cc_b.core = core;
|
| 441 | bcma_core_chipcommon_b_init(&bus->drv_cc_b);
|
| 442 | }
|
| 443 |
|
| 444 |
|
| 445 | core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
|
| 446 | if (core) {
|
| 447 | bus->drv_mips.core = core;
|
| 448 | bcma_core_mips_init(&bus->drv_mips);
|
| 449 | }
|
| 450 |
|
| 451 |
|
| 452 | core = bcma_find_core_unit(bus, BCMA_CORE_PCIE, 0);
|
| 453 | if (core) {
|
| 454 | bus->drv_pci[0].core = core;
|
| 455 | bcma_core_pci_init(&bus->drv_pci[0]);
|
| 456 | }
|
| 457 |
|
| 458 |
|
| 459 | core = bcma_find_core_unit(bus, BCMA_CORE_PCIE, 1);
|
| 460 | if (core) {
|
| 461 | bus->drv_pci[1].core = core;
|
| 462 | bcma_core_pci_init(&bus->drv_pci[1]);
|
| 463 | }
|
| 464 |
|
| 465 |
|
| 466 | core = bcma_find_core_unit(bus, BCMA_CORE_PCIE2, 0);
|
| 467 | if (core) {
|
| 468 | bus->drv_pcie2.core = core;
|
| 469 | bcma_core_pcie2_init(&bus->drv_pcie2);
|
| 470 | }
|
| 471 |
|
| 472 |
|
| 473 | core = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON);
|
| 474 | if (core) {
|
| 475 | bus->drv_gmac_cmn.core = core;
|
| 476 | bcma_core_gmac_cmn_init(&bus->drv_gmac_cmn);
|
| 477 | }
|
| 478 |
|
| 479 |
|
| 480 | bcma_register_devices(bus);
|
| 481 |
|
| 482 | bcma_info(bus, "Bus registered\n");
|
| 483 |
|
| 484 | return 0;
|
| 485 | }
|
| 486 |
|
| 487 | void bcma_bus_unregister(struct bcma_bus *bus)
|
| 488 | {
|
| 489 | int err;
|
| 490 |
|
| 491 | err = bcma_gpio_unregister(&bus->drv_cc);
|
| 492 | if (err == -EBUSY)
|
| 493 | bcma_err(bus, "Some GPIOs are still in use.\n");
|
| 494 | else if (err)
|
| 495 | bcma_err(bus, "Can not unregister GPIO driver: %i\n", err);
|
| 496 |
|
| 497 | bcma_core_chipcommon_b_free(&bus->drv_cc_b);
|
| 498 |
|
| 499 | bcma_unregister_cores(bus);
|
| 500 | }
|
| 501 |
|
| 502 | |
| 503 | * This is a special version of bus registration function designed for SoCs.
|
| 504 | * It scans bus and performs basic initialization of main cores only.
|
| 505 | * Please note it requires memory allocation, however it won't try to sleep.
|
| 506 |
|
| 507 | int __init bcma_bus_early_register(struct bcma_bus *bus)
|
| 508 | {
|
| 509 | int err;
|
| 510 | struct bcma_device *core;
|
| 511 |
|
| 512 |
|
| 513 | err = bcma_bus_scan(bus);
|
| 514 | if (err) {
|
| 515 | bcma_err(bus, "Failed to scan bus: %d\n", err);
|
| 516 | return -1;
|
| 517 | }
|
| 518 |
|
| 519 |
|
| 520 | core = bcma_find_core(bus, bcma_cc_core_id(bus));
|
| 521 | if (core) {
|
| 522 | bus->drv_cc.core = core;
|
| 523 | bcma_core_chipcommon_early_init(&bus->drv_cc);
|
| 524 | }
|
| 525 |
|
| 526 |
|
| 527 | core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
|
| 528 | if (core) {
|
| 529 | bus->drv_mips.core = core;
|
| 530 | bcma_core_mips_early_init(&bus->drv_mips);
|
| 531 | }
|
| 532 |
|
| 533 | bcma_info(bus, "Early bus registered\n");
|
| 534 |
|
| 535 | return 0;
|
| 536 | }
|
| 537 |
|
| 538 | #ifdef CONFIG_PM
|
| 539 | int bcma_bus_suspend(struct bcma_bus *bus)
|
| 540 | {
|
| 541 | struct bcma_device *core;
|
| 542 |
|
| 543 | list_for_each_entry(core, &bus->cores, list) {
|
| 544 | struct device_driver *drv = core->dev.driver;
|
| 545 | if (drv) {
|
| 546 | struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv);
|
| 547 | if (adrv->suspend)
|
| 548 | adrv->suspend(core);
|
| 549 | }
|
| 550 | }
|
| 551 | return 0;
|
| 552 | }
|
| 553 |
|
| 554 | int bcma_bus_resume(struct bcma_bus *bus)
|
| 555 | {
|
| 556 | struct bcma_device *core;
|
| 557 |
|
| 558 |
|
| 559 | if (bus->drv_cc.core) {
|
| 560 | bus->drv_cc.setup_done = false;
|
| 561 | bcma_core_chipcommon_init(&bus->drv_cc);
|
| 562 | }
|
| 563 |
|
| 564 | list_for_each_entry(core, &bus->cores, list) {
|
| 565 | struct device_driver *drv = core->dev.driver;
|
| 566 | if (drv) {
|
| 567 | struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv);
|
| 568 | if (adrv->resume)
|
| 569 | adrv->resume(core);
|
| 570 | }
|
| 571 | }
|
| 572 |
|
| 573 | return 0;
|
| 574 | }
|
| 575 | #endif
|
| 576 |
|
| 577 | int __bcma_driver_register(struct bcma_driver *drv, struct module *owner)
|
| 578 | {
|
| 579 | drv->drv.name = drv->name;
|
| 580 | drv->drv.bus = &bcma_bus_type;
|
| 581 | drv->drv.owner = owner;
|
| 582 |
|
| 583 | return driver_register(&drv->drv);
|
| 584 | }
|
| 585 | EXPORT_SYMBOL_GPL(__bcma_driver_register);
|
| 586 |
|
| 587 | void bcma_driver_unregister(struct bcma_driver *drv)
|
| 588 | {
|
| 589 | driver_unregister(&drv->drv);
|
| 590 | }
|
| 591 | EXPORT_SYMBOL_GPL(bcma_driver_unregister);
|
| 592 |
|
| 593 | static int bcma_bus_match(struct device *dev, const struct device_driver *drv)
|
| 594 | {
|
| 595 | struct bcma_device *core = container_of(dev, struct bcma_device, dev);
|
| 596 | const struct bcma_driver *adrv = container_of_const(drv, struct bcma_driver, drv);
|
| 597 | const struct bcma_device_id *cid = &core->id;
|
| 598 | const struct bcma_device_id *did;
|
| 599 |
|
| 600 | for (did = adrv->id_table; did->manuf || did->id || did->rev; did++) {
|
| 601 | if ((did->manuf == cid->manuf || did->manuf == BCMA_ANY_MANUF) &&
|
| 602 | (did->id == cid->id || did->id == BCMA_ANY_ID) &&
|
| 603 | (did->rev == cid->rev || did->rev == BCMA_ANY_REV) &&
|
| 604 | (did->class == cid->class || did->class == BCMA_ANY_CLASS))
|
| 605 | return 1;
|
| 606 | }
|
| 607 | return 0;
|
| 608 | }
|
| 609 |
|
| 610 | static int bcma_device_probe(struct device *dev)
|
| 611 | {
|
| 612 | struct bcma_device *core = container_of(dev, struct bcma_device, dev);
|
| 613 | struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver,
|
| 614 | drv);
|
| 615 | int err = 0;
|
| 616 |
|
| 617 | get_device(dev);
|
| 618 | if (adrv->probe)
|
| 619 | err = adrv->probe(core);
|
| 620 | if (err)
|
| 621 | put_device(dev);
|
| 622 |
|
| 623 | return err;
|
| 624 | }
|
| 625 |
|
| 626 | static void bcma_device_remove(struct device *dev)
|
| 627 | {
|
| 628 | struct bcma_device *core = container_of(dev, struct bcma_device, dev);
|
| 629 | struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver,
|
| 630 | drv);
|
| 631 |
|
| 632 | if (adrv->remove)
|
| 633 | adrv->remove(core);
|
| 634 | put_device(dev);
|
| 635 | }
|
| 636 |
|
| 637 | static int bcma_device_uevent(const struct device *dev, struct kobj_uevent_env *env)
|
| 638 | {
|
| 639 | const struct bcma_device *core = container_of_const(dev, struct bcma_device, dev);
|
| 640 |
|
| 641 | return add_uevent_var(env,
|
| 642 | "MODALIAS=bcma:m%04Xid%04Xrev%02Xcl%02X",
|
| 643 | core->id.manuf, core->id.id,
|
| 644 | core->id.rev, core->id.class);
|
| 645 | }
|
| 646 |
|
| 647 | static unsigned int bcma_bus_registered;
|
| 648 |
|
| 649 | |
| 650 | * If built-in, bus has to be registered early, before any driver calls
|
| 651 | * bcma_driver_register.
|
| 652 | * Otherwise registering driver would trigger BUG in driver_register.
|
| 653 |
|
| 654 | static int __init bcma_init_bus_register(void)
|
| 655 | {
|
| 656 | int err;
|
| 657 |
|
| 658 | if (bcma_bus_registered)
|
| 659 | return 0;
|
| 660 |
|
| 661 | err = bus_register(&bcma_bus_type);
|
| 662 | if (!err)
|
| 663 | bcma_bus_registered = 1;
|
| 664 |
|
| 665 | return err;
|
| 666 | }
|
| 667 | #ifndef MODULE
|
| 668 | fs_initcall(bcma_init_bus_register);
|
| 669 | #endif
|
| 670 |
|
| 671 |
|
| 672 | static int __init bcma_modinit(void)
|
| 673 | {
|
| 674 | int err;
|
| 675 |
|
| 676 | err = bcma_init_bus_register();
|
| 677 | if (err)
|
| 678 | return err;
|
| 679 |
|
| 680 | err = bcma_host_soc_register_driver();
|
| 681 | if (err) {
|
| 682 | pr_err("SoC host initialization failed\n");
|
| 683 | err = 0;
|
| 684 | }
|
| 685 | #ifdef CONFIG_BCMA_HOST_PCI
|
| 686 | err = bcma_host_pci_init();
|
| 687 | if (err) {
|
| 688 | pr_err("PCI host initialization failed\n");
|
| 689 | err = 0;
|
| 690 | }
|
| 691 | #endif
|
| 692 |
|
| 693 | return err;
|
| 694 | }
|
| 695 | module_init(bcma_modinit);
|
| 696 |
|
| 697 | static void __exit bcma_modexit(void)
|
| 698 | {
|
| 699 | #ifdef CONFIG_BCMA_HOST_PCI
|
| 700 | bcma_host_pci_exit();
|
| 701 | #endif
|
| 702 | bcma_host_soc_unregister_driver();
|
| 703 | bus_unregister(&bcma_bus_type);
|
| 704 | }
|
| 705 | module_exit(bcma_modexit)
|