diff options
Diffstat (limited to 'drivers/base/platform.c')
| -rw-r--r-- | drivers/base/platform.c | 296 |
1 files changed, 288 insertions, 8 deletions
diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 911ec600fe71..3f940393d6c7 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c | |||
| @@ -453,6 +453,8 @@ int platform_driver_register(struct platform_driver *drv) | |||
| 453 | drv->driver.suspend = platform_drv_suspend; | 453 | drv->driver.suspend = platform_drv_suspend; |
| 454 | if (drv->resume) | 454 | if (drv->resume) |
| 455 | drv->driver.resume = platform_drv_resume; | 455 | drv->driver.resume = platform_drv_resume; |
| 456 | if (drv->pm) | ||
| 457 | drv->driver.pm = &drv->pm->base; | ||
| 456 | return driver_register(&drv->driver); | 458 | return driver_register(&drv->driver); |
| 457 | } | 459 | } |
| 458 | EXPORT_SYMBOL_GPL(platform_driver_register); | 460 | EXPORT_SYMBOL_GPL(platform_driver_register); |
| @@ -560,7 +562,9 @@ static int platform_match(struct device *dev, struct device_driver *drv) | |||
| 560 | return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0); | 562 | return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0); |
| 561 | } | 563 | } |
| 562 | 564 | ||
| 563 | static int platform_suspend(struct device *dev, pm_message_t mesg) | 565 | #ifdef CONFIG_PM_SLEEP |
| 566 | |||
| 567 | static int platform_legacy_suspend(struct device *dev, pm_message_t mesg) | ||
| 564 | { | 568 | { |
| 565 | int ret = 0; | 569 | int ret = 0; |
| 566 | 570 | ||
| @@ -570,7 +574,7 @@ static int platform_suspend(struct device *dev, pm_message_t mesg) | |||
| 570 | return ret; | 574 | return ret; |
| 571 | } | 575 | } |
| 572 | 576 | ||
| 573 | static int platform_suspend_late(struct device *dev, pm_message_t mesg) | 577 | static int platform_legacy_suspend_late(struct device *dev, pm_message_t mesg) |
| 574 | { | 578 | { |
| 575 | struct platform_driver *drv = to_platform_driver(dev->driver); | 579 | struct platform_driver *drv = to_platform_driver(dev->driver); |
| 576 | struct platform_device *pdev; | 580 | struct platform_device *pdev; |
| @@ -583,7 +587,7 @@ static int platform_suspend_late(struct device *dev, pm_message_t mesg) | |||
| 583 | return ret; | 587 | return ret; |
| 584 | } | 588 | } |
| 585 | 589 | ||
| 586 | static int platform_resume_early(struct device *dev) | 590 | static int platform_legacy_resume_early(struct device *dev) |
| 587 | { | 591 | { |
| 588 | struct platform_driver *drv = to_platform_driver(dev->driver); | 592 | struct platform_driver *drv = to_platform_driver(dev->driver); |
| 589 | struct platform_device *pdev; | 593 | struct platform_device *pdev; |
| @@ -596,7 +600,7 @@ static int platform_resume_early(struct device *dev) | |||
| 596 | return ret; | 600 | return ret; |
| 597 | } | 601 | } |
| 598 | 602 | ||
| 599 | static int platform_resume(struct device *dev) | 603 | static int platform_legacy_resume(struct device *dev) |
| 600 | { | 604 | { |
| 601 | int ret = 0; | 605 | int ret = 0; |
| 602 | 606 | ||
| @@ -606,15 +610,291 @@ static int platform_resume(struct device *dev) | |||
| 606 | return ret; | 610 | return ret; |
| 607 | } | 611 | } |
| 608 | 612 | ||
| 613 | static int platform_pm_prepare(struct device *dev) | ||
| 614 | { | ||
| 615 | struct device_driver *drv = dev->driver; | ||
| 616 | int ret = 0; | ||
| 617 | |||
| 618 | if (drv && drv->pm && drv->pm->prepare) | ||
| 619 | ret = drv->pm->prepare(dev); | ||
| 620 | |||
| 621 | return ret; | ||
| 622 | } | ||
| 623 | |||
| 624 | static void platform_pm_complete(struct device *dev) | ||
| 625 | { | ||
| 626 | struct device_driver *drv = dev->driver; | ||
| 627 | |||
| 628 | if (drv && drv->pm && drv->pm->complete) | ||
| 629 | drv->pm->complete(dev); | ||
| 630 | } | ||
| 631 | |||
| 632 | #ifdef CONFIG_SUSPEND | ||
| 633 | |||
| 634 | static int platform_pm_suspend(struct device *dev) | ||
| 635 | { | ||
| 636 | struct device_driver *drv = dev->driver; | ||
| 637 | int ret = 0; | ||
| 638 | |||
| 639 | if (drv && drv->pm) { | ||
| 640 | if (drv->pm->suspend) | ||
| 641 | ret = drv->pm->suspend(dev); | ||
| 642 | } else { | ||
| 643 | ret = platform_legacy_suspend(dev, PMSG_SUSPEND); | ||
| 644 | } | ||
| 645 | |||
| 646 | return ret; | ||
| 647 | } | ||
| 648 | |||
| 649 | static int platform_pm_suspend_noirq(struct device *dev) | ||
| 650 | { | ||
| 651 | struct platform_driver *pdrv; | ||
| 652 | int ret = 0; | ||
| 653 | |||
| 654 | if (!dev->driver) | ||
| 655 | return 0; | ||
| 656 | |||
| 657 | pdrv = to_platform_driver(dev->driver); | ||
| 658 | if (pdrv->pm) { | ||
| 659 | if (pdrv->pm->suspend_noirq) | ||
| 660 | ret = pdrv->pm->suspend_noirq(dev); | ||
| 661 | } else { | ||
| 662 | ret = platform_legacy_suspend_late(dev, PMSG_SUSPEND); | ||
| 663 | } | ||
| 664 | |||
| 665 | return ret; | ||
| 666 | } | ||
| 667 | |||
| 668 | static int platform_pm_resume(struct device *dev) | ||
| 669 | { | ||
| 670 | struct device_driver *drv = dev->driver; | ||
| 671 | int ret = 0; | ||
| 672 | |||
| 673 | if (drv && drv->pm) { | ||
| 674 | if (drv->pm->resume) | ||
| 675 | ret = drv->pm->resume(dev); | ||
| 676 | } else { | ||
| 677 | ret = platform_legacy_resume(dev); | ||
| 678 | } | ||
| 679 | |||
| 680 | return ret; | ||
| 681 | } | ||
| 682 | |||
| 683 | static int platform_pm_resume_noirq(struct device *dev) | ||
| 684 | { | ||
| 685 | struct platform_driver *pdrv; | ||
| 686 | int ret = 0; | ||
| 687 | |||
| 688 | if (!dev->driver) | ||
| 689 | return 0; | ||
| 690 | |||
| 691 | pdrv = to_platform_driver(dev->driver); | ||
| 692 | if (pdrv->pm) { | ||
| 693 | if (pdrv->pm->resume_noirq) | ||
| 694 | ret = pdrv->pm->resume_noirq(dev); | ||
| 695 | } else { | ||
| 696 | ret = platform_legacy_resume_early(dev); | ||
| 697 | } | ||
| 698 | |||
| 699 | return ret; | ||
| 700 | } | ||
| 701 | |||
| 702 | #else /* !CONFIG_SUSPEND */ | ||
| 703 | |||
| 704 | #define platform_pm_suspend NULL | ||
| 705 | #define platform_pm_resume NULL | ||
| 706 | #define platform_pm_suspend_noirq NULL | ||
| 707 | #define platform_pm_resume_noirq NULL | ||
| 708 | |||
| 709 | #endif /* !CONFIG_SUSPEND */ | ||
| 710 | |||
| 711 | #ifdef CONFIG_HIBERNATION | ||
| 712 | |||
| 713 | static int platform_pm_freeze(struct device *dev) | ||
| 714 | { | ||
| 715 | struct device_driver *drv = dev->driver; | ||
| 716 | int ret = 0; | ||
| 717 | |||
| 718 | if (!drv) | ||
| 719 | return 0; | ||
| 720 | |||
| 721 | if (drv->pm) { | ||
| 722 | if (drv->pm->freeze) | ||
| 723 | ret = drv->pm->freeze(dev); | ||
| 724 | } else { | ||
| 725 | ret = platform_legacy_suspend(dev, PMSG_FREEZE); | ||
| 726 | } | ||
| 727 | |||
| 728 | return ret; | ||
| 729 | } | ||
| 730 | |||
| 731 | static int platform_pm_freeze_noirq(struct device *dev) | ||
| 732 | { | ||
| 733 | struct platform_driver *pdrv; | ||
| 734 | int ret = 0; | ||
| 735 | |||
| 736 | if (!dev->driver) | ||
| 737 | return 0; | ||
| 738 | |||
| 739 | pdrv = to_platform_driver(dev->driver); | ||
| 740 | if (pdrv->pm) { | ||
| 741 | if (pdrv->pm->freeze_noirq) | ||
| 742 | ret = pdrv->pm->freeze_noirq(dev); | ||
| 743 | } else { | ||
| 744 | ret = platform_legacy_suspend_late(dev, PMSG_FREEZE); | ||
| 745 | } | ||
| 746 | |||
| 747 | return ret; | ||
| 748 | } | ||
| 749 | |||
| 750 | static int platform_pm_thaw(struct device *dev) | ||
| 751 | { | ||
| 752 | struct device_driver *drv = dev->driver; | ||
| 753 | int ret = 0; | ||
| 754 | |||
| 755 | if (drv && drv->pm) { | ||
| 756 | if (drv->pm->thaw) | ||
| 757 | ret = drv->pm->thaw(dev); | ||
| 758 | } else { | ||
| 759 | ret = platform_legacy_resume(dev); | ||
| 760 | } | ||
| 761 | |||
| 762 | return ret; | ||
| 763 | } | ||
| 764 | |||
| 765 | static int platform_pm_thaw_noirq(struct device *dev) | ||
| 766 | { | ||
| 767 | struct platform_driver *pdrv; | ||
| 768 | int ret = 0; | ||
| 769 | |||
| 770 | if (!dev->driver) | ||
| 771 | return 0; | ||
| 772 | |||
| 773 | pdrv = to_platform_driver(dev->driver); | ||
| 774 | if (pdrv->pm) { | ||
| 775 | if (pdrv->pm->thaw_noirq) | ||
| 776 | ret = pdrv->pm->thaw_noirq(dev); | ||
| 777 | } else { | ||
| 778 | ret = platform_legacy_resume_early(dev); | ||
| 779 | } | ||
| 780 | |||
| 781 | return ret; | ||
| 782 | } | ||
| 783 | |||
| 784 | static int platform_pm_poweroff(struct device *dev) | ||
| 785 | { | ||
| 786 | struct device_driver *drv = dev->driver; | ||
| 787 | int ret = 0; | ||
| 788 | |||
| 789 | if (drv && drv->pm) { | ||
| 790 | if (drv->pm->poweroff) | ||
| 791 | ret = drv->pm->poweroff(dev); | ||
| 792 | } else { | ||
| 793 | ret = platform_legacy_suspend(dev, PMSG_HIBERNATE); | ||
| 794 | } | ||
| 795 | |||
| 796 | return ret; | ||
| 797 | } | ||
| 798 | |||
| 799 | static int platform_pm_poweroff_noirq(struct device *dev) | ||
| 800 | { | ||
| 801 | struct platform_driver *pdrv; | ||
| 802 | int ret = 0; | ||
| 803 | |||
| 804 | if (!dev->driver) | ||
| 805 | return 0; | ||
| 806 | |||
| 807 | pdrv = to_platform_driver(dev->driver); | ||
| 808 | if (pdrv->pm) { | ||
| 809 | if (pdrv->pm->poweroff_noirq) | ||
| 810 | ret = pdrv->pm->poweroff_noirq(dev); | ||
| 811 | } else { | ||
| 812 | ret = platform_legacy_suspend_late(dev, PMSG_HIBERNATE); | ||
| 813 | } | ||
| 814 | |||
| 815 | return ret; | ||
| 816 | } | ||
| 817 | |||
| 818 | static int platform_pm_restore(struct device *dev) | ||
| 819 | { | ||
| 820 | struct device_driver *drv = dev->driver; | ||
| 821 | int ret = 0; | ||
| 822 | |||
| 823 | if (drv && drv->pm) { | ||
| 824 | if (drv->pm->restore) | ||
| 825 | ret = drv->pm->restore(dev); | ||
| 826 | } else { | ||
| 827 | ret = platform_legacy_resume(dev); | ||
| 828 | } | ||
| 829 | |||
| 830 | return ret; | ||
| 831 | } | ||
| 832 | |||
| 833 | static int platform_pm_restore_noirq(struct device *dev) | ||
| 834 | { | ||
| 835 | struct platform_driver *pdrv; | ||
| 836 | int ret = 0; | ||
| 837 | |||
| 838 | if (!dev->driver) | ||
| 839 | return 0; | ||
| 840 | |||
| 841 | pdrv = to_platform_driver(dev->driver); | ||
| 842 | if (pdrv->pm) { | ||
| 843 | if (pdrv->pm->restore_noirq) | ||
| 844 | ret = pdrv->pm->restore_noirq(dev); | ||
| 845 | } else { | ||
| 846 | ret = platform_legacy_resume_early(dev); | ||
| 847 | } | ||
| 848 | |||
| 849 | return ret; | ||
| 850 | } | ||
| 851 | |||
| 852 | #else /* !CONFIG_HIBERNATION */ | ||
| 853 | |||
| 854 | #define platform_pm_freeze NULL | ||
| 855 | #define platform_pm_thaw NULL | ||
| 856 | #define platform_pm_poweroff NULL | ||
| 857 | #define platform_pm_restore NULL | ||
| 858 | #define platform_pm_freeze_noirq NULL | ||
| 859 | #define platform_pm_thaw_noirq NULL | ||
| 860 | #define platform_pm_poweroff_noirq NULL | ||
| 861 | #define platform_pm_restore_noirq NULL | ||
| 862 | |||
| 863 | #endif /* !CONFIG_HIBERNATION */ | ||
| 864 | |||
| 865 | struct pm_ext_ops platform_pm_ops = { | ||
| 866 | .base = { | ||
| 867 | .prepare = platform_pm_prepare, | ||
| 868 | .complete = platform_pm_complete, | ||
| 869 | .suspend = platform_pm_suspend, | ||
| 870 | .resume = platform_pm_resume, | ||
| 871 | .freeze = platform_pm_freeze, | ||
| 872 | .thaw = platform_pm_thaw, | ||
| 873 | .poweroff = platform_pm_poweroff, | ||
| 874 | .restore = platform_pm_restore, | ||
| 875 | }, | ||
| 876 | .suspend_noirq = platform_pm_suspend_noirq, | ||
| 877 | .resume_noirq = platform_pm_resume_noirq, | ||
| 878 | .freeze_noirq = platform_pm_freeze_noirq, | ||
| 879 | .thaw_noirq = platform_pm_thaw_noirq, | ||
| 880 | .poweroff_noirq = platform_pm_poweroff_noirq, | ||
| 881 | .restore_noirq = platform_pm_restore_noirq, | ||
| 882 | }; | ||
| 883 | |||
| 884 | #define PLATFORM_PM_OPS_PTR &platform_pm_ops | ||
| 885 | |||
| 886 | #else /* !CONFIG_PM_SLEEP */ | ||
| 887 | |||
| 888 | #define PLATFORM_PM_OPS_PTR NULL | ||
| 889 | |||
| 890 | #endif /* !CONFIG_PM_SLEEP */ | ||
| 891 | |||
| 609 | struct bus_type platform_bus_type = { | 892 | struct bus_type platform_bus_type = { |
| 610 | .name = "platform", | 893 | .name = "platform", |
| 611 | .dev_attrs = platform_dev_attrs, | 894 | .dev_attrs = platform_dev_attrs, |
| 612 | .match = platform_match, | 895 | .match = platform_match, |
| 613 | .uevent = platform_uevent, | 896 | .uevent = platform_uevent, |
| 614 | .suspend = platform_suspend, | 897 | .pm = PLATFORM_PM_OPS_PTR, |
| 615 | .suspend_late = platform_suspend_late, | ||
| 616 | .resume_early = platform_resume_early, | ||
| 617 | .resume = platform_resume, | ||
| 618 | }; | 898 | }; |
| 619 | EXPORT_SYMBOL_GPL(platform_bus_type); | 899 | EXPORT_SYMBOL_GPL(platform_bus_type); |
| 620 | 900 | ||
