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.c228
1 files changed, 144 insertions, 84 deletions
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index c0a842b335c5..db7f8bce7467 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -30,7 +30,7 @@
30 30
31#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) 31#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
32 32
33#define div_mask(d) ((1 << ((d)->width)) - 1) 33#define div_mask(width) ((1 << (width)) - 1)
34 34
35static unsigned int _get_table_maxdiv(const struct clk_div_table *table) 35static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
36{ 36{
@@ -54,15 +54,16 @@ static unsigned int _get_table_mindiv(const struct clk_div_table *table)
54 return mindiv; 54 return mindiv;
55} 55}
56 56
57static unsigned int _get_maxdiv(struct clk_divider *divider) 57static unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width,
58 unsigned long flags)
58{ 59{
59 if (divider->flags & CLK_DIVIDER_ONE_BASED) 60 if (flags & CLK_DIVIDER_ONE_BASED)
60 return div_mask(divider); 61 return div_mask(width);
61 if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) 62 if (flags & CLK_DIVIDER_POWER_OF_TWO)
62 return 1 << div_mask(divider); 63 return 1 << div_mask(width);
63 if (divider->table) 64 if (table)
64 return _get_table_maxdiv(divider->table); 65 return _get_table_maxdiv(table);
65 return div_mask(divider) + 1; 66 return div_mask(width) + 1;
66} 67}
67 68
68static unsigned int _get_table_div(const struct clk_div_table *table, 69static unsigned int _get_table_div(const struct clk_div_table *table,
@@ -76,14 +77,15 @@ static unsigned int _get_table_div(const struct clk_div_table *table,
76 return 0; 77 return 0;
77} 78}
78 79
79static unsigned int _get_div(struct clk_divider *divider, unsigned int val) 80static unsigned int _get_div(const struct clk_div_table *table,
81 unsigned int val, unsigned long flags)
80{ 82{
81 if (divider->flags & CLK_DIVIDER_ONE_BASED) 83 if (flags & CLK_DIVIDER_ONE_BASED)
82 return val; 84 return val;
83 if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) 85 if (flags & CLK_DIVIDER_POWER_OF_TWO)
84 return 1 << val; 86 return 1 << val;
85 if (divider->table) 87 if (table)
86 return _get_table_div(divider->table, val); 88 return _get_table_div(table, val);
87 return val + 1; 89 return val + 1;
88} 90}
89 91
@@ -98,29 +100,28 @@ static unsigned int _get_table_val(const struct clk_div_table *table,
98 return 0; 100 return 0;
99} 101}
100 102
101static unsigned int _get_val(struct clk_divider *divider, unsigned int div) 103static unsigned int _get_val(const struct clk_div_table *table,
104 unsigned int div, unsigned long flags)
102{ 105{
103 if (divider->flags & CLK_DIVIDER_ONE_BASED) 106 if (flags & CLK_DIVIDER_ONE_BASED)
104 return div; 107 return div;
105 if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) 108 if (flags & CLK_DIVIDER_POWER_OF_TWO)
106 return __ffs(div); 109 return __ffs(div);
107 if (divider->table) 110 if (table)
108 return _get_table_val(divider->table, div); 111 return _get_table_val(table, div);
109 return div - 1; 112 return div - 1;
110} 113}
111 114
112static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, 115unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate,
113 unsigned long parent_rate) 116 unsigned int val,
117 const struct clk_div_table *table,
118 unsigned long flags)
114{ 119{
115 struct clk_divider *divider = to_clk_divider(hw); 120 unsigned int div;
116 unsigned int div, val;
117 121
118 val = clk_readl(divider->reg) >> divider->shift; 122 div = _get_div(table, val, flags);
119 val &= div_mask(divider);
120
121 div = _get_div(divider, val);
122 if (!div) { 123 if (!div) {
123 WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO), 124 WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO),
124 "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n", 125 "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
125 __clk_get_name(hw->clk)); 126 __clk_get_name(hw->clk));
126 return parent_rate; 127 return parent_rate;
@@ -128,6 +129,20 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
128 129
129 return DIV_ROUND_UP(parent_rate, div); 130 return DIV_ROUND_UP(parent_rate, div);
130} 131}
132EXPORT_SYMBOL_GPL(divider_recalc_rate);
133
134static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
135 unsigned long parent_rate)
136{
137 struct clk_divider *divider = to_clk_divider(hw);
138 unsigned int val;
139
140 val = clk_readl(divider->reg) >> divider->shift;
141 val &= div_mask(divider->width);
142
143 return divider_recalc_rate(hw, parent_rate, val, divider->table,
144 divider->flags);
145}
131 146
132/* 147/*
133 * The reverse of DIV_ROUND_UP: The maximum number which 148 * The reverse of DIV_ROUND_UP: The maximum number which
@@ -146,12 +161,13 @@ static bool _is_valid_table_div(const struct clk_div_table *table,
146 return false; 161 return false;
147} 162}
148 163
149static bool _is_valid_div(struct clk_divider *divider, unsigned int div) 164static bool _is_valid_div(const struct clk_div_table *table, unsigned int div,
165 unsigned long flags)
150{ 166{
151 if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) 167 if (flags & CLK_DIVIDER_POWER_OF_TWO)
152 return is_power_of_2(div); 168 return is_power_of_2(div);
153 if (divider->table) 169 if (table)
154 return _is_valid_table_div(divider->table, div); 170 return _is_valid_table_div(table, div);
155 return true; 171 return true;
156} 172}
157 173
@@ -191,71 +207,76 @@ static int _round_down_table(const struct clk_div_table *table, int div)
191 return down; 207 return down;
192} 208}
193 209
194static int _div_round_up(struct clk_divider *divider, 210static int _div_round_up(const struct clk_div_table *table,
195 unsigned long parent_rate, unsigned long rate) 211 unsigned long parent_rate, unsigned long rate,
212 unsigned long flags)
196{ 213{
197 int div = DIV_ROUND_UP(parent_rate, rate); 214 int div = DIV_ROUND_UP(parent_rate, rate);
198 215
199 if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) 216 if (flags & CLK_DIVIDER_POWER_OF_TWO)
200 div = __roundup_pow_of_two(div); 217 div = __roundup_pow_of_two(div);
201 if (divider->table) 218 if (table)
202 div = _round_up_table(divider->table, div); 219 div = _round_up_table(table, div);
203 220
204 return div; 221 return div;
205} 222}
206 223
207static int _div_round_closest(struct clk_divider *divider, 224static int _div_round_closest(const struct clk_div_table *table,
208 unsigned long parent_rate, unsigned long rate) 225 unsigned long parent_rate, unsigned long rate,
226 unsigned long flags)
209{ 227{
210 int up, down, div; 228 int up, down, div;
211 229
212 up = down = div = DIV_ROUND_CLOSEST(parent_rate, rate); 230 up = down = div = DIV_ROUND_CLOSEST(parent_rate, rate);
213 231
214 if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) { 232 if (flags & CLK_DIVIDER_POWER_OF_TWO) {
215 up = __roundup_pow_of_two(div); 233 up = __roundup_pow_of_two(div);
216 down = __rounddown_pow_of_two(div); 234 down = __rounddown_pow_of_two(div);
217 } else if (divider->table) { 235 } else if (table) {
218 up = _round_up_table(divider->table, div); 236 up = _round_up_table(table, div);
219 down = _round_down_table(divider->table, div); 237 down = _round_down_table(table, div);
220 } 238 }
221 239
222 return (up - div) <= (div - down) ? up : down; 240 return (up - div) <= (div - down) ? up : down;
223} 241}
224 242
225static int _div_round(struct clk_divider *divider, unsigned long parent_rate, 243static int _div_round(const struct clk_div_table *table,
226 unsigned long rate) 244 unsigned long parent_rate, unsigned long rate,
245 unsigned long flags)
227{ 246{
228 if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST) 247 if (flags & CLK_DIVIDER_ROUND_CLOSEST)
229 return _div_round_closest(divider, parent_rate, rate); 248 return _div_round_closest(table, parent_rate, rate, flags);
230 249
231 return _div_round_up(divider, parent_rate, rate); 250 return _div_round_up(table, parent_rate, rate, flags);
232} 251}
233 252
234static bool _is_best_div(struct clk_divider *divider, 253static bool _is_best_div(unsigned long rate, unsigned long now,
235 unsigned long rate, unsigned long now, unsigned long best) 254 unsigned long best, unsigned long flags)
236{ 255{
237 if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST) 256 if (flags & CLK_DIVIDER_ROUND_CLOSEST)
238 return abs(rate - now) < abs(rate - best); 257 return abs(rate - now) < abs(rate - best);
239 258
240 return now <= rate && now > best; 259 return now <= rate && now > best;
241} 260}
242 261
243static int _next_div(struct clk_divider *divider, int div) 262static int _next_div(const struct clk_div_table *table, int div,
263 unsigned long flags)
244{ 264{
245 div++; 265 div++;
246 266
247 if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) 267 if (flags & CLK_DIVIDER_POWER_OF_TWO)
248 return __roundup_pow_of_two(div); 268 return __roundup_pow_of_two(div);
249 if (divider->table) 269 if (table)
250 return _round_up_table(divider->table, div); 270 return _round_up_table(table, div);
251 271
252 return div; 272 return div;
253} 273}
254 274
255static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, 275static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
256 unsigned long *best_parent_rate) 276 unsigned long *best_parent_rate,
277 const struct clk_div_table *table, u8 width,
278 unsigned long flags)
257{ 279{
258 struct clk_divider *divider = to_clk_divider(hw);
259 int i, bestdiv = 0; 280 int i, bestdiv = 0;
260 unsigned long parent_rate, best = 0, now, maxdiv; 281 unsigned long parent_rate, best = 0, now, maxdiv;
261 unsigned long parent_rate_saved = *best_parent_rate; 282 unsigned long parent_rate_saved = *best_parent_rate;
@@ -263,19 +284,11 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
263 if (!rate) 284 if (!rate)
264 rate = 1; 285 rate = 1;
265 286
266 /* if read only, just return current value */ 287 maxdiv = _get_maxdiv(table, width, flags);
267 if (divider->flags & CLK_DIVIDER_READ_ONLY) {
268 bestdiv = readl(divider->reg) >> divider->shift;
269 bestdiv &= div_mask(divider);
270 bestdiv = _get_div(divider, bestdiv);
271 return bestdiv;
272 }
273
274 maxdiv = _get_maxdiv(divider);
275 288
276 if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) { 289 if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
277 parent_rate = *best_parent_rate; 290 parent_rate = *best_parent_rate;
278 bestdiv = _div_round(divider, parent_rate, rate); 291 bestdiv = _div_round(table, parent_rate, rate, flags);
279 bestdiv = bestdiv == 0 ? 1 : bestdiv; 292 bestdiv = bestdiv == 0 ? 1 : bestdiv;
280 bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; 293 bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
281 return bestdiv; 294 return bestdiv;
@@ -287,8 +300,8 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
287 */ 300 */
288 maxdiv = min(ULONG_MAX / rate, maxdiv); 301 maxdiv = min(ULONG_MAX / rate, maxdiv);
289 302
290 for (i = 1; i <= maxdiv; i = _next_div(divider, i)) { 303 for (i = 1; i <= maxdiv; i = _next_div(table, i, flags)) {
291 if (!_is_valid_div(divider, i)) 304 if (!_is_valid_div(table, i, flags))
292 continue; 305 continue;
293 if (rate * i == parent_rate_saved) { 306 if (rate * i == parent_rate_saved) {
294 /* 307 /*
@@ -302,7 +315,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
302 parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 315 parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
303 MULT_ROUND_UP(rate, i)); 316 MULT_ROUND_UP(rate, i));
304 now = DIV_ROUND_UP(parent_rate, i); 317 now = DIV_ROUND_UP(parent_rate, i);
305 if (_is_best_div(divider, rate, now, best)) { 318 if (_is_best_div(rate, now, best, flags)) {
306 bestdiv = i; 319 bestdiv = i;
307 best = now; 320 best = now;
308 *best_parent_rate = parent_rate; 321 *best_parent_rate = parent_rate;
@@ -310,48 +323,79 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
310 } 323 }
311 324
312 if (!bestdiv) { 325 if (!bestdiv) {
313 bestdiv = _get_maxdiv(divider); 326 bestdiv = _get_maxdiv(table, width, flags);
314 *best_parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1); 327 *best_parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1);
315 } 328 }
316 329
317 return bestdiv; 330 return bestdiv;
318} 331}
319 332
320static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, 333long divider_round_rate(struct clk_hw *hw, unsigned long rate,
321 unsigned long *prate) 334 unsigned long *prate, const struct clk_div_table *table,
335 u8 width, unsigned long flags)
322{ 336{
323 int div; 337 int div;
324 div = clk_divider_bestdiv(hw, rate, prate); 338
339 div = clk_divider_bestdiv(hw, rate, prate, table, width, flags);
325 340
326 return DIV_ROUND_UP(*prate, div); 341 return DIV_ROUND_UP(*prate, div);
327} 342}
343EXPORT_SYMBOL_GPL(divider_round_rate);
328 344
329static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, 345static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
330 unsigned long parent_rate) 346 unsigned long *prate)
331{ 347{
332 struct clk_divider *divider = to_clk_divider(hw); 348 struct clk_divider *divider = to_clk_divider(hw);
349 int bestdiv;
350
351 /* if read only, just return current value */
352 if (divider->flags & CLK_DIVIDER_READ_ONLY) {
353 bestdiv = readl(divider->reg) >> divider->shift;
354 bestdiv &= div_mask(divider->width);
355 bestdiv = _get_div(divider->table, bestdiv, divider->flags);
356 return bestdiv;
357 }
358
359 return divider_round_rate(hw, rate, prate, divider->table,
360 divider->width, divider->flags);
361}
362
363int divider_get_val(unsigned long rate, unsigned long parent_rate,
364 const struct clk_div_table *table, u8 width,
365 unsigned long flags)
366{
333 unsigned int div, value; 367 unsigned int div, value;
334 unsigned long flags = 0;
335 u32 val;
336 368
337 div = DIV_ROUND_UP(parent_rate, rate); 369 div = DIV_ROUND_UP(parent_rate, rate);
338 370
339 if (!_is_valid_div(divider, div)) 371 if (!_is_valid_div(table, div, flags))
340 return -EINVAL; 372 return -EINVAL;
341 373
342 value = _get_val(divider, div); 374 value = _get_val(table, div, flags);
375
376 return min_t(unsigned int, value, div_mask(width));
377}
378EXPORT_SYMBOL_GPL(divider_get_val);
379
380static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
381 unsigned long parent_rate)
382{
383 struct clk_divider *divider = to_clk_divider(hw);
384 unsigned int value;
385 unsigned long flags = 0;
386 u32 val;
343 387
344 if (value > div_mask(divider)) 388 value = divider_get_val(rate, parent_rate, divider->table,
345 value = div_mask(divider); 389 divider->width, divider->flags);
346 390
347 if (divider->lock) 391 if (divider->lock)
348 spin_lock_irqsave(divider->lock, flags); 392 spin_lock_irqsave(divider->lock, flags);
349 393
350 if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { 394 if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
351 val = div_mask(divider) << (divider->shift + 16); 395 val = div_mask(divider->width) << (divider->shift + 16);
352 } else { 396 } else {
353 val = clk_readl(divider->reg); 397 val = clk_readl(divider->reg);
354 val &= ~(div_mask(divider) << divider->shift); 398 val &= ~(div_mask(divider->width) << divider->shift);
355 } 399 }
356 val |= value << divider->shift; 400 val |= value << divider->shift;
357 clk_writel(val, divider->reg); 401 clk_writel(val, divider->reg);
@@ -463,3 +507,19 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
463 width, clk_divider_flags, table, lock); 507 width, clk_divider_flags, table, lock);
464} 508}
465EXPORT_SYMBOL_GPL(clk_register_divider_table); 509EXPORT_SYMBOL_GPL(clk_register_divider_table);
510
511void clk_unregister_divider(struct clk *clk)
512{
513 struct clk_divider *div;
514 struct clk_hw *hw;
515
516 hw = __clk_get_hw(clk);
517 if (!hw)
518 return;
519
520 div = to_clk_divider(hw);
521
522 clk_unregister(clk);
523 kfree(div);
524}
525EXPORT_SYMBOL_GPL(clk_unregister_divider);