diff options
Diffstat (limited to 'arch/arm/plat-stmp3xxx/clock.c')
-rw-r--r-- | arch/arm/plat-stmp3xxx/clock.c | 1135 |
1 files changed, 1135 insertions, 0 deletions
diff --git a/arch/arm/plat-stmp3xxx/clock.c b/arch/arm/plat-stmp3xxx/clock.c new file mode 100644 index 000000000000..5d2f19a09e44 --- /dev/null +++ b/arch/arm/plat-stmp3xxx/clock.c | |||
@@ -0,0 +1,1135 @@ | |||
1 | /* | ||
2 | * Clock manipulation routines for Freescale STMP37XX/STMP378X | ||
3 | * | ||
4 | * Author: Vitaly Wool <vital@embeddedalley.com> | ||
5 | * | ||
6 | * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. | ||
7 | * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * The code contained herein is licensed under the GNU General Public | ||
12 | * License. You may obtain a copy of the GNU General Public License | ||
13 | * Version 2 or later at the following locations: | ||
14 | * | ||
15 | * http://www.opensource.org/licenses/gpl-license.html | ||
16 | * http://www.gnu.org/copyleft/gpl.html | ||
17 | */ | ||
18 | #define DEBUG | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/clk.h> | ||
23 | #include <linux/spinlock.h> | ||
24 | #include <linux/errno.h> | ||
25 | #include <linux/err.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/io.h> | ||
28 | |||
29 | #include <asm/mach-types.h> | ||
30 | #include <asm/clkdev.h> | ||
31 | #include <mach/platform.h> | ||
32 | #include <mach/regs-clkctrl.h> | ||
33 | |||
34 | #include "clock.h" | ||
35 | |||
36 | static DEFINE_SPINLOCK(clocks_lock); | ||
37 | |||
38 | static struct clk osc_24M; | ||
39 | static struct clk pll_clk; | ||
40 | static struct clk cpu_clk; | ||
41 | static struct clk hclk; | ||
42 | |||
43 | static int propagate_rate(struct clk *); | ||
44 | |||
45 | static inline int clk_is_busy(struct clk *clk) | ||
46 | { | ||
47 | return __raw_readl(clk->busy_reg) & (1 << clk->busy_bit); | ||
48 | } | ||
49 | |||
50 | static inline int clk_good(struct clk *clk) | ||
51 | { | ||
52 | return clk && !IS_ERR(clk) && clk->ops; | ||
53 | } | ||
54 | |||
55 | static int std_clk_enable(struct clk *clk) | ||
56 | { | ||
57 | if (clk->enable_reg) { | ||
58 | u32 clk_reg = __raw_readl(clk->enable_reg); | ||
59 | if (clk->enable_negate) | ||
60 | clk_reg &= ~(1 << clk->enable_shift); | ||
61 | else | ||
62 | clk_reg |= (1 << clk->enable_shift); | ||
63 | __raw_writel(clk_reg, clk->enable_reg); | ||
64 | if (clk->enable_wait) | ||
65 | udelay(clk->enable_wait); | ||
66 | return 0; | ||
67 | } else | ||
68 | return -EINVAL; | ||
69 | } | ||
70 | |||
71 | static int std_clk_disable(struct clk *clk) | ||
72 | { | ||
73 | if (clk->enable_reg) { | ||
74 | u32 clk_reg = __raw_readl(clk->enable_reg); | ||
75 | if (clk->enable_negate) | ||
76 | clk_reg |= (1 << clk->enable_shift); | ||
77 | else | ||
78 | clk_reg &= ~(1 << clk->enable_shift); | ||
79 | __raw_writel(clk_reg, clk->enable_reg); | ||
80 | return 0; | ||
81 | } else | ||
82 | return -EINVAL; | ||
83 | } | ||
84 | |||
85 | static int io_set_rate(struct clk *clk, u32 rate) | ||
86 | { | ||
87 | u32 reg_frac, clkctrl_frac; | ||
88 | int i, ret = 0, mask = 0x1f; | ||
89 | |||
90 | clkctrl_frac = (clk->parent->rate * 18 + rate - 1) / rate; | ||
91 | |||
92 | if (clkctrl_frac < 18 || clkctrl_frac > 35) { | ||
93 | ret = -EINVAL; | ||
94 | goto out; | ||
95 | } | ||
96 | |||
97 | reg_frac = __raw_readl(clk->scale_reg); | ||
98 | reg_frac &= ~(mask << clk->scale_shift); | ||
99 | __raw_writel(reg_frac | (clkctrl_frac << clk->scale_shift), | ||
100 | clk->scale_reg); | ||
101 | if (clk->busy_reg) { | ||
102 | for (i = 10000; i; i--) | ||
103 | if (!clk_is_busy(clk)) | ||
104 | break; | ||
105 | if (!i) | ||
106 | ret = -ETIMEDOUT; | ||
107 | else | ||
108 | ret = 0; | ||
109 | } | ||
110 | out: | ||
111 | return ret; | ||
112 | } | ||
113 | |||
114 | static long io_get_rate(struct clk *clk) | ||
115 | { | ||
116 | long rate = clk->parent->rate * 18; | ||
117 | int mask = 0x1f; | ||
118 | |||
119 | rate /= (__raw_readl(clk->scale_reg) >> clk->scale_shift) & mask; | ||
120 | clk->rate = rate; | ||
121 | |||
122 | return rate; | ||
123 | } | ||
124 | |||
125 | static long per_get_rate(struct clk *clk) | ||
126 | { | ||
127 | long rate = clk->parent->rate; | ||
128 | long div; | ||
129 | const int mask = 0xff; | ||
130 | |||
131 | if (clk->enable_reg && | ||
132 | !(__raw_readl(clk->enable_reg) & clk->enable_shift)) | ||
133 | clk->rate = 0; | ||
134 | else { | ||
135 | div = (__raw_readl(clk->scale_reg) >> clk->scale_shift) & mask; | ||
136 | if (div) | ||
137 | rate /= div; | ||
138 | clk->rate = rate; | ||
139 | } | ||
140 | |||
141 | return clk->rate; | ||
142 | } | ||
143 | |||
144 | static int per_set_rate(struct clk *clk, u32 rate) | ||
145 | { | ||
146 | int ret = -EINVAL; | ||
147 | int div = (clk->parent->rate + rate - 1) / rate; | ||
148 | u32 reg_frac; | ||
149 | const int mask = 0xff; | ||
150 | int try = 10; | ||
151 | int i = -1; | ||
152 | |||
153 | if (div == 0 || div > mask) | ||
154 | goto out; | ||
155 | |||
156 | reg_frac = __raw_readl(clk->scale_reg); | ||
157 | reg_frac &= ~(mask << clk->scale_shift); | ||
158 | |||
159 | while (try--) { | ||
160 | __raw_writel(reg_frac | (div << clk->scale_shift), | ||
161 | clk->scale_reg); | ||
162 | |||
163 | if (clk->busy_reg) { | ||
164 | for (i = 10000; i; i--) | ||
165 | if (!clk_is_busy(clk)) | ||
166 | break; | ||
167 | } | ||
168 | if (i) | ||
169 | break; | ||
170 | } | ||
171 | |||
172 | if (!i) | ||
173 | ret = -ETIMEDOUT; | ||
174 | else | ||
175 | ret = 0; | ||
176 | |||
177 | out: | ||
178 | if (ret != 0) | ||
179 | printk(KERN_ERR "%s: error %d\n", __func__, ret); | ||
180 | return ret; | ||
181 | } | ||
182 | |||
183 | static long lcdif_get_rate(struct clk *clk) | ||
184 | { | ||
185 | long rate = clk->parent->rate; | ||
186 | long div; | ||
187 | const int mask = 0xff; | ||
188 | |||
189 | div = (__raw_readl(clk->scale_reg) >> clk->scale_shift) & mask; | ||
190 | if (div) { | ||
191 | rate /= div; | ||
192 | div = (__raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC) & | ||
193 | BM_CLKCTRL_FRAC_PIXFRAC) >> BP_CLKCTRL_FRAC_PIXFRAC; | ||
194 | rate /= div; | ||
195 | } | ||
196 | clk->rate = rate; | ||
197 | |||
198 | return rate; | ||
199 | } | ||
200 | |||
201 | static int lcdif_set_rate(struct clk *clk, u32 rate) | ||
202 | { | ||
203 | int ret = 0; | ||
204 | /* | ||
205 | * On 3700, we can get most timings exact by modifying ref_pix | ||
206 | * and the divider, but keeping the phase timings at 1 (2 | ||
207 | * phases per cycle). | ||
208 | * | ||
209 | * ref_pix can be between 480e6*18/35=246.9MHz and 480e6*18/18=480MHz, | ||
210 | * which is between 18/(18*480e6)=2.084ns and 35/(18*480e6)=4.050ns. | ||
211 | * | ||
212 | * ns_cycle >= 2*18e3/(18*480) = 25/6 | ||
213 | * ns_cycle <= 2*35e3/(18*480) = 875/108 | ||
214 | * | ||
215 | * Multiply the ns_cycle by 'div' to lengthen it until it fits the | ||
216 | * bounds. This is the divider we'll use after ref_pix. | ||
217 | * | ||
218 | * 6 * ns_cycle >= 25 * div | ||
219 | * 108 * ns_cycle <= 875 * div | ||
220 | */ | ||
221 | u32 ns_cycle = 1000000 / rate; | ||
222 | u32 div, reg_val; | ||
223 | u32 lowest_result = (u32) -1; | ||
224 | u32 lowest_div = 0, lowest_fracdiv = 0; | ||
225 | |||
226 | for (div = 1; div < 256; ++div) { | ||
227 | u32 fracdiv; | ||
228 | u32 ps_result; | ||
229 | int lower_bound = 6 * ns_cycle >= 25 * div; | ||
230 | int upper_bound = 108 * ns_cycle <= 875 * div; | ||
231 | if (!lower_bound) | ||
232 | break; | ||
233 | if (!upper_bound) | ||
234 | continue; | ||
235 | /* | ||
236 | * Found a matching div. Calculate fractional divider needed, | ||
237 | * rounded up. | ||
238 | */ | ||
239 | fracdiv = ((clk->parent->rate / 1000 * 18 / 2) * | ||
240 | ns_cycle + 1000 * div - 1) / | ||
241 | (1000 * div); | ||
242 | if (fracdiv < 18 || fracdiv > 35) { | ||
243 | ret = -EINVAL; | ||
244 | goto out; | ||
245 | } | ||
246 | /* Calculate the actual cycle time this results in */ | ||
247 | ps_result = 6250 * div * fracdiv / 27; | ||
248 | |||
249 | /* Use the fastest result that doesn't break ns_cycle */ | ||
250 | if (ps_result <= lowest_result) { | ||
251 | lowest_result = ps_result; | ||
252 | lowest_div = div; | ||
253 | lowest_fracdiv = fracdiv; | ||
254 | } | ||
255 | } | ||
256 | |||
257 | if (div >= 256 || lowest_result == (u32) -1) { | ||
258 | ret = -EINVAL; | ||
259 | goto out; | ||
260 | } | ||
261 | pr_debug("Programming PFD=%u,DIV=%u ref_pix=%uMHz " | ||
262 | "PIXCLK=%uMHz cycle=%u.%03uns\n", | ||
263 | lowest_fracdiv, lowest_div, | ||
264 | 480*18/lowest_fracdiv, 480*18/lowest_fracdiv/lowest_div, | ||
265 | lowest_result / 1000, lowest_result % 1000); | ||
266 | |||
267 | /* Program ref_pix phase fractional divider */ | ||
268 | reg_val = __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC); | ||
269 | reg_val &= ~BM_CLKCTRL_FRAC_PIXFRAC; | ||
270 | reg_val |= BF(lowest_fracdiv, CLKCTRL_FRAC_PIXFRAC); | ||
271 | __raw_writel(reg_val, REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC); | ||
272 | |||
273 | /* Ungate PFD */ | ||
274 | stmp3xxx_clearl(BM_CLKCTRL_FRAC_CLKGATEPIX, | ||
275 | REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC); | ||
276 | |||
277 | /* Program pix divider */ | ||
278 | reg_val = __raw_readl(clk->scale_reg); | ||
279 | reg_val &= ~(BM_CLKCTRL_PIX_DIV | BM_CLKCTRL_PIX_CLKGATE); | ||
280 | reg_val |= BF(lowest_div, CLKCTRL_PIX_DIV); | ||
281 | __raw_writel(reg_val, clk->scale_reg); | ||
282 | |||
283 | /* Wait for divider update */ | ||
284 | if (clk->busy_reg) { | ||
285 | int i; | ||
286 | for (i = 10000; i; i--) | ||
287 | if (!clk_is_busy(clk)) | ||
288 | break; | ||
289 | if (!i) { | ||
290 | ret = -ETIMEDOUT; | ||
291 | goto out; | ||
292 | } | ||
293 | } | ||
294 | |||
295 | /* Switch to ref_pix source */ | ||
296 | reg_val = __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ); | ||
297 | reg_val &= ~BM_CLKCTRL_CLKSEQ_BYPASS_PIX; | ||
298 | __raw_writel(reg_val, REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ); | ||
299 | |||
300 | out: | ||
301 | return ret; | ||
302 | } | ||
303 | |||
304 | |||
305 | static int cpu_set_rate(struct clk *clk, u32 rate) | ||
306 | { | ||
307 | u32 reg_val; | ||
308 | |||
309 | if (rate < 24000) | ||
310 | return -EINVAL; | ||
311 | else if (rate == 24000) { | ||
312 | /* switch to the 24M source */ | ||
313 | clk_set_parent(clk, &osc_24M); | ||
314 | } else { | ||
315 | int i; | ||
316 | u32 clkctrl_cpu = 1; | ||
317 | u32 c = clkctrl_cpu; | ||
318 | u32 clkctrl_frac = 1; | ||
319 | u32 val; | ||
320 | for ( ; c < 0x40; c++) { | ||
321 | u32 f = (pll_clk.rate*18/c + rate/2) / rate; | ||
322 | int s1, s2; | ||
323 | |||
324 | if (f < 18 || f > 35) | ||
325 | continue; | ||
326 | s1 = pll_clk.rate*18/clkctrl_frac/clkctrl_cpu - rate; | ||
327 | s2 = pll_clk.rate*18/c/f - rate; | ||
328 | pr_debug("%s: s1 %d, s2 %d\n", __func__, s1, s2); | ||
329 | if (abs(s1) > abs(s2)) { | ||
330 | clkctrl_cpu = c; | ||
331 | clkctrl_frac = f; | ||
332 | } | ||
333 | if (s2 == 0) | ||
334 | break; | ||
335 | }; | ||
336 | pr_debug("%s: clkctrl_cpu %d, clkctrl_frac %d\n", __func__, | ||
337 | clkctrl_cpu, clkctrl_frac); | ||
338 | if (c == 0x40) { | ||
339 | int d = pll_clk.rate*18/clkctrl_frac/clkctrl_cpu - | ||
340 | rate; | ||
341 | if (abs(d) > 100 || | ||
342 | clkctrl_frac < 18 || clkctrl_frac > 35) | ||
343 | return -EINVAL; | ||
344 | } | ||
345 | |||
346 | /* 4.6.2 */ | ||
347 | val = __raw_readl(clk->scale_reg); | ||
348 | val &= ~(0x3f << clk->scale_shift); | ||
349 | val |= clkctrl_frac; | ||
350 | clk_set_parent(clk, &osc_24M); | ||
351 | udelay(10); | ||
352 | __raw_writel(val, clk->scale_reg); | ||
353 | /* ungate */ | ||
354 | __raw_writel(1<<7, clk->scale_reg + 8); | ||
355 | /* write clkctrl_cpu */ | ||
356 | clk->saved_div = clkctrl_cpu; | ||
357 | |||
358 | reg_val = __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU); | ||
359 | reg_val &= ~0x3F; | ||
360 | reg_val |= clkctrl_cpu; | ||
361 | __raw_writel(reg_val, REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU); | ||
362 | |||
363 | for (i = 10000; i; i--) | ||
364 | if (!clk_is_busy(clk)) | ||
365 | break; | ||
366 | if (!i) { | ||
367 | printk(KERN_ERR "couldn't set up CPU divisor\n"); | ||
368 | return -ETIMEDOUT; | ||
369 | } | ||
370 | clk_set_parent(clk, &pll_clk); | ||
371 | clk->saved_div = 0; | ||
372 | udelay(10); | ||
373 | } | ||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | static long cpu_get_rate(struct clk *clk) | ||
378 | { | ||
379 | long rate = clk->parent->rate * 18; | ||
380 | |||
381 | rate /= (__raw_readl(clk->scale_reg) >> clk->scale_shift) & 0x3f; | ||
382 | rate /= __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU) & 0x3f; | ||
383 | rate = ((rate + 9) / 10) * 10; | ||
384 | clk->rate = rate; | ||
385 | |||
386 | return rate; | ||
387 | } | ||
388 | |||
389 | static long cpu_round_rate(struct clk *clk, u32 rate) | ||
390 | { | ||
391 | unsigned long r = 0; | ||
392 | |||
393 | if (rate <= 24000) | ||
394 | r = 24000; | ||
395 | else { | ||
396 | u32 clkctrl_cpu = 1; | ||
397 | u32 clkctrl_frac; | ||
398 | do { | ||
399 | clkctrl_frac = | ||
400 | (pll_clk.rate*18 / clkctrl_cpu + rate/2) / rate; | ||
401 | if (clkctrl_frac > 35) | ||
402 | continue; | ||
403 | if (pll_clk.rate*18 / clkctrl_frac / clkctrl_cpu/10 == | ||
404 | rate / 10) | ||
405 | break; | ||
406 | } while (pll_clk.rate / 2 >= clkctrl_cpu++ * rate); | ||
407 | if (pll_clk.rate / 2 < (clkctrl_cpu - 1) * rate) | ||
408 | clkctrl_cpu--; | ||
409 | pr_debug("%s: clkctrl_cpu %d, clkctrl_frac %d\n", __func__, | ||
410 | clkctrl_cpu, clkctrl_frac); | ||
411 | if (clkctrl_frac < 18) | ||
412 | clkctrl_frac = 18; | ||
413 | if (clkctrl_frac > 35) | ||
414 | clkctrl_frac = 35; | ||
415 | |||
416 | r = pll_clk.rate * 18; | ||
417 | r /= clkctrl_frac; | ||
418 | r /= clkctrl_cpu; | ||
419 | r = 10 * ((r + 9) / 10); | ||
420 | } | ||
421 | return r; | ||
422 | } | ||
423 | |||
424 | static long emi_get_rate(struct clk *clk) | ||
425 | { | ||
426 | long rate = clk->parent->rate * 18; | ||
427 | |||
428 | rate /= (__raw_readl(clk->scale_reg) >> clk->scale_shift) & 0x3f; | ||
429 | rate /= __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_EMI) & 0x3f; | ||
430 | clk->rate = rate; | ||
431 | |||
432 | return rate; | ||
433 | } | ||
434 | |||
435 | static int clkseq_set_parent(struct clk *clk, struct clk *parent) | ||
436 | { | ||
437 | int ret = -EINVAL; | ||
438 | int shift = 8; | ||
439 | |||
440 | /* bypass? */ | ||
441 | if (parent == &osc_24M) | ||
442 | shift = 4; | ||
443 | |||
444 | if (clk->bypass_reg) { | ||
445 | #ifdef CONFIG_ARCH_STMP378X | ||
446 | u32 hbus_val, cpu_val; | ||
447 | |||
448 | if (clk == &cpu_clk && shift == 4) { | ||
449 | hbus_val = __raw_readl(REGS_CLKCTRL_BASE + | ||
450 | HW_CLKCTRL_HBUS); | ||
451 | cpu_val = __raw_readl(REGS_CLKCTRL_BASE + | ||
452 | HW_CLKCTRL_CPU); | ||
453 | |||
454 | hbus_val &= ~(BM_CLKCTRL_HBUS_DIV_FRAC_EN | | ||
455 | BM_CLKCTRL_HBUS_DIV); | ||
456 | clk->saved_div = cpu_val & BM_CLKCTRL_CPU_DIV_CPU; | ||
457 | cpu_val &= ~BM_CLKCTRL_CPU_DIV_CPU; | ||
458 | cpu_val |= 1; | ||
459 | |||
460 | if (machine_is_stmp378x()) { | ||
461 | __raw_writel(hbus_val, | ||
462 | REGS_CLKCTRL_BASE + HW_CLKCTRL_HBUS); | ||
463 | __raw_writel(cpu_val, | ||
464 | REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU); | ||
465 | hclk.rate = 0; | ||
466 | } | ||
467 | } else if (clk == &cpu_clk && shift == 8) { | ||
468 | hbus_val = __raw_readl(REGS_CLKCTRL_BASE + | ||
469 | HW_CLKCTRL_HBUS); | ||
470 | cpu_val = __raw_readl(REGS_CLKCTRL_BASE + | ||
471 | HW_CLKCTRL_CPU); | ||
472 | hbus_val &= ~(BM_CLKCTRL_HBUS_DIV_FRAC_EN | | ||
473 | BM_CLKCTRL_HBUS_DIV); | ||
474 | hbus_val |= 2; | ||
475 | cpu_val &= ~BM_CLKCTRL_CPU_DIV_CPU; | ||
476 | if (clk->saved_div) | ||
477 | cpu_val |= clk->saved_div; | ||
478 | else | ||
479 | cpu_val |= 2; | ||
480 | |||
481 | if (machine_is_stmp378x()) { | ||
482 | __raw_writel(hbus_val, | ||
483 | REGS_CLKCTRL_BASE + HW_CLKCTRL_HBUS); | ||
484 | __raw_writel(cpu_val, | ||
485 | REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU); | ||
486 | hclk.rate = 0; | ||
487 | } | ||
488 | } | ||
489 | #endif | ||
490 | __raw_writel(1 << clk->bypass_shift, clk->bypass_reg + shift); | ||
491 | |||
492 | ret = 0; | ||
493 | } | ||
494 | |||
495 | return ret; | ||
496 | } | ||
497 | |||
498 | static int hbus_set_rate(struct clk *clk, u32 rate) | ||
499 | { | ||
500 | u8 div = 0; | ||
501 | int is_frac = 0; | ||
502 | u32 clkctrl_hbus; | ||
503 | struct clk *parent = clk->parent; | ||
504 | |||
505 | pr_debug("%s: rate %d, parent rate %d\n", __func__, rate, | ||
506 | parent->rate); | ||
507 | |||
508 | if (rate > parent->rate) | ||
509 | return -EINVAL; | ||
510 | |||
511 | if (((parent->rate + rate/2) / rate) * rate != parent->rate && | ||
512 | parent->rate / rate < 32) { | ||
513 | pr_debug("%s: switching to fractional mode\n", __func__); | ||
514 | is_frac = 1; | ||
515 | } | ||
516 | |||
517 | if (is_frac) | ||
518 | div = (32 * rate + parent->rate / 2) / parent->rate; | ||
519 | else | ||
520 | div = (parent->rate + rate - 1) / rate; | ||
521 | pr_debug("%s: div calculated is %d\n", __func__, div); | ||
522 | if (!div || div > 0x1f) | ||
523 | return -EINVAL; | ||
524 | |||
525 | clk_set_parent(&cpu_clk, &osc_24M); | ||
526 | udelay(10); | ||
527 | clkctrl_hbus = __raw_readl(clk->scale_reg); | ||
528 | clkctrl_hbus &= ~0x3f; | ||
529 | clkctrl_hbus |= div; | ||
530 | clkctrl_hbus |= (is_frac << 5); | ||
531 | |||
532 | __raw_writel(clkctrl_hbus, clk->scale_reg); | ||
533 | if (clk->busy_reg) { | ||
534 | int i; | ||
535 | for (i = 10000; i; i--) | ||
536 | if (!clk_is_busy(clk)) | ||
537 | break; | ||
538 | if (!i) { | ||
539 | printk(KERN_ERR "couldn't set up CPU divisor\n"); | ||
540 | return -ETIMEDOUT; | ||
541 | } | ||
542 | } | ||
543 | clk_set_parent(&cpu_clk, &pll_clk); | ||
544 | __raw_writel(clkctrl_hbus, clk->scale_reg); | ||
545 | udelay(10); | ||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | static long hbus_get_rate(struct clk *clk) | ||
550 | { | ||
551 | long rate = clk->parent->rate; | ||
552 | |||
553 | if (__raw_readl(clk->scale_reg) & 0x20) { | ||
554 | rate *= __raw_readl(clk->scale_reg) & 0x1f; | ||
555 | rate /= 32; | ||
556 | } else | ||
557 | rate /= __raw_readl(clk->scale_reg) & 0x1f; | ||
558 | clk->rate = rate; | ||
559 | |||
560 | return rate; | ||
561 | } | ||
562 | |||
563 | static int xbus_set_rate(struct clk *clk, u32 rate) | ||
564 | { | ||
565 | u16 div = 0; | ||
566 | u32 clkctrl_xbus; | ||
567 | |||
568 | pr_debug("%s: rate %d, parent rate %d\n", __func__, rate, | ||
569 | clk->parent->rate); | ||
570 | |||
571 | div = (clk->parent->rate + rate - 1) / rate; | ||
572 | pr_debug("%s: div calculated is %d\n", __func__, div); | ||
573 | if (!div || div > 0x3ff) | ||
574 | return -EINVAL; | ||
575 | |||
576 | clkctrl_xbus = __raw_readl(clk->scale_reg); | ||
577 | clkctrl_xbus &= ~0x3ff; | ||
578 | clkctrl_xbus |= div; | ||
579 | __raw_writel(clkctrl_xbus, clk->scale_reg); | ||
580 | if (clk->busy_reg) { | ||
581 | int i; | ||
582 | for (i = 10000; i; i--) | ||
583 | if (!clk_is_busy(clk)) | ||
584 | break; | ||
585 | if (!i) { | ||
586 | printk(KERN_ERR "couldn't set up xbus divisor\n"); | ||
587 | return -ETIMEDOUT; | ||
588 | } | ||
589 | } | ||
590 | return 0; | ||
591 | } | ||
592 | |||
593 | static long xbus_get_rate(struct clk *clk) | ||
594 | { | ||
595 | long rate = clk->parent->rate; | ||
596 | |||
597 | rate /= __raw_readl(clk->scale_reg) & 0x3ff; | ||
598 | clk->rate = rate; | ||
599 | |||
600 | return rate; | ||
601 | } | ||
602 | |||
603 | |||
604 | /* Clock ops */ | ||
605 | |||
606 | static struct clk_ops std_ops = { | ||
607 | .enable = std_clk_enable, | ||
608 | .disable = std_clk_disable, | ||
609 | .get_rate = per_get_rate, | ||
610 | .set_rate = per_set_rate, | ||
611 | .set_parent = clkseq_set_parent, | ||
612 | }; | ||
613 | |||
614 | static struct clk_ops min_ops = { | ||
615 | .enable = std_clk_enable, | ||
616 | .disable = std_clk_disable, | ||
617 | }; | ||
618 | |||
619 | static struct clk_ops cpu_ops = { | ||
620 | .enable = std_clk_enable, | ||
621 | .disable = std_clk_disable, | ||
622 | .get_rate = cpu_get_rate, | ||
623 | .set_rate = cpu_set_rate, | ||
624 | .round_rate = cpu_round_rate, | ||
625 | .set_parent = clkseq_set_parent, | ||
626 | }; | ||
627 | |||
628 | static struct clk_ops io_ops = { | ||
629 | .enable = std_clk_enable, | ||
630 | .disable = std_clk_disable, | ||
631 | .get_rate = io_get_rate, | ||
632 | .set_rate = io_set_rate, | ||
633 | }; | ||
634 | |||
635 | static struct clk_ops hbus_ops = { | ||
636 | .get_rate = hbus_get_rate, | ||
637 | .set_rate = hbus_set_rate, | ||
638 | }; | ||
639 | |||
640 | static struct clk_ops xbus_ops = { | ||
641 | .get_rate = xbus_get_rate, | ||
642 | .set_rate = xbus_set_rate, | ||
643 | }; | ||
644 | |||
645 | static struct clk_ops lcdif_ops = { | ||
646 | .enable = std_clk_enable, | ||
647 | .disable = std_clk_disable, | ||
648 | .get_rate = lcdif_get_rate, | ||
649 | .set_rate = lcdif_set_rate, | ||
650 | .set_parent = clkseq_set_parent, | ||
651 | }; | ||
652 | |||
653 | static struct clk_ops emi_ops = { | ||
654 | .get_rate = emi_get_rate, | ||
655 | }; | ||
656 | |||
657 | /* List of on-chip clocks */ | ||
658 | |||
659 | static struct clk osc_24M = { | ||
660 | .flags = FIXED_RATE | ENABLED, | ||
661 | .rate = 24000, | ||
662 | }; | ||
663 | |||
664 | static struct clk pll_clk = { | ||
665 | .parent = &osc_24M, | ||
666 | .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_PLLCTRL0, | ||
667 | .enable_shift = 16, | ||
668 | .enable_wait = 10, | ||
669 | .flags = FIXED_RATE | ENABLED, | ||
670 | .rate = 480000, | ||
671 | .ops = &min_ops, | ||
672 | }; | ||
673 | |||
674 | static struct clk cpu_clk = { | ||
675 | .parent = &pll_clk, | ||
676 | .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC, | ||
677 | .scale_shift = 0, | ||
678 | .bypass_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ, | ||
679 | .bypass_shift = 7, | ||
680 | .busy_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU, | ||
681 | .busy_bit = 28, | ||
682 | .flags = RATE_PROPAGATES | ENABLED, | ||
683 | .ops = &cpu_ops, | ||
684 | }; | ||
685 | |||
686 | static struct clk io_clk = { | ||
687 | .parent = &pll_clk, | ||
688 | .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC, | ||
689 | .enable_shift = 31, | ||
690 | .enable_negate = 1, | ||
691 | .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC, | ||
692 | .scale_shift = 24, | ||
693 | .flags = RATE_PROPAGATES | ENABLED, | ||
694 | .ops = &io_ops, | ||
695 | }; | ||
696 | |||
697 | static struct clk hclk = { | ||
698 | .parent = &cpu_clk, | ||
699 | .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_HBUS, | ||
700 | .bypass_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ, | ||
701 | .bypass_shift = 7, | ||
702 | .busy_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_HBUS, | ||
703 | .busy_bit = 29, | ||
704 | .flags = RATE_PROPAGATES | ENABLED, | ||
705 | .ops = &hbus_ops, | ||
706 | }; | ||
707 | |||
708 | static struct clk xclk = { | ||
709 | .parent = &osc_24M, | ||
710 | .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_XBUS, | ||
711 | .busy_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_XBUS, | ||
712 | .busy_bit = 31, | ||
713 | .flags = RATE_PROPAGATES | ENABLED, | ||
714 | .ops = &xbus_ops, | ||
715 | }; | ||
716 | |||
717 | static struct clk uart_clk = { | ||
718 | .parent = &xclk, | ||
719 | .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL, | ||
720 | .enable_shift = 31, | ||
721 | .enable_negate = 1, | ||
722 | .flags = ENABLED, | ||
723 | .ops = &min_ops, | ||
724 | }; | ||
725 | |||
726 | static struct clk audio_clk = { | ||
727 | .parent = &xclk, | ||
728 | .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL, | ||
729 | .enable_shift = 30, | ||
730 | .enable_negate = 1, | ||
731 | .ops = &min_ops, | ||
732 | }; | ||
733 | |||
734 | static struct clk pwm_clk = { | ||
735 | .parent = &xclk, | ||
736 | .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL, | ||
737 | .enable_shift = 29, | ||
738 | .enable_negate = 1, | ||
739 | .ops = &min_ops, | ||
740 | }; | ||
741 | |||
742 | static struct clk dri_clk = { | ||
743 | .parent = &xclk, | ||
744 | .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL, | ||
745 | .enable_shift = 28, | ||
746 | .enable_negate = 1, | ||
747 | .ops = &min_ops, | ||
748 | }; | ||
749 | |||
750 | static struct clk digctl_clk = { | ||
751 | .parent = &xclk, | ||
752 | .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL, | ||
753 | .enable_shift = 27, | ||
754 | .enable_negate = 1, | ||
755 | .ops = &min_ops, | ||
756 | }; | ||
757 | |||
758 | static struct clk timer_clk = { | ||
759 | .parent = &xclk, | ||
760 | .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL, | ||
761 | .enable_shift = 26, | ||
762 | .enable_negate = 1, | ||
763 | .flags = ENABLED, | ||
764 | .ops = &min_ops, | ||
765 | }; | ||
766 | |||
767 | static struct clk lcdif_clk = { | ||
768 | .parent = &pll_clk, | ||
769 | .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_PIX, | ||
770 | .busy_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_PIX, | ||
771 | .busy_bit = 29, | ||
772 | .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_PIX, | ||
773 | .enable_shift = 31, | ||
774 | .enable_negate = 1, | ||
775 | .bypass_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ, | ||
776 | .bypass_shift = 1, | ||
777 | .flags = NEEDS_SET_PARENT, | ||
778 | .ops = &lcdif_ops, | ||
779 | }; | ||
780 | |||
781 | static struct clk ssp_clk = { | ||
782 | .parent = &io_clk, | ||
783 | .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_SSP, | ||
784 | .busy_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_SSP, | ||
785 | .busy_bit = 29, | ||
786 | .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_SSP, | ||
787 | .enable_shift = 31, | ||
788 | .bypass_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ, | ||
789 | .bypass_shift = 5, | ||
790 | .enable_negate = 1, | ||
791 | .flags = NEEDS_SET_PARENT, | ||
792 | .ops = &std_ops, | ||
793 | }; | ||
794 | |||
795 | static struct clk gpmi_clk = { | ||
796 | .parent = &io_clk, | ||
797 | .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_GPMI, | ||
798 | .busy_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_GPMI, | ||
799 | .busy_bit = 29, | ||
800 | .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_GPMI, | ||
801 | .enable_shift = 31, | ||
802 | .enable_negate = 1, | ||
803 | .bypass_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ, | ||
804 | .bypass_shift = 4, | ||
805 | .flags = NEEDS_SET_PARENT, | ||
806 | .ops = &std_ops, | ||
807 | }; | ||
808 | |||
809 | static struct clk spdif_clk = { | ||
810 | .parent = &pll_clk, | ||
811 | .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_SPDIF, | ||
812 | .enable_shift = 31, | ||
813 | .enable_negate = 1, | ||
814 | .ops = &min_ops, | ||
815 | }; | ||
816 | |||
817 | static struct clk emi_clk = { | ||
818 | .parent = &pll_clk, | ||
819 | .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_EMI, | ||
820 | .enable_shift = 31, | ||
821 | .enable_negate = 1, | ||
822 | .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC, | ||
823 | .scale_shift = 8, | ||
824 | .busy_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_EMI, | ||
825 | .busy_bit = 28, | ||
826 | .bypass_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ, | ||
827 | .bypass_shift = 6, | ||
828 | .flags = ENABLED, | ||
829 | .ops = &emi_ops, | ||
830 | }; | ||
831 | |||
832 | static struct clk ir_clk = { | ||
833 | .parent = &io_clk, | ||
834 | .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_IR, | ||
835 | .enable_shift = 31, | ||
836 | .enable_negate = 1, | ||
837 | .bypass_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ, | ||
838 | .bypass_shift = 3, | ||
839 | .ops = &min_ops, | ||
840 | }; | ||
841 | |||
842 | static struct clk saif_clk = { | ||
843 | .parent = &pll_clk, | ||
844 | .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_SAIF, | ||
845 | .busy_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_SAIF, | ||
846 | .busy_bit = 29, | ||
847 | .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_SAIF, | ||
848 | .enable_shift = 31, | ||
849 | .enable_negate = 1, | ||
850 | .bypass_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ, | ||
851 | .bypass_shift = 0, | ||
852 | .ops = &std_ops, | ||
853 | }; | ||
854 | |||
855 | static struct clk usb_clk = { | ||
856 | .parent = &pll_clk, | ||
857 | .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_PLLCTRL0, | ||
858 | .enable_shift = 18, | ||
859 | .enable_negate = 1, | ||
860 | .ops = &min_ops, | ||
861 | }; | ||
862 | |||
863 | /* list of all the clocks */ | ||
864 | static struct clk_lookup onchip_clks[] = { | ||
865 | { | ||
866 | .con_id = "osc_24M", | ||
867 | .clk = &osc_24M, | ||
868 | }, { | ||
869 | .con_id = "pll", | ||
870 | .clk = &pll_clk, | ||
871 | }, { | ||
872 | .con_id = "cpu", | ||
873 | .clk = &cpu_clk, | ||
874 | }, { | ||
875 | .con_id = "hclk", | ||
876 | .clk = &hclk, | ||
877 | }, { | ||
878 | .con_id = "xclk", | ||
879 | .clk = &xclk, | ||
880 | }, { | ||
881 | .con_id = "io", | ||
882 | .clk = &io_clk, | ||
883 | }, { | ||
884 | .con_id = "uart", | ||
885 | .clk = &uart_clk, | ||
886 | }, { | ||
887 | .con_id = "audio", | ||
888 | .clk = &audio_clk, | ||
889 | }, { | ||
890 | .con_id = "pwm", | ||
891 | .clk = &pwm_clk, | ||
892 | }, { | ||
893 | .con_id = "dri", | ||
894 | .clk = &dri_clk, | ||
895 | }, { | ||
896 | .con_id = "digctl", | ||
897 | .clk = &digctl_clk, | ||
898 | }, { | ||
899 | .con_id = "timer", | ||
900 | .clk = &timer_clk, | ||
901 | }, { | ||
902 | .con_id = "lcdif", | ||
903 | .clk = &lcdif_clk, | ||
904 | }, { | ||
905 | .con_id = "ssp", | ||
906 | .clk = &ssp_clk, | ||
907 | }, { | ||
908 | .con_id = "gpmi", | ||
909 | .clk = &gpmi_clk, | ||
910 | }, { | ||
911 | .con_id = "spdif", | ||
912 | .clk = &spdif_clk, | ||
913 | }, { | ||
914 | .con_id = "emi", | ||
915 | .clk = &emi_clk, | ||
916 | }, { | ||
917 | .con_id = "ir", | ||
918 | .clk = &ir_clk, | ||
919 | }, { | ||
920 | .con_id = "saif", | ||
921 | .clk = &saif_clk, | ||
922 | }, { | ||
923 | .con_id = "usb", | ||
924 | .clk = &usb_clk, | ||
925 | }, | ||
926 | }; | ||
927 | |||
928 | static int __init propagate_rate(struct clk *clk) | ||
929 | { | ||
930 | struct clk_lookup *cl; | ||
931 | |||
932 | for (cl = onchip_clks; cl < onchip_clks + ARRAY_SIZE(onchip_clks); | ||
933 | cl++) { | ||
934 | if (unlikely(!clk_good(cl->clk))) | ||
935 | continue; | ||
936 | if (cl->clk->parent == clk && cl->clk->ops->get_rate) { | ||
937 | cl->clk->ops->get_rate(cl->clk); | ||
938 | if (cl->clk->flags & RATE_PROPAGATES) | ||
939 | propagate_rate(cl->clk); | ||
940 | } | ||
941 | } | ||
942 | |||
943 | return 0; | ||
944 | } | ||
945 | |||
946 | /* Exported API */ | ||
947 | unsigned long clk_get_rate(struct clk *clk) | ||
948 | { | ||
949 | if (unlikely(!clk_good(clk))) | ||
950 | return 0; | ||
951 | |||
952 | if (clk->rate != 0) | ||
953 | return clk->rate; | ||
954 | |||
955 | if (clk->ops->get_rate != NULL) | ||
956 | return clk->ops->get_rate(clk); | ||
957 | |||
958 | return clk_get_rate(clk->parent); | ||
959 | } | ||
960 | EXPORT_SYMBOL(clk_get_rate); | ||
961 | |||
962 | long clk_round_rate(struct clk *clk, unsigned long rate) | ||
963 | { | ||
964 | if (unlikely(!clk_good(clk))) | ||
965 | return 0; | ||
966 | |||
967 | if (clk->ops->round_rate) | ||
968 | return clk->ops->round_rate(clk, rate); | ||
969 | |||
970 | return 0; | ||
971 | } | ||
972 | EXPORT_SYMBOL(clk_round_rate); | ||
973 | |||
974 | static inline int close_enough(long rate1, long rate2) | ||
975 | { | ||
976 | return rate1 && !((rate2 - rate1) * 1000 / rate1); | ||
977 | } | ||
978 | |||
979 | int clk_set_rate(struct clk *clk, unsigned long rate) | ||
980 | { | ||
981 | int ret = -EINVAL; | ||
982 | |||
983 | if (unlikely(!clk_good(clk))) | ||
984 | goto out; | ||
985 | |||
986 | if (clk->flags & FIXED_RATE || !clk->ops->set_rate) | ||
987 | goto out; | ||
988 | |||
989 | else if (!close_enough(clk->rate, rate)) { | ||
990 | ret = clk->ops->set_rate(clk, rate); | ||
991 | if (ret < 0) | ||
992 | goto out; | ||
993 | clk->rate = rate; | ||
994 | if (clk->flags & RATE_PROPAGATES) | ||
995 | propagate_rate(clk); | ||
996 | } else | ||
997 | ret = 0; | ||
998 | |||
999 | out: | ||
1000 | return ret; | ||
1001 | } | ||
1002 | EXPORT_SYMBOL(clk_set_rate); | ||
1003 | |||
1004 | int clk_enable(struct clk *clk) | ||
1005 | { | ||
1006 | unsigned long clocks_flags; | ||
1007 | |||
1008 | if (unlikely(!clk_good(clk))) | ||
1009 | return -EINVAL; | ||
1010 | |||
1011 | if (clk->parent) | ||
1012 | clk_enable(clk->parent); | ||
1013 | |||
1014 | spin_lock_irqsave(&clocks_lock, clocks_flags); | ||
1015 | |||
1016 | clk->usage++; | ||
1017 | if (clk->ops && clk->ops->enable) | ||
1018 | clk->ops->enable(clk); | ||
1019 | |||
1020 | spin_unlock_irqrestore(&clocks_lock, clocks_flags); | ||
1021 | return 0; | ||
1022 | } | ||
1023 | EXPORT_SYMBOL(clk_enable); | ||
1024 | |||
1025 | static void local_clk_disable(struct clk *clk) | ||
1026 | { | ||
1027 | if (unlikely(!clk_good(clk))) | ||
1028 | return; | ||
1029 | |||
1030 | if (clk->usage == 0 && clk->ops->disable) | ||
1031 | clk->ops->disable(clk); | ||
1032 | |||
1033 | if (clk->parent) | ||
1034 | local_clk_disable(clk->parent); | ||
1035 | } | ||
1036 | |||
1037 | void clk_disable(struct clk *clk) | ||
1038 | { | ||
1039 | unsigned long clocks_flags; | ||
1040 | |||
1041 | if (unlikely(!clk_good(clk))) | ||
1042 | return; | ||
1043 | |||
1044 | spin_lock_irqsave(&clocks_lock, clocks_flags); | ||
1045 | |||
1046 | if ((--clk->usage) == 0 && clk->ops->disable) | ||
1047 | clk->ops->disable(clk); | ||
1048 | |||
1049 | spin_unlock_irqrestore(&clocks_lock, clocks_flags); | ||
1050 | if (clk->parent) | ||
1051 | clk_disable(clk->parent); | ||
1052 | } | ||
1053 | EXPORT_SYMBOL(clk_disable); | ||
1054 | |||
1055 | /* Some additional API */ | ||
1056 | int clk_set_parent(struct clk *clk, struct clk *parent) | ||
1057 | { | ||
1058 | int ret = -ENODEV; | ||
1059 | unsigned long clocks_flags; | ||
1060 | |||
1061 | if (unlikely(!clk_good(clk))) | ||
1062 | goto out; | ||
1063 | |||
1064 | if (!clk->ops->set_parent) | ||
1065 | goto out; | ||
1066 | |||
1067 | spin_lock_irqsave(&clocks_lock, clocks_flags); | ||
1068 | |||
1069 | ret = clk->ops->set_parent(clk, parent); | ||
1070 | if (!ret) { | ||
1071 | /* disable if usage count is 0 */ | ||
1072 | local_clk_disable(parent); | ||
1073 | |||
1074 | parent->usage += clk->usage; | ||
1075 | clk->parent->usage -= clk->usage; | ||
1076 | |||
1077 | /* disable if new usage count is 0 */ | ||
1078 | local_clk_disable(clk->parent); | ||
1079 | |||
1080 | clk->parent = parent; | ||
1081 | } | ||
1082 | spin_unlock_irqrestore(&clocks_lock, clocks_flags); | ||
1083 | |||
1084 | out: | ||
1085 | return ret; | ||
1086 | } | ||
1087 | EXPORT_SYMBOL(clk_set_parent); | ||
1088 | |||
1089 | struct clk *clk_get_parent(struct clk *clk) | ||
1090 | { | ||
1091 | if (unlikely(!clk_good(clk))) | ||
1092 | return NULL; | ||
1093 | return clk->parent; | ||
1094 | } | ||
1095 | EXPORT_SYMBOL(clk_get_parent); | ||
1096 | |||
1097 | static int __init clk_init(void) | ||
1098 | { | ||
1099 | struct clk_lookup *cl; | ||
1100 | struct clk_ops *ops; | ||
1101 | |||
1102 | spin_lock_init(&clocks_lock); | ||
1103 | |||
1104 | for (cl = onchip_clks; cl < onchip_clks + ARRAY_SIZE(onchip_clks); | ||
1105 | cl++) { | ||
1106 | if (cl->clk->flags & ENABLED) | ||
1107 | clk_enable(cl->clk); | ||
1108 | else | ||
1109 | local_clk_disable(cl->clk); | ||
1110 | |||
1111 | ops = cl->clk->ops; | ||
1112 | |||
1113 | if ((cl->clk->flags & NEEDS_INITIALIZATION) && | ||
1114 | ops && ops->set_rate) | ||
1115 | ops->set_rate(cl->clk, cl->clk->rate); | ||
1116 | |||
1117 | if (cl->clk->flags & FIXED_RATE) { | ||
1118 | if (cl->clk->flags & RATE_PROPAGATES) | ||
1119 | propagate_rate(cl->clk); | ||
1120 | } else { | ||
1121 | if (ops && ops->get_rate) | ||
1122 | ops->get_rate(cl->clk); | ||
1123 | } | ||
1124 | |||
1125 | if (cl->clk->flags & NEEDS_SET_PARENT) { | ||
1126 | if (ops && ops->set_parent) | ||
1127 | ops->set_parent(cl->clk, cl->clk->parent); | ||
1128 | } | ||
1129 | |||
1130 | clkdev_add(cl); | ||
1131 | } | ||
1132 | return 0; | ||
1133 | } | ||
1134 | |||
1135 | arch_initcall(clk_init); | ||