diff options
Diffstat (limited to 'drivers/clk/clk-divider.c')
-rw-r--r-- | drivers/clk/clk-divider.c | 29 |
1 files changed, 14 insertions, 15 deletions
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index db7f8bce7467..25006a8bb8e6 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c | |||
@@ -144,12 +144,6 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, | |||
144 | divider->flags); | 144 | divider->flags); |
145 | } | 145 | } |
146 | 146 | ||
147 | /* | ||
148 | * The reverse of DIV_ROUND_UP: The maximum number which | ||
149 | * divided by m is r | ||
150 | */ | ||
151 | #define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1) | ||
152 | |||
153 | static bool _is_valid_table_div(const struct clk_div_table *table, | 147 | static bool _is_valid_table_div(const struct clk_div_table *table, |
154 | unsigned int div) | 148 | unsigned int div) |
155 | { | 149 | { |
@@ -225,19 +219,24 @@ static int _div_round_closest(const struct clk_div_table *table, | |||
225 | unsigned long parent_rate, unsigned long rate, | 219 | unsigned long parent_rate, unsigned long rate, |
226 | unsigned long flags) | 220 | unsigned long flags) |
227 | { | 221 | { |
228 | int up, down, div; | 222 | int up, down; |
223 | unsigned long up_rate, down_rate; | ||
229 | 224 | ||
230 | up = down = div = DIV_ROUND_CLOSEST(parent_rate, rate); | 225 | up = DIV_ROUND_UP(parent_rate, rate); |
226 | down = parent_rate / rate; | ||
231 | 227 | ||
232 | if (flags & CLK_DIVIDER_POWER_OF_TWO) { | 228 | if (flags & CLK_DIVIDER_POWER_OF_TWO) { |
233 | up = __roundup_pow_of_two(div); | 229 | up = __roundup_pow_of_two(up); |
234 | down = __rounddown_pow_of_two(div); | 230 | down = __rounddown_pow_of_two(down); |
235 | } else if (table) { | 231 | } else if (table) { |
236 | up = _round_up_table(table, div); | 232 | up = _round_up_table(table, up); |
237 | down = _round_down_table(table, div); | 233 | down = _round_down_table(table, down); |
238 | } | 234 | } |
239 | 235 | ||
240 | return (up - div) <= (div - down) ? up : down; | 236 | up_rate = DIV_ROUND_UP(parent_rate, up); |
237 | down_rate = DIV_ROUND_UP(parent_rate, down); | ||
238 | |||
239 | return (rate - up_rate) <= (down_rate - rate) ? up : down; | ||
241 | } | 240 | } |
242 | 241 | ||
243 | static int _div_round(const struct clk_div_table *table, | 242 | static int _div_round(const struct clk_div_table *table, |
@@ -313,7 +312,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, | |||
313 | return i; | 312 | return i; |
314 | } | 313 | } |
315 | parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), | 314 | parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), |
316 | MULT_ROUND_UP(rate, i)); | 315 | rate * i); |
317 | now = DIV_ROUND_UP(parent_rate, i); | 316 | now = DIV_ROUND_UP(parent_rate, i); |
318 | if (_is_best_div(rate, now, best, flags)) { | 317 | if (_is_best_div(rate, now, best, flags)) { |
319 | bestdiv = i; | 318 | bestdiv = i; |
@@ -353,7 +352,7 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, | |||
353 | bestdiv = readl(divider->reg) >> divider->shift; | 352 | bestdiv = readl(divider->reg) >> divider->shift; |
354 | bestdiv &= div_mask(divider->width); | 353 | bestdiv &= div_mask(divider->width); |
355 | bestdiv = _get_div(divider->table, bestdiv, divider->flags); | 354 | bestdiv = _get_div(divider->table, bestdiv, divider->flags); |
356 | return bestdiv; | 355 | return DIV_ROUND_UP(*prate, bestdiv); |
357 | } | 356 | } |
358 | 357 | ||
359 | return divider_round_rate(hw, rate, prate, divider->table, | 358 | return divider_round_rate(hw, rate, prate, divider->table, |