In the cases where the clock is required to be enabled before the genpd enable add support for the same. Signed-off-by: Taniya Das <tdas@xxxxxxxxxxxxxx> --- drivers/clk/qcom/gdsc.c | 45 +++++++++++++++++++++++++++++++++++++++------ drivers/clk/qcom/gdsc.h | 3 +++ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c index 7e1dd8c..1caca32 100644 --- a/drivers/clk/qcom/gdsc.c +++ b/drivers/clk/qcom/gdsc.c @@ -4,6 +4,7 @@ */ #include <linux/bitops.h> +#include <linux/clk.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/export.h> @@ -256,6 +257,15 @@ static int _gdsc_enable(struct gdsc *sc) if (sc->pwrsts == PWRSTS_ON) return gdsc_deassert_reset(sc); + if (sc->clk) { + ret = clk_enable(sc->clk); + if (ret) { + pr_err("Failed to enable clock %s\n", sc->clk_name); + return ret; + } + sc->clk_enable = true; + } + if (sc->flags & SW_RESET) { gdsc_assert_reset(sc); udelay(1); @@ -269,8 +279,11 @@ static int _gdsc_enable(struct gdsc *sc) } ret = gdsc_toggle_logic(sc, GDSC_ON); - if (ret) + if (ret) { + if (sc->clk) + clk_disable(sc->clk); return ret; + } if (sc->pwrsts & PWRSTS_OFF) gdsc_force_mem_on(sc); @@ -287,8 +300,12 @@ static int _gdsc_enable(struct gdsc *sc) /* Turn on HW trigger mode if supported */ if (sc->flags & HW_CTRL) { ret = gdsc_hwctrl(sc, true); - if (ret) + if (ret) { + if (sc->clk) + clk_disable(sc->clk); return ret; + } + /* * Wait for the GDSC to go through a power down and * up cycle. In case a firmware ends up polling status @@ -329,7 +346,7 @@ static int _gdsc_disable(struct gdsc *sc) if (sc->flags & HW_CTRL) { ret = gdsc_hwctrl(sc, false); if (ret < 0) - return ret; + goto disable_clk; /* * Wait for the GDSC to go through a power down and * up cycle. In case we end up polling status @@ -340,7 +357,7 @@ static int _gdsc_disable(struct gdsc *sc) ret = gdsc_poll_status(sc, GDSC_ON); if (ret) - return ret; + goto disable_clk; } if (sc->pwrsts & PWRSTS_OFF) @@ -348,12 +365,16 @@ static int _gdsc_disable(struct gdsc *sc) ret = gdsc_toggle_logic(sc, GDSC_OFF); if (ret) - return ret; + goto disable_clk; if (sc->flags & CLAMP_IO) gdsc_assert_clamp_io(sc); - return 0; +disable_clk: + if (sc->clk && sc->clk_enable) + clk_disable(sc->clk); + + return ret; } static int gdsc_disable(struct generic_pm_domain *domain) @@ -478,6 +499,18 @@ int gdsc_register(struct gdsc_desc *desc, return PTR_ERR(scs[i]->rsupply); } + for (i = 0; i < num; i++) { + if (!scs[i]) + continue; + + scs[i]->clk = devm_clk_get(dev, scs[i]->clk_name); + if (IS_ERR(scs[i]->clk)) + return PTR_ERR(scs[i]->clk); + ret = clk_prepare(scs[i]->clk); + if (ret) + return ret; + } + data->num_domains = num; for (i = 0; i < num; i++) { if (!scs[i]) diff --git a/drivers/clk/qcom/gdsc.h b/drivers/clk/qcom/gdsc.h index 702d47a..cff5440 100644 --- a/drivers/clk/qcom/gdsc.h +++ b/drivers/clk/qcom/gdsc.h @@ -59,6 +59,9 @@ struct gdsc { const char *supply; struct regulator *rsupply; + const char *clk_name; + struct clk *clk; + bool clk_enable; struct device *dev; }; -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.