msm: clock-8960: Properly hand off QDSS clocks

Some QDSS clocks come out of reset enabled. This causes problems
for drivers which wish to use the clocks during kernel init as
the clock driver view of the hardware isn't in sync with the
actual hardware state causing clk_set_rate() to hang the device
when it switches the clock to a PLL that is off. Hand off these
clocks so that drivers can call clk_set_rate() during kernel init
and not hang the system.

Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 34f78b7..5bd125b 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -1171,6 +1171,7 @@
 		.sys_vdd = v, \
 	}
 static struct clk_freq_tbl clk_tbl_qdss[] = {
+	F_QDSS( 27000000, pxo,  1, LOW),
 	F_QDSS(128000000, pll8, 3, LOW),
 	F_QDSS(300000000, pll3, 4, NOMINAL),
 	F_END
@@ -1182,6 +1183,38 @@
 	const u32 ns_mask;
 };
 
+#define QDSS_CLK_ROOT_ENA BIT(1)
+
+static void qdss_clk_handoff(struct clk *c)
+{
+	struct rcg_clk *clk = to_rcg_clk(c);
+	const struct qdss_bank *bank = clk->bank_info;
+	u32 reg, ns_val, bank_sel;
+	struct clk_freq_tbl *freq;
+
+	reg = readl_relaxed(clk->ns_reg);
+	if (!(reg & QDSS_CLK_ROOT_ENA))
+		return;
+
+	bank_sel = reg & bank->bank_sel_mask;
+	/* Force bank 1 to PXO if bank 0 is in use */
+	if (bank_sel == 0)
+		writel_relaxed(0, bank->ns_reg);
+	ns_val = readl_relaxed(bank->ns_reg) & bank->ns_mask;
+	for (freq = clk->freq_tbl; freq->freq_hz != FREQ_END; freq++) {
+		if ((freq->ns_val & bank->ns_mask) == ns_val) {
+			pr_info("%s rate=%d\n", clk->c.dbg_name, freq->freq_hz);
+			break;
+		}
+	}
+	if (freq->freq_hz == FREQ_END)
+		return;
+
+	clk->current_freq = freq;
+	c->flags |= CLKFLAG_HANDOFF_RATE;
+	clk_enable(c);
+}
+
 static void set_rate_qdss(struct rcg_clk *clk, struct clk_freq_tbl *nf)
 {
 	const struct qdss_bank *bank = clk->bank_info;
@@ -1267,6 +1300,7 @@
 	.enable = qdss_clk_enable,
 	.disable = qdss_clk_disable,
 	.auto_off = qdss_clk_auto_off,
+	.handoff = qdss_clk_handoff,
 	.set_rate = rcg_clk_set_rate,
 	.set_min_rate = rcg_clk_set_min_rate,
 	.get_rate = rcg_clk_get_rate,
@@ -1350,6 +1384,7 @@
 };
 
 static struct clk_freq_tbl clk_tbl_qdss_tsctr[] = {
+	F_QDSS( 27000000, pxo,  1, LOW),
 	F_QDSS(200000000, pll3, 6, LOW),
 	F_QDSS(400000000, pll3, 3, NOMINAL),
 	F_END