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 | |
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
-rw-r--r-- | arch/arm/mach-shmobile/setup-sh7372.c | 2 | ||||
-rw-r--r-- | drivers/base/power/domain.c | 69 | ||||
-rw-r--r-- | drivers/clocksource/sh_cmt.c | 4 | ||||
-rw-r--r-- | drivers/clocksource/sh_mtu2.c | 4 | ||||
-rw-r--r-- | drivers/clocksource/sh_tmu.c | 4 | ||||
-rw-r--r-- | include/linux/pm_domain.h | 3 |
6 files changed, 70 insertions, 16 deletions
diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c index a83cf51fc099..cccf91b8fae1 100644 --- a/arch/arm/mach-shmobile/setup-sh7372.c +++ b/arch/arm/mach-shmobile/setup-sh7372.c | |||
@@ -1043,6 +1043,8 @@ void __init sh7372_add_standard_devices(void) | |||
1043 | sh7372_add_device_to_domain(&sh7372_a4r, &veu2_device); | 1043 | sh7372_add_device_to_domain(&sh7372_a4r, &veu2_device); |
1044 | sh7372_add_device_to_domain(&sh7372_a4r, &veu3_device); | 1044 | sh7372_add_device_to_domain(&sh7372_a4r, &veu3_device); |
1045 | sh7372_add_device_to_domain(&sh7372_a4r, &jpu_device); | 1045 | sh7372_add_device_to_domain(&sh7372_a4r, &jpu_device); |
1046 | sh7372_add_device_to_domain(&sh7372_a4r, &tmu00_device); | ||
1047 | sh7372_add_device_to_domain(&sh7372_a4r, &tmu01_device); | ||
1046 | } | 1048 | } |
1047 | 1049 | ||
1048 | void __init sh7372_add_early_devices(void) | 1050 | void __init sh7372_add_early_devices(void) |
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; |
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index ca09bc421ddb..32fe9ef5cc5c 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/sh_timer.h> | 32 | #include <linux/sh_timer.h> |
33 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
34 | #include <linux/module.h> | 34 | #include <linux/module.h> |
35 | #include <linux/pm_domain.h> | ||
35 | 36 | ||
36 | struct sh_cmt_priv { | 37 | struct sh_cmt_priv { |
37 | void __iomem *mapbase; | 38 | void __iomem *mapbase; |
@@ -689,6 +690,9 @@ static int __devinit sh_cmt_probe(struct platform_device *pdev) | |||
689 | struct sh_cmt_priv *p = platform_get_drvdata(pdev); | 690 | struct sh_cmt_priv *p = platform_get_drvdata(pdev); |
690 | int ret; | 691 | int ret; |
691 | 692 | ||
693 | if (!is_early_platform_device(pdev)) | ||
694 | pm_genpd_dev_always_on(&pdev->dev, true); | ||
695 | |||
692 | if (p) { | 696 | if (p) { |
693 | dev_info(&pdev->dev, "kept as earlytimer\n"); | 697 | dev_info(&pdev->dev, "kept as earlytimer\n"); |
694 | return 0; | 698 | return 0; |
diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c index db8d5955bad4..a2172f690418 100644 --- a/drivers/clocksource/sh_mtu2.c +++ b/drivers/clocksource/sh_mtu2.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/sh_timer.h> | 31 | #include <linux/sh_timer.h> |
32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
34 | #include <linux/pm_domain.h> | ||
34 | 35 | ||
35 | struct sh_mtu2_priv { | 36 | struct sh_mtu2_priv { |
36 | void __iomem *mapbase; | 37 | void __iomem *mapbase; |
@@ -306,6 +307,9 @@ static int __devinit sh_mtu2_probe(struct platform_device *pdev) | |||
306 | struct sh_mtu2_priv *p = platform_get_drvdata(pdev); | 307 | struct sh_mtu2_priv *p = platform_get_drvdata(pdev); |
307 | int ret; | 308 | int ret; |
308 | 309 | ||
310 | if (!is_early_platform_device(pdev)) | ||
311 | pm_genpd_dev_always_on(&pdev->dev, true); | ||
312 | |||
309 | if (p) { | 313 | if (p) { |
310 | dev_info(&pdev->dev, "kept as earlytimer\n"); | 314 | dev_info(&pdev->dev, "kept as earlytimer\n"); |
311 | return 0; | 315 | return 0; |
diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c index 079e96ad44e8..97f54b634be4 100644 --- a/drivers/clocksource/sh_tmu.c +++ b/drivers/clocksource/sh_tmu.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/sh_timer.h> | 32 | #include <linux/sh_timer.h> |
33 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
34 | #include <linux/module.h> | 34 | #include <linux/module.h> |
35 | #include <linux/pm_domain.h> | ||
35 | 36 | ||
36 | struct sh_tmu_priv { | 37 | struct sh_tmu_priv { |
37 | void __iomem *mapbase; | 38 | void __iomem *mapbase; |
@@ -410,6 +411,9 @@ static int __devinit sh_tmu_probe(struct platform_device *pdev) | |||
410 | struct sh_tmu_priv *p = platform_get_drvdata(pdev); | 411 | struct sh_tmu_priv *p = platform_get_drvdata(pdev); |
411 | int ret; | 412 | int ret; |
412 | 413 | ||
414 | if (!is_early_platform_device(pdev)) | ||
415 | pm_genpd_dev_always_on(&pdev->dev, true); | ||
416 | |||
413 | if (p) { | 417 | if (p) { |
414 | dev_info(&pdev->dev, "kept as earlytimer\n"); | 418 | dev_info(&pdev->dev, "kept as earlytimer\n"); |
415 | return 0; | 419 | return 0; |
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 5c2bbc248c11..1236d262b3e8 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h | |||
@@ -99,6 +99,7 @@ struct generic_pm_domain_data { | |||
99 | struct gpd_dev_ops ops; | 99 | struct gpd_dev_ops ops; |
100 | struct gpd_timing_data td; | 100 | struct gpd_timing_data td; |
101 | bool need_restore; | 101 | bool need_restore; |
102 | bool always_on; | ||
102 | }; | 103 | }; |
103 | 104 | ||
104 | #ifdef CONFIG_PM_GENERIC_DOMAINS | 105 | #ifdef CONFIG_PM_GENERIC_DOMAINS |
@@ -137,6 +138,7 @@ static inline int pm_genpd_of_add_device(struct device_node *genpd_node, | |||
137 | 138 | ||
138 | extern int pm_genpd_remove_device(struct generic_pm_domain *genpd, | 139 | extern int pm_genpd_remove_device(struct generic_pm_domain *genpd, |
139 | struct device *dev); | 140 | struct device *dev); |
141 | extern void pm_genpd_dev_always_on(struct device *dev, bool val); | ||
140 | extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, | 142 | extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, |
141 | struct generic_pm_domain *new_subdomain); | 143 | struct generic_pm_domain *new_subdomain); |
142 | extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, | 144 | extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, |
@@ -179,6 +181,7 @@ static inline int pm_genpd_remove_device(struct generic_pm_domain *genpd, | |||
179 | { | 181 | { |
180 | return -ENOSYS; | 182 | return -ENOSYS; |
181 | } | 183 | } |
184 | static inline void pm_genpd_dev_always_on(struct device *dev, bool val) {} | ||
182 | static inline int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, | 185 | static inline int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, |
183 | struct generic_pm_domain *new_sd) | 186 | struct generic_pm_domain *new_sd) |
184 | { | 187 | { |