aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2012-03-16 16:50:08 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2012-03-16 16:50:08 -0400
commit62dc7c02c31c2cc66c46cc8761d421c60bb07a6f (patch)
tree73068d760963dc8e154a4e54025e41a529c67b83 /drivers/base/power
parentcf3bbcaf09cb158590d1a9e0c0a6796d4fe92452 (diff)
parent57d13370cfaf6017c68981e66ff5b3bf20a2705c (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.c69
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 */
1332void 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}
1345EXPORT_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;