ARM: tegra: clock: Round frequency up in clock dividers
authorColin Cross <ccross@android.com>
Wed, 12 Jan 2011 00:59:55 +0000 (16:59 -0800)
committerColin Cross <ccross@android.com>
Wed, 12 Jan 2011 00:59:55 +0000 (16:59 -0800)
When picking clock divider values, the clock framework picks
the closest frequency that is lower than the requested
frequency.  If the value from a clock divider rounds down,
and then the new rounded down frequency is requested, it
will get rounded down again, resulting in a frequency two
steps lower than the original requested frequency.

Fix the problem by rounding up when calculating the frequency
coming out of a clock divider, so if that frequency is
requested again, the same divider value will be picked.

Change-Id: Ieaf74448f67d91aeb7ba08226e48c092d8afaa2b
Signed-off-by: Colin Cross <ccross@android.com>
arch/arm/mach-tegra/clock.c
arch/arm/mach-tegra/tegra2_clocks.c

index f55697765cdfd9a48b35977c4a593561e13b84f6..e97cc2532aef3d35cc849810a5c6bfba03a2b912 100644 (file)
@@ -143,6 +143,7 @@ static unsigned long clk_predict_rate_from_parent(struct clk *c, struct clk *p)
 
        if (c->mul != 0 && c->div != 0) {
                rate *= c->mul;
+               rate += c->div / 2; /* round up */
                do_div(rate, c->div);
        }
 
index b59e9c381f8546d1247107f82a2bcd0a34a0c5ff..3dcc11616e90578ebcba5a21deb82f2691d0cda2 100644 (file)
@@ -827,9 +827,9 @@ static long tegra2_pll_div_clk_round_rate(struct clk *c, unsigned long rate)
                divider = clk_div71_get_divider(parent_rate, rate);
                if (divider < 0)
                        return divider;
-               return parent_rate * 2 / (divider + 2);
+               return DIV_ROUND_UP(parent_rate * 2, divider + 2);
        } else if (c->flags & DIV_2) {
-               return parent_rate / 2;
+               return DIV_ROUND_UP(parent_rate, 2);
        }
        return -EINVAL;
 }
@@ -1006,12 +1006,12 @@ static long tegra2_periph_clk_round_rate(struct clk *c,
                if (divider < 0)
                        return divider;
 
-               return parent_rate * 2 / (divider + 2);
+               return DIV_ROUND_UP(parent_rate * 2, divider + 2);
        } else if (c->flags & DIV_U16) {
                divider = clk_div16_get_divider(parent_rate, rate);
                if (divider < 0)
                        return divider;
-               return parent_rate / (divider + 1);
+               return DIV_ROUND_UP(parent_rate, divider + 1);
        }
        return -EINVAL;
 }