[PATCH 2/2] clk: qcom: Modify RCG shared ops to support freq_tbl without XO entry

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



There could be some clock sources where there is no entry corresponding
XO in their frequency table, for such sources rcg2_shared_ops would
wrongly configure the RCG registers during enable/disable, which leads
to mismatch between the hardware and software rate so modify the shared
ops to handle such cases.

Signed-off-by: Amit Nischal <anischal@xxxxxxxxxxxxxx>
---
 drivers/clk/qcom/clk-rcg2.c | 79 +++++++++++++++++++++++++++++++++++++++------
 1 file changed, 70 insertions(+), 9 deletions(-)

diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index ac9ce61..8f7ca0c 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -48,6 +48,14 @@
 #define N_REG			0xc
 #define D_REG			0x10

+static struct freq_tbl cxo_f = {
+	.freq = 19200000,
+	.src = 0,
+	.pre_div = 1,
+	.m = 0,
+	.n = 0,
+};
+
 enum freq_policy {
 	FLOOR,
 	CEIL,
@@ -359,7 +367,7 @@ static int clk_rcg2_set_floor_rate_and_parent(struct clk_hw *hw,
 };
 EXPORT_SYMBOL_GPL(clk_rcg2_floor_ops);

-static int clk_rcg2_shared_force_enable(struct clk_hw *hw, unsigned long rate)
+static int clk_rcg2_set_force_enable(struct clk_hw *hw)
 {
 	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
 	const char *name = clk_hw_get_name(hw);
@@ -373,22 +381,41 @@ static int clk_rcg2_shared_force_enable(struct clk_hw *hw, unsigned long rate)

 	/* wait for RCG to turn ON */
 	for (count = 500; count > 0; count--) {
-		ret = clk_rcg2_is_enabled(hw);
-		if (ret)
-			break;
+		if (clk_rcg2_is_enabled(hw))
+			return 0;
+
+		/* Delay for 1usec and retry polling the status bit */
 		udelay(1);
 	}
 	if (!count)
 		pr_err("%s: RCG did not turn on\n", name);

+	return -ETIMEDOUT;
+}
+
+static int clk_rcg2_clear_force_enable(struct clk_hw *hw)
+{
+	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+
+	/* clear force enable RCG */
+	return regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
+					CMD_ROOT_EN, 0);
+}
+
+static int clk_rcg2_shared_force_enable(struct clk_hw *hw, unsigned long rate)
+{
+	int ret;
+
+	ret = clk_rcg2_set_force_enable(hw);
+	if (ret)
+		return ret;
+
 	/* set clock rate */
 	ret = __clk_rcg2_set_rate(hw, rate, CEIL);
 	if (ret)
 		return ret;

-	/* clear force enable RCG */
-	return regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
-				 CMD_ROOT_EN, 0);
+	return clk_rcg2_clear_force_enable(hw);
 }

 static int clk_rcg2_shared_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -399,6 +426,11 @@ static int clk_rcg2_shared_set_rate(struct clk_hw *hw, unsigned long rate,
 	/* cache the rate */
 	rcg->current_freq = rate;

+	/*
+	 * Return if the RCG is currently disabled. This configuration
+	 * update will happen as part of the RCG enable sequence.
+	 */
+
 	if (!__clk_is_enabled(hw->clk))
 		return 0;

@@ -410,6 +442,12 @@ static int clk_rcg2_shared_set_rate(struct clk_hw *hw, unsigned long rate,
 {
 	struct clk_rcg2 *rcg = to_clk_rcg2(hw);

+	if (!__clk_is_enabled(hw->clk)) {
+		if (!rcg->current_freq)
+			rcg->current_freq = cxo_f.freq;
+		return rcg->current_freq;
+	}
+
 	return rcg->current_freq = clk_rcg2_recalc_rate(hw, parent_rate);
 }

@@ -417,6 +455,20 @@ static int clk_rcg2_shared_enable(struct clk_hw *hw)
 {
 	struct clk_rcg2 *rcg = to_clk_rcg2(hw);

+	if (rcg->current_freq == cxo_f.freq) {
+		clk_rcg2_set_force_enable(hw);
+		clk_rcg2_configure(rcg, &cxo_f);
+		clk_rcg2_clear_force_enable(hw);
+
+		return 0;
+	}
+
+	/*
+	 * Switch from CXO to the stashed mux selection. The current
+	 * parent has already been prepared and enabled at this point,
+	 * and the CXO source is always on while application processor
+	 * subsystem is online. Therefore, the RCG can safely be switched.
+	 */
 	return clk_rcg2_shared_force_enable(hw, rcg->current_freq);
 }

@@ -424,8 +476,17 @@ static void clk_rcg2_shared_disable(struct clk_hw *hw)
 {
 	struct clk_rcg2 *rcg = to_clk_rcg2(hw);

-	/* switch to XO, which is the lowest entry in the freq table */
-	clk_rcg2_shared_set_rate(hw, rcg->freq_tbl[0].freq, 0);
+	/*
+	 * Park the RCG at a safe configuration - sourced off the CXO.
+	 * Force enable and disable the RCG while configuring it to
+	 * safeguard against any update signal coming from the downstream
+	 * clock. The current parent is still prepared and enabled at this
+	 * point, and the CXO source is always on while application processor
+	 * subsystem is online. Therefore, the RCG can safely be switched.
+	 */
+	clk_rcg2_set_force_enable(hw);
+	clk_rcg2_configure(rcg, &cxo_f);
+	clk_rcg2_clear_force_enable(hw);
 }

 const struct clk_ops clk_rcg2_shared_ops = {
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [Linux for Sparc]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux