diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c index 65a3c9f6a3ff88..3d339935e40ee6 100644 --- a/arch/arm/mach-msm/clock-mdss-8974.c +++ b/arch/arm/mach-msm/clock-mdss-8974.c @@ -167,12 +167,48 @@ static int mdss_gdsc_enabled(void) (!(readl_relaxed(gdsc_base) & BIT(0))); } +/* Auto PLL calibaration */ +static int mdss_ahb_clk_enable(int enable) +{ + int rc = 0; + + /* todo: Ideally, we should enable/disable GDSC whenever we are + * attempting to enable/disable MDSS AHB clock. + * For now, just return error if GDSC is not enabled. + */ + if (!mdss_gdsc_enabled()) { + pr_err("%s: mdss GDSC is not enabled\n", __func__); + return -EPERM; + } + + if (enable) + rc = clk_prepare_enable(mdss_ahb_clk); + else + clk_disable_unprepare(mdss_ahb_clk); + + return rc; +} + static void hdmi_vco_disable(struct clk *c) { - clk_enable(mdss_ahb_clk); + u32 rc; + + if (!mdss_gdsc_enabled()) { + pr_err("%s: mdss GDSC is not enabled\n", __func__); + return; + } + + rc = clk_enable(mdss_ahb_clk); + if (rc) { + pr_err("%s: failed to enable mdss ahb clock. rc=%d\n", + __func__, rc); + return; + } + REG_W(0x0, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); udelay(5); REG_W(0x0, hdmi_phy_base + HDMI_PHY_GLB_CFG); + clk_disable(mdss_ahb_clk); hdmi_pll_on = 0; @@ -181,9 +217,21 @@ static void hdmi_vco_disable(struct clk *c) static int hdmi_vco_enable(struct clk *c) { u32 status; + u32 rc; u32 max_reads, timeout_us; - clk_enable(mdss_ahb_clk); + if (!mdss_gdsc_enabled()) { + pr_err("%s: mdss GDSC is not enabled\n", __func__); + return -EPERM; + } + + rc = clk_enable(mdss_ahb_clk); + if (rc) { + pr_err("%s: failed to enable mdss ahb clock. rc=%d\n", + __func__, rc); + return rc; + } + /* Global Enable */ REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG); /* Power up power gen */ @@ -242,6 +290,7 @@ static inline struct hdmi_pll_vco_clk *to_hdmi_vco_clk(struct clk *clk) static int hdmi_vco_set_rate(struct clk *c, unsigned long rate) { unsigned int set_power_dwn = 0; + int rc = 0; struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c); @@ -250,7 +299,13 @@ static int hdmi_vco_set_rate(struct clk *c, unsigned long rate) set_power_dwn = 1; } - clk_enable(mdss_ahb_clk); + rc = mdss_ahb_clk_enable(1); + if (rc) { + pr_err("%s: failed to enable mdss ahb clock. rc=%d\n", + __func__, rc); + return rc; + } + pr_debug("%s: rate=%ld\n", __func__, rate); switch (rate) { @@ -610,7 +665,7 @@ static int hdmi_vco_set_rate(struct clk *c, unsigned long rate) /* Make sure writes complete before disabling iface clock */ mb(); - clk_disable(mdss_ahb_clk); + mdss_ahb_clk_enable(0); if (set_power_dwn) hdmi_vco_enable(c); @@ -621,26 +676,6 @@ static int hdmi_vco_set_rate(struct clk *c, unsigned long rate) return 0; } /* hdmi_pll_set_rate */ -/* Auto PLL calibaration */ -int mdss_ahb_clk_enable(int enable) -{ - int rc = 0; - - /* todo: Ideally, we should enable/disable GDSC whenever we are - * attempting to enable/disable MDSS AHB clock. - * For now, just return error if GDSC is not enabled. - */ - if (!mdss_gdsc_enabled()) - return -EPERM; - - if (enable) - rc = clk_prepare_enable(mdss_ahb_clk); - else - clk_disable_unprepare(mdss_ahb_clk); - - return rc; -} - int set_byte_mux_sel(struct mux_clk *clk, int sel) { pr_debug("%s: byte mux set to %s mode\n", __func__, @@ -1610,6 +1645,11 @@ static unsigned long hdmi_vco_get_rate(struct clk *c) { unsigned long freq = 0; + if (mdss_ahb_clk_enable(1)) { + pr_err("%s: Failed to enable mdss ahb clock\n", __func__); + return freq; + } + freq = DSS_REG_R(hdmi_phy_pll_base, HDMI_UNI_PLL_CAL_CFG11) << 8 | DSS_REG_R(hdmi_phy_pll_base, HDMI_UNI_PLL_CAL_CFG10); @@ -1630,6 +1670,8 @@ static unsigned long hdmi_vco_get_rate(struct clk *c) freq *= 1000000; } + mdss_ahb_clk_enable(0); + return freq; } @@ -1664,9 +1706,17 @@ static int hdmi_vco_prepare(struct clk *c) vco->rate_set = false; + if (!ret) + ret = clk_prepare(mdss_ahb_clk); + return ret; } +static void hdmi_vco_unprepare(struct clk *c) +{ + clk_unprepare(mdss_ahb_clk); +} + static int hdmi_pll_lock_status(void) { u32 status; @@ -1677,7 +1727,7 @@ static int hdmi_pll_lock_status(void) if (rc) { pr_err("%s: failed to enable mdss ahb clock. rc=%d\n", __func__, rc); - return rc; + return 0; } /* poll for PLL ready status */ if (readl_poll_timeout_noirq((hdmi_phy_base + HDMI_PHY_STATUS), @@ -1727,6 +1777,7 @@ static struct clk_ops hdmi_vco_clk_ops = { .get_rate = hdmi_vco_get_rate, .round_rate = hdmi_vco_round_rate, .prepare = hdmi_vco_prepare, + .unprepare = hdmi_vco_unprepare, .disable = hdmi_vco_disable, .handoff = hdmi_vco_handoff, }; @@ -1786,9 +1837,24 @@ static struct div_clk hdmipll_div6_clk = { static int hdmipll_set_mux_sel(struct mux_clk *clk, int mux_sel) { + int rc; + + if (!mdss_gdsc_enabled()) { + pr_err("%s: mdss GDSC is not enabled\n", __func__); + return -EPERM; + } + + rc = clk_enable(mdss_ahb_clk); + if (rc) { + pr_err("%s: Failed to enable mdss ahb clock\n", __func__); + return rc; + } + pr_debug("%s: mux_sel=%d\n", __func__, mux_sel); DSS_REG_W(hdmi_phy_pll_base, HDMI_UNI_PLL_POSTDIV1_CFG, mux_sel); + clk_disable(mdss_ahb_clk); + return 0; } @@ -1797,13 +1863,14 @@ static int hdmipll_get_mux_sel(struct mux_clk *clk) int mux_sel = 0; if (mdss_ahb_clk_enable(1)) { - pr_debug("%s: Failed to enable mdss ahb clock\n", __func__); - return 1; + pr_err("%s: Failed to enable mdss ahb clock\n", __func__); + return mux_sel; } mux_sel = DSS_REG_R(hdmi_phy_pll_base, HDMI_UNI_PLL_POSTDIV1_CFG); mux_sel &= 0x03; pr_debug("%s: mux_sel=%d\n", __func__, mux_sel); + mdss_ahb_clk_enable(0); return mux_sel;