aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Boyd <sboyd@codeaurora.org>2014-07-11 15:55:27 -0400
committerStephen Boyd <sboyd@codeaurora.org>2014-07-15 19:38:59 -0400
commit404c1ff67d241e8503fd46a09d324343aa321a8a (patch)
treeef9e18a1029de024540d02550d1a99d162d164a1
parent24d8fba44af32163334c1f162e65ba93eb2993fd (diff)
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 <robdclark@gmail.com> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-rw-r--r--drivers/clk/qcom/clk-rcg.c51
-rw-r--r--drivers/clk/qcom/clk-rcg.h1
-rw-r--r--drivers/clk/qcom/mmcc-msm8960.c9
3 files changed, 47 insertions, 14 deletions
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,
417 return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p); 417 return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p);
418} 418}
419 419
420static int clk_rcg_set_rate(struct clk_hw *hw, unsigned long rate, 420static long clk_rcg_bypass_determine_rate(struct clk_hw *hw, unsigned long rate,
421 unsigned long parent_rate) 421 unsigned long *p_rate, struct clk **p)
422{ 422{
423 struct clk_rcg *rcg = to_clk_rcg(hw); 423 struct clk_rcg *rcg = to_clk_rcg(hw);
424 const struct freq_tbl *f; 424 const struct freq_tbl *f = rcg->freq_tbl;
425
426 *p = clk_get_parent_by_index(hw->clk, f->src);
427 *p_rate = __clk_round_rate(*p, rate);
428
429 return *p_rate;
430}
431
432static int __clk_rcg_set_rate(struct clk_rcg *rcg, const struct freq_tbl *f)
433{
425 u32 ns, md, ctl; 434 u32 ns, md, ctl;
426 struct mn *mn = &rcg->mn; 435 struct mn *mn = &rcg->mn;
427 u32 mask = 0; 436 u32 mask = 0;
428 unsigned int reset_reg; 437 unsigned int reset_reg;
429 438
430 f = find_freq(rcg->freq_tbl, rate);
431 if (!f)
432 return -EINVAL;
433
434 if (rcg->mn.reset_in_cc) 439 if (rcg->mn.reset_in_cc)
435 reset_reg = rcg->clkr.enable_reg; 440 reset_reg = rcg->clkr.enable_reg;
436 else 441 else
@@ -466,6 +471,27 @@ static int clk_rcg_set_rate(struct clk_hw *hw, unsigned long rate,
466 return 0; 471 return 0;
467} 472}
468 473
474static int clk_rcg_set_rate(struct clk_hw *hw, unsigned long rate,
475 unsigned long parent_rate)
476{
477 struct clk_rcg *rcg = to_clk_rcg(hw);
478 const struct freq_tbl *f;
479
480 f = find_freq(rcg->freq_tbl, rate);
481 if (!f)
482 return -EINVAL;
483
484 return __clk_rcg_set_rate(rcg, f);
485}
486
487static int clk_rcg_bypass_set_rate(struct clk_hw *hw, unsigned long rate,
488 unsigned long parent_rate)
489{
490 struct clk_rcg *rcg = to_clk_rcg(hw);
491
492 return __clk_rcg_set_rate(rcg, rcg->freq_tbl);
493}
494
469static int __clk_dyn_rcg_set_rate(struct clk_hw *hw, unsigned long rate) 495static int __clk_dyn_rcg_set_rate(struct clk_hw *hw, unsigned long rate)
470{ 496{
471 struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); 497 struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);
@@ -503,6 +529,17 @@ const struct clk_ops clk_rcg_ops = {
503}; 529};
504EXPORT_SYMBOL_GPL(clk_rcg_ops); 530EXPORT_SYMBOL_GPL(clk_rcg_ops);
505 531
532const struct clk_ops clk_rcg_bypass_ops = {
533 .enable = clk_enable_regmap,
534 .disable = clk_disable_regmap,
535 .get_parent = clk_rcg_get_parent,
536 .set_parent = clk_rcg_set_parent,
537 .recalc_rate = clk_rcg_recalc_rate,
538 .determine_rate = clk_rcg_bypass_determine_rate,
539 .set_rate = clk_rcg_bypass_set_rate,
540};
541EXPORT_SYMBOL_GPL(clk_rcg_bypass_ops);
542
506const struct clk_ops clk_dyn_rcg_ops = { 543const struct clk_ops clk_dyn_rcg_ops = {
507 .enable = clk_enable_regmap, 544 .enable = clk_enable_regmap,
508 .is_enabled = clk_is_enabled_regmap, 545 .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 {
95}; 95};
96 96
97extern const struct clk_ops clk_rcg_ops; 97extern const struct clk_ops clk_rcg_ops;
98extern const struct clk_ops clk_rcg_bypass_ops;
98 99
99#define to_clk_rcg(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg, clkr) 100#define to_clk_rcg(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg, clkr)
100 101
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[] = {
1218}; 1218};
1219 1219
1220static struct freq_tbl clk_tbl_tv[] = { 1220static struct freq_tbl clk_tbl_tv[] = {
1221 { 25200000, P_HDMI_PLL, 1, 0, 0 }, 1221 { .src = P_HDMI_PLL, .pre_div = 1 },
1222 { 27000000, P_HDMI_PLL, 1, 0, 0 },
1223 { 27030000, P_HDMI_PLL, 1, 0, 0 },
1224 { 74250000, P_HDMI_PLL, 1, 0, 0 },
1225 { 108000000, P_HDMI_PLL, 1, 0, 0 },
1226 { 148500000, P_HDMI_PLL, 1, 0, 0 },
1227 { } 1222 { }
1228}; 1223};
1229 1224
@@ -1254,7 +1249,7 @@ static struct clk_rcg tv_src = {
1254 .name = "tv_src", 1249 .name = "tv_src",
1255 .parent_names = mmcc_pxo_hdmi, 1250 .parent_names = mmcc_pxo_hdmi,
1256 .num_parents = 2, 1251 .num_parents = 2,
1257 .ops = &clk_rcg_ops, 1252 .ops = &clk_rcg_bypass_ops,
1258 .flags = CLK_SET_RATE_PARENT, 1253 .flags = CLK_SET_RATE_PARENT,
1259 }, 1254 },
1260 }, 1255 },