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: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org> Link: https://lore.kernel.org/r/20210829154757.784699-6-dmitry.baryshkov@linaro.org Signed-off-by: Stephen Boyd <sboyd@kernel.org>
This commit is contained in:
parent
a91c483b42
commit
1b771839de
2 changed files with 50 additions and 3 deletions
|
@ -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 {
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
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;
|
||||||
* @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 {
|
||||||
|
|
||||||
const char *supply;
|
const char *supply;
|
||||||
struct regulator *rsupply;
|
struct regulator *rsupply;
|
||||||
|
struct device *dev;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct gdsc_desc {
|
struct gdsc_desc {
|
||||||
|
|
Loading…
Add table
Reference in a new issue