aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk/clk-divider.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/clk-divider.c')
-rw-r--r--drivers/clk/clk-divider.c58
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
33static unsigned int _get_table_maxdiv(const struct clk_div_table *table, 31static 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
68static unsigned int _get_table_div(const struct clk_div_table *table, 66static 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}
345EXPORT_SYMBOL_GPL(divider_round_rate_parent); 343EXPORT_SYMBOL_GPL(divider_round_rate_parent);
346 344
345long 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}
364EXPORT_SYMBOL_GPL(divider_ro_round_rate_parent);
365
366
347static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, 367static 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}
381EXPORT_SYMBOL_GPL(divider_get_val); 403EXPORT_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);