summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUwe Kleine-König <u.kleine-koenig@pengutronix.de>2015-02-21 11:40:24 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-04-19 10:10:26 +0200
commit765c20456c868989e179b14640ebe65347f2f57a (patch)
tree2ce9a464982b069aaebbb08331a4d4802f9a9d4c
parent4858bcfdbcddd3e319f7621bb8044ebec2bacbeb (diff)
downloadlinux-stable-765c20456c868989e179b14640ebe65347f2f57a.tar.gz
linux-stable-765c20456c868989e179b14640ebe65347f2f57a.tar.bz2
linux-stable-765c20456c868989e179b14640ebe65347f2f57a.zip
clk: divider: fix selection of divider when rounding to closest
commit 26bac95aa88c2b1747808c0b885abe7814c0165d upstream. It's an invalid approach to assume that among two divider values the one nearer the exact divider is the better one. Assume a parent rate of 1000 Hz, a divider with CLK_DIVIDER_POWER_OF_TWO and a target rate of 89 Hz. The exact divider is ~ 11.236 so 8 and 16 are the candidates to choose from yielding rates 125 Hz and 62.5 Hz respectivly. While 8 is nearer to 11.236 than 16 is, the latter is still the better divider as 62.5 is nearer to 89 than 125 is. Fixes: 774b514390b1 (clk: divider: Add round to closest divider) Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Acked-by: Sascha Hauer <s.hauer@pengutronix.de> Acked-by: Maxime Coquelin <maxime.coquelin@st.com> Signed-off-by: Michael Turquette <mturquette@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/clk/clk-divider.c6
1 files changed, 5 insertions, 1 deletions
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index c0a842b335c5..0c0a865c1266 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -208,6 +208,7 @@ static int _div_round_closest(struct clk_divider *divider,
unsigned long parent_rate, unsigned long rate)
{
int up, down, div;
+ unsigned long up_rate, down_rate;
up = down = div = DIV_ROUND_CLOSEST(parent_rate, rate);
@@ -219,7 +220,10 @@ static int _div_round_closest(struct clk_divider *divider,
down = _round_down_table(divider->table, div);
}
- return (up - div) <= (div - down) ? up : down;
+ up_rate = DIV_ROUND_UP(parent_rate, up);
+ down_rate = DIV_ROUND_UP(parent_rate, down);
+
+ return (rate - up_rate) <= (down_rate - rate) ? up : down;
}
static int _div_round(struct clk_divider *divider, unsigned long parent_rate,