diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index f6204b324368..e6fab684884f 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -247,6 +247,9 @@ static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed) if (!genpd->power_on) return 0; + pr_debug("%s: Power-%s (idle state %d timed %s)\n", genpd->name, "on", + state_idx, timed ? "true" : "false"); + if (!timed) return genpd->power_on(genpd); @@ -277,6 +280,9 @@ static int _genpd_power_off(struct generic_pm_domain *genpd, bool timed) if (!genpd->power_off) return 0; + pr_debug("%s: Power-%s (idle state %d timed %s)\n", genpd->name, "off", + state_idx, timed ? "true" : "false"); + if (!timed) return genpd->power_off(genpd); @@ -795,7 +801,20 @@ static void genpd_sync_power_off(struct generic_pm_domain *genpd, bool use_lock, { struct gpd_link *link; - if (!genpd_status_on(genpd) || genpd_is_always_on(genpd)) + /* + * Give the power domain a chance to switch to the deepest state in + * case it's already off but in an intermediate low power state. + * Due to power domain is alway off, so no need to check device wakeup + * here anymore + */ + + genpd->state_idx_saved = genpd->state_idx; + + if (genpd_is_always_on(genpd)) + return; + + if (!genpd_status_on(genpd) && + genpd->state_idx == (genpd->state_count - 1)) return; if (genpd->suspended_count != genpd->device_count @@ -807,6 +826,9 @@ static void genpd_sync_power_off(struct generic_pm_domain *genpd, bool use_lock, if (_genpd_power_off(genpd, false)) return; + if (genpd->status == GPD_STATE_POWER_OFF) + return; + genpd->status = GPD_STATE_POWER_OFF; list_for_each_entry(link, &genpd->slave_links, slave_node) { @@ -854,6 +876,8 @@ static void genpd_sync_power_on(struct generic_pm_domain *genpd, bool use_lock, _genpd_power_on(genpd, false); + /* restore save power domain state after resume */ + genpd->state_idx = genpd->state_idx_saved; genpd->status = GPD_STATE_ACTIVE; } diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index ff88488ef2cc..49e92073517c 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -90,6 +90,7 @@ struct generic_pm_domain { }; }; + unsigned int state_idx_saved; /* saved power state for recovery after system suspend/resume */ }; static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)