aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-11-27 07:11:51 -0500
committerRafael J. Wysocki <rjw@sisk.pl>2011-12-01 15:47:29 -0500
commitd23b9b00cdde5c93b914a172cecd57d5625fcd04 (patch)
tree62be5b5b35697e95ef6f71bfeb28ba658e299266 /drivers/base/power
parentecf00475f229fcf06362412ad2d15a3267e354a1 (diff)
PM / Domains: Rework system suspend callback routines (v2)
The current generic PM domains code attempts to use the generic system suspend operations along with the domains' device stop/start routines, which requires device drivers to assume that their system suspend/resume (and hibernation/restore) callbacks will always be used with generic PM domains. However, in theory, the same hardware may be used in devices that don't belong to any PM domain, in which case it would be necessary to add "fake" PM domains to satisfy the above assumption. Also, the domain the hardware belongs to may not be handled with the help of the generic code. To allow device drivers that may be used along with the generic PM domains code of more flexibility, add new device callbacks, .suspend(), .suspend_late(), .resume_early(), .resume(), .freeze(), .freeze_late(), .thaw_early(), and .thaw(), that can be supplied by the drivers in addition to their "standard" system suspend and hibernation callbacks. These new callbacks, if defined, will be used by the generic PM domains code for the handling of system suspend and hibernation instead of the "standard" ones. This will allow drivers to be designed to work with generic PM domains as well as without them. For backwards compatibility, introduce default implementations of the new callbacks for PM domains that will execute pm_generic_suspend(), pm_generic_suspend_noirq(), pm_generic_resume_noirq(), pm_generic_resume(), pm_generic_freeze(), pm_generic_freeze_noirq(), pm_generic_thaw_noirq(), and pm_generic_thaw(), respectively, for the given device if its driver doesn't define those callbacks. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'drivers/base/power')
-rw-r--r--drivers/base/power/domain.c249
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
564static int genpd_suspend_dev(struct generic_pm_domain *genpd, struct device *dev)
565{
566 return GENPD_DEV_CALLBACK(genpd, int, suspend, dev);
567}
568
569static 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
574static 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
579static int genpd_resume_dev(struct generic_pm_domain *genpd, struct device *dev)
580{
581 return GENPD_DEV_CALLBACK(genpd, int, resume, dev);
582}
583
584static int genpd_freeze_dev(struct generic_pm_domain *genpd, struct device *dev)
585{
586 return GENPD_DEV_CALLBACK(genpd, int, freeze, dev);
587}
588
589static 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
594static 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
599static 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 */
924static 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 */
945static 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 */
1029static 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}
1362EXPORT_SYMBOL_GPL(pm_genpd_remove_callbacks); 1315EXPORT_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 */
1361static 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 */
1372static 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 */
1383static 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 */
1394static 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 */
1405static 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 */
1416static 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 */
1427static 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 */
1438static 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);