diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2012-03-04 17:11:20 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2012-03-04 17:11:20 -0500 |
commit | 48ed00031681c373ff81e78fd248710fe4cddda0 (patch) | |
tree | dd90809d6017924ee528114a4205ab8cfd8422af /drivers/base | |
parent | 643161ace2a7624fd0106ede12ae43bcbbfc1de0 (diff) | |
parent | b642631d38c28fefd1232a6b96713eb54b60130d (diff) |
Merge branch 'pm-domains'
* pm-domains:
PM / Domains: Fix include for PM_GENERIC_DOMAINS=n case
PM / Domains: Provide a dummy dev_gpd_data() when generic domains are not used
PM / Domains: Run late/early device suspend callbacks at the right time
ARM: EXYNOS: Hook up power domains to generic power domain infrastructure
PM / Domains: Add OF support
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/power/domain.c | 189 |
1 files changed, 143 insertions, 46 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 978bbf7ac6af..d2c03239abcf 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c | |||
@@ -820,17 +820,16 @@ static int pm_genpd_suspend(struct device *dev) | |||
820 | } | 820 | } |
821 | 821 | ||
822 | /** | 822 | /** |
823 | * pm_genpd_suspend_noirq - Late suspend of a device from an I/O PM domain. | 823 | * pm_genpd_suspend_late - Late suspend of a device from an I/O PM domain. |
824 | * @dev: Device to suspend. | 824 | * @dev: Device to suspend. |
825 | * | 825 | * |
826 | * Carry out a late suspend of a device under the assumption that its | 826 | * Carry out a late suspend of a device under the assumption that its |
827 | * pm_domain field points to the domain member of an object of type | 827 | * pm_domain field points to the domain member of an object of type |
828 | * struct generic_pm_domain representing a PM domain consisting of I/O devices. | 828 | * struct generic_pm_domain representing a PM domain consisting of I/O devices. |
829 | */ | 829 | */ |
830 | static int pm_genpd_suspend_noirq(struct device *dev) | 830 | static int pm_genpd_suspend_late(struct device *dev) |
831 | { | 831 | { |
832 | struct generic_pm_domain *genpd; | 832 | struct generic_pm_domain *genpd; |
833 | int ret; | ||
834 | 833 | ||
835 | dev_dbg(dev, "%s()\n", __func__); | 834 | dev_dbg(dev, "%s()\n", __func__); |
836 | 835 | ||
@@ -838,14 +837,28 @@ static int pm_genpd_suspend_noirq(struct device *dev) | |||
838 | if (IS_ERR(genpd)) | 837 | if (IS_ERR(genpd)) |
839 | return -EINVAL; | 838 | return -EINVAL; |
840 | 839 | ||
841 | if (genpd->suspend_power_off) | 840 | return genpd->suspend_power_off ? 0 : genpd_suspend_late(genpd, dev); |
842 | return 0; | 841 | } |
843 | 842 | ||
844 | ret = genpd_suspend_late(genpd, dev); | 843 | /** |
845 | if (ret) | 844 | * pm_genpd_suspend_noirq - Completion of suspend of device in an I/O PM domain. |
846 | return ret; | 845 | * @dev: Device to suspend. |
846 | * | ||
847 | * Stop the device and remove power from the domain if all devices in it have | ||
848 | * been stopped. | ||
849 | */ | ||
850 | static int pm_genpd_suspend_noirq(struct device *dev) | ||
851 | { | ||
852 | struct generic_pm_domain *genpd; | ||
847 | 853 | ||
848 | if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev)) | 854 | dev_dbg(dev, "%s()\n", __func__); |
855 | |||
856 | genpd = dev_to_genpd(dev); | ||
857 | if (IS_ERR(genpd)) | ||
858 | return -EINVAL; | ||
859 | |||
860 | if (genpd->suspend_power_off | ||
861 | || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) | ||
849 | return 0; | 862 | return 0; |
850 | 863 | ||
851 | genpd_stop_dev(genpd, dev); | 864 | genpd_stop_dev(genpd, dev); |
@@ -862,13 +875,10 @@ static int pm_genpd_suspend_noirq(struct device *dev) | |||
862 | } | 875 | } |
863 | 876 | ||
864 | /** | 877 | /** |
865 | * pm_genpd_resume_noirq - Early resume of a device from an I/O power domain. | 878 | * pm_genpd_resume_noirq - Start of resume of device in an I/O PM domain. |
866 | * @dev: Device to resume. | 879 | * @dev: Device to resume. |
867 | * | 880 | * |
868 | * Carry out an early resume of a device under the assumption that its | 881 | * Restore power to the device's PM domain, if necessary, and start the device. |
869 | * pm_domain field points to the domain member of an object of type | ||
870 | * struct generic_pm_domain representing a power domain consisting of I/O | ||
871 | * devices. | ||
872 | */ | 882 | */ |
873 | static int pm_genpd_resume_noirq(struct device *dev) | 883 | static int pm_genpd_resume_noirq(struct device *dev) |
874 | { | 884 | { |
@@ -890,13 +900,34 @@ static int pm_genpd_resume_noirq(struct device *dev) | |||
890 | */ | 900 | */ |
891 | pm_genpd_poweron(genpd); | 901 | pm_genpd_poweron(genpd); |
892 | genpd->suspended_count--; | 902 | genpd->suspended_count--; |
893 | genpd_start_dev(genpd, dev); | ||
894 | 903 | ||
895 | return genpd_resume_early(genpd, dev); | 904 | return genpd_start_dev(genpd, dev); |
896 | } | 905 | } |
897 | 906 | ||
898 | /** | 907 | /** |
899 | * pm_genpd_resume - Resume a device belonging to an I/O power domain. | 908 | * pm_genpd_resume_early - Early resume of a device in an I/O PM domain. |
909 | * @dev: Device to resume. | ||
910 | * | ||
911 | * Carry out an early resume of a device under the assumption that its | ||
912 | * pm_domain field points to the domain member of an object of type | ||
913 | * struct generic_pm_domain representing a power domain consisting of I/O | ||
914 | * devices. | ||
915 | */ | ||
916 | static int pm_genpd_resume_early(struct device *dev) | ||
917 | { | ||
918 | struct generic_pm_domain *genpd; | ||
919 | |||
920 | dev_dbg(dev, "%s()\n", __func__); | ||
921 | |||
922 | genpd = dev_to_genpd(dev); | ||
923 | if (IS_ERR(genpd)) | ||
924 | return -EINVAL; | ||
925 | |||
926 | return genpd->suspend_power_off ? 0 : genpd_resume_early(genpd, dev); | ||
927 | } | ||
928 | |||
929 | /** | ||
930 | * pm_genpd_resume - Resume of device in an I/O PM domain. | ||
900 | * @dev: Device to resume. | 931 | * @dev: Device to resume. |
901 | * | 932 | * |
902 | * Resume a device under the assumption that its pm_domain field points to the | 933 | * Resume a device under the assumption that its pm_domain field points to the |
@@ -917,7 +948,7 @@ static int pm_genpd_resume(struct device *dev) | |||
917 | } | 948 | } |
918 | 949 | ||
919 | /** | 950 | /** |
920 | * pm_genpd_freeze - Freeze a device belonging to an I/O power domain. | 951 | * pm_genpd_freeze - Freezing a device in an I/O PM domain. |
921 | * @dev: Device to freeze. | 952 | * @dev: Device to freeze. |
922 | * | 953 | * |
923 | * Freeze a device under the assumption that its pm_domain field points to the | 954 | * Freeze a device under the assumption that its pm_domain field points to the |
@@ -938,7 +969,29 @@ static int pm_genpd_freeze(struct device *dev) | |||
938 | } | 969 | } |
939 | 970 | ||
940 | /** | 971 | /** |
941 | * pm_genpd_freeze_noirq - Late freeze of a device from an I/O power domain. | 972 | * pm_genpd_freeze_late - Late freeze of a device in an I/O PM domain. |
973 | * @dev: Device to freeze. | ||
974 | * | ||
975 | * Carry out a late freeze of a device under the assumption that its | ||
976 | * pm_domain field points to the domain member of an object of type | ||
977 | * struct generic_pm_domain representing a power domain consisting of I/O | ||
978 | * devices. | ||
979 | */ | ||
980 | static int pm_genpd_freeze_late(struct device *dev) | ||
981 | { | ||
982 | struct generic_pm_domain *genpd; | ||
983 | |||
984 | dev_dbg(dev, "%s()\n", __func__); | ||
985 | |||
986 | genpd = dev_to_genpd(dev); | ||
987 | if (IS_ERR(genpd)) | ||
988 | return -EINVAL; | ||
989 | |||
990 | return genpd->suspend_power_off ? 0 : genpd_freeze_late(genpd, dev); | ||
991 | } | ||
992 | |||
993 | /** | ||
994 | * pm_genpd_freeze_noirq - Completion of freezing a device in an I/O PM domain. | ||
942 | * @dev: Device to freeze. | 995 | * @dev: Device to freeze. |
943 | * | 996 | * |
944 | * Carry out a late freeze of a device under the assumption that its | 997 | * Carry out a late freeze of a device under the assumption that its |
@@ -949,7 +1002,6 @@ static int pm_genpd_freeze(struct device *dev) | |||
949 | static int pm_genpd_freeze_noirq(struct device *dev) | 1002 | static int pm_genpd_freeze_noirq(struct device *dev) |
950 | { | 1003 | { |
951 | struct generic_pm_domain *genpd; | 1004 | struct generic_pm_domain *genpd; |
952 | int ret; | ||
953 | 1005 | ||
954 | dev_dbg(dev, "%s()\n", __func__); | 1006 | dev_dbg(dev, "%s()\n", __func__); |
955 | 1007 | ||
@@ -957,20 +1009,31 @@ static int pm_genpd_freeze_noirq(struct device *dev) | |||
957 | if (IS_ERR(genpd)) | 1009 | if (IS_ERR(genpd)) |
958 | return -EINVAL; | 1010 | return -EINVAL; |
959 | 1011 | ||
960 | if (genpd->suspend_power_off) | 1012 | return genpd->suspend_power_off ? 0 : genpd_stop_dev(genpd, dev); |
961 | return 0; | 1013 | } |
962 | 1014 | ||
963 | ret = genpd_freeze_late(genpd, dev); | 1015 | /** |
964 | if (ret) | 1016 | * pm_genpd_thaw_noirq - Early thaw of device in an I/O PM domain. |
965 | return ret; | 1017 | * @dev: Device to thaw. |
1018 | * | ||
1019 | * Start the device, unless power has been removed from the domain already | ||
1020 | * before the system transition. | ||
1021 | */ | ||
1022 | static int pm_genpd_thaw_noirq(struct device *dev) | ||
1023 | { | ||
1024 | struct generic_pm_domain *genpd; | ||
966 | 1025 | ||
967 | genpd_stop_dev(genpd, dev); | 1026 | dev_dbg(dev, "%s()\n", __func__); |
968 | 1027 | ||
969 | return 0; | 1028 | genpd = dev_to_genpd(dev); |
1029 | if (IS_ERR(genpd)) | ||
1030 | return -EINVAL; | ||
1031 | |||
1032 | return genpd->suspend_power_off ? 0 : genpd_start_dev(genpd, dev); | ||
970 | } | 1033 | } |
971 | 1034 | ||
972 | /** | 1035 | /** |
973 | * pm_genpd_thaw_noirq - Early thaw of a device from an I/O power domain. | 1036 | * pm_genpd_thaw_early - Early thaw of device in an I/O PM domain. |
974 | * @dev: Device to thaw. | 1037 | * @dev: Device to thaw. |
975 | * | 1038 | * |
976 | * Carry out an early thaw of a device under the assumption that its | 1039 | * Carry out an early thaw of a device under the assumption that its |
@@ -978,7 +1041,7 @@ static int pm_genpd_freeze_noirq(struct device *dev) | |||
978 | * struct generic_pm_domain representing a power domain consisting of I/O | 1041 | * struct generic_pm_domain representing a power domain consisting of I/O |
979 | * devices. | 1042 | * devices. |
980 | */ | 1043 | */ |
981 | static int pm_genpd_thaw_noirq(struct device *dev) | 1044 | static int pm_genpd_thaw_early(struct device *dev) |
982 | { | 1045 | { |
983 | struct generic_pm_domain *genpd; | 1046 | struct generic_pm_domain *genpd; |
984 | 1047 | ||
@@ -988,12 +1051,7 @@ static int pm_genpd_thaw_noirq(struct device *dev) | |||
988 | if (IS_ERR(genpd)) | 1051 | if (IS_ERR(genpd)) |
989 | return -EINVAL; | 1052 | return -EINVAL; |
990 | 1053 | ||
991 | if (genpd->suspend_power_off) | 1054 | return genpd->suspend_power_off ? 0 : genpd_thaw_early(genpd, dev); |
992 | return 0; | ||
993 | |||
994 | genpd_start_dev(genpd, dev); | ||
995 | |||
996 | return genpd_thaw_early(genpd, dev); | ||
997 | } | 1055 | } |
998 | 1056 | ||
999 | /** | 1057 | /** |
@@ -1018,13 +1076,11 @@ static int pm_genpd_thaw(struct device *dev) | |||
1018 | } | 1076 | } |
1019 | 1077 | ||
1020 | /** | 1078 | /** |
1021 | * pm_genpd_restore_noirq - Early restore of a device from an I/O power domain. | 1079 | * pm_genpd_restore_noirq - Start of restore of device in an I/O PM domain. |
1022 | * @dev: Device to resume. | 1080 | * @dev: Device to resume. |
1023 | * | 1081 | * |
1024 | * Carry out an early restore of a device under the assumption that its | 1082 | * Make sure the domain will be in the same power state as before the |
1025 | * pm_domain field points to the domain member of an object of type | 1083 | * hibernation the system is resuming from and start the device if necessary. |
1026 | * struct generic_pm_domain representing a power domain consisting of I/O | ||
1027 | * devices. | ||
1028 | */ | 1084 | */ |
1029 | static int pm_genpd_restore_noirq(struct device *dev) | 1085 | static int pm_genpd_restore_noirq(struct device *dev) |
1030 | { | 1086 | { |
@@ -1054,9 +1110,8 @@ static int pm_genpd_restore_noirq(struct device *dev) | |||
1054 | 1110 | ||
1055 | pm_genpd_poweron(genpd); | 1111 | pm_genpd_poweron(genpd); |
1056 | genpd->suspended_count--; | 1112 | genpd->suspended_count--; |
1057 | genpd_start_dev(genpd, dev); | ||
1058 | 1113 | ||
1059 | return genpd_resume_early(genpd, dev); | 1114 | return genpd_start_dev(genpd, dev); |
1060 | } | 1115 | } |
1061 | 1116 | ||
1062 | /** | 1117 | /** |
@@ -1099,11 +1154,15 @@ static void pm_genpd_complete(struct device *dev) | |||
1099 | 1154 | ||
1100 | #define pm_genpd_prepare NULL | 1155 | #define pm_genpd_prepare NULL |
1101 | #define pm_genpd_suspend NULL | 1156 | #define pm_genpd_suspend NULL |
1157 | #define pm_genpd_suspend_late NULL | ||
1102 | #define pm_genpd_suspend_noirq NULL | 1158 | #define pm_genpd_suspend_noirq NULL |
1159 | #define pm_genpd_resume_early NULL | ||
1103 | #define pm_genpd_resume_noirq NULL | 1160 | #define pm_genpd_resume_noirq NULL |
1104 | #define pm_genpd_resume NULL | 1161 | #define pm_genpd_resume NULL |
1105 | #define pm_genpd_freeze NULL | 1162 | #define pm_genpd_freeze NULL |
1163 | #define pm_genpd_freeze_late NULL | ||
1106 | #define pm_genpd_freeze_noirq NULL | 1164 | #define pm_genpd_freeze_noirq NULL |
1165 | #define pm_genpd_thaw_early NULL | ||
1107 | #define pm_genpd_thaw_noirq NULL | 1166 | #define pm_genpd_thaw_noirq NULL |
1108 | #define pm_genpd_thaw NULL | 1167 | #define pm_genpd_thaw NULL |
1109 | #define pm_genpd_restore_noirq NULL | 1168 | #define pm_genpd_restore_noirq NULL |
@@ -1171,6 +1230,38 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, | |||
1171 | } | 1230 | } |
1172 | 1231 | ||
1173 | /** | 1232 | /** |
1233 | * __pm_genpd_of_add_device - Add a device to an I/O PM domain. | ||
1234 | * @genpd_node: Device tree node pointer representing a PM domain to which the | ||
1235 | * the device is added to. | ||
1236 | * @dev: Device to be added. | ||
1237 | * @td: Set of PM QoS timing parameters to attach to the device. | ||
1238 | */ | ||
1239 | int __pm_genpd_of_add_device(struct device_node *genpd_node, struct device *dev, | ||
1240 | struct gpd_timing_data *td) | ||
1241 | { | ||
1242 | struct generic_pm_domain *genpd = NULL, *gpd; | ||
1243 | |||
1244 | dev_dbg(dev, "%s()\n", __func__); | ||
1245 | |||
1246 | if (IS_ERR_OR_NULL(genpd_node) || IS_ERR_OR_NULL(dev)) | ||
1247 | return -EINVAL; | ||
1248 | |||
1249 | mutex_lock(&gpd_list_lock); | ||
1250 | list_for_each_entry(gpd, &gpd_list, gpd_list_node) { | ||
1251 | if (gpd->of_node == genpd_node) { | ||
1252 | genpd = gpd; | ||
1253 | break; | ||
1254 | } | ||
1255 | } | ||
1256 | mutex_unlock(&gpd_list_lock); | ||
1257 | |||
1258 | if (!genpd) | ||
1259 | return -EINVAL; | ||
1260 | |||
1261 | return __pm_genpd_add_device(genpd, dev, td); | ||
1262 | } | ||
1263 | |||
1264 | /** | ||
1174 | * pm_genpd_remove_device - Remove a device from an I/O PM domain. | 1265 | * pm_genpd_remove_device - Remove a device from an I/O PM domain. |
1175 | * @genpd: PM domain to remove the device from. | 1266 | * @genpd: PM domain to remove the device from. |
1176 | * @dev: Device to be removed. | 1267 | * @dev: Device to be removed. |
@@ -1450,7 +1541,7 @@ static int pm_genpd_default_suspend_late(struct device *dev) | |||
1450 | { | 1541 | { |
1451 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.suspend_late; | 1542 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.suspend_late; |
1452 | 1543 | ||
1453 | return cb ? cb(dev) : pm_generic_suspend_noirq(dev); | 1544 | return cb ? cb(dev) : pm_generic_suspend_late(dev); |
1454 | } | 1545 | } |
1455 | 1546 | ||
1456 | /** | 1547 | /** |
@@ -1461,7 +1552,7 @@ static int pm_genpd_default_resume_early(struct device *dev) | |||
1461 | { | 1552 | { |
1462 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.resume_early; | 1553 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.resume_early; |
1463 | 1554 | ||
1464 | return cb ? cb(dev) : pm_generic_resume_noirq(dev); | 1555 | return cb ? cb(dev) : pm_generic_resume_early(dev); |
1465 | } | 1556 | } |
1466 | 1557 | ||
1467 | /** | 1558 | /** |
@@ -1494,7 +1585,7 @@ static int pm_genpd_default_freeze_late(struct device *dev) | |||
1494 | { | 1585 | { |
1495 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze_late; | 1586 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze_late; |
1496 | 1587 | ||
1497 | return cb ? cb(dev) : pm_generic_freeze_noirq(dev); | 1588 | return cb ? cb(dev) : pm_generic_freeze_late(dev); |
1498 | } | 1589 | } |
1499 | 1590 | ||
1500 | /** | 1591 | /** |
@@ -1505,7 +1596,7 @@ static int pm_genpd_default_thaw_early(struct device *dev) | |||
1505 | { | 1596 | { |
1506 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw_early; | 1597 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw_early; |
1507 | 1598 | ||
1508 | return cb ? cb(dev) : pm_generic_thaw_noirq(dev); | 1599 | return cb ? cb(dev) : pm_generic_thaw_early(dev); |
1509 | } | 1600 | } |
1510 | 1601 | ||
1511 | /** | 1602 | /** |
@@ -1564,16 +1655,22 @@ void pm_genpd_init(struct generic_pm_domain *genpd, | |||
1564 | genpd->domain.ops.runtime_idle = pm_generic_runtime_idle; | 1655 | genpd->domain.ops.runtime_idle = pm_generic_runtime_idle; |
1565 | genpd->domain.ops.prepare = pm_genpd_prepare; | 1656 | genpd->domain.ops.prepare = pm_genpd_prepare; |
1566 | genpd->domain.ops.suspend = pm_genpd_suspend; | 1657 | genpd->domain.ops.suspend = pm_genpd_suspend; |
1658 | genpd->domain.ops.suspend_late = pm_genpd_suspend_late; | ||
1567 | genpd->domain.ops.suspend_noirq = pm_genpd_suspend_noirq; | 1659 | genpd->domain.ops.suspend_noirq = pm_genpd_suspend_noirq; |
1568 | genpd->domain.ops.resume_noirq = pm_genpd_resume_noirq; | 1660 | genpd->domain.ops.resume_noirq = pm_genpd_resume_noirq; |
1661 | genpd->domain.ops.resume_early = pm_genpd_resume_early; | ||
1569 | genpd->domain.ops.resume = pm_genpd_resume; | 1662 | genpd->domain.ops.resume = pm_genpd_resume; |
1570 | genpd->domain.ops.freeze = pm_genpd_freeze; | 1663 | genpd->domain.ops.freeze = pm_genpd_freeze; |
1664 | genpd->domain.ops.freeze_late = pm_genpd_freeze_late; | ||
1571 | genpd->domain.ops.freeze_noirq = pm_genpd_freeze_noirq; | 1665 | genpd->domain.ops.freeze_noirq = pm_genpd_freeze_noirq; |
1572 | genpd->domain.ops.thaw_noirq = pm_genpd_thaw_noirq; | 1666 | genpd->domain.ops.thaw_noirq = pm_genpd_thaw_noirq; |
1667 | genpd->domain.ops.thaw_early = pm_genpd_thaw_early; | ||
1573 | genpd->domain.ops.thaw = pm_genpd_thaw; | 1668 | genpd->domain.ops.thaw = pm_genpd_thaw; |
1574 | genpd->domain.ops.poweroff = pm_genpd_suspend; | 1669 | genpd->domain.ops.poweroff = pm_genpd_suspend; |
1670 | genpd->domain.ops.poweroff_late = pm_genpd_suspend_late; | ||
1575 | genpd->domain.ops.poweroff_noirq = pm_genpd_suspend_noirq; | 1671 | genpd->domain.ops.poweroff_noirq = pm_genpd_suspend_noirq; |
1576 | genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq; | 1672 | genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq; |
1673 | genpd->domain.ops.restore_early = pm_genpd_resume_early; | ||
1577 | genpd->domain.ops.restore = pm_genpd_resume; | 1674 | genpd->domain.ops.restore = pm_genpd_resume; |
1578 | genpd->domain.ops.complete = pm_genpd_complete; | 1675 | genpd->domain.ops.complete = pm_genpd_complete; |
1579 | genpd->dev_ops.save_state = pm_genpd_default_save_state; | 1676 | genpd->dev_ops.save_state = pm_genpd_default_save_state; |