diff options
Diffstat (limited to 'drivers/clk/clk-divider.c')
-rw-r--r-- | drivers/clk/clk-divider.c | 58 |
1 files changed, 40 insertions, 18 deletions
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index b49942b9fe50..b6234a5da12d 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c | |||
@@ -28,12 +28,10 @@ | |||
28 | * parent - fixed parent. No clk_set_parent support | 28 | * parent - fixed parent. No clk_set_parent support |
29 | */ | 29 | */ |
30 | 30 | ||
31 | #define div_mask(width) ((1 << (width)) - 1) | ||
32 | |||
33 | static unsigned int _get_table_maxdiv(const struct clk_div_table *table, | 31 | static unsigned int _get_table_maxdiv(const struct clk_div_table *table, |
34 | u8 width) | 32 | u8 width) |
35 | { | 33 | { |
36 | unsigned int maxdiv = 0, mask = div_mask(width); | 34 | unsigned int maxdiv = 0, mask = clk_div_mask(width); |
37 | const struct clk_div_table *clkt; | 35 | const struct clk_div_table *clkt; |
38 | 36 | ||
39 | for (clkt = table; clkt->div; clkt++) | 37 | for (clkt = table; clkt->div; clkt++) |
@@ -57,12 +55,12 @@ static unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width, | |||
57 | unsigned long flags) | 55 | unsigned long flags) |
58 | { | 56 | { |
59 | if (flags & CLK_DIVIDER_ONE_BASED) | 57 | if (flags & CLK_DIVIDER_ONE_BASED) |
60 | return div_mask(width); | 58 | return clk_div_mask(width); |
61 | if (flags & CLK_DIVIDER_POWER_OF_TWO) | 59 | if (flags & CLK_DIVIDER_POWER_OF_TWO) |
62 | return 1 << div_mask(width); | 60 | return 1 << clk_div_mask(width); |
63 | if (table) | 61 | if (table) |
64 | return _get_table_maxdiv(table, width); | 62 | return _get_table_maxdiv(table, width); |
65 | return div_mask(width) + 1; | 63 | return clk_div_mask(width) + 1; |
66 | } | 64 | } |
67 | 65 | ||
68 | static unsigned int _get_table_div(const struct clk_div_table *table, | 66 | static unsigned int _get_table_div(const struct clk_div_table *table, |
@@ -84,7 +82,7 @@ static unsigned int _get_div(const struct clk_div_table *table, | |||
84 | if (flags & CLK_DIVIDER_POWER_OF_TWO) | 82 | if (flags & CLK_DIVIDER_POWER_OF_TWO) |
85 | return 1 << val; | 83 | return 1 << val; |
86 | if (flags & CLK_DIVIDER_MAX_AT_ZERO) | 84 | if (flags & CLK_DIVIDER_MAX_AT_ZERO) |
87 | return val ? val : div_mask(width) + 1; | 85 | return val ? val : clk_div_mask(width) + 1; |
88 | if (table) | 86 | if (table) |
89 | return _get_table_div(table, val); | 87 | return _get_table_div(table, val); |
90 | return val + 1; | 88 | return val + 1; |
@@ -109,7 +107,7 @@ static unsigned int _get_val(const struct clk_div_table *table, | |||
109 | if (flags & CLK_DIVIDER_POWER_OF_TWO) | 107 | if (flags & CLK_DIVIDER_POWER_OF_TWO) |
110 | return __ffs(div); | 108 | return __ffs(div); |
111 | if (flags & CLK_DIVIDER_MAX_AT_ZERO) | 109 | if (flags & CLK_DIVIDER_MAX_AT_ZERO) |
112 | return (div == div_mask(width) + 1) ? 0 : div; | 110 | return (div == clk_div_mask(width) + 1) ? 0 : div; |
113 | if (table) | 111 | if (table) |
114 | return _get_table_val(table, div); | 112 | return _get_table_val(table, div); |
115 | return div - 1; | 113 | return div - 1; |
@@ -141,7 +139,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, | |||
141 | unsigned int val; | 139 | unsigned int val; |
142 | 140 | ||
143 | val = clk_readl(divider->reg) >> divider->shift; | 141 | val = clk_readl(divider->reg) >> divider->shift; |
144 | val &= div_mask(divider->width); | 142 | val &= clk_div_mask(divider->width); |
145 | 143 | ||
146 | return divider_recalc_rate(hw, parent_rate, val, divider->table, | 144 | return divider_recalc_rate(hw, parent_rate, val, divider->table, |
147 | divider->flags, divider->width); | 145 | divider->flags, divider->width); |
@@ -344,19 +342,43 @@ long divider_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent, | |||
344 | } | 342 | } |
345 | EXPORT_SYMBOL_GPL(divider_round_rate_parent); | 343 | EXPORT_SYMBOL_GPL(divider_round_rate_parent); |
346 | 344 | ||
345 | long divider_ro_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent, | ||
346 | unsigned long rate, unsigned long *prate, | ||
347 | const struct clk_div_table *table, u8 width, | ||
348 | unsigned long flags, unsigned int val) | ||
349 | { | ||
350 | int div; | ||
351 | |||
352 | div = _get_div(table, val, flags, width); | ||
353 | |||
354 | /* Even a read-only clock can propagate a rate change */ | ||
355 | if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) { | ||
356 | if (!parent) | ||
357 | return -EINVAL; | ||
358 | |||
359 | *prate = clk_hw_round_rate(parent, rate * div); | ||
360 | } | ||
361 | |||
362 | return DIV_ROUND_UP_ULL((u64)*prate, div); | ||
363 | } | ||
364 | EXPORT_SYMBOL_GPL(divider_ro_round_rate_parent); | ||
365 | |||
366 | |||
347 | static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, | 367 | static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, |
348 | unsigned long *prate) | 368 | unsigned long *prate) |
349 | { | 369 | { |
350 | struct clk_divider *divider = to_clk_divider(hw); | 370 | struct clk_divider *divider = to_clk_divider(hw); |
351 | int bestdiv; | ||
352 | 371 | ||
353 | /* if read only, just return current value */ | 372 | /* if read only, just return current value */ |
354 | if (divider->flags & CLK_DIVIDER_READ_ONLY) { | 373 | if (divider->flags & CLK_DIVIDER_READ_ONLY) { |
355 | bestdiv = clk_readl(divider->reg) >> divider->shift; | 374 | u32 val; |
356 | bestdiv &= div_mask(divider->width); | 375 | |
357 | bestdiv = _get_div(divider->table, bestdiv, divider->flags, | 376 | val = clk_readl(divider->reg) >> divider->shift; |
358 | divider->width); | 377 | val &= clk_div_mask(divider->width); |
359 | return DIV_ROUND_UP_ULL((u64)*prate, bestdiv); | 378 | |
379 | return divider_ro_round_rate(hw, rate, prate, divider->table, | ||
380 | divider->width, divider->flags, | ||
381 | val); | ||
360 | } | 382 | } |
361 | 383 | ||
362 | return divider_round_rate(hw, rate, prate, divider->table, | 384 | return divider_round_rate(hw, rate, prate, divider->table, |
@@ -376,7 +398,7 @@ int divider_get_val(unsigned long rate, unsigned long parent_rate, | |||
376 | 398 | ||
377 | value = _get_val(table, div, flags, width); | 399 | value = _get_val(table, div, flags, width); |
378 | 400 | ||
379 | return min_t(unsigned int, value, div_mask(width)); | 401 | return min_t(unsigned int, value, clk_div_mask(width)); |
380 | } | 402 | } |
381 | EXPORT_SYMBOL_GPL(divider_get_val); | 403 | EXPORT_SYMBOL_GPL(divider_get_val); |
382 | 404 | ||
@@ -399,10 +421,10 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, | |||
399 | __acquire(divider->lock); | 421 | __acquire(divider->lock); |
400 | 422 | ||
401 | if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { | 423 | if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { |
402 | val = div_mask(divider->width) << (divider->shift + 16); | 424 | val = clk_div_mask(divider->width) << (divider->shift + 16); |
403 | } else { | 425 | } else { |
404 | val = clk_readl(divider->reg); | 426 | val = clk_readl(divider->reg); |
405 | val &= ~(div_mask(divider->width) << divider->shift); | 427 | val &= ~(clk_div_mask(divider->width) << divider->shift); |
406 | } | 428 | } |
407 | val |= (u32)value << divider->shift; | 429 | val |= (u32)value << divider->shift; |
408 | clk_writel(val, divider->reg); | 430 | clk_writel(val, divider->reg); |