[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1509434380-24372-3-git-send-email-anischal@codeaurora.org>
Date: Tue, 31 Oct 2017 12:49:40 +0530
From: Amit Nischal <anischal@...eaurora.org>
To: Stephen Boyd <sboyd@...eaurora.org>,
Michael Turquette <mturquette@...libre.com>
Cc: Andy Gross <andy.gross@...aro.org>,
David Brown <david.brown@...aro.org>,
Rajendra Nayak <rnayak@...eaurora.org>,
Odelu Kukatla <okukatla@...eaurora.org>,
linux-arm-msm@...r.kernel.org, linux-soc@...r.kernel.org,
linux-clk@...r.kernel.org, linux-kernel@...r.kernel.org,
Amit Nischal <anischal@...eaurora.org>
Subject: [PATCH 2/2] clk: qcom: Modify RCG shared ops to support freq_tbl without XO entry
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@...eaurora.org>
---
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
Powered by blists - more mailing lists