Skip to content

Commit bca9690

Browse files
bebarinoMichael Turquette
authored andcommitted
clk: divider: Make generic for usage elsewhere
Some devices don't use mmio to interact with dividers. Split out the logic from the register read/write parts so that we can reuse the division logic elsewhere. Signed-off-by: Stephen Boyd <sboyd@codeaurora.org> Tested-by: Kenneth Westfield <kwestfie@codeaurora.org> Signed-off-by: Michael Turquette <mturquette@linaro.org>
1 parent 15a02c1 commit bca9690

File tree

2 files changed

+139
-84
lines changed

2 files changed

+139
-84
lines changed

drivers/clk/clk-divider.c

Lines changed: 128 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
3232

33-
#define div_mask(d) ((1 << ((d)->width)) - 1)
33+
#define div_mask(width) ((1 << (width)) - 1)
3434

3535
static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
3636
{
@@ -54,15 +54,16 @@ static unsigned int _get_table_mindiv(const struct clk_div_table *table)
5454
return mindiv;
5555
}
5656

57-
static unsigned int _get_maxdiv(struct clk_divider *divider)
57+
static unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width,
58+
unsigned long flags)
5859
{
59-
if (divider->flags & CLK_DIVIDER_ONE_BASED)
60-
return div_mask(divider);
61-
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
62-
return 1 << div_mask(divider);
63-
if (divider->table)
64-
return _get_table_maxdiv(divider->table);
65-
return div_mask(divider) + 1;
60+
if (flags & CLK_DIVIDER_ONE_BASED)
61+
return div_mask(width);
62+
if (flags & CLK_DIVIDER_POWER_OF_TWO)
63+
return 1 << div_mask(width);
64+
if (table)
65+
return _get_table_maxdiv(table);
66+
return div_mask(width) + 1;
6667
}
6768

6869
static 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,
7677
return 0;
7778
}
7879

79-
static unsigned int _get_div(struct clk_divider *divider, unsigned int val)
80+
static unsigned int _get_div(const struct clk_div_table *table,
81+
unsigned int val, unsigned long flags)
8082
{
81-
if (divider->flags & CLK_DIVIDER_ONE_BASED)
83+
if (flags & CLK_DIVIDER_ONE_BASED)
8284
return val;
83-
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
85+
if (flags & CLK_DIVIDER_POWER_OF_TWO)
8486
return 1 << val;
85-
if (divider->table)
86-
return _get_table_div(divider->table, val);
87+
if (table)
88+
return _get_table_div(table, val);
8789
return val + 1;
8890
}
8991

@@ -98,36 +100,49 @@ static unsigned int _get_table_val(const struct clk_div_table *table,
98100
return 0;
99101
}
100102

101-
static unsigned int _get_val(struct clk_divider *divider, unsigned int div)
103+
static unsigned int _get_val(const struct clk_div_table *table,
104+
unsigned int div, unsigned long flags)
102105
{
103-
if (divider->flags & CLK_DIVIDER_ONE_BASED)
106+
if (flags & CLK_DIVIDER_ONE_BASED)
104107
return div;
105-
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
108+
if (flags & CLK_DIVIDER_POWER_OF_TWO)
106109
return __ffs(div);
107-
if (divider->table)
108-
return _get_table_val(divider->table, div);
110+
if (table)
111+
return _get_table_val(table, div);
109112
return div - 1;
110113
}
111114

112-
static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
113-
unsigned long parent_rate)
115+
unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate,
116+
unsigned int val,
117+
const struct clk_div_table *table,
118+
unsigned long flags)
114119
{
115-
struct clk_divider *divider = to_clk_divider(hw);
116-
unsigned int div, val;
120+
unsigned int div;
117121

118-
val = clk_readl(divider->reg) >> divider->shift;
119-
val &= div_mask(divider);
120-
121-
div = _get_div(divider, val);
122+
div = _get_div(table, val, flags);
122123
if (!div) {
123-
WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO),
124+
WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO),
124125
"%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
125126
__clk_get_name(hw->clk));
126127
return parent_rate;
127128
}
128129

129130
return DIV_ROUND_UP(parent_rate, div);
130131
}
132+
EXPORT_SYMBOL_GPL(divider_recalc_rate);
133+
134+
static 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+
}
131146

