Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.1-rc6 787 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 /* Hard-coded primecell ID instead of plug-n-play */ 607 if (dev->periphid != 0) 608 goto skip_probe; 609 610 /* 611 * Dynamically calculate the size of the resource 612 * and use this for iomap 613 */ 614 size = resource_size(&dev->res); 615 tmp = ioremap(dev->res.start, size); 616 if (!tmp) { 617 ret = -ENOMEM; 618 goto err_release; 619 } 620 621 ret = amba_get_enable_pclk(dev); 622 if (ret == 0) { 623 u32 pid, cid; 624 625 /* 626 * Read pid and cid based on size of resource 627 * they are located at end of region 628 */ 629 for (pid = 0, i = 0; i < 4; i++) 630 pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) << 631 (i * 8); 632 for (cid = 0, i = 0; i < 4; i++) 633 cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) << 634 (i * 8); 635 636 amba_put_disable_pclk(dev); 637 638 if (cid == AMBA_CID) 639 dev->periphid = pid; 640 641 if (!dev->periphid) 642 ret = -ENODEV; 643 } 644 645 iounmap(tmp); 646 647 if (ret) 648 goto err_release; 649 650 skip_probe: 651 ret = device_add(&dev->dev); 652 if (ret) 653 goto err_release; 654 655 if (dev->irq[0] != NO_IRQ) 656 ret = device_create_file(&dev->dev, &dev_attr_irq0); 657 if (ret == 0 && dev->irq[1] != NO_IRQ) 658 ret = device_create_file(&dev->dev, &dev_attr_irq1); 659 if (ret == 0) 660 return ret; 661 662 device_unregister(&dev->dev); 663 664 err_release: 665 release_resource(&dev->res); 666 err_out: 667 return ret; 668} 669 670/** 671 * amba_device_unregister - unregister an AMBA device 672 * @dev: AMBA device to remove 673 * 674 * Remove the specified AMBA device from the Linux device 675 * manager. All files associated with this object will be 676 * destroyed, and device drivers notified that the device has 677 * been removed. The AMBA device's resources including 678 * the amba_device structure will be freed once all 679 * references to it have been dropped. 680 */ 681void amba_device_unregister(struct amba_device *dev) 682{ 683 device_unregister(&dev->dev); 684} 685 686 687struct find_data { 688 struct amba_device *dev; 689 struct device *parent; 690 const char *busid; 691 unsigned int id; 692 unsigned int mask; 693}; 694 695static int amba_find_match(struct device *dev, void *data) 696{ 697 struct find_data *d = data; 698 struct amba_device *pcdev = to_amba_device(dev); 699 int r; 700 701 r = (pcdev->periphid & d->mask) == d->id; 702 if (d->parent) 703 r &= d->parent == dev->parent; 704 if (d->busid) 705 r &= strcmp(dev_name(dev), d->busid) == 0; 706 707 if (r) { 708 get_device(dev); 709 d->dev = pcdev; 710 } 711 712 return r; 713} 714 715/** 716 * amba_find_device - locate an AMBA device given a bus id 717 * @busid: bus id for device (or NULL) 718 * @parent: parent device (or NULL) 719 * @id: peripheral ID (or 0) 720 * @mask: peripheral ID mask (or 0) 721 * 722 * Return the AMBA device corresponding to the supplied parameters. 723 * If no device matches, returns NULL. 724 * 725 * NOTE: When a valid device is found, its refcount is 726 * incremented, and must be decremented before the returned 727 * reference. 728 */ 729struct amba_device * 730amba_find_device(const char *busid, struct device *parent, unsigned int id, 731 unsigned int mask) 732{ 733 struct find_data data; 734 735 data.dev = NULL; 736 data.parent = parent; 737 data.busid = busid; 738 data.id = id; 739 data.mask = mask; 740 741 bus_for_each_dev(&amba_bustype, NULL, &data, amba_find_match); 742 743 return data.dev; 744} 745 746/** 747 * amba_request_regions - request all mem regions associated with device 748 * @dev: amba_device structure for device 749 * @name: name, or NULL to use driver name 750 */ 751int amba_request_regions(struct amba_device *dev, const char *name) 752{ 753 int ret = 0; 754 u32 size; 755 756 if (!name) 757 name = dev->dev.driver->name; 758 759 size = resource_size(&dev->res); 760 761 if (!request_mem_region(dev->res.start, size, name)) 762 ret = -EBUSY; 763 764 return ret; 765} 766 767/** 768 * amba_release_regions - release mem regions associated with device 769 * @dev: amba_device structure for device 770 * 771 * Release regions claimed by a successful call to amba_request_regions. 772 */ 773void amba_release_regions(struct amba_device *dev) 774{ 775 u32 size; 776 777 size = resource_size(&dev->res); 778 release_mem_region(dev->res.start, size); 779} 780 781EXPORT_SYMBOL(amba_driver_register); 782EXPORT_SYMBOL(amba_driver_unregister); 783EXPORT_SYMBOL(amba_device_register); 784EXPORT_SYMBOL(amba_device_unregister); 785EXPORT_SYMBOL(amba_find_device); 786EXPORT_SYMBOL(amba_request_regions); 787EXPORT_SYMBOL(amba_release_regions);