Commit 1b771839 authored by Dmitry Baryshkov's avatar Dmitry Baryshkov Committed by Stephen Boyd

clk: qcom: gdsc: enable optional power domain support

On sm8250 dispcc and videocc registers are powered up by the MMCX power
domain. Currently we use a regulator to enable this domain on demand,
however this has some consequences, as genpd code is not reentrant.

Make gdsc code also use pm_runtime calls to ensure that registers are
accessible during the gdsc_enable/gdsc_disable operations.
Signed-off-by: default avatarDmitry Baryshkov <dmitry.baryshkov@linaro.org>
Reviewed-by: default avatarBjorn Andersson <bjorn.andersson@linaro.org>
Link: https://lore.kernel.org/r/20210829154757.784699-6-dmitry.baryshkov@linaro.orgSigned-off-by: default avatarStephen Boyd <sboyd@kernel.org>
parent a91c483b
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/ktime.h> #include <linux/ktime.h>
#include <linux/pm_domain.h> #include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/reset-controller.h> #include <linux/reset-controller.h>
...@@ -50,6 +51,22 @@ enum gdsc_status { ...@@ -50,6 +51,22 @@ enum gdsc_status {
GDSC_ON GDSC_ON
}; };
static int gdsc_pm_runtime_get(struct gdsc *sc)
{
if (!sc->dev)
return 0;
return pm_runtime_resume_and_get(sc->dev);
}
static int gdsc_pm_runtime_put(struct gdsc *sc)
{
if (!sc->dev)
return 0;
return pm_runtime_put_sync(sc->dev);
}
/* Returns 1 if GDSC status is status, 0 if not, and < 0 on error */ /* Returns 1 if GDSC status is status, 0 if not, and < 0 on error */
static int gdsc_check_status(struct gdsc *sc, enum gdsc_status status) static int gdsc_check_status(struct gdsc *sc, enum gdsc_status status)
{ {
...@@ -232,9 +249,8 @@ static void gdsc_retain_ff_on(struct gdsc *sc) ...@@ -232,9 +249,8 @@ static void gdsc_retain_ff_on(struct gdsc *sc)
regmap_update_bits(sc->regmap, sc->gdscr, mask, mask); regmap_update_bits(sc->regmap, sc->gdscr, mask, mask);
} }
static int gdsc_enable(struct generic_pm_domain *domain) static int _gdsc_enable(struct gdsc *sc)
{ {
struct gdsc *sc = domain_to_gdsc(domain);
int ret; int ret;
if (sc->pwrsts == PWRSTS_ON) if (sc->pwrsts == PWRSTS_ON)
...@@ -290,11 +306,22 @@ static int gdsc_enable(struct generic_pm_domain *domain) ...@@ -290,11 +306,22 @@ static int gdsc_enable(struct generic_pm_domain *domain)
return 0; return 0;
} }
static int gdsc_disable(struct generic_pm_domain *domain) static int gdsc_enable(struct generic_pm_domain *domain)
{ {
struct gdsc *sc = domain_to_gdsc(domain); struct gdsc *sc = domain_to_gdsc(domain);
int ret; int ret;
ret = gdsc_pm_runtime_get(sc);
if (ret)
return ret;
return _gdsc_enable(sc);
}
static int _gdsc_disable(struct gdsc *sc)
{
int ret;
if (sc->pwrsts == PWRSTS_ON) if (sc->pwrsts == PWRSTS_ON)
return gdsc_assert_reset(sc); return gdsc_assert_reset(sc);
...@@ -329,6 +356,18 @@ static int gdsc_disable(struct generic_pm_domain *domain) ...@@ -329,6 +356,18 @@ static int gdsc_disable(struct generic_pm_domain *domain)
return 0; return 0;
} }
static int gdsc_disable(struct generic_pm_domain *domain)
{
struct gdsc *sc = domain_to_gdsc(domain);
int ret;
ret = _gdsc_disable(sc);
gdsc_pm_runtime_put(sc);
return ret;
}
static int gdsc_init(struct gdsc *sc) static int gdsc_init(struct gdsc *sc)
{ {
u32 mask, val; u32 mask, val;
...@@ -443,6 +482,8 @@ int gdsc_register(struct gdsc_desc *desc, ...@@ -443,6 +482,8 @@ int gdsc_register(struct gdsc_desc *desc,
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
if (!scs[i]) if (!scs[i])
continue; continue;
if (pm_runtime_enabled(dev))
scs[i]->dev = dev;
scs[i]->regmap = regmap; scs[i]->regmap = regmap;
scs[i]->rcdev = rcdev; scs[i]->rcdev = rcdev;
ret = gdsc_init(scs[i]); ret = gdsc_init(scs[i]);
...@@ -457,6 +498,8 @@ int gdsc_register(struct gdsc_desc *desc, ...@@ -457,6 +498,8 @@ int gdsc_register(struct gdsc_desc *desc,
continue; continue;
if (scs[i]->parent) if (scs[i]->parent)
pm_genpd_add_subdomain(scs[i]->parent, &scs[i]->pd); pm_genpd_add_subdomain(scs[i]->parent, &scs[i]->pd);
else if (!IS_ERR_OR_NULL(dev->pm_domain))
pm_genpd_add_subdomain(pd_to_genpd(dev->pm_domain), &scs[i]->pd);
} }
return of_genpd_add_provider_onecell(dev->of_node, data); return of_genpd_add_provider_onecell(dev->of_node, data);
...@@ -475,6 +518,8 @@ void gdsc_unregister(struct gdsc_desc *desc) ...@@ -475,6 +518,8 @@ void gdsc_unregister(struct gdsc_desc *desc)
continue; continue;
if (scs[i]->parent) if (scs[i]->parent)
pm_genpd_remove_subdomain(scs[i]->parent, &scs[i]->pd); pm_genpd_remove_subdomain(scs[i]->parent, &scs[i]->pd);
else if (!IS_ERR_OR_NULL(dev->pm_domain))
pm_genpd_remove_subdomain(pd_to_genpd(dev->pm_domain), &scs[i]->pd);
} }
of_genpd_del_provider(dev->of_node); of_genpd_del_provider(dev->of_node);
} }
......
...@@ -25,6 +25,7 @@ struct reset_controller_dev; ...@@ -25,6 +25,7 @@ struct reset_controller_dev;
* @resets: ids of resets associated with this gdsc * @resets: ids of resets associated with this gdsc
* @reset_count: number of @resets * @reset_count: number of @resets
* @rcdev: reset controller * @rcdev: reset controller
* @dev: the device holding the GDSC, used for pm_runtime calls
*/ */
struct gdsc { struct gdsc {
struct generic_pm_domain pd; struct generic_pm_domain pd;
...@@ -58,6 +59,7 @@ struct gdsc { ...@@ -58,6 +59,7 @@ struct gdsc {
const char *supply; const char *supply;
struct regulator *rsupply; struct regulator *rsupply;
struct device *dev;
}; };
struct gdsc_desc { struct gdsc_desc {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment