Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.39-rc7 782 lines 16 kB view raw
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/amba/bus.h> 19 20#include <asm/irq.h> 21#include <asm/sizes.h> 22 23#define to_amba_driver(d) container_of(d, struct amba_driver, drv) 24 25static const struct amba_id * 26amba_lookup(const struct amba_id *table, struct amba_device *dev) 27{ 28 int ret = 0; 29 30 while (table->mask) { 31 ret = (dev->periphid & table->mask) == table->id; 32 if (ret) 33 break; 34 table++; 35 } 36 37 return ret ? table : NULL; 38} 39 40static int amba_match(struct device *dev, struct device_driver *drv) 41{ 42 struct amba_device *pcdev = to_amba_device(dev); 43 struct amba_driver *pcdrv = to_amba_driver(drv); 44 45 return amba_lookup(pcdrv->id_table, pcdev) != NULL; 46} 47 48#ifdef CONFIG_HOTPLUG 49static int amba_uevent(struct device *dev, struct kobj_uevent_env *env) 50{ 51 struct amba_device *pcdev = to_amba_device(dev); 52 int retval = 0; 53 54 retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid); 55 return retval; 56} 57#else 58#define amba_uevent NULL 59#endif 60 61#define amba_attr_func(name,fmt,arg...) \ 62static ssize_t name##_show(struct device *_dev, \ 63 struct device_attribute *attr, char *buf) \ 64{ \ 65 struct amba_device *dev = to_amba_device(_dev); \ 66 return sprintf(buf, fmt, arg); \ 67} 68 69#define amba_attr(name,fmt,arg...) \ 70amba_attr_func(name,fmt,arg) \ 71static DEVICE_ATTR(name, S_IRUGO, name##_show, NULL) 72 73amba_attr_func(id, "%08x\n", dev->periphid); 74amba_attr(irq0, "%u\n", dev->irq[0]); 75amba_attr(irq1, "%u\n", dev->irq[1]); 76amba_attr_func(resource, "\t%016llx\t%016llx\t%016lx\n", 77 (unsigned long long)dev->res.start, (unsigned long long)dev->res.end, 78 dev->res.flags); 79 80static struct device_attribute amba_dev_attrs[] = { 81 __ATTR_RO(id), 82 __ATTR_RO(resource), 83 __ATTR_NULL, 84}; 85 86#ifdef CONFIG_PM_SLEEP 87 88static int amba_legacy_suspend(struct device *dev, pm_message_t mesg) 89{ 90 struct amba_driver *adrv = to_amba_driver(dev->driver); 91 struct amba_device *adev = to_amba_device(dev); 92 int ret = 0; 93 94 if (dev->driver && adrv->suspend) 95 ret = adrv->suspend(adev, mesg); 96 97 return ret; 98} 99 100static int amba_legacy_resume(struct device *dev) 101{ 102 struct amba_driver *adrv = to_amba_driver(dev->driver); 103 struct amba_device *adev = to_amba_device(dev); 104 int ret = 0; 105 106 if (dev->driver && adrv->resume) 107 ret = adrv->resume(adev); 108 109 return ret; 110} 111 112static int amba_pm_prepare(struct device *dev) 113{ 114 struct device_driver *drv = dev->driver; 115 int ret = 0; 116 117 if (drv && drv->pm && drv->pm->prepare) 118 ret = drv->pm->prepare(dev); 119 120 return ret; 121} 122 123static void amba_pm_complete(struct device *dev) 124{ 125 struct device_driver *drv = dev->driver; 126 127 if (drv && drv->pm && drv->pm->complete) 128 drv->pm->complete(dev); 129} 130 131#else /* !CONFIG_PM_SLEEP */ 132 133#define amba_pm_prepare NULL 134#define amba_pm_complete NULL 135 136#endif /* !CONFIG_PM_SLEEP */ 137 138#ifdef CONFIG_SUSPEND 139 140static int amba_pm_suspend(struct device *dev) 141{ 142 struct device_driver *drv = dev->driver; 143 int ret = 0; 144 145 if (!drv) 146 return 0; 147 148 if (drv->pm) { 149 if (drv->pm->suspend) 150 ret = drv->pm->suspend(dev); 151 } else { 152 ret = amba_legacy_suspend(dev, PMSG_SUSPEND); 153 } 154 155 return ret; 156} 157 158static int amba_pm_suspend_noirq(struct device *dev) 159{ 160 struct device_driver *drv = dev->driver; 161 int ret = 0; 162 163 if (!drv) 164 return 0; 165 166 if (drv->pm) { 167 if (drv->pm->suspend_noirq) 168 ret = drv->pm->suspend_noirq(dev); 169 } 170 171 return ret; 172} 173 174static int amba_pm_resume(struct device *dev) 175{ 176 struct device_driver *drv = dev->driver; 177 int ret = 0; 178 179 if (!drv) 180 return 0; 181 182 if (drv->pm) { 183 if (drv->pm->resume) 184 ret = drv->pm->resume(dev); 185 } else { 186 ret = amba_legacy_resume(dev); 187 } 188 189 return ret; 190} 191 192static int amba_pm_resume_noirq(struct device *dev) 193{ 194 struct device_driver *drv = dev->driver; 195 int ret = 0; 196 197 if (!drv) 198 return 0; 199 200 if (drv->pm) { 201 if (drv->pm->resume_noirq) 202 ret = drv->pm->resume_noirq(dev); 203 } 204 205 return ret; 206} 207 208#else /* !CONFIG_SUSPEND */ 209 210#define amba_pm_suspend NULL 211#define amba_pm_resume NULL 212#define amba_pm_suspend_noirq NULL 213#define amba_pm_resume_noirq NULL 214 215#endif /* !CONFIG_SUSPEND */ 216 217#ifdef CONFIG_HIBERNATE_CALLBACKS 218 219static int amba_pm_freeze(struct device *dev) 220{ 221 struct device_driver *drv = dev->driver; 222 int ret = 0; 223 224 if (!drv) 225 return 0; 226 227 if (drv->pm) { 228 if (drv->pm->freeze) 229 ret = drv->pm->freeze(dev); 230 } else { 231 ret = amba_legacy_suspend(dev, PMSG_FREEZE); 232 } 233 234 return ret; 235} 236 237static int amba_pm_freeze_noirq(struct device *dev) 238{ 239 struct device_driver *drv = dev->driver; 240 int ret = 0; 241 242 if (!drv) 243 return 0; 244 245 if (drv->pm) { 246 if (drv->pm->freeze_noirq) 247 ret = drv->pm->freeze_noirq(dev); 248 } 249 250 return ret; 251} 252 253static int amba_pm_thaw(struct device *dev) 254{ 255 struct device_driver *drv = dev->driver; 256 int ret = 0; 257 258 if (!drv) 259 return 0; 260 261 if (drv->pm) { 262 if (drv->pm->thaw) 263 ret = drv->pm->thaw(dev); 264 } else { 265 ret = amba_legacy_resume(dev); 266 } 267 268 return ret; 269} 270 271static int amba_pm_thaw_noirq(struct device *dev) 272{ 273 struct device_driver *drv = dev->driver; 274 int ret = 0; 275 276 if (!drv) 277 return 0; 278 279 if (drv->pm) { 280 if (drv->pm->thaw_noirq) 281 ret = drv->pm->thaw_noirq(dev); 282 } 283 284 return ret; 285} 286 287static int amba_pm_poweroff(struct device *dev) 288{ 289 struct device_driver *drv = dev->driver; 290 int ret = 0; 291 292 if (!drv) 293 return 0; 294 295 if (drv->pm) { 296 if (drv->pm->poweroff) 297 ret = drv->pm->poweroff(dev); 298 } else { 299 ret = amba_legacy_suspend(dev, PMSG_HIBERNATE); 300 } 301 302 return ret; 303} 304 305static int amba_pm_poweroff_noirq(struct device *dev) 306{ 307 struct device_driver *drv = dev->driver; 308 int ret = 0; 309 310 if (!drv) 311 return 0; 312 313 if (drv->pm) { 314 if (drv->pm->poweroff_noirq) 315 ret = drv->pm->poweroff_noirq(dev); 316 } 317 318 return ret; 319} 320 321static int amba_pm_restore(struct device *dev) 322{ 323 struct device_driver *drv = dev->driver; 324 int ret = 0; 325 326 if (!drv) 327 return 0; 328 329 if (drv->pm) { 330 if (drv->pm->restore) 331 ret = drv->pm->restore(dev); 332 } else { 333 ret = amba_legacy_resume(dev); 334 } 335 336 return ret; 337} 338 339static int amba_pm_restore_noirq(struct device *dev) 340{ 341 struct device_driver *drv = dev->driver; 342 int ret = 0; 343 344 if (!drv) 345 return 0; 346 347 if (drv->pm) { 348 if (drv->pm->restore_noirq) 349 ret = drv->pm->restore_noirq(dev); 350 } 351 352 return ret; 353} 354 355#else /* !CONFIG_HIBERNATE_CALLBACKS */ 356 357#define amba_pm_freeze NULL 358#define amba_pm_thaw NULL 359#define amba_pm_poweroff NULL 360#define amba_pm_restore NULL 361#define amba_pm_freeze_noirq NULL 362#define amba_pm_thaw_noirq NULL 363#define amba_pm_poweroff_noirq NULL 364#define amba_pm_restore_noirq NULL 365 366#endif /* !CONFIG_HIBERNATE_CALLBACKS */ 367 368#ifdef CONFIG_PM 369 370static const struct dev_pm_ops amba_pm = { 371 .prepare = amba_pm_prepare, 372 .complete = amba_pm_complete, 373 .suspend = amba_pm_suspend, 374 .resume = amba_pm_resume, 375 .freeze = amba_pm_freeze, 376 .thaw = amba_pm_thaw, 377 .poweroff = amba_pm_poweroff, 378 .restore = amba_pm_restore, 379 .suspend_noirq = amba_pm_suspend_noirq, 380 .resume_noirq = amba_pm_resume_noirq, 381 .freeze_noirq = amba_pm_freeze_noirq, 382 .thaw_noirq = amba_pm_thaw_noirq, 383 .poweroff_noirq = amba_pm_poweroff_noirq, 384 .restore_noirq = amba_pm_restore_noirq, 385 SET_RUNTIME_PM_OPS( 386 pm_generic_runtime_suspend, 387 pm_generic_runtime_resume, 388 pm_generic_runtime_idle 389 ) 390}; 391 392#define AMBA_PM (&amba_pm) 393 394#else /* !CONFIG_PM */ 395 396#define AMBA_PM NULL 397 398#endif /* !CONFIG_PM */ 399 400/* 401 * Primecells are part of the Advanced Microcontroller Bus Architecture, 402 * so we call the bus "amba". 403 */ 404struct bus_type amba_bustype = { 405 .name = "amba", 406 .dev_attrs = amba_dev_attrs, 407 .match = amba_match, 408 .uevent = amba_uevent, 409 .pm = AMBA_PM, 410}; 411 412static int __init amba_init(void) 413{ 414 return bus_register(&amba_bustype); 415} 416 417postcore_initcall(amba_init); 418 419static int amba_get_enable_pclk(struct amba_device *pcdev) 420{ 421 struct clk *pclk = clk_get(&pcdev->dev, "apb_pclk"); 422 int ret; 423 424 pcdev->pclk = pclk; 425 426 if (IS_ERR(pclk)) 427 return PTR_ERR(pclk); 428 429 ret = clk_enable(pclk); 430 if (ret) 431 clk_put(pclk); 432 433 return ret; 434} 435 436static void amba_put_disable_pclk(struct amba_device *pcdev) 437{ 438 struct clk *pclk = pcdev->pclk; 439 440 clk_disable(pclk); 441 clk_put(pclk); 442} 443 444static int amba_get_enable_vcore(struct amba_device *pcdev) 445{ 446 struct regulator *vcore = regulator_get(&pcdev->dev, "vcore"); 447 int ret; 448 449 pcdev->vcore = vcore; 450 451 if (IS_ERR(vcore)) { 452 /* It is OK not to supply a vcore regulator */ 453 if (PTR_ERR(vcore) == -ENODEV) 454 return 0; 455 return PTR_ERR(vcore); 456 } 457 458 ret = regulator_enable(vcore); 459 if (ret) { 460 regulator_put(vcore); 461 pcdev->vcore = ERR_PTR(-ENODEV); 462 } 463 464 return ret; 465} 466 467static void amba_put_disable_vcore(struct amba_device *pcdev) 468{ 469 struct regulator *vcore = pcdev->vcore; 470 471 if (!IS_ERR(vcore)) { 472 regulator_disable(vcore); 473 regulator_put(vcore); 474 } 475} 476 477/* 478 * These are the device model conversion veneers; they convert the 479 * device model structures to our more specific structures. 480 */ 481static int amba_probe(struct device *dev) 482{ 483 struct amba_device *pcdev = to_amba_device(dev); 484 struct amba_driver *pcdrv = to_amba_driver(dev->driver); 485 const struct amba_id *id = amba_lookup(pcdrv->id_table, pcdev); 486 int ret; 487 488 do { 489 ret = amba_get_enable_vcore(pcdev); 490 if (ret) 491 break; 492 493 ret = amba_get_enable_pclk(pcdev); 494 if (ret) 495 break; 496 497 ret = pcdrv->probe(pcdev, id); 498 if (ret == 0) 499 break; 500 501 amba_put_disable_pclk(pcdev); 502 amba_put_disable_vcore(pcdev); 503 } while (0); 504 505 return ret; 506} 507 508static int amba_remove(struct device *dev) 509{ 510 struct amba_device *pcdev = to_amba_device(dev); 511 struct amba_driver *drv = to_amba_driver(dev->driver); 512 int ret = drv->remove(pcdev); 513 514 amba_put_disable_pclk(pcdev); 515 amba_put_disable_vcore(pcdev); 516 517 return ret; 518} 519 520static void amba_shutdown(struct device *dev) 521{ 522 struct amba_driver *drv = to_amba_driver(dev->driver); 523 drv->shutdown(to_amba_device(dev)); 524} 525 526/** 527 * amba_driver_register - register an AMBA device driver 528 * @drv: amba device driver structure 529 * 530 * Register an AMBA device driver with the Linux device model 531 * core. If devices pre-exist, the drivers probe function will 532 * be called. 533 */ 534int amba_driver_register(struct amba_driver *drv) 535{ 536 drv->drv.bus = &amba_bustype; 537 538#define SETFN(fn) if (drv->fn) drv->drv.fn = amba_##fn 539 SETFN(probe); 540 SETFN(remove); 541 SETFN(shutdown); 542 543 return driver_register(&drv->drv); 544} 545 546/** 547 * amba_driver_unregister - remove an AMBA device driver 548 * @drv: AMBA device driver structure to remove 549 * 550 * Unregister an AMBA device driver from the Linux device 551 * model. The device model will call the drivers remove function 552 * for each device the device driver is currently handling. 553 */ 554void amba_driver_unregister(struct amba_driver *drv) 555{ 556 driver_unregister(&drv->drv); 557} 558 559 560static void amba_device_release(struct device *dev) 561{ 562 struct amba_device *d = to_amba_device(dev); 563 564 if (d->res.parent) 565 release_resource(&d->res); 566 kfree(d); 567} 568 569/** 570 * amba_device_register - register an AMBA device 571 * @dev: AMBA device to register 572 * @parent: parent memory resource 573 * 574 * Setup the AMBA device, reading the cell ID if present. 575 * Claim the resource, and register the AMBA device with 576 * the Linux device manager. 577 */ 578int amba_device_register(struct amba_device *dev, struct resource *parent) 579{ 580 u32 size; 581 void __iomem *tmp; 582 int i, ret; 583 584 device_initialize(&dev->dev); 585 586 /* 587 * Copy from device_add 588 */ 589 if (dev->dev.init_name) { 590 dev_set_name(&dev->dev, "%s", dev->dev.init_name); 591 dev->dev.init_name = NULL; 592 } 593 594 dev->dev.release = amba_device_release; 595 dev->dev.bus = &amba_bustype; 596 dev->dev.dma_mask = &dev->dma_mask; 597 dev->res.name = dev_name(&dev->dev); 598 599 if (!dev->dev.coherent_dma_mask && dev->dma_mask) 600 dev_warn(&dev->dev, "coherent dma mask is unset\n"); 601 602 ret = request_resource(parent, &dev->res); 603 if (ret) 604 goto err_out; 605 606 /* 607 * Dynamically calculate the size of the resource 608 * and use this for iomap 609 */ 610 size = resource_size(&dev->res); 611 tmp = ioremap(dev->res.start, size); 612 if (!tmp) { 613 ret = -ENOMEM; 614 goto err_release; 615 } 616 617 ret = amba_get_enable_pclk(dev); 618 if (ret == 0) { 619 u32 pid, cid; 620 621 /* 622 * Read pid and cid based on size of resource 623 * they are located at end of region 624 */ 625 for (pid = 0, i = 0; i < 4; i++) 626 pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) << 627 (i * 8); 628 for (cid = 0, i = 0; i < 4; i++) 629 cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) << 630 (i * 8); 631 632 amba_put_disable_pclk(dev); 633 634 if (cid == AMBA_CID) 635 dev->periphid = pid; 636 637 if (!dev->periphid) 638 ret = -ENODEV; 639 } 640 641 iounmap(tmp); 642 643 if (ret) 644 goto err_release; 645 646 ret = device_add(&dev->dev); 647 if (ret) 648 goto err_release; 649 650 if (dev->irq[0] != NO_IRQ) 651 ret = device_create_file(&dev->dev, &dev_attr_irq0); 652 if (ret == 0 && dev->irq[1] != NO_IRQ) 653 ret = device_create_file(&dev->dev, &dev_attr_irq1); 654 if (ret == 0) 655 return ret; 656 657 device_unregister(&dev->dev); 658 659 err_release: 660 release_resource(&dev->res); 661 err_out: 662 return ret; 663} 664 665/** 666 * amba_device_unregister - unregister an AMBA device 667 * @dev: AMBA device to remove 668 * 669 * Remove the specified AMBA device from the Linux device 670 * manager. All files associated with this object will be 671 * destroyed, and device drivers notified that the device has 672 * been removed. The AMBA device's resources including 673 * the amba_device structure will be freed once all 674 * references to it have been dropped. 675 */ 676void amba_device_unregister(struct amba_device *dev) 677{ 678 device_unregister(&dev->dev); 679} 680 681 682struct find_data { 683 struct amba_device *dev; 684 struct device *parent; 685 const char *busid; 686 unsigned int id; 687 unsigned int mask; 688}; 689 690static int amba_find_match(struct device *dev, void *data) 691{ 692 struct find_data *d = data; 693 struct amba_device *pcdev = to_amba_device(dev); 694 int r; 695 696 r = (pcdev->periphid & d->mask) == d->id; 697 if (d->parent) 698 r &= d->parent == dev->parent; 699 if (d->busid) 700 r &= strcmp(dev_name(dev), d->busid) == 0; 701 702 if (r) { 703 get_device(dev); 704 d->dev = pcdev; 705 } 706 707 return r; 708} 709 710/** 711 * amba_find_device - locate an AMBA device given a bus id 712 * @busid: bus id for device (or NULL) 713 * @parent: parent device (or NULL) 714 * @id: peripheral ID (or 0) 715 * @mask: peripheral ID mask (or 0) 716 * 717 * Return the AMBA device corresponding to the supplied parameters. 718 * If no device matches, returns NULL. 719 * 720 * NOTE: When a valid device is found, its refcount is 721 * incremented, and must be decremented before the returned 722 * reference. 723 */ 724struct amba_device * 725amba_find_device(const char *busid, struct device *parent, unsigned int id, 726 unsigned int mask) 727{ 728 struct find_data data; 729 730 data.dev = NULL; 731 data.parent = parent; 732 data.busid = busid; 733 data.id = id; 734 data.mask = mask; 735 736 bus_for_each_dev(&amba_bustype, NULL, &data, amba_find_match); 737 738 return data.dev; 739} 740 741/** 742 * amba_request_regions - request all mem regions associated with device 743 * @dev: amba_device structure for device 744 * @name: name, or NULL to use driver name 745 */ 746int amba_request_regions(struct amba_device *dev, const char *name) 747{ 748 int ret = 0; 749 u32 size; 750 751 if (!name) 752 name = dev->dev.driver->name; 753 754 size = resource_size(&dev->res); 755 756 if (!request_mem_region(dev->res.start, size, name)) 757 ret = -EBUSY; 758 759 return ret; 760} 761 762/** 763 * amba_release_regions - release mem regions associated with device 764 * @dev: amba_device structure for device 765 * 766 * Release regions claimed by a successful call to amba_request_regions. 767 */ 768void amba_release_regions(struct amba_device *dev) 769{ 770 u32 size; 771 772 size = resource_size(&dev->res); 773 release_mem_region(dev->res.start, size); 774} 775 776EXPORT_SYMBOL(amba_driver_register); 777EXPORT_SYMBOL(amba_driver_unregister); 778EXPORT_SYMBOL(amba_device_register); 779EXPORT_SYMBOL(amba_device_unregister); 780EXPORT_SYMBOL(amba_find_device); 781EXPORT_SYMBOL(amba_request_regions); 782EXPORT_SYMBOL(amba_release_regions);