From: Stephen Boyd Date: Fri, 11 Jul 2014 19:55:27 +0000 (-0700) Subject: clk: qcom: Support bypass RCG configuration X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=404c1ff67d241e8503fd46a09d324343aa321a8a;p=openwrt%2Fstaging%2Fblogic.git clk: qcom: Support bypass RCG configuration In the case of HDMI clocks, we want to bypass the RCG's ability to divide the output clock and pass through the parent HDMI PLL rate. Add a simple set of clk_ops to configure the RCG to do this. This removes the need to keep adding more frequency entries to the tv_src clock whenever we want to support a new rate. Tested-by: Rob Clark Signed-off-by: Stephen Boyd --- diff --git a/drivers/clk/qcom/clk-rcg.c b/drivers/clk/qcom/clk-rcg.c index abfc2b675aea..b638c5846dbf 100644 --- a/drivers/clk/qcom/clk-rcg.c +++ b/drivers/clk/qcom/clk-rcg.c @@ -417,20 +417,25 @@ static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate, return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p); } -static int clk_rcg_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) +static long clk_rcg_bypass_determine_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *p_rate, struct clk **p) { struct clk_rcg *rcg = to_clk_rcg(hw); - const struct freq_tbl *f; + const struct freq_tbl *f = rcg->freq_tbl; + + *p = clk_get_parent_by_index(hw->clk, f->src); + *p_rate = __clk_round_rate(*p, rate); + + return *p_rate; +} + +static int __clk_rcg_set_rate(struct clk_rcg *rcg, const struct freq_tbl *f) +{ u32 ns, md, ctl; struct mn *mn = &rcg->mn; u32 mask = 0; unsigned int reset_reg; - f = find_freq(rcg->freq_tbl, rate); - if (!f) - return -EINVAL; - if (rcg->mn.reset_in_cc) reset_reg = rcg->clkr.enable_reg; else @@ -466,6 +471,27 @@ static int clk_rcg_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } +static int clk_rcg_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_rcg *rcg = to_clk_rcg(hw); + const struct freq_tbl *f; + + f = find_freq(rcg->freq_tbl, rate); + if (!f) + return -EINVAL; + + return __clk_rcg_set_rate(rcg, f); +} + +static int clk_rcg_bypass_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_rcg *rcg = to_clk_rcg(hw); + + return __clk_rcg_set_rate(rcg, rcg->freq_tbl); +} + static int __clk_dyn_rcg_set_rate(struct clk_hw *hw, unsigned long rate) { struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); @@ -503,6 +529,17 @@ const struct clk_ops clk_rcg_ops = { }; EXPORT_SYMBOL_GPL(clk_rcg_ops); +const struct clk_ops clk_rcg_bypass_ops = { + .enable = clk_enable_regmap, + .disable = clk_disable_regmap, + .get_parent = clk_rcg_get_parent, + .set_parent = clk_rcg_set_parent, + .recalc_rate = clk_rcg_recalc_rate, + .determine_rate = clk_rcg_bypass_determine_rate, + .set_rate = clk_rcg_bypass_set_rate, +}; +EXPORT_SYMBOL_GPL(clk_rcg_bypass_ops); + const struct clk_ops clk_dyn_rcg_ops = { .enable = clk_enable_regmap, .is_enabled = clk_is_enabled_regmap, diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index b9ec11dfd1b4..ba0523cefd2e 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -95,6 +95,7 @@ struct clk_rcg { }; extern const struct clk_ops clk_rcg_ops; +extern const struct clk_ops clk_rcg_bypass_ops; #define to_clk_rcg(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg, clkr) diff --git a/drivers/clk/qcom/mmcc-msm8960.c b/drivers/clk/qcom/mmcc-msm8960.c index 12f3c0b64fcd..14eeeba005f3 100644 --- a/drivers/clk/qcom/mmcc-msm8960.c +++ b/drivers/clk/qcom/mmcc-msm8960.c @@ -1218,12 +1218,7 @@ static const char *mmcc_pxo_hdmi[] = { }; static struct freq_tbl clk_tbl_tv[] = { - { 25200000, P_HDMI_PLL, 1, 0, 0 }, - { 27000000, P_HDMI_PLL, 1, 0, 0 }, - { 27030000, P_HDMI_PLL, 1, 0, 0 }, - { 74250000, P_HDMI_PLL, 1, 0, 0 }, - { 108000000, P_HDMI_PLL, 1, 0, 0 }, - { 148500000, P_HDMI_PLL, 1, 0, 0 }, + { .src = P_HDMI_PLL, .pre_div = 1 }, { } }; @@ -1254,7 +1249,7 @@ static struct clk_rcg tv_src = { .name = "tv_src", .parent_names = mmcc_pxo_hdmi, .num_parents = 2, - .ops = &clk_rcg_ops, + .ops = &clk_rcg_bypass_ops, .flags = CLK_SET_RATE_PARENT, }, },