Commit | Line | Data |
---|---|---|
543d9378 PW |
1 | /* |
2 | * linux/arch/arm/mach-omap2/clock.c | |
3 | * | |
4 | * Copyright (C) 2005 Texas Instruments Inc. | |
5 | * Richard Woodruff <r-woodruff2@ti.com> | |
6 | * Created for OMAP2. | |
7 | * | |
8 | * Cleaned up and modified to use omap shared clock framework by | |
9 | * Tony Lindgren <tony@atomide.com> | |
10 | * | |
11 | * Copyright (C) 2007 Texas Instruments, Inc. | |
12 | * Copyright (C) 2007 Nokia Corporation | |
13 | * Paul Walmsley | |
14 | * | |
15 | * Based on omap1 clock.c, Copyright (C) 2004 - 2005 Nokia corporation | |
16 | * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> | |
17 | * | |
18 | * This program is free software; you can redistribute it and/or modify | |
19 | * it under the terms of the GNU General Public License version 2 as | |
20 | * published by the Free Software Foundation. | |
21 | */ | |
22 | #undef DEBUG | |
23 | ||
24 | #include <linux/module.h> | |
25 | #include <linux/kernel.h> | |
26 | #include <linux/device.h> | |
27 | #include <linux/list.h> | |
28 | #include <linux/errno.h> | |
29 | #include <linux/delay.h> | |
30 | #include <linux/clk.h> | |
31 | #include <asm/bitops.h> | |
32 | ||
33 | #include <asm/io.h> | |
34 | ||
35 | #include <asm/arch/clock.h> | |
36 | #include <asm/arch/sram.h> | |
37 | #include <asm/arch/cpu.h> | |
38 | #include <asm/div64.h> | |
39 | ||
40 | #include "memory.h" | |
41 | #include "sdrc.h" | |
42 | #include "clock.h" | |
43 | #include "prm.h" | |
44 | #include "prm-regbits-24xx.h" | |
45 | #include "cm.h" | |
46 | #include "cm-regbits-24xx.h" | |
47 | #include "cm-regbits-34xx.h" | |
48 | ||
49 | #define MAX_CLOCK_ENABLE_WAIT 100000 | |
50 | ||
51 | u8 cpu_mask; | |
52 | ||
53 | /*------------------------------------------------------------------------- | |
54 | * Omap2 specific clock functions | |
55 | *-------------------------------------------------------------------------*/ | |
56 | ||
57 | /** | |
58 | * omap2_init_clksel_parent - set a clksel clk's parent field from the hardware | |
59 | * @clk: OMAP clock struct ptr to use | |
60 | * | |
61 | * Given a pointer to a source-selectable struct clk, read the hardware | |
62 | * register and determine what its parent is currently set to. Update the | |
63 | * clk->parent field with the appropriate clk ptr. | |
64 | */ | |
65 | void omap2_init_clksel_parent(struct clk *clk) | |
66 | { | |
67 | const struct clksel *clks; | |
68 | const struct clksel_rate *clkr; | |
69 | u32 r, found = 0; | |
70 | ||
71 | if (!clk->clksel) | |
72 | return; | |
73 | ||
74 | r = __raw_readl(clk->clksel_reg) & clk->clksel_mask; | |
75 | r >>= __ffs(clk->clksel_mask); | |
76 | ||
77 | for (clks = clk->clksel; clks->parent && !found; clks++) { | |
78 | for (clkr = clks->rates; clkr->div && !found; clkr++) { | |
79 | if ((clkr->flags & cpu_mask) && (clkr->val == r)) { | |
80 | if (clk->parent != clks->parent) { | |
81 | pr_debug("clock: inited %s parent " | |
82 | "to %s (was %s)\n", | |
83 | clk->name, clks->parent->name, | |
84 | ((clk->parent) ? | |
85 | clk->parent->name : "NULL")); | |
86 | clk->parent = clks->parent; | |
87 | }; | |
88 | found = 1; | |
89 | } | |
90 | } | |
91 | } | |
92 | ||
93 | if (!found) | |
94 | printk(KERN_ERR "clock: init parent: could not find " | |
95 | "regval %0x for clock %s\n", r, clk->name); | |
96 | ||
97 | return; | |
98 | } | |
99 | ||
100 | /* Returns the DPLL rate */ | |
101 | u32 omap2_get_dpll_rate(struct clk *clk) | |
102 | { | |
103 | long long dpll_clk; | |
104 | u32 dpll_mult, dpll_div, dpll; | |
105 | const struct dpll_data *dd; | |
106 | ||
107 | dd = clk->dpll_data; | |
108 | /* REVISIT: What do we return on error? */ | |
109 | if (!dd) | |
110 | return 0; | |
111 | ||
112 | dpll = __raw_readl(dd->mult_div1_reg); | |
113 | dpll_mult = dpll & dd->mult_mask; | |
114 | dpll_mult >>= __ffs(dd->mult_mask); | |
115 | dpll_div = dpll & dd->div1_mask; | |
116 | dpll_div >>= __ffs(dd->div1_mask); | |
117 | ||
118 | dpll_clk = (long long)clk->parent->rate * dpll_mult; | |
119 | do_div(dpll_clk, dpll_div + 1); | |
120 | ||
121 | /* 34XX only */ | |
122 | if (dd->div2_reg) { | |
123 | dpll = __raw_readl(dd->div2_reg); | |
124 | dpll_div = dpll & dd->div2_mask; | |
6b8858a9 | 125 | dpll_div >>= __ffs(dd->div2_mask); |
543d9378 PW |
126 | do_div(dpll_clk, dpll_div + 1); |
127 | } | |
128 | ||
129 | return dpll_clk; | |
130 | } | |
131 | ||
132 | /* | |
133 | * Used for clocks that have the same value as the parent clock, | |
134 | * divided by some factor | |
135 | */ | |
136 | void omap2_fixed_divisor_recalc(struct clk *clk) | |
137 | { | |
138 | WARN_ON(!clk->fixed_div); | |
139 | ||
140 | clk->rate = clk->parent->rate / clk->fixed_div; | |
141 | ||
142 | if (clk->flags & RATE_PROPAGATES) | |
143 | propagate_rate(clk); | |
144 | } | |
145 | ||
146 | /** | |
147 | * omap2_wait_clock_ready - wait for clock to enable | |
148 | * @reg: physical address of clock IDLEST register | |
149 | * @mask: value to mask against to determine if the clock is active | |
150 | * @name: name of the clock (for printk) | |
151 | * | |
152 | * Returns 1 if the clock enabled in time, or 0 if it failed to enable | |
153 | * in roughly MAX_CLOCK_ENABLE_WAIT microseconds. | |
154 | */ | |
155 | int omap2_wait_clock_ready(void __iomem *reg, u32 mask, const char *name) | |
156 | { | |
157 | int i = 0; | |
158 | int ena = 0; | |
159 | ||
160 | /* | |
161 | * 24xx uses 0 to indicate not ready, and 1 to indicate ready. | |
162 | * 34xx reverses this, just to keep us on our toes | |
163 | */ | |
164 | if (cpu_mask & (RATE_IN_242X | RATE_IN_243X)) { | |
165 | ena = mask; | |
166 | } else if (cpu_mask & RATE_IN_343X) { | |
167 | ena = 0; | |
168 | } | |
169 | ||
170 | /* Wait for lock */ | |
171 | while (((__raw_readl(reg) & mask) != ena) && | |
172 | (i++ < MAX_CLOCK_ENABLE_WAIT)) { | |
173 | udelay(1); | |
174 | } | |
175 | ||
176 | if (i < MAX_CLOCK_ENABLE_WAIT) | |
177 | pr_debug("Clock %s stable after %d loops\n", name, i); | |
178 | else | |
179 | printk(KERN_ERR "Clock %s didn't enable in %d tries\n", | |
180 | name, MAX_CLOCK_ENABLE_WAIT); | |
181 | ||
182 | ||
183 | return (i < MAX_CLOCK_ENABLE_WAIT) ? 1 : 0; | |
184 | }; | |
185 | ||
186 | ||
187 | /* | |
188 | * Note: We don't need special code here for INVERT_ENABLE | |
189 | * for the time being since INVERT_ENABLE only applies to clocks enabled by | |
190 | * CM_CLKEN_PLL | |
191 | */ | |
192 | static void omap2_clk_wait_ready(struct clk *clk) | |
193 | { | |
194 | void __iomem *reg, *other_reg, *st_reg; | |
195 | u32 bit; | |
196 | ||
197 | /* | |
198 | * REVISIT: This code is pretty ugly. It would be nice to generalize | |
199 | * it and pull it into struct clk itself somehow. | |
200 | */ | |
201 | reg = clk->enable_reg; | |
202 | if ((((u32)reg & 0xff) >= CM_FCLKEN1) && | |
203 | (((u32)reg & 0xff) <= OMAP24XX_CM_FCLKEN2)) | |
204 | other_reg = (void __iomem *)(((u32)reg & ~0xf0) | 0x10); /* CM_ICLKEN* */ | |
205 | else if ((((u32)reg & 0xff) >= CM_ICLKEN1) && | |
206 | (((u32)reg & 0xff) <= OMAP24XX_CM_ICLKEN4)) | |
207 | other_reg = (void __iomem *)(((u32)reg & ~0xf0) | 0x00); /* CM_FCLKEN* */ | |
208 | else | |
209 | return; | |
210 | ||
211 | /* REVISIT: What are the appropriate exclusions for 34XX? */ | |
212 | /* No check for DSS or cam clocks */ | |
213 | if (cpu_is_omap24xx() && ((u32)reg & 0x0f) == 0) { /* CM_{F,I}CLKEN1 */ | |
214 | if (clk->enable_bit == OMAP24XX_EN_DSS2_SHIFT || | |
215 | clk->enable_bit == OMAP24XX_EN_DSS1_SHIFT || | |
216 | clk->enable_bit == OMAP24XX_EN_CAM_SHIFT) | |
217 | return; | |
218 | } | |
219 | ||
220 | /* REVISIT: What are the appropriate exclusions for 34XX? */ | |
221 | /* OMAP3: ignore DSS-mod clocks */ | |
222 | if (cpu_is_omap34xx() && | |
223 | (((u32)reg & ~0xff) == (u32)OMAP_CM_REGADDR(OMAP3430_DSS_MOD, 0))) | |
224 | return; | |
225 | ||
226 | /* Check if both functional and interface clocks | |
227 | * are running. */ | |
228 | bit = 1 << clk->enable_bit; | |
229 | if (!(__raw_readl(other_reg) & bit)) | |
230 | return; | |
231 | st_reg = (void __iomem *)(((u32)other_reg & ~0xf0) | 0x20); /* CM_IDLEST* */ | |
232 | ||
233 | omap2_wait_clock_ready(st_reg, bit, clk->name); | |
234 | } | |
235 | ||
236 | /* Enables clock without considering parent dependencies or use count | |
237 | * REVISIT: Maybe change this to use clk->enable like on omap1? | |
238 | */ | |
239 | int _omap2_clk_enable(struct clk *clk) | |
240 | { | |
241 | u32 regval32; | |
242 | ||
243 | if (clk->flags & (ALWAYS_ENABLED | PARENT_CONTROLS_CLOCK)) | |
244 | return 0; | |
245 | ||
246 | if (clk->enable) | |
247 | return clk->enable(clk); | |
248 | ||
249 | if (unlikely(clk->enable_reg == 0)) { | |
250 | printk(KERN_ERR "clock.c: Enable for %s without enable code\n", | |
251 | clk->name); | |
252 | return 0; /* REVISIT: -EINVAL */ | |
253 | } | |
254 | ||
255 | regval32 = __raw_readl(clk->enable_reg); | |
256 | if (clk->flags & INVERT_ENABLE) | |
257 | regval32 &= ~(1 << clk->enable_bit); | |
258 | else | |
259 | regval32 |= (1 << clk->enable_bit); | |
260 | __raw_writel(regval32, clk->enable_reg); | |
261 | wmb(); | |
262 | ||
263 | omap2_clk_wait_ready(clk); | |
264 | ||
265 | return 0; | |
266 | } | |
267 | ||
268 | /* Disables clock without considering parent dependencies or use count */ | |
269 | void _omap2_clk_disable(struct clk *clk) | |
270 | { | |
271 | u32 regval32; | |
272 | ||
273 | if (clk->flags & (ALWAYS_ENABLED | PARENT_CONTROLS_CLOCK)) | |
274 | return; | |
275 | ||
276 | if (clk->disable) { | |
277 | clk->disable(clk); | |
278 | return; | |
279 | } | |
280 | ||
281 | if (clk->enable_reg == 0) { | |
282 | /* | |
283 | * 'Independent' here refers to a clock which is not | |
284 | * controlled by its parent. | |
285 | */ | |
286 | printk(KERN_ERR "clock: clk_disable called on independent " | |
287 | "clock %s which has no enable_reg\n", clk->name); | |
288 | return; | |
289 | } | |
290 | ||
291 | regval32 = __raw_readl(clk->enable_reg); | |
292 | if (clk->flags & INVERT_ENABLE) | |
293 | regval32 |= (1 << clk->enable_bit); | |
294 | else | |
295 | regval32 &= ~(1 << clk->enable_bit); | |
296 | __raw_writel(regval32, clk->enable_reg); | |
297 | wmb(); | |
298 | } | |
299 | ||
300 | void omap2_clk_disable(struct clk *clk) | |
301 | { | |
302 | if (clk->usecount > 0 && !(--clk->usecount)) { | |
303 | _omap2_clk_disable(clk); | |
304 | if (likely((u32)clk->parent)) | |
305 | omap2_clk_disable(clk->parent); | |
306 | } | |
307 | } | |
308 | ||
309 | int omap2_clk_enable(struct clk *clk) | |
310 | { | |
311 | int ret = 0; | |
312 | ||
313 | if (clk->usecount++ == 0) { | |
314 | if (likely((u32)clk->parent)) | |
315 | ret = omap2_clk_enable(clk->parent); | |
316 | ||
317 | if (unlikely(ret != 0)) { | |
318 | clk->usecount--; | |
319 | return ret; | |
320 | } | |
321 | ||
322 | ret = _omap2_clk_enable(clk); | |
323 | ||
324 | if (unlikely(ret != 0) && clk->parent) { | |
325 | omap2_clk_disable(clk->parent); | |
326 | clk->usecount--; | |
327 | } | |
328 | } | |
329 | ||
330 | return ret; | |
331 | } | |
332 | ||
333 | /* | |
334 | * Used for clocks that are part of CLKSEL_xyz governed clocks. | |
335 | * REVISIT: Maybe change to use clk->enable() functions like on omap1? | |
336 | */ | |
337 | void omap2_clksel_recalc(struct clk *clk) | |
338 | { | |
339 | u32 div = 0; | |
340 | ||
341 | pr_debug("clock: recalc'ing clksel clk %s\n", clk->name); | |
342 | ||
343 | div = omap2_clksel_get_divisor(clk); | |
344 | if (div == 0) | |
345 | return; | |
346 | ||
347 | if (unlikely(clk->rate == clk->parent->rate / div)) | |
348 | return; | |
349 | clk->rate = clk->parent->rate / div; | |
350 | ||
351 | pr_debug("clock: new clock rate is %ld (div %d)\n", clk->rate, div); | |
352 | ||
353 | if (unlikely(clk->flags & RATE_PROPAGATES)) | |
354 | propagate_rate(clk); | |
355 | } | |
356 | ||
357 | /** | |
358 | * omap2_get_clksel_by_parent - return clksel struct for a given clk & parent | |
359 | * @clk: OMAP struct clk ptr to inspect | |
360 | * @src_clk: OMAP struct clk ptr of the parent clk to search for | |
361 | * | |
362 | * Scan the struct clksel array associated with the clock to find | |
363 | * the element associated with the supplied parent clock address. | |
364 | * Returns a pointer to the struct clksel on success or NULL on error. | |
365 | */ | |
366 | const struct clksel *omap2_get_clksel_by_parent(struct clk *clk, | |
367 | struct clk *src_clk) | |
368 | { | |
369 | const struct clksel *clks; | |
370 | ||
371 | if (!clk->clksel) | |
372 | return NULL; | |
373 | ||
374 | for (clks = clk->clksel; clks->parent; clks++) { | |
375 | if (clks->parent == src_clk) | |
376 | break; /* Found the requested parent */ | |
377 | } | |
378 | ||
379 | if (!clks->parent) { | |
380 | printk(KERN_ERR "clock: Could not find parent clock %s in " | |
381 | "clksel array of clock %s\n", src_clk->name, | |
382 | clk->name); | |
383 | return NULL; | |
384 | } | |
385 | ||
386 | return clks; | |
387 | } | |
388 | ||
389 | /** | |
390 | * omap2_clksel_round_rate_div - find divisor for the given clock and rate | |
391 | * @clk: OMAP struct clk to use | |
392 | * @target_rate: desired clock rate | |
393 | * @new_div: ptr to where we should store the divisor | |
394 | * | |
395 | * Finds 'best' divider value in an array based on the source and target | |
396 | * rates. The divider array must be sorted with smallest divider first. | |
397 | * Note that this will not work for clocks which are part of CONFIG_PARTICIPANT, | |
398 | * they are only settable as part of virtual_prcm set. | |
399 | * | |
400 | * Returns the rounded clock rate or returns 0xffffffff on error. | |
401 | */ | |
402 | u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate, | |
403 | u32 *new_div) | |
404 | { | |
405 | unsigned long test_rate; | |
406 | const struct clksel *clks; | |
407 | const struct clksel_rate *clkr; | |
408 | u32 last_div = 0; | |
409 | ||
410 | printk(KERN_INFO "clock: clksel_round_rate_div: %s target_rate %ld\n", | |
411 | clk->name, target_rate); | |
412 | ||
413 | *new_div = 1; | |
414 | ||
415 | clks = omap2_get_clksel_by_parent(clk, clk->parent); | |
416 | if (clks == NULL) | |
417 | return ~0; | |
418 | ||
419 | for (clkr = clks->rates; clkr->div; clkr++) { | |
420 | if (!(clkr->flags & cpu_mask)) | |
421 | continue; | |
422 | ||
423 | /* Sanity check */ | |
424 | if (clkr->div <= last_div) | |
425 | printk(KERN_ERR "clock: clksel_rate table not sorted " | |
426 | "for clock %s", clk->name); | |
427 | ||
428 | last_div = clkr->div; | |
429 | ||
430 | test_rate = clk->parent->rate / clkr->div; | |
431 | ||
432 | if (test_rate <= target_rate) | |
433 | break; /* found it */ | |
434 | } | |
435 | ||
436 | if (!clkr->div) { | |
437 | printk(KERN_ERR "clock: Could not find divisor for target " | |
438 | "rate %ld for clock %s parent %s\n", target_rate, | |
439 | clk->name, clk->parent->name); | |
440 | return ~0; | |
441 | } | |
442 | ||
443 | *new_div = clkr->div; | |
444 | ||
445 | printk(KERN_INFO "clock: new_div = %d, new_rate = %ld\n", *new_div, | |
446 | (clk->parent->rate / clkr->div)); | |
447 | ||
448 | return (clk->parent->rate / clkr->div); | |
449 | } | |
450 | ||
451 | /** | |
452 | * omap2_clksel_round_rate - find rounded rate for the given clock and rate | |
453 | * @clk: OMAP struct clk to use | |
454 | * @target_rate: desired clock rate | |
455 | * | |
456 | * Compatibility wrapper for OMAP clock framework | |
457 | * Finds best target rate based on the source clock and possible dividers. | |
458 | * rates. The divider array must be sorted with smallest divider first. | |
459 | * Note that this will not work for clocks which are part of CONFIG_PARTICIPANT, | |
460 | * they are only settable as part of virtual_prcm set. | |
461 | * | |
462 | * Returns the rounded clock rate or returns 0xffffffff on error. | |
463 | */ | |
464 | long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate) | |
465 | { | |
466 | u32 new_div; | |
467 | ||
468 | return omap2_clksel_round_rate_div(clk, target_rate, &new_div); | |
469 | } | |
470 | ||
471 | ||
472 | /* Given a clock and a rate apply a clock specific rounding function */ | |
473 | long omap2_clk_round_rate(struct clk *clk, unsigned long rate) | |
474 | { | |
475 | if (clk->round_rate != 0) | |
476 | return clk->round_rate(clk, rate); | |
477 | ||
478 | if (clk->flags & RATE_FIXED) | |
479 | printk(KERN_ERR "clock: generic omap2_clk_round_rate called " | |
480 | "on fixed-rate clock %s\n", clk->name); | |
481 | ||
482 | return clk->rate; | |
483 | } | |
484 | ||
485 | /** | |
486 | * omap2_clksel_to_divisor() - turn clksel field value into integer divider | |
487 | * @clk: OMAP struct clk to use | |
488 | * @field_val: register field value to find | |
489 | * | |
490 | * Given a struct clk of a rate-selectable clksel clock, and a register field | |
491 | * value to search for, find the corresponding clock divisor. The register | |
492 | * field value should be pre-masked and shifted down so the LSB is at bit 0 | |
493 | * before calling. Returns 0 on error | |
494 | */ | |
495 | u32 omap2_clksel_to_divisor(struct clk *clk, u32 field_val) | |
496 | { | |
497 | const struct clksel *clks; | |
498 | const struct clksel_rate *clkr; | |
499 | ||
500 | clks = omap2_get_clksel_by_parent(clk, clk->parent); | |
501 | if (clks == NULL) | |
502 | return 0; | |
503 | ||
504 | for (clkr = clks->rates; clkr->div; clkr++) { | |
505 | if ((clkr->flags & cpu_mask) && (clkr->val == field_val)) | |
506 | break; | |
507 | } | |
508 | ||
509 | if (!clkr->div) { | |
510 | printk(KERN_ERR "clock: Could not find fieldval %d for " | |
511 | "clock %s parent %s\n", field_val, clk->name, | |
512 | clk->parent->name); | |
513 | return 0; | |
514 | } | |
515 | ||
516 | return clkr->div; | |
517 | } | |
518 | ||
519 | /** | |
520 | * omap2_divisor_to_clksel() - turn clksel integer divisor into a field value | |
521 | * @clk: OMAP struct clk to use | |
522 | * @div: integer divisor to search for | |
523 | * | |
524 | * Given a struct clk of a rate-selectable clksel clock, and a clock divisor, | |
525 | * find the corresponding register field value. The return register value is | |
526 | * the value before left-shifting. Returns 0xffffffff on error | |
527 | */ | |
528 | u32 omap2_divisor_to_clksel(struct clk *clk, u32 div) | |
529 | { | |
530 | const struct clksel *clks; | |
531 | const struct clksel_rate *clkr; | |
532 | ||
533 | /* should never happen */ | |
534 | WARN_ON(div == 0); | |
535 | ||
536 | clks = omap2_get_clksel_by_parent(clk, clk->parent); | |
537 | if (clks == NULL) | |
538 | return 0; | |
539 | ||
540 | for (clkr = clks->rates; clkr->div; clkr++) { | |
541 | if ((clkr->flags & cpu_mask) && (clkr->div == div)) | |
542 | break; | |
543 | } | |
544 | ||
545 | if (!clkr->div) { | |
546 | printk(KERN_ERR "clock: Could not find divisor %d for " | |
547 | "clock %s parent %s\n", div, clk->name, | |
548 | clk->parent->name); | |
549 | return 0; | |
550 | } | |
551 | ||
552 | return clkr->val; | |
553 | } | |
554 | ||
555 | /** | |
556 | * omap2_get_clksel - find clksel register addr & field mask for a clk | |
557 | * @clk: struct clk to use | |
558 | * @field_mask: ptr to u32 to store the register field mask | |
559 | * | |
560 | * Returns the address of the clksel register upon success or NULL on error. | |
561 | */ | |
562 | void __iomem *omap2_get_clksel(struct clk *clk, u32 *field_mask) | |
563 | { | |
564 | if (unlikely((clk->clksel_reg == 0) || (clk->clksel_mask == 0))) | |
565 | return NULL; | |
566 | ||
567 | *field_mask = clk->clksel_mask; | |
568 | ||
569 | return clk->clksel_reg; | |
570 | } | |
571 | ||
572 | /** | |
573 | * omap2_clksel_get_divisor - get current divider applied to parent clock. | |
574 | * @clk: OMAP struct clk to use. | |
575 | * | |
576 | * Returns the integer divisor upon success or 0 on error. | |
577 | */ | |
578 | u32 omap2_clksel_get_divisor(struct clk *clk) | |
579 | { | |
580 | u32 field_mask, field_val; | |
581 | void __iomem *div_addr; | |
582 | ||
583 | div_addr = omap2_get_clksel(clk, &field_mask); | |
584 | if (div_addr == 0) | |
585 | return 0; | |
586 | ||
587 | field_val = __raw_readl(div_addr) & field_mask; | |
588 | field_val >>= __ffs(field_mask); | |
589 | ||
590 | return omap2_clksel_to_divisor(clk, field_val); | |
591 | } | |
592 | ||
593 | int omap2_clksel_set_rate(struct clk *clk, unsigned long rate) | |
594 | { | |
595 | u32 field_mask, field_val, reg_val, validrate, new_div = 0; | |
596 | void __iomem *div_addr; | |
597 | ||
598 | validrate = omap2_clksel_round_rate_div(clk, rate, &new_div); | |
599 | if (validrate != rate) | |
600 | return -EINVAL; | |
601 | ||
602 | div_addr = omap2_get_clksel(clk, &field_mask); | |
603 | if (div_addr == 0) | |
604 | return -EINVAL; | |
605 | ||
606 | field_val = omap2_divisor_to_clksel(clk, new_div); | |
607 | if (field_val == ~0) | |
608 | return -EINVAL; | |
609 | ||
610 | reg_val = __raw_readl(div_addr); | |
611 | reg_val &= ~field_mask; | |
612 | reg_val |= (field_val << __ffs(field_mask)); | |
613 | __raw_writel(reg_val, div_addr); | |
614 | wmb(); | |
615 | ||
616 | clk->rate = clk->parent->rate / new_div; | |
617 | ||
618 | if (clk->flags & DELAYED_APP && cpu_is_omap24xx()) { | |
619 | __raw_writel(OMAP24XX_VALID_CONFIG, OMAP24XX_PRCM_CLKCFG_CTRL); | |
620 | wmb(); | |
621 | } | |
622 | ||
623 | return 0; | |
624 | } | |
625 | ||
626 | ||
627 | /* Set the clock rate for a clock source */ | |
628 | int omap2_clk_set_rate(struct clk *clk, unsigned long rate) | |
629 | { | |
630 | int ret = -EINVAL; | |
631 | ||
632 | pr_debug("clock: set_rate for clock %s to rate %ld\n", clk->name, rate); | |
633 | ||
634 | /* CONFIG_PARTICIPANT clocks are changed only in sets via the | |
635 | rate table mechanism, driven by mpu_speed */ | |
636 | if (clk->flags & CONFIG_PARTICIPANT) | |
637 | return -EINVAL; | |
638 | ||
639 | /* dpll_ck, core_ck, virt_prcm_set; plus all clksel clocks */ | |
640 | if (clk->set_rate != 0) | |
641 | ret = clk->set_rate(clk, rate); | |
642 | ||
643 | if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES))) | |
644 | propagate_rate(clk); | |
645 | ||
646 | return ret; | |
647 | } | |
648 | ||
649 | /* | |
650 | * Converts encoded control register address into a full address | |
651 | * On error, *src_addr will be returned as 0. | |
652 | */ | |
653 | static u32 omap2_clksel_get_src_field(void __iomem **src_addr, | |
654 | struct clk *src_clk, u32 *field_mask, | |
655 | struct clk *clk, u32 *parent_div) | |
656 | { | |
657 | const struct clksel *clks; | |
658 | const struct clksel_rate *clkr; | |
659 | ||
660 | *parent_div = 0; | |
661 | *src_addr = 0; | |
662 | ||
663 | clks = omap2_get_clksel_by_parent(clk, src_clk); | |
664 | if (clks == NULL) | |
665 | return 0; | |
666 | ||
667 | for (clkr = clks->rates; clkr->div; clkr++) { | |
668 | if (clkr->flags & (cpu_mask | DEFAULT_RATE)) | |
669 | break; /* Found the default rate for this platform */ | |
670 | } | |
671 | ||
672 | if (!clkr->div) { | |
673 | printk(KERN_ERR "clock: Could not find default rate for " | |
674 | "clock %s parent %s\n", clk->name, | |
675 | src_clk->parent->name); | |
676 | return 0; | |
677 | } | |
678 | ||
679 | /* Should never happen. Add a clksel mask to the struct clk. */ | |
680 | WARN_ON(clk->clksel_mask == 0); | |
681 | ||
682 | *field_mask = clk->clksel_mask; | |
683 | *src_addr = clk->clksel_reg; | |
684 | *parent_div = clkr->div; | |
685 | ||
686 | return clkr->val; | |
687 | } | |
688 | ||
689 | int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent) | |
690 | { | |
691 | void __iomem *src_addr; | |
692 | u32 field_val, field_mask, reg_val, parent_div; | |
693 | ||
694 | if (unlikely(clk->flags & CONFIG_PARTICIPANT)) | |
695 | return -EINVAL; | |
696 | ||
697 | if (!clk->clksel) | |
698 | return -EINVAL; | |
699 | ||
700 | field_val = omap2_clksel_get_src_field(&src_addr, new_parent, | |
701 | &field_mask, clk, &parent_div); | |
702 | if (src_addr == 0) | |
703 | return -EINVAL; | |
704 | ||
705 | if (clk->usecount > 0) | |
706 | _omap2_clk_disable(clk); | |
707 | ||
708 | /* Set new source value (previous dividers if any in effect) */ | |
709 | reg_val = __raw_readl(src_addr) & ~field_mask; | |
710 | reg_val |= (field_val << __ffs(field_mask)); | |
711 | __raw_writel(reg_val, src_addr); | |
712 | wmb(); | |
713 | ||
714 | if (clk->flags & DELAYED_APP && cpu_is_omap24xx()) { | |
715 | __raw_writel(OMAP24XX_VALID_CONFIG, OMAP24XX_PRCM_CLKCFG_CTRL); | |
716 | wmb(); | |
717 | } | |
718 | ||
719 | if (clk->usecount > 0) | |
720 | _omap2_clk_enable(clk); | |
721 | ||
722 | clk->parent = new_parent; | |
723 | ||
724 | /* CLKSEL clocks follow their parents' rates, divided by a divisor */ | |
725 | clk->rate = new_parent->rate; | |
726 | ||
727 | if (parent_div > 0) | |
728 | clk->rate /= parent_div; | |
729 | ||
730 | pr_debug("clock: set parent of %s to %s (new rate %ld)\n", | |
731 | clk->name, clk->parent->name, clk->rate); | |
732 | ||
733 | if (unlikely(clk->flags & RATE_PROPAGATES)) | |
734 | propagate_rate(clk); | |
735 | ||
736 | return 0; | |
737 | } | |
738 | ||
739 | /*------------------------------------------------------------------------- | |
740 | * Omap2 clock reset and init functions | |
741 | *-------------------------------------------------------------------------*/ | |
742 | ||
743 | #ifdef CONFIG_OMAP_RESET_CLOCKS | |
744 | void omap2_clk_disable_unused(struct clk *clk) | |
745 | { | |
746 | u32 regval32, v; | |
747 | ||
748 | v = (clk->flags & INVERT_ENABLE) ? (1 << clk->enable_bit) : 0; | |
749 | ||
750 | regval32 = __raw_readl(clk->enable_reg); | |
751 | if ((regval32 & (1 << clk->enable_bit)) == v) | |
752 | return; | |
753 | ||
754 | printk(KERN_INFO "Disabling unused clock \"%s\"\n", clk->name); | |
755 | _omap2_clk_disable(clk); | |
756 | } | |
757 | #endif |