132147
/*
133148
* 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,
146161
return false;
147162
}
148163

149-
static bool _is_valid_div(struct clk_divider *divider, unsigned int div)
164+
static bool _is_valid_div(const struct clk_div_table *table, unsigned int div,
165+
unsigned long flags)
150166
{
151-
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
167+
if (flags & CLK_DIVIDER_POWER_OF_TWO)
152168
return is_power_of_2(div);
153-
if (divider->table)
154-
return _is_valid_table_div(divider->table, div);
169+
if (table)
170+
return _is_valid_table_div(table, div);
155171
return true;
156172
}
157173

@@ -191,91 +207,88 @@ static int _round_down_table(const struct clk_div_table *table, int div)
191207
return down;
192208
}
193209

194-
static int _div_round_up(struct clk_divider *divider,
195-
unsigned long parent_rate, unsigned long rate)
210+
static int _div_round_up(const struct clk_div_table *table,
211+
unsigned long parent_rate, unsigned long rate,
212+
unsigned long flags)
196213
{
197214
int div = DIV_ROUND_UP(parent_rate, rate);
198215

199-
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
216+
if (flags & CLK_DIVIDER_POWER_OF_TWO)
200217
div = __roundup_pow_of_two(div);
201-
if (divider->table)
202-
div = _round_up_table(divider->table, div);
218+
if (table)
219+
div = _round_up_table(table, div);
203220

204221
return div;
205222
}
206223

207-
static int _div_round_closest(struct clk_divider *divider,
208-
unsigned long parent_rate, unsigned long rate)
224+
static int _div_round_closest(const struct clk_div_table *table,
225+
unsigned long parent_rate, unsigned long rate,
226+
unsigned long flags)
209227
{
210228
int up, down, div;
211229

212230
up = down = div = DIV_ROUND_CLOSEST(parent_rate, rate);
213231

214-
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) {
232+
if (flags & CLK_DIVIDER_POWER_OF_TWO) {
215233
up = __roundup_pow_of_two(div);
216234
down = __rounddown_pow_of_two(div);
217-
} else if (divider->table) {
218-
up = _round_up_table(divider->table, div);
219-
down = _round_down_table(divider->table, div);
235+
} else if (table) {
236+
up = _round_up_table(table, div);
237+
down = _round_down_table(table, div);
220238
}
221239

222240
return (up - div) <= (div - down) ? up : down;
223241
}
224242

225-
static int _div_round(struct clk_divider *divider, unsigned long parent_rate,
226-
unsigned long rate)
243+
static int _div_round(const struct clk_div_table *table,
244+
unsigned long parent_rate, unsigned long rate,
245+
unsigned long flags)
227246
{
228-
if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST)
229-
return _div_round_closest(divider, parent_rate, rate);
247+
if (flags & CLK_DIVIDER_ROUND_CLOSEST)
248+
return _div_round_closest(table, parent_rate, rate, flags);
230249

231-
return _div_round_up(divider, parent_rate, rate);
250+
return _div_round_up(table, parent_rate, rate, flags);
232251
}
233252

234-
static bool _is_best_div(struct clk_divider *divider,
235-
unsigned long rate, unsigned long now, unsigned long best)
253+
static bool _is_best_div(unsigned long rate, unsigned long now,
254+
unsigned long best, unsigned long flags)
236255
{
237-
if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST)
256+
if (flags & CLK_DIVIDER_ROUND_CLOSEST)
238257
return abs(rate - now) < abs(rate - best);
239258

240259
return now <= rate && now > best;
241260
}
242261

243-
static int _next_div(struct clk_divider *divider, int div)
262+
static int _next_div(const struct clk_div_table *table, int div,
263+
unsigned long flags)
244264
{
245265
div++;
246266

247-
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
267+
if (flags & CLK_DIVIDER_POWER_OF_TWO)
248268
return __roundup_pow_of_two(div);
249-
if (divider->table)
250-
return _round_up_table(divider->table, div);
269+
if (table)
270+
return _round_up_table(table, div);
251271

252272
return div;
253273
}
254274

255275
static 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)
257279
{
258-
struct clk_divider *divider = to_clk_divider(hw);
259280
int i, bestdiv = 0;
260281
unsigned long parent_rate, best = 0, now, maxdiv;
261282
unsigned long parent_rate_saved = *best_parent_rate;
262283

263284
if (!rate)
264285
rate = 1;
265286

266-
/* if read only, just return current value */
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);
287+
maxdiv = _get_maxdiv(table, width, flags);
275288

