Commit | Line | Data |
---|---|---|
e1bd55e5 | 1 | // SPDX-License-Identifier: GPL-2.0 |
9d9f78ed MT |
2 | /* |
3 | * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> | |
4 | * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org> | |
5 | * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org> | |
6 | * | |
9d9f78ed MT |
7 | * Adjustable divider clock implementation |
8 | */ | |
9 | ||
10 | #include <linux/clk-provider.h> | |
11 | #include <linux/module.h> | |
12 | #include <linux/slab.h> | |
13 | #include <linux/io.h> | |
14 | #include <linux/err.h> | |
15 | #include <linux/string.h> | |
1a3cd184 | 16 | #include <linux/log2.h> |
9d9f78ed MT |
17 | |
18 | /* | |
19 | * DOC: basic adjustable divider clock that cannot gate | |
20 | * | |
21 | * Traits of this clock: | |
22 | * prepare - clk_prepare only ensures that parents are prepared | |
23 | * enable - clk_enable only ensures that parents are enabled | |
9556f9da | 24 | * rate - rate is adjustable. clk->rate = ceiling(parent->rate / divisor) |
9d9f78ed MT |
25 | * parent - fixed parent. No clk_set_parent support |
26 | */ | |
27 | ||
434d69fa JG |
28 | static inline u32 clk_div_readl(struct clk_divider *divider) |
29 | { | |
30 | if (divider->flags & CLK_DIVIDER_BIG_ENDIAN) | |
31 | return ioread32be(divider->reg); | |
32 | ||
5834fd75 | 33 | return readl(divider->reg); |
434d69fa JG |
34 | } |
35 | ||
36 | static inline void clk_div_writel(struct clk_divider *divider, u32 val) | |
37 | { | |
38 | if (divider->flags & CLK_DIVIDER_BIG_ENDIAN) | |
39 | iowrite32be(val, divider->reg); | |
40 | else | |
5834fd75 | 41 | writel(val, divider->reg); |
434d69fa JG |
42 | } |
43 | ||
fab88ca7 SB |
44 | static unsigned int _get_table_maxdiv(const struct clk_div_table *table, |
45 | u8 width) | |
357c3f0a | 46 | { |
e6d3cc7b | 47 | unsigned int maxdiv = 0, mask = clk_div_mask(width); |
357c3f0a RN |
48 | const struct clk_div_table *clkt; |
49 | ||
50 | for (clkt = table; clkt->div; clkt++) | |
fab88ca7 | 51 | if (clkt->div > maxdiv && clkt->val <= mask) |
357c3f0a RN |
52 | maxdiv = clkt->div; |
53 | return maxdiv; | |
54 | } | |
55 | ||
774b5143 MC |
56 | static unsigned int _get_table_mindiv(const struct clk_div_table *table) |
57 | { | |
58 | unsigned int mindiv = UINT_MAX; | |
59 | const struct clk_div_table *clkt; | |
60 | ||
61 | for (clkt = table; clkt->div; clkt++) | |
62 | if (clkt->div < mindiv) | |
63 | mindiv = clkt->div; | |
64 | return mindiv; | |
65 | } | |
66 | ||
bca9690b SB |
67 | static unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width, |
68 | unsigned long flags) | |
6d9252bd | 69 | { |
bca9690b | 70 | if (flags & CLK_DIVIDER_ONE_BASED) |
e6d3cc7b | 71 | return clk_div_mask(width); |
bca9690b | 72 | if (flags & CLK_DIVIDER_POWER_OF_TWO) |
e6d3cc7b | 73 | return 1 << clk_div_mask(width); |
bca9690b | 74 | if (table) |
fab88ca7 | 75 | return _get_table_maxdiv(table, width); |
e6d3cc7b | 76 | return clk_div_mask(width) + 1; |
6d9252bd RN |
77 | } |
78 | ||
357c3f0a RN |
79 | static unsigned int _get_table_div(const struct clk_div_table *table, |
80 | unsigned int val) | |
81 | { | |
82 | const struct clk_div_table *clkt; | |
83 | ||
84 | for (clkt = table; clkt->div; clkt++) | |
85 | if (clkt->val == val) | |
86 | return clkt->div; | |
87 | return 0; | |
88 | } | |
89 | ||
bca9690b | 90 | static unsigned int _get_div(const struct clk_div_table *table, |
afe76c8f | 91 | unsigned int val, unsigned long flags, u8 width) |
6d9252bd | 92 | { |
bca9690b | 93 | if (flags & CLK_DIVIDER_ONE_BASED) |
6d9252bd | 94 | return val; |
bca9690b | 95 | if (flags & CLK_DIVIDER_POWER_OF_TWO) |
6d9252bd | 96 | return 1 << val; |
afe76c8f | 97 | if (flags & CLK_DIVIDER_MAX_AT_ZERO) |
e6d3cc7b | 98 | return val ? val : clk_div_mask(width) + 1; |
bca9690b SB |
99 | if (table) |
100 | return _get_table_div(table, val); | |
6d9252bd RN |
101 | return val + 1; |
102 | } | |
103 | ||
357c3f0a RN |
104 | static unsigned int _get_table_val(const struct clk_div_table *table, |
105 | unsigned int div) | |
106 | { | |
107 | const struct clk_div_table *clkt; | |
108 | ||
109 | for (clkt = table; clkt->div; clkt++) | |
110 | if (clkt->div == div) | |
111 | return clkt->val; | |
112 | return 0; | |
113 | } | |
114 | ||
bca9690b | 115 | static unsigned int _get_val(const struct clk_div_table *table, |
afe76c8f | 116 | unsigned int div, unsigned long flags, u8 width) |
6d9252bd | 117 | { |
bca9690b | 118 | if (flags & CLK_DIVIDER_ONE_BASED) |
6d9252bd | 119 | return div; |
bca9690b | 120 | if (flags & CLK_DIVIDER_POWER_OF_TWO) |
6d9252bd | 121 | return __ffs(div); |
afe76c8f | 122 | if (flags & CLK_DIVIDER_MAX_AT_ZERO) |
e6d3cc7b | 123 | return (div == clk_div_mask(width) + 1) ? 0 : div; |
bca9690b SB |
124 | if (table) |
125 | return _get_table_val(table, div); | |
6d9252bd RN |
126 | return div - 1; |
127 | } | |
9d9f78ed | 128 | |
bca9690b SB |
129 | unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate, |
130 | unsigned int val, | |
131 | const struct clk_div_table *table, | |
12a26c29 | 132 | unsigned long flags, unsigned long width) |
9d9f78ed | 133 | { |
bca9690b | 134 | unsigned int div; |
9d9f78ed | 135 | |
12a26c29 | 136 | div = _get_div(table, val, flags, width); |
6d9252bd | 137 | if (!div) { |
bca9690b | 138 | WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO), |
056b2053 | 139 | "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n", |
2f508a95 | 140 | clk_hw_get_name(hw)); |
6d9252bd RN |
141 | return parent_rate; |
142 | } | |
9d9f78ed | 143 | |
9556f9da | 144 | return DIV_ROUND_UP_ULL((u64)parent_rate, div); |
9d9f78ed | 145 | } |
bca9690b SB |
146 | EXPORT_SYMBOL_GPL(divider_recalc_rate); |
147 | ||
148 | static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, | |
149 | unsigned long parent_rate) | |
150 | { | |
151 | struct clk_divider *divider = to_clk_divider(hw); | |
152 | unsigned int val; | |
153 | ||
434d69fa | 154 | val = clk_div_readl(divider) >> divider->shift; |
e6d3cc7b | 155 | val &= clk_div_mask(divider->width); |
bca9690b SB |
156 | |
157 | return divider_recalc_rate(hw, parent_rate, val, divider->table, | |
12a26c29 | 158 | divider->flags, divider->width); |
bca9690b | 159 | } |
9d9f78ed | 160 | |
357c3f0a RN |
161 | static bool _is_valid_table_div(const struct clk_div_table *table, |
162 | unsigned int div) | |
163 | { | |
164 | const struct clk_div_table *clkt; | |
165 | ||
166 | for (clkt = table; clkt->div; clkt++) | |
167 | if (clkt->div == div) | |
168 | return true; | |
169 | return false; | |
170 | } | |
171 | ||
bca9690b SB |
172 | static bool _is_valid_div(const struct clk_div_table *table, unsigned int div, |
173 | unsigned long flags) | |
357c3f0a | 174 | { |
bca9690b | 175 | if (flags & CLK_DIVIDER_POWER_OF_TWO) |
1a3cd184 | 176 | return is_power_of_2(div); |
bca9690b SB |
177 | if (table) |
178 | return _is_valid_table_div(table, div); | |
357c3f0a RN |
179 | return true; |
180 | } | |
181 | ||
dd23c2cd MC |
182 | static int _round_up_table(const struct clk_div_table *table, int div) |
183 | { | |
184 | const struct clk_div_table *clkt; | |
fe52e750 | 185 | int up = INT_MAX; |
dd23c2cd MC |
186 | |
187 | for (clkt = table; clkt->div; clkt++) { | |
188 | if (clkt->div == div) | |
189 | return clkt->div; | |
190 | else if (clkt->div < div) | |
191 | continue; | |
192 | ||
193 | if ((clkt->div - div) < (up - div)) | |
194 | up = clkt->div; | |
195 | } | |
196 | ||
197 | return up; | |
198 | } | |
199 | ||
774b5143 MC |
200 | static int _round_down_table(const struct clk_div_table *table, int div) |
201 | { | |
202 | const struct clk_div_table *clkt; | |
203 | int down = _get_table_mindiv(table); | |
204 | ||
205 | for (clkt = table; clkt->div; clkt++) { | |
206 | if (clkt->div == div) | |
207 | return clkt->div; | |
208 | else if (clkt->div > div) | |
209 | continue; | |
210 | ||
211 | if ((div - clkt->div) < (div - down)) | |
212 | down = clkt->div; | |
213 | } | |
214 | ||
215 | return down; | |
216 | } | |
217 | ||
bca9690b SB |
218 | static int _div_round_up(const struct clk_div_table *table, |
219 | unsigned long parent_rate, unsigned long rate, | |
220 | unsigned long flags) | |
dd23c2cd | 221 | { |
9556f9da | 222 | int div = DIV_ROUND_UP_ULL((u64)parent_rate, rate); |
dd23c2cd | 223 | |
bca9690b | 224 | if (flags & CLK_DIVIDER_POWER_OF_TWO) |
dd23c2cd | 225 | div = __roundup_pow_of_two(div); |
bca9690b SB |
226 | if (table) |
227 | div = _round_up_table(table, div); | |
dd23c2cd MC |
228 | |
229 | return div; | |
230 | } | |
231 | ||
bca9690b SB |
232 | static int _div_round_closest(const struct clk_div_table *table, |
233 | unsigned long parent_rate, unsigned long rate, | |
234 | unsigned long flags) | |
774b5143 | 235 | { |
93155142 | 236 | int up, down; |
26bac95a | 237 | unsigned long up_rate, down_rate; |
774b5143 | 238 | |
9556f9da | 239 | up = DIV_ROUND_UP_ULL((u64)parent_rate, rate); |
93155142 | 240 | down = parent_rate / rate; |
774b5143 | 241 | |
bca9690b | 242 | if (flags & CLK_DIVIDER_POWER_OF_TWO) { |
93155142 UKK |
243 | up = __roundup_pow_of_two(up); |
244 | down = __rounddown_pow_of_two(down); | |
bca9690b | 245 | } else if (table) { |
93155142 UKK |
246 | up = _round_up_table(table, up); |
247 | down = _round_down_table(table, down); | |
774b5143 MC |
248 | } |
249 | ||
9556f9da BN |
250 | up_rate = DIV_ROUND_UP_ULL((u64)parent_rate, up); |
251 | down_rate = DIV_ROUND_UP_ULL((u64)parent_rate, down); | |
26bac95a UKK |
252 | |
253 | return (rate - up_rate) <= (down_rate - rate) ? up : down; | |
774b5143 MC |
254 | } |
255 | ||
bca9690b SB |
256 | static int _div_round(const struct clk_div_table *table, |
257 | unsigned long parent_rate, unsigned long rate, | |
258 | unsigned long flags) | |
774b5143 | 259 | { |
bca9690b SB |
260 | if (flags & CLK_DIVIDER_ROUND_CLOSEST) |
261 | return _div_round_closest(table, parent_rate, rate, flags); | |
774b5143 | 262 | |
bca9690b | 263 | return _div_round_up(table, parent_rate, rate, flags); |
774b5143 MC |
264 | } |
265 | ||
bca9690b SB |
266 | static bool _is_best_div(unsigned long rate, unsigned long now, |
267 | unsigned long best, unsigned long flags) | |
774b5143 | 268 | { |
bca9690b | 269 | if (flags & CLK_DIVIDER_ROUND_CLOSEST) |
774b5143 MC |
270 | return abs(rate - now) < abs(rate - best); |
271 | ||
272 | return now <= rate && now > best; | |
273 | } | |
274 | ||
bca9690b SB |
275 | static int _next_div(const struct clk_div_table *table, int div, |
276 | unsigned long flags) | |
0e2de78e MC |
277 | { |
278 | div++; | |
279 | ||
bca9690b | 280 | if (flags & CLK_DIVIDER_POWER_OF_TWO) |
0e2de78e | 281 | return __roundup_pow_of_two(div); |
bca9690b SB |
282 | if (table) |
283 | return _round_up_table(table, div); | |
0e2de78e MC |
284 | |
285 | return div; | |
286 | } | |
287 | ||
22833a91 MR |
288 | static int clk_divider_bestdiv(struct clk_hw *hw, struct clk_hw *parent, |
289 | unsigned long rate, | |
bca9690b SB |
290 | unsigned long *best_parent_rate, |
291 | const struct clk_div_table *table, u8 width, | |
292 | unsigned long flags) | |
9d9f78ed | 293 | { |
9d9f78ed MT |
294 | int i, bestdiv = 0; |
295 | unsigned long parent_rate, best = 0, now, maxdiv; | |
081c9025 | 296 | unsigned long parent_rate_saved = *best_parent_rate; |
9d9f78ed MT |
297 | |
298 | if (!rate) | |
299 | rate = 1; | |
300 | ||
bca9690b | 301 | maxdiv = _get_maxdiv(table, width, flags); |
9d9f78ed | 302 | |
98d8a60e | 303 | if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) { |
81536e07 | 304 | parent_rate = *best_parent_rate; |
bca9690b | 305 | bestdiv = _div_round(table, parent_rate, rate, flags); |
9d9f78ed MT |
306 | bestdiv = bestdiv == 0 ? 1 : bestdiv; |
307 | bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; | |
308 | return bestdiv; | |
309 | } | |
310 | ||
311 | /* | |
312 | * The maximum divider we can use without overflowing | |
313 | * unsigned long in rate * i below | |
314 | */ | |
315 | maxdiv = min(ULONG_MAX / rate, maxdiv); | |
316 | ||
653d1452 MY |
317 | for (i = _next_div(table, 0, flags); i <= maxdiv; |
318 | i = _next_div(table, i, flags)) { | |
081c9025 SG |
319 | if (rate * i == parent_rate_saved) { |
320 | /* | |
321 | * It's the most ideal case if the requested rate can be | |
322 | * divided from parent clock without needing to change | |
323 | * parent rate, so return the divider immediately. | |
324 | */ | |
325 | *best_parent_rate = parent_rate_saved; | |
326 | return i; | |
327 | } | |
22833a91 | 328 | parent_rate = clk_hw_round_rate(parent, rate * i); |
9556f9da | 329 | now = DIV_ROUND_UP_ULL((u64)parent_rate, i); |
bca9690b | 330 | if (_is_best_div(rate, now, best, flags)) { |
9d9f78ed MT |
331 | bestdiv = i; |
332 | best = now; | |
333 | *best_parent_rate = parent_rate; | |
334 | } | |
335 | } | |
336 | ||
337 | if (!bestdiv) { | |
bca9690b | 338 | bestdiv = _get_maxdiv(table, width, flags); |
22833a91 | 339 | *best_parent_rate = clk_hw_round_rate(parent, 1); |
9d9f78ed MT |
340 | } |
341 | ||
342 | return bestdiv; | |
343 | } | |
344 | ||
22833a91 MR |
345 | long divider_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, | |
348 | u8 width, unsigned long flags) | |
9d9f78ed MT |
349 | { |
350 | int div; | |
bca9690b | 351 | |
22833a91 | 352 | div = clk_divider_bestdiv(hw, parent, rate, prate, table, width, flags); |
9d9f78ed | 353 | |
9556f9da | 354 | return DIV_ROUND_UP_ULL((u64)*prate, div); |
9d9f78ed | 355 | } |
22833a91 | 356 | EXPORT_SYMBOL_GPL(divider_round_rate_parent); |
9d9f78ed | 357 | |
b15ee490 JB |
358 | long divider_ro_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent, |
359 | unsigned long rate, unsigned long *prate, | |
360 | const struct clk_div_table *table, u8 width, | |
361 | unsigned long flags, unsigned int val) | |
362 | { | |
363 | int div; | |
364 | ||
365 | div = _get_div(table, val, flags, width); | |
366 | ||
367 | /* Even a read-only clock can propagate a rate change */ | |
368 | if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) { | |
369 | if (!parent) | |
370 | return -EINVAL; | |
371 | ||
372 | *prate = clk_hw_round_rate(parent, rate * div); | |
373 | } | |
374 | ||
375 | return DIV_ROUND_UP_ULL((u64)*prate, div); | |
376 | } | |
377 | EXPORT_SYMBOL_GPL(divider_ro_round_rate_parent); | |
378 | ||
379 | ||
bca9690b SB |
380 | static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, |
381 | unsigned long *prate) | |
9d9f78ed MT |
382 | { |
383 | struct clk_divider *divider = to_clk_divider(hw); | |
bca9690b SB |
384 | |
385 | /* if read only, just return current value */ | |
386 | if (divider->flags & CLK_DIVIDER_READ_ONLY) { | |
b15ee490 JB |
387 | u32 val; |
388 | ||
434d69fa | 389 | val = clk_div_readl(divider) >> divider->shift; |
b15ee490 JB |
390 | val &= clk_div_mask(divider->width); |
391 | ||
392 | return divider_ro_round_rate(hw, rate, prate, divider->table, | |
393 | divider->width, divider->flags, | |
394 | val); | |
bca9690b SB |
395 | } |
396 | ||
397 | return divider_round_rate(hw, rate, prate, divider->table, | |
398 | divider->width, divider->flags); | |
399 | } | |
400 | ||
401 | int divider_get_val(unsigned long rate, unsigned long parent_rate, | |
402 | const struct clk_div_table *table, u8 width, | |
403 | unsigned long flags) | |
404 | { | |
6d9252bd | 405 | unsigned int div, value; |
9d9f78ed | 406 | |
9556f9da | 407 | div = DIV_ROUND_UP_ULL((u64)parent_rate, rate); |
dd23c2cd | 408 | |
bca9690b | 409 | if (!_is_valid_div(table, div, flags)) |
dd23c2cd MC |
410 | return -EINVAL; |
411 | ||
afe76c8f | 412 | value = _get_val(table, div, flags, width); |
bca9690b | 413 | |
e6d3cc7b | 414 | return min_t(unsigned int, value, clk_div_mask(width)); |
bca9690b SB |
415 | } |
416 | EXPORT_SYMBOL_GPL(divider_get_val); | |
417 | ||
418 | static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, | |
419 | unsigned long parent_rate) | |
420 | { | |
421 | struct clk_divider *divider = to_clk_divider(hw); | |
2316a7a3 | 422 | int value; |
bca9690b SB |
423 | unsigned long flags = 0; |
424 | u32 val; | |
9d9f78ed | 425 | |
bca9690b SB |
426 | value = divider_get_val(rate, parent_rate, divider->table, |
427 | divider->width, divider->flags); | |
2316a7a3 AF |
428 | if (value < 0) |
429 | return value; | |
9d9f78ed MT |
430 | |
431 | if (divider->lock) | |
432 | spin_lock_irqsave(divider->lock, flags); | |
661e2180 SB |
433 | else |
434 | __acquire(divider->lock); | |
9d9f78ed | 435 | |
d57dfe75 | 436 | if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { |
e6d3cc7b | 437 | val = clk_div_mask(divider->width) << (divider->shift + 16); |
d57dfe75 | 438 | } else { |
434d69fa | 439 | val = clk_div_readl(divider); |
e6d3cc7b | 440 | val &= ~(clk_div_mask(divider->width) << divider->shift); |
d57dfe75 | 441 | } |
2316a7a3 | 442 | val |= (u32)value << divider->shift; |
434d69fa | 443 | clk_div_writel(divider, val); |
9d9f78ed MT |
444 | |
445 | if (divider->lock) | |
446 | spin_unlock_irqrestore(divider->lock, flags); | |
661e2180 SB |
447 | else |
448 | __release(divider->lock); | |
9d9f78ed MT |
449 | |
450 | return 0; | |
451 | } | |
9d9f78ed | 452 | |
822c250e | 453 | const struct clk_ops clk_divider_ops = { |
9d9f78ed MT |
454 | .recalc_rate = clk_divider_recalc_rate, |
455 | .round_rate = clk_divider_round_rate, | |
456 | .set_rate = clk_divider_set_rate, | |
457 | }; | |
458 | EXPORT_SYMBOL_GPL(clk_divider_ops); | |
459 | ||
50359819 HS |
460 | const struct clk_ops clk_divider_ro_ops = { |
461 | .recalc_rate = clk_divider_recalc_rate, | |
462 | .round_rate = clk_divider_round_rate, | |
463 | }; | |
464 | EXPORT_SYMBOL_GPL(clk_divider_ro_ops); | |
465 | ||
eb7d264f | 466 | static struct clk_hw *_register_divider(struct device *dev, const char *name, |
9d9f78ed MT |
467 | const char *parent_name, unsigned long flags, |
468 | void __iomem *reg, u8 shift, u8 width, | |
357c3f0a RN |
469 | u8 clk_divider_flags, const struct clk_div_table *table, |
470 | spinlock_t *lock) | |
9d9f78ed MT |
471 | { |
472 | struct clk_divider *div; | |
eb7d264f | 473 | struct clk_hw *hw; |
0197b3ea | 474 | struct clk_init_data init; |
eb7d264f | 475 | int ret; |
9d9f78ed | 476 | |
d57dfe75 HZ |
477 | if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) { |
478 | if (width + shift > 16) { | |
479 | pr_warn("divider value exceeds LOWORD field\n"); | |
480 | return ERR_PTR(-EINVAL); | |
481 | } | |
482 | } | |
483 | ||
27d54591 | 484 | /* allocate the divider */ |
d122db7e SB |
485 | div = kzalloc(sizeof(*div), GFP_KERNEL); |
486 | if (!div) | |
27d54591 | 487 | return ERR_PTR(-ENOMEM); |
9d9f78ed | 488 | |
0197b3ea | 489 | init.name = name; |
50359819 HS |
490 | if (clk_divider_flags & CLK_DIVIDER_READ_ONLY) |
491 | init.ops = &clk_divider_ro_ops; | |
492 | else | |
493 | init.ops = &clk_divider_ops; | |
90b6c5c7 | 494 | init.flags = flags; |
0197b3ea SK |
495 | init.parent_names = (parent_name ? &parent_name: NULL); |
496 | init.num_parents = (parent_name ? 1 : 0); | |
497 | ||
9d9f78ed MT |
498 | /* struct clk_divider assignments */ |
499 | div->reg = reg; | |
500 | div->shift = shift; | |
501 | div->width = width; | |
502 | div->flags = clk_divider_flags; | |
503 | div->lock = lock; | |
0197b3ea | 504 | div->hw.init = &init; |
357c3f0a | 505 | div->table = table; |
9d9f78ed | 506 | |
27d54591 | 507 | /* register the clock */ |
eb7d264f SB |
508 | hw = &div->hw; |
509 | ret = clk_hw_register(dev, hw); | |
510 | if (ret) { | |
27d54591 | 511 | kfree(div); |
eb7d264f SB |
512 | hw = ERR_PTR(ret); |
513 | } | |
9d9f78ed | 514 | |
eb7d264f | 515 | return hw; |
9d9f78ed | 516 | } |
357c3f0a RN |
517 | |
518 | /** | |
519 | * clk_register_divider - register a divider clock with the clock framework | |
520 | * @dev: device registering this clock | |
521 | * @name: name of this clock | |
522 | * @parent_name: name of clock's parent | |
523 | * @flags: framework-specific flags | |
524 | * @reg: register address to adjust divider | |
525 | * @shift: number of bits to shift the bitfield | |
526 | * @width: width of the bitfield | |
527 | * @clk_divider_flags: divider-specific flags for this clock | |
528 | * @lock: shared register lock for this clock | |
529 | */ | |
530 | struct clk *clk_register_divider(struct device *dev, const char *name, | |
531 | const char *parent_name, unsigned long flags, | |
532 | void __iomem *reg, u8 shift, u8 width, | |
533 | u8 clk_divider_flags, spinlock_t *lock) | |
534 | { | |
eb7d264f SB |
535 | struct clk_hw *hw; |
536 | ||
537 | hw = _register_divider(dev, name, parent_name, flags, reg, shift, | |
357c3f0a | 538 | width, clk_divider_flags, NULL, lock); |
eb7d264f SB |
539 | if (IS_ERR(hw)) |
540 | return ERR_CAST(hw); | |
541 | return hw->clk; | |
357c3f0a | 542 | } |
4c5eeea9 | 543 | EXPORT_SYMBOL_GPL(clk_register_divider); |
357c3f0a | 544 | |
eb7d264f SB |
545 | /** |
546 | * clk_hw_register_divider - register a divider clock with the clock framework | |
547 | * @dev: device registering this clock | |
548 | * @name: name of this clock | |
549 | * @parent_name: name of clock's parent | |
550 | * @flags: framework-specific flags | |
551 | * @reg: register address to adjust divider | |
552 | * @shift: number of bits to shift the bitfield | |
553 | * @width: width of the bitfield | |
554 | * @clk_divider_flags: divider-specific flags for this clock | |
555 | * @lock: shared register lock for this clock | |
556 | */ | |
557 | struct clk_hw *clk_hw_register_divider(struct device *dev, const char *name, | |
558 | const char *parent_name, unsigned long flags, | |
559 | void __iomem *reg, u8 shift, u8 width, | |
560 | u8 clk_divider_flags, spinlock_t *lock) | |
561 | { | |
562 | return _register_divider(dev, name, parent_name, flags, reg, shift, | |
563 | width, clk_divider_flags, NULL, lock); | |
564 | } | |
565 | EXPORT_SYMBOL_GPL(clk_hw_register_divider); | |
566 | ||
357c3f0a RN |
567 | /** |
568 | * clk_register_divider_table - register a table based divider clock with | |
569 | * the clock framework | |
570 | * @dev: device registering this clock | |
571 | * @name: name of this clock | |
572 | * @parent_name: name of clock's parent | |
573 | * @flags: framework-specific flags | |
574 | * @reg: register address to adjust divider | |
575 | * @shift: number of bits to shift the bitfield | |
576 | * @width: width of the bitfield | |
577 | * @clk_divider_flags: divider-specific flags for this clock | |
578 | * @table: array of divider/value pairs ending with a div set to 0 | |
579 | * @lock: shared register lock for this clock | |
580 | */ | |
581 | struct clk *clk_register_divider_table(struct device *dev, const char *name, | |
582 | const char *parent_name, unsigned long flags, | |
583 | void __iomem *reg, u8 shift, u8 width, | |
584 | u8 clk_divider_flags, const struct clk_div_table *table, | |
585 | spinlock_t *lock) | |
586 | { | |
eb7d264f SB |
587 | struct clk_hw *hw; |
588 | ||
589 | hw = _register_divider(dev, name, parent_name, flags, reg, shift, | |
357c3f0a | 590 | width, clk_divider_flags, table, lock); |
eb7d264f SB |
591 | if (IS_ERR(hw)) |
592 | return ERR_CAST(hw); | |
593 | return hw->clk; | |
357c3f0a | 594 | } |
4c5eeea9 | 595 | EXPORT_SYMBOL_GPL(clk_register_divider_table); |
4e3c021f | 596 | |
eb7d264f SB |
597 | /** |
598 | * clk_hw_register_divider_table - register a table based divider clock with | |
599 | * the clock framework | |
600 | * @dev: device registering this clock | |
601 | * @name: name of this clock | |
602 | * @parent_name: name of clock's parent | |
603 | * @flags: framework-specific flags | |
604 | * @reg: register address to adjust divider | |
605 | * @shift: number of bits to shift the bitfield | |
606 | * @width: width of the bitfield | |
607 | * @clk_divider_flags: divider-specific flags for this clock | |
608 | * @table: array of divider/value pairs ending with a div set to 0 | |
609 | * @lock: shared register lock for this clock | |
610 | */ | |
611 | struct clk_hw *clk_hw_register_divider_table(struct device *dev, | |
612 | const char *name, const char *parent_name, unsigned long flags, | |
613 | void __iomem *reg, u8 shift, u8 width, | |
614 | u8 clk_divider_flags, const struct clk_div_table *table, | |
615 | spinlock_t *lock) | |
616 | { | |
617 | return _register_divider(dev, name, parent_name, flags, reg, shift, | |
618 | width, clk_divider_flags, table, lock); | |
619 | } | |
620 | EXPORT_SYMBOL_GPL(clk_hw_register_divider_table); | |
621 | ||
4e3c021f KK |
622 | void clk_unregister_divider(struct clk *clk) |
623 | { | |
624 | struct clk_divider *div; | |
625 | struct clk_hw *hw; | |
626 | ||
627 | hw = __clk_get_hw(clk); | |
628 | if (!hw) | |
629 | return; | |
630 | ||
631 | div = to_clk_divider(hw); | |
632 | ||
633 | clk_unregister(clk); | |
634 | kfree(div); | |
635 | } | |
636 | EXPORT_SYMBOL_GPL(clk_unregister_divider); | |
eb7d264f SB |
637 | |
638 | /** | |
639 | * clk_hw_unregister_divider - unregister a clk divider | |
640 | * @hw: hardware-specific clock data to unregister | |
641 | */ | |
642 | void clk_hw_unregister_divider(struct clk_hw *hw) | |
643 | { | |
644 | struct clk_divider *div; | |
645 | ||
646 | div = to_clk_divider(hw); | |
647 | ||
648 | clk_hw_unregister(hw); | |
649 | kfree(div); | |
650 | } | |
651 | EXPORT_SYMBOL_GPL(clk_hw_unregister_divider); |