aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk/clk-composite.c
diff options
context:
space:
mode:
authorBoris BREZILLON <b.brezillon@overkiz.com>2014-07-02 19:56:45 -0400
committerMike Turquette <mturquette@linaro.org>2014-07-13 15:16:08 -0400
commit3eb635f1ca2d25bd11a697f5bdb52ac3d08c240e (patch)
treeabf4cea3e07c44c2049078c35b9cf3e70138192a /drivers/clk/clk-composite.c
parent4c834452aad01531db949414f94f817a86348d59 (diff)
clk: composite: support determine_rate using rate_ops->round_rate + mux_ops->set_parent
In case the rate_hw does not implement determine_rate, but only round_rate we fallback to best_parent selection if mux_hw is present and support reparenting. This also fixes a rate calculation problem when using the standard div and mux ops, as in this case currently only the mux->determine_rate is used in the composite rate calculation. So when for example the composite clock has two parents at 600 and 800MHz, the requested rate is 75MHz, which the divider could provide, without this change the rate would be set 600MHz ignoring the divider completely. This may be way out of spec for the component. Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com> Signed-off-by: Heiko Stuebner <heiko@sntech.de> [heiko@sntech.de: fixed output return a rate instead of the diff] Acked-By: Max Schwarz <max.schwarz@online.de> Tested-By: Max Schwarz <max.schwarz@online.de> Tested-by: Gabriel Fernandez <gabriel.fernandez@linaro.org> Signed-off-by: Mike Turquette <mturquette@linaro.org>
Diffstat (limited to 'drivers/clk/clk-composite.c')
-rw-r--r--drivers/clk/clk-composite.c48
1 files changed, 47 insertions, 1 deletions
diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c
index 57a078e06efe..9548bfcbd56b 100644
--- a/drivers/clk/clk-composite.c
+++ b/drivers/clk/clk-composite.c
@@ -64,11 +64,56 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
64 const struct clk_ops *mux_ops = composite->mux_ops; 64 const struct clk_ops *mux_ops = composite->mux_ops;
65 struct clk_hw *rate_hw = composite->rate_hw; 65 struct clk_hw *rate_hw = composite->rate_hw;
66 struct clk_hw *mux_hw = composite->mux_hw; 66 struct clk_hw *mux_hw = composite->mux_hw;
67 struct clk *parent;
68 unsigned long parent_rate;
69 long tmp_rate, best_rate = 0;
70 unsigned long rate_diff;
71 unsigned long best_rate_diff = ULONG_MAX;
72 int i;
67 73
68 if (rate_hw && rate_ops && rate_ops->determine_rate) { 74 if (rate_hw && rate_ops && rate_ops->determine_rate) {
69 rate_hw->clk = hw->clk; 75 rate_hw->clk = hw->clk;
70 return rate_ops->determine_rate(rate_hw, rate, best_parent_rate, 76 return rate_ops->determine_rate(rate_hw, rate, best_parent_rate,
71 best_parent_p); 77 best_parent_p);
78 } else if (rate_hw && rate_ops && rate_ops->round_rate &&
79 mux_hw && mux_ops && mux_ops->set_parent) {
80 *best_parent_p = NULL;
81
82 if (__clk_get_flags(hw->clk) & CLK_SET_RATE_NO_REPARENT) {
83 *best_parent_p = clk_get_parent(mux_hw->clk);
84 *best_parent_rate = __clk_get_rate(*best_parent_p);
85
86 return rate_ops->round_rate(rate_hw, rate,
87 best_parent_rate);
88 }
89
90 for (i = 0; i < __clk_get_num_parents(mux_hw->clk); i++) {
91 parent = clk_get_parent_by_index(mux_hw->clk, i);
92 if (!parent)
93 continue;
94
95 parent_rate = __clk_get_rate(parent);
96
97 tmp_rate = rate_ops->round_rate(rate_hw, rate,
98 &parent_rate);
99 if (tmp_rate < 0)
100 continue;
101
102 rate_diff = abs(rate - tmp_rate);
103
104 if (!rate_diff || !*best_parent_p
105 || best_rate_diff > rate_diff) {
106 *best_parent_p = parent;
107 *best_parent_rate = parent_rate;
108 best_rate_diff = rate_diff;
109 best_rate = tmp_rate;
110 }
111
112 if (!rate_diff)
113 return rate;
114 }
115
116 return best_rate;
72 } else if (mux_hw && mux_ops && mux_ops->determine_rate) { 117 } else if (mux_hw && mux_ops && mux_ops->determine_rate) {
73 mux_hw->clk = hw->clk; 118 mux_hw->clk = hw->clk;
74 return mux_ops->determine_rate(mux_hw, rate, best_parent_rate, 119 return mux_ops->determine_rate(mux_hw, rate, best_parent_rate,
@@ -196,7 +241,8 @@ struct clk *clk_register_composite(struct device *dev, const char *name,
196 composite->rate_hw = rate_hw; 241 composite->rate_hw = rate_hw;
197 composite->rate_ops = rate_ops; 242 composite->rate_ops = rate_ops;
198 clk_composite_ops->recalc_rate = clk_composite_recalc_rate; 243 clk_composite_ops->recalc_rate = clk_composite_recalc_rate;
199 if (rate_ops->determine_rate) 244 if (rate_ops->determine_rate ||
245 (rate_ops->round_rate && clk_composite_ops->set_parent))
200 clk_composite_ops->determine_rate = clk_composite_determine_rate; 246 clk_composite_ops->determine_rate = clk_composite_determine_rate;
201 } 247 }
202 248