276289
if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
277290
parent_rate = *best_parent_rate;
278-
bestdiv = _div_round(divider, parent_rate, rate);
291+
bestdiv = _div_round(table, parent_rate, rate, flags);
279292
bestdiv = bestdiv == 0 ? 1 : bestdiv;
280293
bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
281294
return bestdiv;
@@ -287,8 +300,8 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
287300
*/
288301
maxdiv = min(ULONG_MAX / rate, maxdiv);
289302

290-
for (i = 1; i <= maxdiv; i = _next_div(divider, i)) {
291-
if (!_is_valid_div(divider, i))
303+
for (i = 1; i <= maxdiv; i = _next_div(table, i, flags)) {
304+
if (!_is_valid_div(table, i, flags))
292305
continue;
293306
if (rate * i == parent_rate_saved) {
294307
/*
@@ -302,56 +315,87 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
302315
parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
303316
MULT_ROUND_UP(rate, i));
304317
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)) {
306319
bestdiv = i;
307320
best = now;
308321
*best_parent_rate = parent_rate;
309322
}
310323
}
311324

312325
if (!bestdiv) {
313-
bestdiv = _get_maxdiv(divider);
326+
bestdiv = _get_maxdiv(table, width, flags);
314327
*best_parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1);
315328
}
316329

317330
return bestdiv;
318331
}
319332

320-
static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
321-
unsigned long *prate)
333+
long divider_round_rate(struct clk_hw *hw, unsigned long rate,
334+
unsigned long *prate, const struct clk_div_table *table,
335+
u8 width, unsigned long flags)
322336
{
323337
int div;
324-
div = clk_divider_bestdiv(hw, rate, prate);
338+
339+
div = clk_divider_bestdiv(hw, rate, prate, table, width, flags);
325340

326341
return DIV_ROUND_UP(*prate, div);
327342
}
343+
EXPORT_SYMBOL_GPL(divider_round_rate);
328344

329-
static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
330-
unsigned long parent_rate)
345+
static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
346+
unsigned long *prate)
331347
{
332348
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+
363+
int divider_get_val(unsigned long rate, unsigned long parent_rate,
364+
const struct clk_div_table *table, u8 width,
365+
unsigned long flags)
366+
{
333367
unsigned int div, value;
334-
unsigned long flags = 0;
335-
u32 val;
336368

337369
div = DIV_ROUND_UP(parent_rate, rate);
338370

339-
if (!_is_valid_div(divider, div))
371+
if (!_is_valid_div(table, div, flags))
340372
return -EINVAL;
341373

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+
}
378+
EXPORT_SYMBOL_GPL(divider_get_val);
379+
380+
static 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;
343387

344-
if (value > div_mask(divider))
345-
value = div_mask(divider);
388+
value = divider_get_val(rate, parent_rate, divider->table,
389+
divider->width, divider->flags);
346390

347391
if (divider->lock)
348392
spin_lock_irqsave(divider->lock, flags);
349393

350394
if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
351-
val = div_mask(divider) << (divider->shift + 16);
395+
val = div_mask(divider->width) << (divider->shift + 16);
352396
} else {
353397
val = clk_readl(divider->reg);
354-
val &= ~(div_mask(divider) << divider->shift);
398+
val &= ~(div_mask(divider->width) << divider->shift);
355399
}
356400
val |= value << divider->shift;
357401
clk_writel(val, divider->reg);

include/linux/clk-provider.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,17 @@ struct clk_divider {
353353
#define CLK_DIVIDER_READ_ONLY BIT(5)
354354

355355
extern const struct clk_ops clk_divider_ops;
356+
357+
unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate,
358+
unsigned int val, const struct clk_div_table *table,
359+
unsigned long flags);
360+
long divider_round_rate(struct clk_hw *hw, unsigned long rate,
361+
unsigned long *prate, const struct clk_div_table *table,
362+
u8 width, unsigned long flags);
363+
int divider_get_val(unsigned long rate, unsigned long parent_rate,
364+
const struct clk_div_table *table, u8 width,
365+
unsigned long flags);
366+
356367
struct clk *clk_register_divider(struct device *dev, const char *name,
357368
const char *parent_name, unsigned long flags,
358369
void __iomem *reg, u8 shift, u8 width,

0 commit comments

Comments
 (0)