aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/base/power/domain.c57
-rw-r--r--include/linux/pm_domain.h16
-rw-r--r--kernel/power/Kconfig4
3 files changed, 71 insertions, 6 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 55c39f5b7a59..515c8ecf01ce 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -697,6 +697,24 @@ static inline void genpd_power_off_work_fn(struct work_struct *work) {}
697 697
698#ifdef CONFIG_PM_SLEEP 698#ifdef CONFIG_PM_SLEEP
699 699
700/**
701 * pm_genpd_present - Check if the given PM domain has been initialized.
702 * @genpd: PM domain to check.
703 */
704static bool pm_genpd_present(struct generic_pm_domain *genpd)
705{
706 struct generic_pm_domain *gpd;
707
708 if (IS_ERR_OR_NULL(genpd))
709 return false;
710
711 list_for_each_entry(gpd, &gpd_list, gpd_list_node)
712 if (gpd == genpd)
713 return true;
714
715 return false;
716}
717
700static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd, 718static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd,
701 struct device *dev) 719 struct device *dev)
702{ 720{
@@ -750,9 +768,10 @@ static int genpd_thaw_dev(struct generic_pm_domain *genpd, struct device *dev)
750 * Check if the given PM domain can be powered off (during system suspend or 768 * Check if the given PM domain can be powered off (during system suspend or
751 * hibernation) and do that if so. Also, in that case propagate to its masters. 769 * hibernation) and do that if so. Also, in that case propagate to its masters.
752 * 770 *
753 * This function is only called in "noirq" stages of system power transitions, 771 * This function is only called in "noirq" and "syscore" stages of system power
754 * so it need not acquire locks (all of the "noirq" callbacks are executed 772 * transitions, so it need not acquire locks (all of the "noirq" callbacks are
755 * sequentially, so it is guaranteed that it will never run twice in parallel). 773 * executed sequentially, so it is guaranteed that it will never run twice in
774 * parallel).
756 */ 775 */
757static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd) 776static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd)
758{ 777{
@@ -780,9 +799,10 @@ static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd)
780 * pm_genpd_sync_poweron - Synchronously power on a PM domain and its masters. 799 * pm_genpd_sync_poweron - Synchronously power on a PM domain and its masters.
781 * @genpd: PM domain to power on. 800 * @genpd: PM domain to power on.
782 * 801 *
783 * This function is only called in "noirq" stage of system power transitions, so 802 * This function is only called in "noirq" and "syscore" stages of system power
784 * it need not acquire locks (all of the "noirq" callbacks are executed 803 * transitions, so it need not acquire locks (all of the "noirq" callbacks are
785 * sequentially, so it is guaranteed that it will never run twice in parallel). 804 * executed sequentially, so it is guaranteed that it will never run twice in
805 * parallel).
786 */ 806 */
787static void pm_genpd_sync_poweron(struct generic_pm_domain *genpd) 807static void pm_genpd_sync_poweron(struct generic_pm_domain *genpd)
788{ 808{
@@ -1272,6 +1292,31 @@ static void pm_genpd_complete(struct device *dev)
1272 } 1292 }
1273} 1293}
1274 1294
1295/**
1296 * pm_genpd_syscore_switch - Switch power during system core suspend or resume.
1297 * @dev: Device that normally is marked as "always on" to switch power for.
1298 *
1299 * This routine may only be called during the system core (syscore) suspend or
1300 * resume phase for devices whose "always on" flags are set.
1301 */
1302void pm_genpd_syscore_switch(struct device *dev, bool suspend)
1303{
1304 struct generic_pm_domain *genpd;
1305
1306 genpd = dev_to_genpd(dev);
1307 if (!pm_genpd_present(genpd))
1308 return;
1309
1310 if (suspend) {
1311 genpd->suspended_count++;
1312 pm_genpd_sync_poweroff(genpd);
1313 } else {
1314 pm_genpd_sync_poweron(genpd);
1315 genpd->suspended_count--;
1316 }
1317}
1318EXPORT_SYMBOL_GPL(pm_genpd_syscore_switch);
1319
1275#else 1320#else
1276 1321
1277#define pm_genpd_prepare NULL 1322#define pm_genpd_prepare NULL
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index a7d6172922d4..ab83cf3dfaac 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -258,4 +258,20 @@ static inline void genpd_queue_power_off_work(struct generic_pm_domain *gpd) {}
258static inline void pm_genpd_poweroff_unused(void) {} 258static inline void pm_genpd_poweroff_unused(void) {}
259#endif 259#endif
260 260
261#ifdef CONFIG_PM_GENERIC_DOMAINS_SLEEP
262extern void pm_genpd_syscore_switch(struct device *dev, bool suspend);
263#else
264static inline void pm_genpd_syscore_switch(struct device *dev, bool suspend) {}
265#endif
266
267static inline void pm_genpd_syscore_poweroff(struct device *dev)
268{
269 pm_genpd_syscore_switch(dev, true);
270}
271
272static inline void pm_genpd_syscore_poweron(struct device *dev)
273{
274 pm_genpd_syscore_switch(dev, false);
275}
276
261#endif /* _LINUX_PM_DOMAIN_H */ 277#endif /* _LINUX_PM_DOMAIN_H */
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index a70518c9d82f..5dfdc9ea180b 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -263,6 +263,10 @@ config PM_GENERIC_DOMAINS
263 bool 263 bool
264 depends on PM 264 depends on PM
265 265
266config PM_GENERIC_DOMAINS_SLEEP
267 def_bool y
268 depends on PM_SLEEP && PM_GENERIC_DOMAINS
269
266config PM_GENERIC_DOMAINS_RUNTIME 270config PM_GENERIC_DOMAINS_RUNTIME
267 def_bool y 271 def_bool y
268 depends on PM_RUNTIME && PM_GENERIC_DOMAINS 272 depends on PM_RUNTIME && PM_GENERIC_DOMAINS