aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Guo <shawn.guo@linaro.org>2013-06-02 10:20:55 -0400
committerNitin Garg <nitin.garg@freescale.com>2014-04-16 09:00:33 -0400
commitd350678d0d9744e639ebd5435dc2ced29b9c00d9 (patch)
tree0bffa435f9ac8e713c10ba1dc479e1262d9e882b
parenta43e02cf87d0c1ddce1719d93478f0f6a3a095e8 (diff)
clk: divider: do not propagate rate change request when unnecessary
Commit 081c9025f49da427faf50b5c14143f98a21c5e85 upstream. If the current rate of parent clock is sufficient to provide child a requested rate with a proper divider setting, the rate change request should not be propagated. Instead, changing the divider setting is good enough to get child clock run at the requested rate. On an imx6q clock configuration illustrated below, ahb --> ipg --> ipg_per 132M 66M 66M calling clk_set_rate(ipg_per, 22M) with the current clk_divider_bestdiv() implementation will result in the rate change up to ahb level like the following, because of the unnecessary/incorrect rate change propagation. ahb --> ipg --> ipg_per 66M 22M 22M Fix the problem by trying to see if the requested rate can be achieved by simply changing the divider value, and in that case return the divider immediately from function clk_divider_bestdiv() as the best one, so that all those unnecessary rate change propagation can be saved. Reported-by: Anson Huang <b20788@freescale.com> Signed-off-by: Shawn Guo <shawn.guo@linaro.org> Signed-off-by: Mike Turquette <mturquette@linaro.org> Signed-off-by: Shawn Guo <shawn.guo@freescale.com>
-rw-r--r--drivers/clk/clk-divider.c10
1 files changed, 10 insertions, 0 deletions
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 2ce22447d76e..945405fee1ab 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -150,6 +150,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
150 struct clk_divider *divider = to_clk_divider(hw); 150 struct clk_divider *divider = to_clk_divider(hw);
151 int i, bestdiv = 0; 151 int i, bestdiv = 0;
152 unsigned long parent_rate, best = 0, now, maxdiv; 152 unsigned long parent_rate, best = 0, now, maxdiv;
153 unsigned long parent_rate_saved = *best_parent_rate;
153 154
154 if (!rate) 155 if (!rate)
155 rate = 1; 156 rate = 1;
@@ -173,6 +174,15 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
173 for (i = 1; i <= maxdiv; i++) { 174 for (i = 1; i <= maxdiv; i++) {
174 if (!_is_valid_div(divider, i)) 175 if (!_is_valid_div(divider, i))
175 continue; 176 continue;
177 if (rate * i == parent_rate_saved) {
178 /*
179 * It's the most ideal case if the requested rate can be
180 * divided from parent clock without needing to change
181 * parent rate, so return the divider immediately.
182 */
183 *best_parent_rate = parent_rate_saved;
184 return i;
185 }
176 parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 186 parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
177 MULT_ROUND_UP(rate, i)); 187 MULT_ROUND_UP(rate, i));
178 now = parent_rate / i; 188 now = parent_rate / i;