diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2012-03-16 16:50:08 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2012-03-16 16:50:08 -0400 |
commit | 62dc7c02c31c2cc66c46cc8761d421c60bb07a6f (patch) | |
tree | 73068d760963dc8e154a4e54025e41a529c67b83 /drivers/base/power | |
parent | cf3bbcaf09cb158590d1a9e0c0a6796d4fe92452 (diff) | |
parent | 57d13370cfaf6017c68981e66ff5b3bf20a2705c (diff) |
Merge branch 'pm-domains'
* pm-domains:
PM / shmobile: Make MTU2 driver use pm_genpd_dev_always_on()
PM / shmobile: Make CMT driver use pm_genpd_dev_always_on()
PM / shmobile: Make TMU driver use pm_genpd_dev_always_on()
PM / Domains: Introduce "always on" device flag
PM / Domains: Fix hibernation restore of devices, v2
PM / Domains: Fix handling of wakeup devices during system resume
Diffstat (limited to 'drivers/base/power')
-rw-r--r-- | drivers/base/power/domain.c | 69 |
1 files changed, 53 insertions, 16 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index d2c03239abcf..b6ff6ecf519d 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c | |||
@@ -366,7 +366,7 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) | |||
366 | not_suspended = 0; | 366 | not_suspended = 0; |
367 | list_for_each_entry(pdd, &genpd->dev_list, list_node) | 367 | list_for_each_entry(pdd, &genpd->dev_list, list_node) |
368 | if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev) | 368 | if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev) |
369 | || pdd->dev->power.irq_safe)) | 369 | || pdd->dev->power.irq_safe || to_gpd_data(pdd)->always_on)) |
370 | not_suspended++; | 370 | not_suspended++; |
371 | 371 | ||
372 | if (not_suspended > genpd->in_progress) | 372 | if (not_suspended > genpd->in_progress) |
@@ -503,6 +503,9 @@ static int pm_genpd_runtime_suspend(struct device *dev) | |||
503 | 503 | ||
504 | might_sleep_if(!genpd->dev_irq_safe); | 504 | might_sleep_if(!genpd->dev_irq_safe); |
505 | 505 | ||
506 | if (dev_gpd_data(dev)->always_on) | ||
507 | return -EBUSY; | ||
508 | |||
506 | stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL; | 509 | stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL; |
507 | if (stop_ok && !stop_ok(dev)) | 510 | if (stop_ok && !stop_ok(dev)) |
508 | return -EBUSY; | 511 | return -EBUSY; |
@@ -764,8 +767,10 @@ static int pm_genpd_prepare(struct device *dev) | |||
764 | 767 | ||
765 | genpd_acquire_lock(genpd); | 768 | genpd_acquire_lock(genpd); |
766 | 769 | ||
767 | if (genpd->prepared_count++ == 0) | 770 | if (genpd->prepared_count++ == 0) { |
771 | genpd->suspended_count = 0; | ||
768 | genpd->suspend_power_off = genpd->status == GPD_STATE_POWER_OFF; | 772 | genpd->suspend_power_off = genpd->status == GPD_STATE_POWER_OFF; |
773 | } | ||
769 | 774 | ||
770 | genpd_release_lock(genpd); | 775 | genpd_release_lock(genpd); |
771 | 776 | ||
@@ -857,7 +862,7 @@ static int pm_genpd_suspend_noirq(struct device *dev) | |||
857 | if (IS_ERR(genpd)) | 862 | if (IS_ERR(genpd)) |
858 | return -EINVAL; | 863 | return -EINVAL; |
859 | 864 | ||
860 | if (genpd->suspend_power_off | 865 | if (genpd->suspend_power_off || dev_gpd_data(dev)->always_on |
861 | || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) | 866 | || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) |
862 | return 0; | 867 | return 0; |
863 | 868 | ||
@@ -890,7 +895,8 @@ static int pm_genpd_resume_noirq(struct device *dev) | |||
890 | if (IS_ERR(genpd)) | 895 | if (IS_ERR(genpd)) |
891 | return -EINVAL; | 896 | return -EINVAL; |
892 | 897 | ||
893 | if (genpd->suspend_power_off) | 898 | if (genpd->suspend_power_off || dev_gpd_data(dev)->always_on |
899 | || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) | ||
894 | return 0; | 900 | return 0; |
895 | 901 | ||
896 | /* | 902 | /* |
@@ -1009,7 +1015,8 @@ static int pm_genpd_freeze_noirq(struct device *dev) | |||
1009 | if (IS_ERR(genpd)) | 1015 | if (IS_ERR(genpd)) |
1010 | return -EINVAL; | 1016 | return -EINVAL; |
1011 | 1017 | ||
1012 | return genpd->suspend_power_off ? 0 : genpd_stop_dev(genpd, dev); | 1018 | return genpd->suspend_power_off || dev_gpd_data(dev)->always_on ? |
1019 | 0 : genpd_stop_dev(genpd, dev); | ||
1013 | } | 1020 | } |
1014 | 1021 | ||
1015 | /** | 1022 | /** |
@@ -1029,7 +1036,8 @@ static int pm_genpd_thaw_noirq(struct device *dev) | |||
1029 | if (IS_ERR(genpd)) | 1036 | if (IS_ERR(genpd)) |
1030 | return -EINVAL; | 1037 | return -EINVAL; |
1031 | 1038 | ||
1032 | return genpd->suspend_power_off ? 0 : genpd_start_dev(genpd, dev); | 1039 | return genpd->suspend_power_off || dev_gpd_data(dev)->always_on ? |
1040 | 0 : genpd_start_dev(genpd, dev); | ||
1033 | } | 1041 | } |
1034 | 1042 | ||
1035 | /** | 1043 | /** |
@@ -1096,22 +1104,32 @@ static int pm_genpd_restore_noirq(struct device *dev) | |||
1096 | * Since all of the "noirq" callbacks are executed sequentially, it is | 1104 | * Since all of the "noirq" callbacks are executed sequentially, it is |
1097 | * guaranteed that this function will never run twice in parallel for | 1105 | * guaranteed that this function will never run twice in parallel for |
1098 | * the same PM domain, so it is not necessary to use locking here. | 1106 | * the same PM domain, so it is not necessary to use locking here. |
1107 | * | ||
1108 | * At this point suspended_count == 0 means we are being run for the | ||
1109 | * first time for the given domain in the present cycle. | ||
1099 | */ | 1110 | */ |
1100 | genpd->status = GPD_STATE_POWER_OFF; | 1111 | if (genpd->suspended_count++ == 0) { |
1101 | if (genpd->suspend_power_off) { | ||
1102 | /* | 1112 | /* |
1103 | * The boot kernel might put the domain into the power on state, | 1113 | * The boot kernel might put the domain into arbitrary state, |
1104 | * so make sure it really is powered off. | 1114 | * so make it appear as powered off to pm_genpd_poweron(), so |
1115 | * that it tries to power it on in case it was really off. | ||
1105 | */ | 1116 | */ |
1106 | if (genpd->power_off) | 1117 | genpd->status = GPD_STATE_POWER_OFF; |
1107 | genpd->power_off(genpd); | 1118 | if (genpd->suspend_power_off) { |
1108 | return 0; | 1119 | /* |
1120 | * If the domain was off before the hibernation, make | ||
1121 | * sure it will be off going forward. | ||
1122 | */ | ||
1123 | if (genpd->power_off) | ||
1124 | genpd->power_off(genpd); | ||
1125 | |||
1126 | return 0; | ||
1127 | } | ||
1109 | } | 1128 | } |
1110 | 1129 | ||
1111 | pm_genpd_poweron(genpd); | 1130 | pm_genpd_poweron(genpd); |
1112 | genpd->suspended_count--; | ||
1113 | 1131 | ||
1114 | return genpd_start_dev(genpd, dev); | 1132 | return dev_gpd_data(dev)->always_on ? 0 : genpd_start_dev(genpd, dev); |
1115 | } | 1133 | } |
1116 | 1134 | ||
1117 | /** | 1135 | /** |
@@ -1307,6 +1325,26 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, | |||
1307 | } | 1325 | } |
1308 | 1326 | ||
1309 | /** | 1327 | /** |
1328 | * pm_genpd_dev_always_on - Set/unset the "always on" flag for a given device. | ||
1329 | * @dev: Device to set/unset the flag for. | ||
1330 | * @val: The new value of the device's "always on" flag. | ||
1331 | */ | ||
1332 | void pm_genpd_dev_always_on(struct device *dev, bool val) | ||
1333 | { | ||
1334 | struct pm_subsys_data *psd; | ||
1335 | unsigned long flags; | ||
1336 | |||
1337 | spin_lock_irqsave(&dev->power.lock, flags); | ||
1338 | |||
1339 | psd = dev_to_psd(dev); | ||
1340 | if (psd && psd->domain_data) | ||
1341 | to_gpd_data(psd->domain_data)->always_on = val; | ||
1342 | |||
1343 | spin_unlock_irqrestore(&dev->power.lock, flags); | ||
1344 | } | ||
1345 | EXPORT_SYMBOL_GPL(pm_genpd_dev_always_on); | ||
1346 | |||
1347 | /** | ||
1310 | * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain. | 1348 | * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain. |
1311 | * @genpd: Master PM domain to add the subdomain to. | 1349 | * @genpd: Master PM domain to add the subdomain to. |
1312 | * @subdomain: Subdomain to be added. | 1350 | * @subdomain: Subdomain to be added. |
@@ -1648,7 +1686,6 @@ void pm_genpd_init(struct generic_pm_domain *genpd, | |||
1648 | genpd->poweroff_task = NULL; | 1686 | genpd->poweroff_task = NULL; |
1649 | genpd->resume_count = 0; | 1687 | genpd->resume_count = 0; |
1650 | genpd->device_count = 0; | 1688 | genpd->device_count = 0; |
1651 | genpd->suspended_count = 0; | ||
1652 | genpd->max_off_time_ns = -1; | 1689 | genpd->max_off_time_ns = -1; |
1653 | genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend; | 1690 | genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend; |
1654 | genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume; | 1691 | genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume; |