diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c index dc51a63c9625..150692879e92 100644 --- a/drivers/clk/qcom/common.c +++ b/drivers/clk/qcom/common.c @@ -125,7 +125,8 @@ int qcom_cc_really_probe(struct platform_device *pdev, goto err_reset; if (desc->gdscs && desc->num_gdscs) { - ret = gdsc_register(dev, desc->gdscs, desc->num_gdscs, regmap); + ret = gdsc_register(dev, desc->gdscs, desc->num_gdscs, + &reset->rcdev, regmap); if (ret) goto err_pd; } diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c index e6bbb7608b57..da9fad8b642b 100644 --- a/drivers/clk/qcom/gdsc.c +++ b/drivers/clk/qcom/gdsc.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "gdsc.h" @@ -84,6 +85,24 @@ static int gdsc_toggle_logic(struct gdsc *sc, bool en) return -ETIMEDOUT; } +static inline int gdsc_deassert_reset(struct gdsc *sc) +{ + int i; + + for (i = 0; i < sc->reset_count; i++) + sc->rcdev->ops->deassert(sc->rcdev, sc->resets[i]); + return 0; +} + +static inline int gdsc_assert_reset(struct gdsc *sc) +{ + int i; + + for (i = 0; i < sc->reset_count; i++) + sc->rcdev->ops->assert(sc->rcdev, sc->resets[i]); + return 0; +} + static inline void gdsc_force_mem_on(struct gdsc *sc) { int i; @@ -107,6 +126,9 @@ static int gdsc_enable(struct generic_pm_domain *domain) struct gdsc *sc = domain_to_gdsc(domain); int ret; + if (sc->pwrsts == PWRSTS_ON) + return gdsc_deassert_reset(sc); + ret = gdsc_toggle_logic(sc, true); if (ret) return ret; @@ -130,6 +152,9 @@ static int gdsc_disable(struct generic_pm_domain *domain) { struct gdsc *sc = domain_to_gdsc(domain); + if (sc->pwrsts == PWRSTS_ON) + return gdsc_assert_reset(sc); + if (sc->pwrsts & PWRSTS_OFF) gdsc_clear_mem_on(sc); @@ -153,6 +178,13 @@ static int gdsc_init(struct gdsc *sc) if (ret) return ret; + /* Force gdsc ON if only ON state is supported */ + if (sc->pwrsts == PWRSTS_ON) { + ret = gdsc_toggle_logic(sc, true); + if (ret) + return ret; + } + on = gdsc_is_enabled(sc); if (on < 0) return on; @@ -170,7 +202,7 @@ static int gdsc_init(struct gdsc *sc) } int gdsc_register(struct device *dev, struct gdsc **scs, size_t num, - struct regmap *regmap) + struct reset_controller_dev *rcdev, struct regmap *regmap) { int i, ret; struct genpd_onecell_data *data; @@ -189,6 +221,7 @@ int gdsc_register(struct device *dev, struct gdsc **scs, size_t num, if (!scs[i]) continue; scs[i]->regmap = regmap; + scs[i]->rcdev = rcdev; ret = gdsc_init(scs[i]); if (ret) return ret; diff --git a/drivers/clk/qcom/gdsc.h b/drivers/clk/qcom/gdsc.h index 0ff251a5523f..5ded26884f08 100644 --- a/drivers/clk/qcom/gdsc.h +++ b/drivers/clk/qcom/gdsc.h @@ -18,6 +18,7 @@ #include struct regmap; +struct reset_controller_dev; /* Powerdomain allowable state bitfields */ #define PWRSTS_OFF BIT(0) @@ -34,6 +35,9 @@ struct regmap; * @cxcs: offsets of branch registers to toggle mem/periph bits in * @cxc_count: number of @cxcs * @pwrsts: Possible powerdomain power states + * @resets: ids of resets associated with this gdsc + * @reset_count: number of @resets + * @rcdev: reset controller */ struct gdsc { struct generic_pm_domain pd; @@ -42,13 +46,18 @@ struct gdsc { unsigned int *cxcs; unsigned int cxc_count; const u8 pwrsts; + struct reset_controller_dev *rcdev; + unsigned int *resets; + unsigned int reset_count; }; #ifdef CONFIG_QCOM_GDSC -int gdsc_register(struct device *, struct gdsc **, size_t n, struct regmap *); +int gdsc_register(struct device *, struct gdsc **, size_t n, + struct reset_controller_dev *, struct regmap *); void gdsc_unregister(struct device *); #else static inline int gdsc_register(struct device *d, struct gdsc **g, size_t n, + struct reset_controller_dev *rcdev, struct regmap *r) { return -ENOSYS;