linux/drivers/amba/bus.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/arm/common/amba.c
   3 *
   4 *  Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10#include <linux/module.h>
  11#include <linux/init.h>
  12#include <linux/device.h>
  13#include <linux/string.h>
  14#include <linux/slab.h>
  15#include <linux/io.h>
  16#include <linux/pm.h>
  17#include <linux/pm_runtime.h>
  18#include <linux/pm_domain.h>
  19#include <linux/amba/bus.h>
  20#include <linux/sizes.h>
  21#include <linux/limits.h>
  22
  23#include <asm/irq.h>
  24
  25#define to_amba_driver(d)       container_of(d, struct amba_driver, drv)
  26
  27static const struct amba_id *
  28amba_lookup(const struct amba_id *table, struct amba_device *dev)
  29{
  30        int ret = 0;
  31
  32        while (table->mask) {
  33                ret = (dev->periphid & table->mask) == table->id;
  34                if (ret)
  35                        break;
  36                table++;
  37        }
  38
  39        return ret ? table : NULL;
  40}
  41
  42static int amba_match(struct device *dev, struct device_driver *drv)
  43{
  44        struct amba_device *pcdev = to_amba_device(dev);
  45        struct amba_driver *pcdrv = to_amba_driver(drv);
  46
  47        /* When driver_override is set, only bind to the matching driver */
  48        if (pcdev->driver_override)
  49                return !strcmp(pcdev->driver_override, drv->name);
  50
  51        return amba_lookup(pcdrv->id_table, pcdev) != NULL;
  52}
  53
  54static int amba_uevent(struct device *dev, struct kobj_uevent_env *env)
  55{
  56        struct amba_device *pcdev = to_amba_device(dev);
  57        int retval = 0;
  58
  59        retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid);
  60        if (retval)
  61                return retval;
  62
  63        retval = add_uevent_var(env, "MODALIAS=amba:d%08X", pcdev->periphid);
  64        return retval;
  65}
  66
  67static ssize_t driver_override_show(struct device *_dev,
  68                                    struct device_attribute *attr, char *buf)
  69{
  70        struct amba_device *dev = to_amba_device(_dev);
  71
  72        if (!dev->driver_override)
  73                return 0;
  74
  75        return sprintf(buf, "%s\n", dev->driver_override);
  76}
  77
  78static ssize_t driver_override_store(struct device *_dev,
  79                                     struct device_attribute *attr,
  80                                     const char *buf, size_t count)
  81{
  82        struct amba_device *dev = to_amba_device(_dev);
  83        char *driver_override, *old = dev->driver_override, *cp;
  84
  85        if (count > PATH_MAX)
  86                return -EINVAL;
  87
  88        driver_override = kstrndup(buf, count, GFP_KERNEL);
  89        if (!driver_override)
  90                return -ENOMEM;
  91
  92        cp = strchr(driver_override, '\n');
  93        if (cp)
  94                *cp = '\0';
  95
  96        if (strlen(driver_override)) {
  97                dev->driver_override = driver_override;
  98        } else {
  99               kfree(driver_override);
 100               dev->driver_override = NULL;
 101        }
 102
 103        kfree(old);
 104
 105        return count;
 106}
 107
 108#define amba_attr_func(name,fmt,arg...)                                 \
 109static ssize_t name##_show(struct device *_dev,                         \
 110                           struct device_attribute *attr, char *buf)    \
 111{                                                                       \
 112        struct amba_device *dev = to_amba_device(_dev);                 \
 113        return sprintf(buf, fmt, arg);                                  \
 114}
 115
 116#define amba_attr(name,fmt,arg...)      \
 117amba_attr_func(name,fmt,arg)            \
 118static DEVICE_ATTR(name, S_IRUGO, name##_show, NULL)
 119
 120amba_attr_func(id, "%08x\n", dev->periphid);
 121amba_attr(irq0, "%u\n", dev->irq[0]);
 122amba_attr(irq1, "%u\n", dev->irq[1]);
 123amba_attr_func(resource, "\t%016llx\t%016llx\t%016lx\n",
 124         (unsigned long long)dev->res.start, (unsigned long long)dev->res.end,
 125         dev->res.flags);
 126
 127static struct device_attribute amba_dev_attrs[] = {
 128        __ATTR_RO(id),
 129        __ATTR_RO(resource),
 130        __ATTR_RW(driver_override),
 131        __ATTR_NULL,
 132};
 133
 134#ifdef CONFIG_PM
 135/*
 136 * Hooks to provide runtime PM of the pclk (bus clock).  It is safe to
 137 * enable/disable the bus clock at runtime PM suspend/resume as this
 138 * does not result in loss of context.
 139 */
 140static int amba_pm_runtime_suspend(struct device *dev)
 141{
 142        struct amba_device *pcdev = to_amba_device(dev);
 143        int ret = pm_generic_runtime_suspend(dev);
 144
 145        if (ret == 0 && dev->driver) {
 146                if (pm_runtime_is_irq_safe(dev))
 147                        clk_disable(pcdev->pclk);
 148                else
 149                        clk_disable_unprepare(pcdev->pclk);
 150        }
 151
 152        return ret;
 153}
 154
 155static int amba_pm_runtime_resume(struct device *dev)
 156{
 157        struct amba_device *pcdev = to_amba_device(dev);
 158        int ret;
 159
 160        if (dev->driver) {
 161                if (pm_runtime_is_irq_safe(dev))
 162                        ret = clk_enable(pcdev->pclk);
 163                else
 164                        ret = clk_prepare_enable(pcdev->pclk);
 165                /* Failure is probably fatal to the system, but... */
 166                if (ret)
 167                        return ret;
 168        }
 169
 170        return pm_generic_runtime_resume(dev);
 171}
 172#endif /* CONFIG_PM */
 173
 174static const struct dev_pm_ops amba_pm = {
 175        .suspend        = pm_generic_suspend,
 176        .resume         = pm_generic_resume,
 177        .freeze         = pm_generic_freeze,
 178        .thaw           = pm_generic_thaw,
 179        .poweroff       = pm_generic_poweroff,
 180        .restore        = pm_generic_restore,
 181        SET_RUNTIME_PM_OPS(
 182                amba_pm_runtime_suspend,
 183                amba_pm_runtime_resume,
 184                NULL
 185        )
 186};
 187
 188/*
 189 * Primecells are part of the Advanced Microcontroller Bus Architecture,
 190 * so we call the bus "amba".
 191 */
 192struct bus_type amba_bustype = {
 193        .name           = "amba",
 194        .dev_attrs      = amba_dev_attrs,
 195        .match          = amba_match,
 196        .uevent         = amba_uevent,
 197        .pm             = &amba_pm,
 198};
 199
 200static int __init amba_init(void)
 201{
 202        return bus_register(&amba_bustype);
 203}
 204
 205postcore_initcall(amba_init);
 206
 207static int amba_get_enable_pclk(struct amba_device *pcdev)
 208{
 209        int ret;
 210
 211        pcdev->pclk = clk_get(&pcdev->dev, "apb_pclk");
 212        if (IS_ERR(pcdev->pclk))
 213                return PTR_ERR(pcdev->pclk);
 214
 215        ret = clk_prepare_enable(pcdev->pclk);
 216        if (ret)
 217                clk_put(pcdev->pclk);
 218
 219        return ret;
 220}
 221
 222static void amba_put_disable_pclk(struct amba_device *pcdev)
 223{
 224        clk_disable_unprepare(pcdev->pclk);
 225        clk_put(pcdev->pclk);
 226}
 227
 228/*
 229 * These are the device model conversion veneers; they convert the
 230 * device model structures to our more specific structures.
 231 */
 232static int amba_probe(struct device *dev)
 233{
 234        struct amba_device *pcdev = to_amba_device(dev);
 235        struct amba_driver *pcdrv = to_amba_driver(dev->driver);
 236        const struct amba_id *id = amba_lookup(pcdrv->id_table, pcdev);
 237        int ret;
 238
 239        do {
 240                ret = dev_pm_domain_attach(dev, true);
 241                if (ret == -EPROBE_DEFER)
 242                        break;
 243
 244                ret = amba_get_enable_pclk(pcdev);
 245                if (ret) {
 246                        dev_pm_domain_detach(dev, true);
 247                        break;
 248                }
 249
 250                pm_runtime_get_noresume(dev);
 251                pm_runtime_set_active(dev);
 252                pm_runtime_enable(dev);
 253
 254                ret = pcdrv->probe(pcdev, id);
 255                if (ret == 0)
 256                        break;
 257
 258                pm_runtime_disable(dev);
 259                pm_runtime_set_suspended(dev);
 260                pm_runtime_put_noidle(dev);
 261
 262                amba_put_disable_pclk(pcdev);
 263                dev_pm_domain_detach(dev, true);
 264        } while (0);
 265
 266        return ret;
 267}
 268
 269static int amba_remove(struct device *dev)
 270{
 271        struct amba_device *pcdev = to_amba_device(dev);
 272        struct amba_driver *drv = to_amba_driver(dev->driver);
 273        int ret;
 274
 275        pm_runtime_get_sync(dev);
 276        ret = drv->remove(pcdev);
 277        pm_runtime_put_noidle(dev);
 278
 279        /* Undo the runtime PM settings in amba_probe() */
 280        pm_runtime_disable(dev);
 281        pm_runtime_set_suspended(dev);
 282        pm_runtime_put_noidle(dev);
 283
 284        amba_put_disable_pclk(pcdev);
 285        dev_pm_domain_detach(dev, true);
 286
 287        return ret;
 288}
 289
 290static void amba_shutdown(struct device *dev)
 291{
 292        struct amba_driver *drv = to_amba_driver(dev->driver);
 293        drv->shutdown(to_amba_device(dev));
 294}
 295
 296/**
 297 *      amba_driver_register - register an AMBA device driver
 298 *      @drv: amba device driver structure
 299 *
 300 *      Register an AMBA device driver with the Linux device model
 301 *      core.  If devices pre-exist, the drivers probe function will
 302 *      be called.
 303 */
 304int amba_driver_register(struct amba_driver *drv)
 305{
 306        drv->drv.bus = &amba_bustype;
 307
 308#define SETFN(fn)       if (drv->fn) drv->drv.fn = amba_##fn
 309        SETFN(probe);
 310        SETFN(remove);
 311        SETFN(shutdown);
 312
 313        return driver_register(&drv->drv);
 314}
 315
 316/**
 317 *      amba_driver_unregister - remove an AMBA device driver
 318 *      @drv: AMBA device driver structure to remove
 319 *
 320 *      Unregister an AMBA device driver from the Linux device
 321 *      model.  The device model will call the drivers remove function
 322 *      for each device the device driver is currently handling.
 323 */
 324void amba_driver_unregister(struct amba_driver *drv)
 325{
 326        driver_unregister(&drv->drv);
 327}
 328
 329
 330static void amba_device_release(struct device *dev)
 331{
 332        struct amba_device *d = to_amba_device(dev);
 333
 334        if (d->res.parent)
 335                release_resource(&d->res);
 336        kfree(d);
 337}
 338
 339/**
 340 *      amba_device_add - add a previously allocated AMBA device structure
 341 *      @dev: AMBA device allocated by amba_device_alloc
 342 *      @parent: resource parent for this devices resources
 343 *
 344 *      Claim the resource, and read the device cell ID if not already
 345 *      initialized.  Register the AMBA device with the Linux device
 346 *      manager.
 347 */
 348int amba_device_add(struct amba_device *dev, struct resource *parent)
 349{
 350        u32 size;
 351        void __iomem *tmp;
 352        int i, ret;
 353
 354        WARN_ON(dev->irq[0] == (unsigned int)-1);
 355        WARN_ON(dev->irq[1] == (unsigned int)-1);
 356
 357        ret = request_resource(parent, &dev->res);
 358        if (ret)
 359                goto err_out;
 360
 361        /* Hard-coded primecell ID instead of plug-n-play */
 362        if (dev->periphid != 0)
 363                goto skip_probe;
 364
 365        /*
 366         * Dynamically calculate the size of the resource
 367         * and use this for iomap
 368         */
 369        size = resource_size(&dev->res);
 370        tmp = ioremap(dev->res.start, size);
 371        if (!tmp) {
 372                ret = -ENOMEM;
 373                goto err_release;
 374        }
 375
 376        ret = amba_get_enable_pclk(dev);
 377        if (ret == 0) {
 378                u32 pid, cid;
 379
 380                /*
 381                 * Read pid and cid based on size of resource
 382                 * they are located at end of region
 383                 */
 384                for (pid = 0, i = 0; i < 4; i++)
 385                        pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) <<
 386                                (i * 8);
 387                for (cid = 0, i = 0; i < 4; i++)
 388                        cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) <<
 389                                (i * 8);
 390
 391                amba_put_disable_pclk(dev);
 392
 393                if (cid == AMBA_CID || cid == CORESIGHT_CID)
 394                        dev->periphid = pid;
 395
 396                if (!dev->periphid)
 397                        ret = -ENODEV;
 398        }
 399
 400        iounmap(tmp);
 401
 402        if (ret)
 403                goto err_release;
 404
 405 skip_probe:
 406        ret = device_add(&dev->dev);
 407        if (ret)
 408                goto err_release;
 409
 410        if (dev->irq[0])
 411                ret = device_create_file(&dev->dev, &dev_attr_irq0);
 412        if (ret == 0 && dev->irq[1])
 413                ret = device_create_file(&dev->dev, &dev_attr_irq1);
 414        if (ret == 0)
 415                return ret;
 416
 417        device_unregister(&dev->dev);
 418
 419 err_release:
 420        release_resource(&dev->res);
 421 err_out:
 422        return ret;
 423}
 424EXPORT_SYMBOL_GPL(amba_device_add);
 425
 426static struct amba_device *
 427amba_aphb_device_add(struct device *parent, const char *name,
 428                     resource_size_t base, size_t size, int irq1, int irq2,
 429                     void *pdata, unsigned int periphid, u64 dma_mask,
 430                     struct resource *resbase)
 431{
 432        struct amba_device *dev;
 433        int ret;
 434
 435        dev = amba_device_alloc(name, base, size);
 436        if (!dev)
 437                return ERR_PTR(-ENOMEM);
 438
 439        dev->dev.coherent_dma_mask = dma_mask;
 440        dev->irq[0] = irq1;
 441        dev->irq[1] = irq2;
 442        dev->periphid = periphid;
 443        dev->dev.platform_data = pdata;
 444        dev->dev.parent = parent;
 445
 446        ret = amba_device_add(dev, resbase);
 447        if (ret) {
 448                amba_device_put(dev);
 449                return ERR_PTR(ret);
 450        }
 451
 452        return dev;
 453}
 454
 455struct amba_device *
 456amba_apb_device_add(struct device *parent, const char *name,
 457                    resource_size_t base, size_t size, int irq1, int irq2,
 458                    void *pdata, unsigned int periphid)
 459{
 460        return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata,
 461                                    periphid, 0, &iomem_resource);
 462}
 463EXPORT_SYMBOL_GPL(amba_apb_device_add);
 464
 465struct amba_device *
 466amba_ahb_device_add(struct device *parent, const char *name,
 467                    resource_size_t base, size_t size, int irq1, int irq2,
 468                    void *pdata, unsigned int periphid)
 469{
 470        return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata,
 471                                    periphid, ~0ULL, &iomem_resource);
 472}
 473EXPORT_SYMBOL_GPL(amba_ahb_device_add);
 474
 475struct amba_device *
 476amba_apb_device_add_res(struct device *parent, const char *name,
 477                        resource_size_t base, size_t size, int irq1,
 478                        int irq2, void *pdata, unsigned int periphid,
 479                        struct resource *resbase)
 480{
 481        return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata,
 482                                    periphid, 0, resbase);
 483}
 484EXPORT_SYMBOL_GPL(amba_apb_device_add_res);
 485
 486struct amba_device *
 487amba_ahb_device_add_res(struct device *parent, const char *name,
 488                        resource_size_t base, size_t size, int irq1,
 489                        int irq2, void *pdata, unsigned int periphid,
 490                        struct resource *resbase)
 491{
 492        return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata,
 493                                    periphid, ~0ULL, resbase);
 494}
 495EXPORT_SYMBOL_GPL(amba_ahb_device_add_res);
 496
 497
 498static void amba_device_initialize(struct amba_device *dev, const char *name)
 499{
 500        device_initialize(&dev->dev);
 501        if (name)
 502                dev_set_name(&dev->dev, "%s", name);
 503        dev->dev.release = amba_device_release;
 504        dev->dev.bus = &amba_bustype;
 505        dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
 506        dev->res.name = dev_name(&dev->dev);
 507}
 508
 509/**
 510 *      amba_device_alloc - allocate an AMBA device
 511 *      @name: sysfs name of the AMBA device
 512 *      @base: base of AMBA device
 513 *      @size: size of AMBA device
 514 *
 515 *      Allocate and initialize an AMBA device structure.  Returns %NULL
 516 *      on failure.
 517 */
 518struct amba_device *amba_device_alloc(const char *name, resource_size_t base,
 519        size_t size)
 520{
 521        struct amba_device *dev;
 522
 523        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 524        if (dev) {
 525                amba_device_initialize(dev, name);
 526                dev->res.start = base;
 527                dev->res.end = base + size - 1;
 528                dev->res.flags = IORESOURCE_MEM;
 529        }
 530
 531        return dev;
 532}
 533EXPORT_SYMBOL_GPL(amba_device_alloc);
 534
 535/**
 536 *      amba_device_register - register an AMBA device
 537 *      @dev: AMBA device to register
 538 *      @parent: parent memory resource
 539 *
 540 *      Setup the AMBA device, reading the cell ID if present.
 541 *      Claim the resource, and register the AMBA device with
 542 *      the Linux device manager.
 543 */
 544int amba_device_register(struct amba_device *dev, struct resource *parent)
 545{
 546        amba_device_initialize(dev, dev->dev.init_name);
 547        dev->dev.init_name = NULL;
 548
 549        return amba_device_add(dev, parent);
 550}
 551
 552/**
 553 *      amba_device_put - put an AMBA device
 554 *      @dev: AMBA device to put
 555 */
 556void amba_device_put(struct amba_device *dev)
 557{
 558        put_device(&dev->dev);
 559}
 560EXPORT_SYMBOL_GPL(amba_device_put);
 561
 562/**
 563 *      amba_device_unregister - unregister an AMBA device
 564 *      @dev: AMBA device to remove
 565 *
 566 *      Remove the specified AMBA device from the Linux device
 567 *      manager.  All files associated with this object will be
 568 *      destroyed, and device drivers notified that the device has
 569 *      been removed.  The AMBA device's resources including
 570 *      the amba_device structure will be freed once all
 571 *      references to it have been dropped.
 572 */
 573void amba_device_unregister(struct amba_device *dev)
 574{
 575        device_unregister(&dev->dev);
 576}
 577
 578
 579struct find_data {
 580        struct amba_device *dev;
 581        struct device *parent;
 582        const char *busid;
 583        unsigned int id;
 584        unsigned int mask;
 585};
 586
 587static int amba_find_match(struct device *dev, void *data)
 588{
 589        struct find_data *d = data;
 590        struct amba_device *pcdev = to_amba_device(dev);
 591        int r;
 592
 593        r = (pcdev->periphid & d->mask) == d->id;
 594        if (d->parent)
 595                r &= d->parent == dev->parent;
 596        if (d->busid)
 597                r &= strcmp(dev_name(dev), d->busid) == 0;
 598
 599        if (r) {
 600                get_device(dev);
 601                d->dev = pcdev;
 602        }
 603
 604        return r;
 605}
 606
 607/**
 608 *      amba_find_device - locate an AMBA device given a bus id
 609 *      @busid: bus id for device (or NULL)
 610 *      @parent: parent device (or NULL)
 611 *      @id: peripheral ID (or 0)
 612 *      @mask: peripheral ID mask (or 0)
 613 *
 614 *      Return the AMBA device corresponding to the supplied parameters.
 615 *      If no device matches, returns NULL.
 616 *
 617 *      NOTE: When a valid device is found, its refcount is
 618 *      incremented, and must be decremented before the returned
 619 *      reference.
 620 */
 621struct amba_device *
 622amba_find_device(const char *busid, struct device *parent, unsigned int id,
 623                 unsigned int mask)
 624{
 625        struct find_data data;
 626
 627        data.dev = NULL;
 628        data.parent = parent;
 629        data.busid = busid;
 630        data.id = id;
 631        data.mask = mask;
 632
 633        bus_for_each_dev(&amba_bustype, NULL, &data, amba_find_match);
 634
 635        return data.dev;
 636}
 637
 638/**
 639 *      amba_request_regions - request all mem regions associated with device
 640 *      @dev: amba_device structure for device
 641 *      @name: name, or NULL to use driver name
 642 */
 643int amba_request_regions(struct amba_device *dev, const char *name)
 644{
 645        int ret = 0;
 646        u32 size;
 647
 648        if (!name)
 649                name = dev->dev.driver->name;
 650
 651        size = resource_size(&dev->res);
 652
 653        if (!request_mem_region(dev->res.start, size, name))
 654                ret = -EBUSY;
 655
 656        return ret;
 657}
 658
 659/**
 660 *      amba_release_regions - release mem regions associated with device
 661 *      @dev: amba_device structure for device
 662 *
 663 *      Release regions claimed by a successful call to amba_request_regions.
 664 */
 665void amba_release_regions(struct amba_device *dev)
 666{
 667        u32 size;
 668
 669        size = resource_size(&dev->res);
 670        release_mem_region(dev->res.start, size);
 671}
 672
 673EXPORT_SYMBOL(amba_driver_register);
 674EXPORT_SYMBOL(amba_driver_unregister);
 675EXPORT_SYMBOL(amba_device_register);
 676EXPORT_SYMBOL(amba_device_unregister);
 677EXPORT_SYMBOL(amba_find_device);
 678EXPORT_SYMBOL(amba_request_regions);
 679EXPORT_SYMBOL(amba_release_regions);
 680