diff options
Diffstat (limited to 'drivers/base/power')
-rw-r--r-- | drivers/base/power/domain.c | 249 |
1 files changed, 150 insertions, 99 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 3c9451b10427..9a77080cb799 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c | |||
@@ -561,6 +561,46 @@ static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd, | |||
561 | return GENPD_DEV_CALLBACK(genpd, bool, active_wakeup, dev); | 561 | return GENPD_DEV_CALLBACK(genpd, bool, active_wakeup, dev); |
562 | } | 562 | } |
563 | 563 | ||
564 | static int genpd_suspend_dev(struct generic_pm_domain *genpd, struct device *dev) | ||
565 | { | ||
566 | return GENPD_DEV_CALLBACK(genpd, int, suspend, dev); | ||
567 | } | ||
568 | |||
569 | static int genpd_suspend_late(struct generic_pm_domain *genpd, struct device *dev) | ||
570 | { | ||
571 | return GENPD_DEV_CALLBACK(genpd, int, suspend_late, dev); | ||
572 | } | ||
573 | |||
574 | static int genpd_resume_early(struct generic_pm_domain *genpd, struct device *dev) | ||
575 | { | ||
576 | return GENPD_DEV_CALLBACK(genpd, int, resume_early, dev); | ||
577 | } | ||
578 | |||
579 | static int genpd_resume_dev(struct generic_pm_domain *genpd, struct device *dev) | ||
580 | { | ||
581 | return GENPD_DEV_CALLBACK(genpd, int, resume, dev); | ||
582 | } | ||
583 | |||
584 | static int genpd_freeze_dev(struct generic_pm_domain *genpd, struct device *dev) | ||
585 | { | ||
586 | return GENPD_DEV_CALLBACK(genpd, int, freeze, dev); | ||
587 | } | ||
588 | |||
589 | static int genpd_freeze_late(struct generic_pm_domain *genpd, struct device *dev) | ||
590 | { | ||
591 | return GENPD_DEV_CALLBACK(genpd, int, freeze_late, dev); | ||
592 | } | ||
593 | |||
594 | static int genpd_thaw_early(struct generic_pm_domain *genpd, struct device *dev) | ||
595 | { | ||
596 | return GENPD_DEV_CALLBACK(genpd, int, thaw_early, dev); | ||
597 | } | ||
598 | |||
599 | static int genpd_thaw_dev(struct generic_pm_domain *genpd, struct device *dev) | ||
600 | { | ||
601 | return GENPD_DEV_CALLBACK(genpd, int, thaw, dev); | ||
602 | } | ||
603 | |||
564 | /** | 604 | /** |
565 | * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its masters. | 605 | * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its masters. |
566 | * @genpd: PM domain to power off, if possible. | 606 | * @genpd: PM domain to power off, if possible. |
@@ -712,7 +752,7 @@ static int pm_genpd_suspend(struct device *dev) | |||
712 | if (IS_ERR(genpd)) | 752 | if (IS_ERR(genpd)) |
713 | return -EINVAL; | 753 | return -EINVAL; |
714 | 754 | ||
715 | return genpd->suspend_power_off ? 0 : pm_generic_suspend(dev); | 755 | return genpd->suspend_power_off ? 0 : genpd_suspend_dev(genpd, dev); |
716 | } | 756 | } |
717 | 757 | ||
718 | /** | 758 | /** |
@@ -737,7 +777,7 @@ static int pm_genpd_suspend_noirq(struct device *dev) | |||
737 | if (genpd->suspend_power_off) | 777 | if (genpd->suspend_power_off) |
738 | return 0; | 778 | return 0; |
739 | 779 | ||
740 | ret = pm_generic_suspend_noirq(dev); | 780 | ret = genpd_suspend_late(genpd, dev); |
741 | if (ret) | 781 | if (ret) |
742 | return ret; | 782 | return ret; |
743 | 783 | ||
@@ -788,7 +828,7 @@ static int pm_genpd_resume_noirq(struct device *dev) | |||
788 | genpd->suspended_count--; | 828 | genpd->suspended_count--; |
789 | genpd_start_dev(genpd, dev); | 829 | genpd_start_dev(genpd, dev); |
790 | 830 | ||
791 | return pm_generic_resume_noirq(dev); | 831 | return genpd_resume_early(genpd, dev); |
792 | } | 832 | } |
793 | 833 | ||
794 | /** | 834 | /** |
@@ -809,7 +849,7 @@ static int pm_genpd_resume(struct device *dev) | |||
809 | if (IS_ERR(genpd)) | 849 | if (IS_ERR(genpd)) |
810 | return -EINVAL; | 850 | return -EINVAL; |
811 | 851 | ||
812 | return genpd->suspend_power_off ? 0 : pm_generic_resume(dev); | 852 | return genpd->suspend_power_off ? 0 : genpd_resume_dev(genpd, dev); |
813 | } | 853 | } |
814 | 854 | ||
815 | /** | 855 | /** |
@@ -830,7 +870,7 @@ static int pm_genpd_freeze(struct device *dev) | |||
830 | if (IS_ERR(genpd)) | 870 | if (IS_ERR(genpd)) |
831 | return -EINVAL; | 871 | return -EINVAL; |
832 | 872 | ||
833 | return genpd->suspend_power_off ? 0 : pm_generic_freeze(dev); | 873 | return genpd->suspend_power_off ? 0 : genpd_freeze_dev(genpd, dev); |
834 | } | 874 | } |
835 | 875 | ||
836 | /** | 876 | /** |
@@ -856,7 +896,7 @@ static int pm_genpd_freeze_noirq(struct device *dev) | |||
856 | if (genpd->suspend_power_off) | 896 | if (genpd->suspend_power_off) |
857 | return 0; | 897 | return 0; |
858 | 898 | ||
859 | ret = pm_generic_freeze_noirq(dev); | 899 | ret = genpd_freeze_late(genpd, dev); |
860 | if (ret) | 900 | if (ret) |
861 | return ret; | 901 | return ret; |
862 | 902 | ||
@@ -889,7 +929,7 @@ static int pm_genpd_thaw_noirq(struct device *dev) | |||
889 | 929 | ||
890 | genpd_start_dev(genpd, dev); | 930 | genpd_start_dev(genpd, dev); |
891 | 931 | ||
892 | return pm_generic_thaw_noirq(dev); | 932 | return genpd_thaw_early(genpd, dev); |
893 | } | 933 | } |
894 | 934 | ||
895 | /** | 935 | /** |
@@ -910,70 +950,7 @@ static int pm_genpd_thaw(struct device *dev) | |||
910 | if (IS_ERR(genpd)) | 950 | if (IS_ERR(genpd)) |
911 | return -EINVAL; | 951 | return -EINVAL; |
912 | 952 | ||
913 | return genpd->suspend_power_off ? 0 : pm_generic_thaw(dev); | 953 | return genpd->suspend_power_off ? 0 : genpd_thaw_dev(genpd, dev); |
914 | } | ||
915 | |||
916 | /** | ||
917 | * pm_genpd_dev_poweroff - Power off a device belonging to an I/O PM domain. | ||
918 | * @dev: Device to suspend. | ||
919 | * | ||
920 | * Power off a device under the assumption that its pm_domain field points to | ||
921 | * the domain member of an object of type struct generic_pm_domain representing | ||
922 | * a PM domain consisting of I/O devices. | ||
923 | */ | ||
924 | static int pm_genpd_dev_poweroff(struct device *dev) | ||
925 | { | ||
926 | struct generic_pm_domain *genpd; | ||
927 | |||
928 | dev_dbg(dev, "%s()\n", __func__); | ||
929 | |||
930 | genpd = dev_to_genpd(dev); | ||
931 | if (IS_ERR(genpd)) | ||
932 | return -EINVAL; | ||
933 | |||
934 | return genpd->suspend_power_off ? 0 : pm_generic_poweroff(dev); | ||
935 | } | ||
936 | |||
937 | /** | ||
938 | * pm_genpd_dev_poweroff_noirq - Late power off of a device from a PM domain. | ||
939 | * @dev: Device to suspend. | ||
940 | * | ||
941 | * Carry out a late powering off of a device under the assumption that its | ||
942 | * pm_domain field points to the domain member of an object of type | ||
943 | * struct generic_pm_domain representing a PM domain consisting of I/O devices. | ||
944 | */ | ||
945 | static int pm_genpd_dev_poweroff_noirq(struct device *dev) | ||
946 | { | ||
947 | struct generic_pm_domain *genpd; | ||
948 | int ret; | ||
949 | |||
950 | dev_dbg(dev, "%s()\n", __func__); | ||
951 | |||
952 | genpd = dev_to_genpd(dev); | ||
953 | if (IS_ERR(genpd)) | ||
954 | return -EINVAL; | ||
955 | |||
956 | if (genpd->suspend_power_off) | ||
957 | return 0; | ||
958 | |||
959 | ret = pm_generic_poweroff_noirq(dev); | ||
960 | if (ret) | ||
961 | return ret; | ||
962 | |||
963 | if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev)) | ||
964 | return 0; | ||
965 | |||
966 | genpd_stop_dev(genpd, dev); | ||
967 | |||
968 | /* | ||
969 | * Since all of the "noirq" callbacks are executed sequentially, it is | ||
970 | * guaranteed that this function will never run twice in parallel for | ||
971 | * the same PM domain, so it is not necessary to use locking here. | ||
972 | */ | ||
973 | genpd->suspended_count++; | ||
974 | pm_genpd_sync_poweroff(genpd); | ||
975 | |||
976 | return 0; | ||
977 | } | 954 | } |
978 | 955 | ||
979 | /** | 956 | /** |
@@ -1015,28 +992,7 @@ static int pm_genpd_restore_noirq(struct device *dev) | |||
1015 | genpd->suspended_count--; | 992 | genpd->suspended_count--; |
1016 | genpd_start_dev(genpd, dev); | 993 | genpd_start_dev(genpd, dev); |
1017 | 994 | ||
1018 | return pm_generic_restore_noirq(dev); | 995 | return genpd_resume_early(genpd, dev); |
1019 | } | ||
1020 | |||
1021 | /** | ||
1022 | * pm_genpd_restore - Restore a device belonging to an I/O power domain. | ||
1023 | * @dev: Device to resume. | ||
1024 | * | ||
1025 | * Restore a device under the assumption that its pm_domain field points to the | ||
1026 | * domain member of an object of type struct generic_pm_domain representing | ||
1027 | * a power domain consisting of I/O devices. | ||
1028 | */ | ||
1029 | static int pm_genpd_restore(struct device *dev) | ||
1030 | { | ||
1031 | struct generic_pm_domain *genpd; | ||
1032 | |||
1033 | dev_dbg(dev, "%s()\n", __func__); | ||
1034 | |||
1035 | genpd = dev_to_genpd(dev); | ||
1036 | if (IS_ERR(genpd)) | ||
1037 | return -EINVAL; | ||
1038 | |||
1039 | return genpd->suspend_power_off ? 0 : pm_generic_restore(dev); | ||
1040 | } | 996 | } |
1041 | 997 | ||
1042 | /** | 998 | /** |
@@ -1086,10 +1042,7 @@ static void pm_genpd_complete(struct device *dev) | |||
1086 | #define pm_genpd_freeze_noirq NULL | 1042 | #define pm_genpd_freeze_noirq NULL |
1087 | #define pm_genpd_thaw_noirq NULL | 1043 | #define pm_genpd_thaw_noirq NULL |
1088 | #define pm_genpd_thaw NULL | 1044 | #define pm_genpd_thaw NULL |
1089 | #define pm_genpd_dev_poweroff_noirq NULL | ||
1090 | #define pm_genpd_dev_poweroff NULL | ||
1091 | #define pm_genpd_restore_noirq NULL | 1045 | #define pm_genpd_restore_noirq NULL |
1092 | #define pm_genpd_restore NULL | ||
1093 | #define pm_genpd_complete NULL | 1046 | #define pm_genpd_complete NULL |
1094 | 1047 | ||
1095 | #endif /* CONFIG_PM_SLEEP */ | 1048 | #endif /* CONFIG_PM_SLEEP */ |
@@ -1361,6 +1314,8 @@ int pm_genpd_remove_callbacks(struct device *dev) | |||
1361 | } | 1314 | } |
1362 | EXPORT_SYMBOL_GPL(pm_genpd_remove_callbacks); | 1315 | EXPORT_SYMBOL_GPL(pm_genpd_remove_callbacks); |
1363 | 1316 | ||
1317 | /* Default device callbacks for generic PM domains. */ | ||
1318 | |||
1364 | /** | 1319 | /** |
1365 | * pm_genpd_default_save_state - Default "save device state" for PM domians. | 1320 | * pm_genpd_default_save_state - Default "save device state" for PM domians. |
1366 | * @dev: Device to handle. | 1321 | * @dev: Device to handle. |
@@ -1400,6 +1355,94 @@ static int pm_genpd_default_restore_state(struct device *dev) | |||
1400 | } | 1355 | } |
1401 | 1356 | ||
1402 | /** | 1357 | /** |
1358 | * pm_genpd_default_suspend - Default "device suspend" for PM domians. | ||
1359 | * @dev: Device to handle. | ||
1360 | */ | ||
1361 | static int pm_genpd_default_suspend(struct device *dev) | ||
1362 | { | ||
1363 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze; | ||
1364 | |||
1365 | return cb ? cb(dev) : pm_generic_suspend(dev); | ||
1366 | } | ||
1367 | |||
1368 | /** | ||
1369 | * pm_genpd_default_suspend_late - Default "late device suspend" for PM domians. | ||
1370 | * @dev: Device to handle. | ||
1371 | */ | ||
1372 | static int pm_genpd_default_suspend_late(struct device *dev) | ||
1373 | { | ||
1374 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze_late; | ||
1375 | |||
1376 | return cb ? cb(dev) : pm_generic_suspend_noirq(dev); | ||
1377 | } | ||
1378 | |||
1379 | /** | ||
1380 | * pm_genpd_default_resume_early - Default "early device resume" for PM domians. | ||
1381 | * @dev: Device to handle. | ||
1382 | */ | ||
1383 | static int pm_genpd_default_resume_early(struct device *dev) | ||
1384 | { | ||
1385 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw_early; | ||
1386 | |||
1387 | return cb ? cb(dev) : pm_generic_resume_noirq(dev); | ||
1388 | } | ||
1389 | |||
1390 | /** | ||
1391 | * pm_genpd_default_resume - Default "device resume" for PM domians. | ||
1392 | * @dev: Device to handle. | ||
1393 | */ | ||
1394 | static int pm_genpd_default_resume(struct device *dev) | ||
1395 | { | ||
1396 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw; | ||
1397 | |||
1398 | return cb ? cb(dev) : pm_generic_resume(dev); | ||
1399 | } | ||
1400 | |||
1401 | /** | ||
1402 | * pm_genpd_default_freeze - Default "device freeze" for PM domians. | ||
1403 | * @dev: Device to handle. | ||
1404 | */ | ||
1405 | static int pm_genpd_default_freeze(struct device *dev) | ||
1406 | { | ||
1407 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze; | ||
1408 | |||
1409 | return cb ? cb(dev) : pm_generic_freeze(dev); | ||
1410 | } | ||
1411 | |||
1412 | /** | ||
1413 | * pm_genpd_default_freeze_late - Default "late device freeze" for PM domians. | ||
1414 | * @dev: Device to handle. | ||
1415 | */ | ||
1416 | static int pm_genpd_default_freeze_late(struct device *dev) | ||
1417 | { | ||
1418 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze_late; | ||
1419 | |||
1420 | return cb ? cb(dev) : pm_generic_freeze_noirq(dev); | ||
1421 | } | ||
1422 | |||
1423 | /** | ||
1424 | * pm_genpd_default_thaw_early - Default "early device thaw" for PM domians. | ||
1425 | * @dev: Device to handle. | ||
1426 | */ | ||
1427 | static int pm_genpd_default_thaw_early(struct device *dev) | ||
1428 | { | ||
1429 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw_early; | ||
1430 | |||
1431 | return cb ? cb(dev) : pm_generic_thaw_noirq(dev); | ||
1432 | } | ||
1433 | |||
1434 | /** | ||
1435 | * pm_genpd_default_thaw - Default "device thaw" for PM domians. | ||
1436 | * @dev: Device to handle. | ||
1437 | */ | ||
1438 | static int pm_genpd_default_thaw(struct device *dev) | ||
1439 | { | ||
1440 | int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw; | ||
1441 | |||
1442 | return cb ? cb(dev) : pm_generic_thaw(dev); | ||
1443 | } | ||
1444 | |||
1445 | /** | ||
1403 | * pm_genpd_init - Initialize a generic I/O PM domain object. | 1446 | * pm_genpd_init - Initialize a generic I/O PM domain object. |
1404 | * @genpd: PM domain object to initialize. | 1447 | * @genpd: PM domain object to initialize. |
1405 | * @gov: PM domain governor to associate with the domain (may be NULL). | 1448 | * @gov: PM domain governor to associate with the domain (may be NULL). |
@@ -1437,13 +1480,21 @@ void pm_genpd_init(struct generic_pm_domain *genpd, | |||
1437 | genpd->domain.ops.freeze_noirq = pm_genpd_freeze_noirq; | 1480 | genpd->domain.ops.freeze_noirq = pm_genpd_freeze_noirq; |
1438 | genpd->domain.ops.thaw_noirq = pm_genpd_thaw_noirq; | 1481 | genpd->domain.ops.thaw_noirq = pm_genpd_thaw_noirq; |
1439 | genpd->domain.ops.thaw = pm_genpd_thaw; | 1482 | genpd->domain.ops.thaw = pm_genpd_thaw; |
1440 | genpd->domain.ops.poweroff = pm_genpd_dev_poweroff; | 1483 | genpd->domain.ops.poweroff = pm_genpd_suspend; |
1441 | genpd->domain.ops.poweroff_noirq = pm_genpd_dev_poweroff_noirq; | 1484 | genpd->domain.ops.poweroff_noirq = pm_genpd_suspend_noirq; |
1442 | genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq; | 1485 | genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq; |
1443 | genpd->domain.ops.restore = pm_genpd_restore; | 1486 | genpd->domain.ops.restore = pm_genpd_resume; |
1444 | genpd->domain.ops.complete = pm_genpd_complete; | 1487 | genpd->domain.ops.complete = pm_genpd_complete; |
1445 | genpd->dev_ops.save_state = pm_genpd_default_save_state; | 1488 | genpd->dev_ops.save_state = pm_genpd_default_save_state; |
1446 | genpd->dev_ops.restore_state = pm_genpd_default_restore_state; | 1489 | genpd->dev_ops.restore_state = pm_genpd_default_restore_state; |
1490 | genpd->dev_ops.freeze = pm_genpd_default_suspend; | ||
1491 | genpd->dev_ops.freeze_late = pm_genpd_default_suspend_late; | ||
1492 | genpd->dev_ops.thaw_early = pm_genpd_default_resume_early; | ||
1493 | genpd->dev_ops.thaw = pm_genpd_default_resume; | ||
1494 | genpd->dev_ops.freeze = pm_genpd_default_freeze; | ||
1495 | genpd->dev_ops.freeze_late = pm_genpd_default_freeze_late; | ||
1496 | genpd->dev_ops.thaw_early = pm_genpd_default_thaw_early; | ||
1497 | genpd->dev_ops.thaw = pm_genpd_default_thaw; | ||
1447 | mutex_lock(&gpd_list_lock); | 1498 | mutex_lock(&gpd_list_lock); |
1448 | list_add(&genpd->gpd_list_node, &gpd_list); | 1499 | list_add(&genpd->gpd_list_node, &gpd_list); |
1449 | mutex_unlock(&gpd_list_lock); | 1500 | mutex_unlock(&gpd_list_lock); |