diff options
Diffstat (limited to 'drivers/base')
-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 | ||