Commit | Line | Data |
---|---|---|
8c3d7c30 HS |
1 | /* |
2 | * Common code for SoCs starting with the S3C2443 | |
af337f3e BD |
3 | * |
4 | * Copyright (c) 2007, 2010 Simtec Electronics | |
5 | * Ben Dooks <ben@simtec.co.uk> | |
6 | * | |
8c3d7c30 HS |
7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation; either version 2 of the License, or | |
10 | * (at your option) any later version. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
af337f3e BD |
16 | */ |
17 | ||
18 | #include <linux/init.h> | |
19 | #include <linux/clk.h> | |
20 | #include <linux/io.h> | |
21 | ||
22 | #include <mach/regs-s3c2443-clock.h> | |
23 | ||
af337f3e BD |
24 | #include <plat/clock.h> |
25 | #include <plat/clock-clksrc.h> | |
26 | #include <plat/cpu.h> | |
27 | ||
28 | #include <plat/cpu-freq.h> | |
29 | ||
30 | ||
31 | static int s3c2443_gate(void __iomem *reg, struct clk *clk, int enable) | |
32 | { | |
33 | u32 ctrlbit = clk->ctrlbit; | |
34 | u32 con = __raw_readl(reg); | |
35 | ||
36 | if (enable) | |
37 | con |= ctrlbit; | |
38 | else | |
39 | con &= ~ctrlbit; | |
40 | ||
41 | __raw_writel(con, reg); | |
42 | return 0; | |
43 | } | |
44 | ||
45 | int s3c2443_clkcon_enable_h(struct clk *clk, int enable) | |
46 | { | |
47 | return s3c2443_gate(S3C2443_HCLKCON, clk, enable); | |
48 | } | |
49 | ||
50 | int s3c2443_clkcon_enable_p(struct clk *clk, int enable) | |
51 | { | |
52 | return s3c2443_gate(S3C2443_PCLKCON, clk, enable); | |
53 | } | |
54 | ||
55 | int s3c2443_clkcon_enable_s(struct clk *clk, int enable) | |
56 | { | |
57 | return s3c2443_gate(S3C2443_SCLKCON, clk, enable); | |
58 | } | |
59 | ||
60 | /* mpllref is a direct descendant of clk_xtal by default, but it is not | |
61 | * elided as the EPLL can be either sourced by the XTAL or EXTCLK and as | |
62 | * such directly equating the two source clocks is impossible. | |
63 | */ | |
4cfb7b7c | 64 | static struct clk clk_mpllref = { |
af337f3e BD |
65 | .name = "mpllref", |
66 | .parent = &clk_xtal, | |
af337f3e BD |
67 | }; |
68 | ||
69 | static struct clk *clk_epllref_sources[] = { | |
70 | [0] = &clk_mpllref, | |
71 | [1] = &clk_mpllref, | |
72 | [2] = &clk_xtal, | |
73 | [3] = &clk_ext, | |
74 | }; | |
75 | ||
76 | struct clksrc_clk clk_epllref = { | |
77 | .clk = { | |
78 | .name = "epllref", | |
af337f3e BD |
79 | }, |
80 | .sources = &(struct clksrc_sources) { | |
81 | .sources = clk_epllref_sources, | |
82 | .nr_sources = ARRAY_SIZE(clk_epllref_sources), | |
83 | }, | |
84 | .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 7 }, | |
85 | }; | |
86 | ||
87 | /* esysclk | |
88 | * | |
89 | * this is sourced from either the EPLL or the EPLLref clock | |
90 | */ | |
91 | ||
92 | static struct clk *clk_sysclk_sources[] = { | |
93 | [0] = &clk_epllref.clk, | |
94 | [1] = &clk_epll, | |
95 | }; | |
96 | ||
97 | struct clksrc_clk clk_esysclk = { | |
98 | .clk = { | |
99 | .name = "esysclk", | |
100 | .parent = &clk_epll, | |
af337f3e BD |
101 | }, |
102 | .sources = &(struct clksrc_sources) { | |
103 | .sources = clk_sysclk_sources, | |
104 | .nr_sources = ARRAY_SIZE(clk_sysclk_sources), | |
105 | }, | |
106 | .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 6 }, | |
107 | }; | |
108 | ||
109 | static unsigned long s3c2443_getrate_mdivclk(struct clk *clk) | |
110 | { | |
111 | unsigned long parent_rate = clk_get_rate(clk->parent); | |
112 | unsigned long div = __raw_readl(S3C2443_CLKDIV0); | |
113 | ||
114 | div &= S3C2443_CLKDIV0_EXTDIV_MASK; | |
115 | div >>= (S3C2443_CLKDIV0_EXTDIV_SHIFT-1); /* x2 */ | |
116 | ||
117 | return parent_rate / (div + 1); | |
118 | } | |
119 | ||
120 | static struct clk clk_mdivclk = { | |
121 | .name = "mdivclk", | |
122 | .parent = &clk_mpllref, | |
af337f3e BD |
123 | .ops = &(struct clk_ops) { |
124 | .get_rate = s3c2443_getrate_mdivclk, | |
125 | }, | |
126 | }; | |
127 | ||
128 | static struct clk *clk_msysclk_sources[] = { | |
129 | [0] = &clk_mpllref, | |
130 | [1] = &clk_mpll, | |
131 | [2] = &clk_mdivclk, | |
132 | [3] = &clk_mpllref, | |
133 | }; | |
134 | ||
135 | struct clksrc_clk clk_msysclk = { | |
136 | .clk = { | |
137 | .name = "msysclk", | |
138 | .parent = &clk_xtal, | |
af337f3e BD |
139 | }, |
140 | .sources = &(struct clksrc_sources) { | |
141 | .sources = clk_msysclk_sources, | |
142 | .nr_sources = ARRAY_SIZE(clk_msysclk_sources), | |
143 | }, | |
144 | .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 3 }, | |
145 | }; | |
146 | ||
147 | /* prediv | |
148 | * | |
149 | * this divides the msysclk down to pass to h/p/etc. | |
150 | */ | |
151 | ||
152 | static unsigned long s3c2443_prediv_getrate(struct clk *clk) | |
153 | { | |
154 | unsigned long rate = clk_get_rate(clk->parent); | |
155 | unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0); | |
156 | ||
157 | clkdiv0 &= S3C2443_CLKDIV0_PREDIV_MASK; | |
158 | clkdiv0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT; | |
159 | ||
160 | return rate / (clkdiv0 + 1); | |
161 | } | |
162 | ||
163 | static struct clk clk_prediv = { | |
164 | .name = "prediv", | |
af337f3e BD |
165 | .parent = &clk_msysclk.clk, |
166 | .ops = &(struct clk_ops) { | |
167 | .get_rate = s3c2443_prediv_getrate, | |
168 | }, | |
169 | }; | |
170 | ||
b681bfcf HS |
171 | /* hclk divider |
172 | * | |
173 | * divides the prediv and provides the hclk. | |
174 | */ | |
175 | ||
176 | static unsigned long s3c2443_hclkdiv_getrate(struct clk *clk) | |
177 | { | |
178 | unsigned long rate = clk_get_rate(clk->parent); | |
179 | unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0); | |
180 | ||
181 | clkdiv0 &= S3C2443_CLKDIV0_HCLKDIV_MASK; | |
182 | ||
183 | return rate / (clkdiv0 + 1); | |
184 | } | |
185 | ||
186 | static struct clk_ops clk_h_ops = { | |
187 | .get_rate = s3c2443_hclkdiv_getrate, | |
188 | }; | |
189 | ||
9edc12a1 HS |
190 | /* pclk divider |
191 | * | |
192 | * divides the hclk and provides the pclk. | |
193 | */ | |
194 | ||
195 | static unsigned long s3c2443_pclkdiv_getrate(struct clk *clk) | |
196 | { | |
197 | unsigned long rate = clk_get_rate(clk->parent); | |
198 | unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0); | |
199 | ||
200 | clkdiv0 = ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 1 : 0); | |
201 | ||
202 | return rate / (clkdiv0 + 1); | |
203 | } | |
204 | ||
205 | static struct clk_ops clk_p_ops = { | |
206 | .get_rate = s3c2443_pclkdiv_getrate, | |
207 | }; | |
208 | ||
aab08eeb HS |
209 | /* armdiv |
210 | * | |
211 | * this clock is sourced from msysclk and can have a number of | |
212 | * divider values applied to it to then be fed into armclk. | |
213 | */ | |
214 | ||
d9a3bfbd HS |
215 | static unsigned int *armdiv; |
216 | static int nr_armdiv; | |
217 | static int armdivmask; | |
218 | ||
aab08eeb HS |
219 | static unsigned long s3c2443_armclk_roundrate(struct clk *clk, |
220 | unsigned long rate) | |
221 | { | |
222 | unsigned long parent = clk_get_rate(clk->parent); | |
223 | unsigned long calc; | |
224 | unsigned best = 256; /* bigger than any value */ | |
225 | unsigned div; | |
226 | int ptr; | |
227 | ||
f9f7c750 HS |
228 | if (!nr_armdiv) |
229 | return -EINVAL; | |
230 | ||
aab08eeb HS |
231 | for (ptr = 0; ptr < nr_armdiv; ptr++) { |
232 | div = armdiv[ptr]; | |
f9f7c750 | 233 | if (div) { |
866a1c8c HS |
234 | /* cpufreq provides 266mhz as 266666000 not 266666666 */ |
235 | calc = (parent / div / 1000) * 1000; | |
f9f7c750 HS |
236 | if (calc <= rate && div < best) |
237 | best = div; | |
238 | } | |
aab08eeb HS |
239 | } |
240 | ||
241 | return parent / best; | |
242 | } | |
243 | ||
5f33bd76 HS |
244 | static unsigned long s3c2443_armclk_getrate(struct clk *clk) |
245 | { | |
246 | unsigned long rate = clk_get_rate(clk->parent); | |
247 | unsigned long clkcon0; | |
248 | int val; | |
249 | ||
f9f7c750 HS |
250 | if (!nr_armdiv || !armdivmask) |
251 | return -EINVAL; | |
252 | ||
5f33bd76 HS |
253 | clkcon0 = __raw_readl(S3C2443_CLKDIV0); |
254 | clkcon0 &= armdivmask; | |
255 | val = clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT; | |
256 | ||
257 | return rate / armdiv[val]; | |
258 | } | |
259 | ||
aab08eeb HS |
260 | static int s3c2443_armclk_setrate(struct clk *clk, unsigned long rate) |
261 | { | |
262 | unsigned long parent = clk_get_rate(clk->parent); | |
263 | unsigned long calc; | |
264 | unsigned div; | |
265 | unsigned best = 256; /* bigger than any value */ | |
266 | int ptr; | |
267 | int val = -1; | |
268 | ||
f9f7c750 HS |
269 | if (!nr_armdiv || !armdivmask) |
270 | return -EINVAL; | |
271 | ||
aab08eeb HS |
272 | for (ptr = 0; ptr < nr_armdiv; ptr++) { |
273 | div = armdiv[ptr]; | |
f9f7c750 | 274 | if (div) { |
866a1c8c HS |
275 | /* cpufreq provides 266mhz as 266666000 not 266666666 */ |
276 | calc = (parent / div / 1000) * 1000; | |
f9f7c750 HS |
277 | if (calc <= rate && div < best) { |
278 | best = div; | |
279 | val = ptr; | |
280 | } | |
aab08eeb HS |
281 | } |
282 | } | |
283 | ||
284 | if (val >= 0) { | |
285 | unsigned long clkcon0; | |
286 | ||
287 | clkcon0 = __raw_readl(S3C2443_CLKDIV0); | |
288 | clkcon0 &= ~armdivmask; | |
289 | clkcon0 |= val << S3C2443_CLKDIV0_ARMDIV_SHIFT; | |
290 | __raw_writel(clkcon0, S3C2443_CLKDIV0); | |
291 | } | |
292 | ||
293 | return (val == -1) ? -EINVAL : 0; | |
294 | } | |
295 | ||
296 | static struct clk clk_armdiv = { | |
297 | .name = "armdiv", | |
298 | .parent = &clk_msysclk.clk, | |
299 | .ops = &(struct clk_ops) { | |
300 | .round_rate = s3c2443_armclk_roundrate, | |
5f33bd76 | 301 | .get_rate = s3c2443_armclk_getrate, |
aab08eeb HS |
302 | .set_rate = s3c2443_armclk_setrate, |
303 | }, | |
304 | }; | |
305 | ||
306 | /* armclk | |
307 | * | |
308 | * this is the clock fed into the ARM core itself, from armdiv or from hclk. | |
309 | */ | |
310 | ||
311 | static struct clk *clk_arm_sources[] = { | |
312 | [0] = &clk_armdiv, | |
313 | [1] = &clk_h, | |
314 | }; | |
315 | ||
316 | static struct clksrc_clk clk_arm = { | |
317 | .clk = { | |
318 | .name = "armclk", | |
319 | }, | |
320 | .sources = &(struct clksrc_sources) { | |
321 | .sources = clk_arm_sources, | |
322 | .nr_sources = ARRAY_SIZE(clk_arm_sources), | |
323 | }, | |
324 | .reg_src = { .reg = S3C2443_CLKDIV0, .size = 1, .shift = 13 }, | |
325 | }; | |
326 | ||
af337f3e BD |
327 | /* usbhost |
328 | * | |
329 | * usb host bus-clock, usually 48MHz to provide USB bus clock timing | |
330 | */ | |
331 | ||
332 | static struct clksrc_clk clk_usb_bus_host = { | |
333 | .clk = { | |
334 | .name = "usb-bus-host-parent", | |
af337f3e BD |
335 | .parent = &clk_esysclk.clk, |
336 | .ctrlbit = S3C2443_SCLKCON_USBHOST, | |
337 | .enable = s3c2443_clkcon_enable_s, | |
338 | }, | |
339 | .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 }, | |
340 | }; | |
341 | ||
342 | /* common clksrc clocks */ | |
343 | ||
344 | static struct clksrc_clk clksrc_clks[] = { | |
345 | { | |
af337f3e BD |
346 | /* camera interface bus-clock, divided down from esysclk */ |
347 | .clk = { | |
348 | .name = "camif-upll", /* same as 2440 name */ | |
af337f3e BD |
349 | .parent = &clk_esysclk.clk, |
350 | .ctrlbit = S3C2443_SCLKCON_CAMCLK, | |
351 | .enable = s3c2443_clkcon_enable_s, | |
352 | }, | |
353 | .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 26 }, | |
354 | }, { | |
355 | .clk = { | |
356 | .name = "display-if", | |
af337f3e BD |
357 | .parent = &clk_esysclk.clk, |
358 | .ctrlbit = S3C2443_SCLKCON_DISPCLK, | |
359 | .enable = s3c2443_clkcon_enable_s, | |
360 | }, | |
361 | .reg_div = { .reg = S3C2443_CLKDIV1, .size = 8, .shift = 16 }, | |
362 | }, | |
363 | }; | |
364 | ||
0cfb26e1 TA |
365 | static struct clksrc_clk clk_esys_uart = { |
366 | /* ART baud-rate clock sourced from esysclk via a divisor */ | |
367 | .clk = { | |
368 | .name = "uartclk", | |
369 | .parent = &clk_esysclk.clk, | |
370 | }, | |
371 | .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 8 }, | |
372 | }; | |
373 | ||
e3b454f7 HS |
374 | static struct clk clk_i2s_ext = { |
375 | .name = "i2s-ext", | |
376 | }; | |
377 | ||
378 | /* i2s_eplldiv | |
379 | * | |
380 | * This clock is the output from the I2S divisor of ESYSCLK, and is separate | |
381 | * from the mux that comes after it (cannot merge into one single clock) | |
382 | */ | |
383 | ||
384 | static struct clksrc_clk clk_i2s_eplldiv = { | |
385 | .clk = { | |
386 | .name = "i2s-eplldiv", | |
387 | .parent = &clk_esysclk.clk, | |
388 | }, | |
389 | .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 12, }, | |
390 | }; | |
391 | ||
392 | /* i2s-ref | |
393 | * | |
394 | * i2s bus reference clock, selectable from external, esysclk or epllref | |
395 | * | |
396 | * Note, this used to be two clocks, but was compressed into one. | |
397 | */ | |
398 | ||
399 | static struct clk *clk_i2s_srclist[] = { | |
400 | [0] = &clk_i2s_eplldiv.clk, | |
401 | [1] = &clk_i2s_ext, | |
402 | [2] = &clk_epllref.clk, | |
403 | [3] = &clk_epllref.clk, | |
404 | }; | |
405 | ||
406 | static struct clksrc_clk clk_i2s = { | |
407 | .clk = { | |
408 | .name = "i2s-if", | |
409 | .ctrlbit = S3C2443_SCLKCON_I2SCLK, | |
410 | .enable = s3c2443_clkcon_enable_s, | |
411 | ||
412 | }, | |
413 | .sources = &(struct clksrc_sources) { | |
414 | .sources = clk_i2s_srclist, | |
415 | .nr_sources = ARRAY_SIZE(clk_i2s_srclist), | |
416 | }, | |
417 | .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 14 }, | |
418 | }; | |
af337f3e BD |
419 | |
420 | static struct clk init_clocks_off[] = { | |
421 | { | |
e3b454f7 HS |
422 | .name = "iis", |
423 | .parent = &clk_p, | |
424 | .enable = s3c2443_clkcon_enable_p, | |
425 | .ctrlbit = S3C2443_PCLKCON_IIS, | |
426 | }, { | |
af337f3e | 427 | .name = "adc", |
af337f3e BD |
428 | .parent = &clk_p, |
429 | .enable = s3c2443_clkcon_enable_p, | |
430 | .ctrlbit = S3C2443_PCLKCON_ADC, | |
431 | }, { | |
432 | .name = "i2c", | |
af337f3e BD |
433 | .parent = &clk_p, |
434 | .enable = s3c2443_clkcon_enable_p, | |
435 | .ctrlbit = S3C2443_PCLKCON_IIC, | |
436 | } | |
437 | }; | |
438 | ||
439 | static struct clk init_clocks[] = { | |
440 | { | |
441 | .name = "dma", | |
af337f3e BD |
442 | .parent = &clk_h, |
443 | .enable = s3c2443_clkcon_enable_h, | |
444 | .ctrlbit = S3C2443_HCLKCON_DMA0, | |
445 | }, { | |
446 | .name = "dma", | |
af337f3e BD |
447 | .parent = &clk_h, |
448 | .enable = s3c2443_clkcon_enable_h, | |
449 | .ctrlbit = S3C2443_HCLKCON_DMA1, | |
450 | }, { | |
451 | .name = "dma", | |
af337f3e BD |
452 | .parent = &clk_h, |
453 | .enable = s3c2443_clkcon_enable_h, | |
454 | .ctrlbit = S3C2443_HCLKCON_DMA2, | |
455 | }, { | |
456 | .name = "dma", | |
af337f3e BD |
457 | .parent = &clk_h, |
458 | .enable = s3c2443_clkcon_enable_h, | |
459 | .ctrlbit = S3C2443_HCLKCON_DMA3, | |
460 | }, { | |
461 | .name = "dma", | |
af337f3e BD |
462 | .parent = &clk_h, |
463 | .enable = s3c2443_clkcon_enable_h, | |
464 | .ctrlbit = S3C2443_HCLKCON_DMA4, | |
465 | }, { | |
466 | .name = "dma", | |
af337f3e BD |
467 | .parent = &clk_h, |
468 | .enable = s3c2443_clkcon_enable_h, | |
469 | .ctrlbit = S3C2443_HCLKCON_DMA5, | |
af337f3e BD |
470 | }, { |
471 | .name = "gpio", | |
af337f3e BD |
472 | .parent = &clk_p, |
473 | .enable = s3c2443_clkcon_enable_p, | |
474 | .ctrlbit = S3C2443_PCLKCON_GPIO, | |
475 | }, { | |
476 | .name = "usb-host", | |
af337f3e BD |
477 | .parent = &clk_h, |
478 | .enable = s3c2443_clkcon_enable_h, | |
479 | .ctrlbit = S3C2443_HCLKCON_USBH, | |
480 | }, { | |
481 | .name = "usb-device", | |
af337f3e BD |
482 | .parent = &clk_h, |
483 | .enable = s3c2443_clkcon_enable_h, | |
484 | .ctrlbit = S3C2443_HCLKCON_USBD, | |
485 | }, { | |
486 | .name = "lcd", | |
af337f3e BD |
487 | .parent = &clk_h, |
488 | .enable = s3c2443_clkcon_enable_h, | |
489 | .ctrlbit = S3C2443_HCLKCON_LCDC, | |
490 | ||
491 | }, { | |
492 | .name = "timers", | |
af337f3e BD |
493 | .parent = &clk_p, |
494 | .enable = s3c2443_clkcon_enable_p, | |
495 | .ctrlbit = S3C2443_PCLKCON_PWMT, | |
496 | }, { | |
497 | .name = "cfc", | |
af337f3e BD |
498 | .parent = &clk_h, |
499 | .enable = s3c2443_clkcon_enable_h, | |
500 | .ctrlbit = S3C2443_HCLKCON_CFC, | |
501 | }, { | |
502 | .name = "ssmc", | |
af337f3e BD |
503 | .parent = &clk_h, |
504 | .enable = s3c2443_clkcon_enable_h, | |
505 | .ctrlbit = S3C2443_HCLKCON_SSMC, | |
506 | }, { | |
507 | .name = "uart", | |
e83626f2 | 508 | .devname = "s3c2440-uart.0", |
af337f3e BD |
509 | .parent = &clk_p, |
510 | .enable = s3c2443_clkcon_enable_p, | |
511 | .ctrlbit = S3C2443_PCLKCON_UART0, | |
512 | }, { | |
513 | .name = "uart", | |
e83626f2 | 514 | .devname = "s3c2440-uart.1", |
af337f3e BD |
515 | .parent = &clk_p, |
516 | .enable = s3c2443_clkcon_enable_p, | |
517 | .ctrlbit = S3C2443_PCLKCON_UART1, | |
518 | }, { | |
519 | .name = "uart", | |
e83626f2 | 520 | .devname = "s3c2440-uart.2", |
af337f3e BD |
521 | .parent = &clk_p, |
522 | .enable = s3c2443_clkcon_enable_p, | |
523 | .ctrlbit = S3C2443_PCLKCON_UART2, | |
524 | }, { | |
525 | .name = "uart", | |
e83626f2 | 526 | .devname = "s3c2440-uart.3", |
af337f3e BD |
527 | .parent = &clk_p, |
528 | .enable = s3c2443_clkcon_enable_p, | |
529 | .ctrlbit = S3C2443_PCLKCON_UART3, | |
530 | }, { | |
531 | .name = "rtc", | |
af337f3e BD |
532 | .parent = &clk_p, |
533 | .enable = s3c2443_clkcon_enable_p, | |
534 | .ctrlbit = S3C2443_PCLKCON_RTC, | |
535 | }, { | |
536 | .name = "watchdog", | |
af337f3e BD |
537 | .parent = &clk_p, |
538 | .ctrlbit = S3C2443_PCLKCON_WDT, | |
539 | }, { | |
540 | .name = "ac97", | |
af337f3e BD |
541 | .parent = &clk_p, |
542 | .ctrlbit = S3C2443_PCLKCON_AC97, | |
543 | }, { | |
544 | .name = "nand", | |
af337f3e BD |
545 | .parent = &clk_h, |
546 | }, { | |
547 | .name = "usb-bus-host", | |
af337f3e BD |
548 | .parent = &clk_usb_bus_host.clk, |
549 | } | |
550 | }; | |
551 | ||
a361d10a RS |
552 | static struct clk hsmmc1_clk = { |
553 | .name = "hsmmc", | |
554 | .devname = "s3c-sdhci.1", | |
555 | .parent = &clk_h, | |
556 | .enable = s3c2443_clkcon_enable_h, | |
557 | .ctrlbit = S3C2443_HCLKCON_HSMMC, | |
558 | }; | |
559 | ||
5c2f2917 HS |
560 | static struct clk hsspi_clk = { |
561 | .name = "spi", | |
a5238e36 | 562 | .devname = "s3c2443-spi.0", |
5c2f2917 HS |
563 | .parent = &clk_p, |
564 | .enable = s3c2443_clkcon_enable_p, | |
565 | .ctrlbit = S3C2443_PCLKCON_HSSPI, | |
566 | }; | |
567 | ||
af337f3e BD |
568 | /* EPLLCON compatible enough to get on/off information */ |
569 | ||
33ccedfd | 570 | void __init_or_cpufreq s3c2443_common_setup_clocks(pll_fn get_mpll) |
af337f3e BD |
571 | { |
572 | unsigned long epllcon = __raw_readl(S3C2443_EPLLCON); | |
573 | unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON); | |
af337f3e BD |
574 | struct clk *xtal_clk; |
575 | unsigned long xtal; | |
576 | unsigned long pll; | |
af337f3e BD |
577 | int ptr; |
578 | ||
579 | xtal_clk = clk_get(NULL, "xtal"); | |
580 | xtal = clk_get_rate(xtal_clk); | |
581 | clk_put(xtal_clk); | |
582 | ||
583 | pll = get_mpll(mpllcon, xtal); | |
584 | clk_msysclk.clk.rate = pll; | |
2e5ac943 | 585 | clk_mpll.rate = pll; |
af337f3e BD |
586 | |
587 | printk("CPU: MPLL %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n", | |
8c3d7c30 | 588 | (mpllcon & S3C2443_PLLCON_OFF) ? "off" : "on", |
2e5ac943 HS |
589 | print_mhz(pll), print_mhz(clk_get_rate(&clk_armdiv)), |
590 | print_mhz(clk_get_rate(&clk_h)), | |
591 | print_mhz(clk_get_rate(&clk_p))); | |
af337f3e BD |
592 | |
593 | for (ptr = 0; ptr < ARRAY_SIZE(clksrc_clks); ptr++) | |
594 | s3c_set_clksrc(&clksrc_clks[ptr], true); | |
595 | ||
596 | /* ensure usb bus clock is within correct rate of 48MHz */ | |
597 | ||
598 | if (clk_get_rate(&clk_usb_bus_host.clk) != (48 * 1000 * 1000)) { | |
599 | printk(KERN_INFO "Warning: USB host bus not at 48MHz\n"); | |
600 | clk_set_rate(&clk_usb_bus_host.clk, 48*1000*1000); | |
601 | } | |
602 | ||
603 | printk("CPU: EPLL %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n", | |
8c3d7c30 | 604 | (epllcon & S3C2443_PLLCON_OFF) ? "off" : "on", |
af337f3e BD |
605 | print_mhz(clk_get_rate(&clk_epll)), |
606 | print_mhz(clk_get_rate(&clk_usb_bus))); | |
607 | } | |
608 | ||
609 | static struct clk *clks[] __initdata = { | |
610 | &clk_prediv, | |
611 | &clk_mpllref, | |
612 | &clk_mdivclk, | |
613 | &clk_ext, | |
614 | &clk_epll, | |
615 | &clk_usb_bus, | |
aab08eeb | 616 | &clk_armdiv, |
a361d10a | 617 | &hsmmc1_clk, |
5c2f2917 | 618 | &hsspi_clk, |
af337f3e BD |
619 | }; |
620 | ||
621 | static struct clksrc_clk *clksrcs[] __initdata = { | |
e3b454f7 HS |
622 | &clk_i2s_eplldiv, |
623 | &clk_i2s, | |
af337f3e BD |
624 | &clk_usb_bus_host, |
625 | &clk_epllref, | |
626 | &clk_esysclk, | |
627 | &clk_msysclk, | |
aab08eeb | 628 | &clk_arm, |
af337f3e BD |
629 | }; |
630 | ||
0cfb26e1 TA |
631 | static struct clk_lookup s3c2443_clk_lookup[] = { |
632 | CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk), | |
633 | CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_p), | |
634 | CLKDEV_INIT(NULL, "clk_uart_baud3", &clk_esys_uart.clk), | |
a361d10a | 635 | CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.0", &hsmmc1_clk), |
a5238e36 | 636 | CLKDEV_INIT("s3c2443-spi.0", "spi_busclk0", &hsspi_clk), |
0cfb26e1 TA |
637 | }; |
638 | ||
af337f3e | 639 | void __init s3c2443_common_init_clocks(int xtal, pll_fn get_mpll, |
d9a3bfbd HS |
640 | unsigned int *divs, int nr_divs, |
641 | int divmask) | |
af337f3e BD |
642 | { |
643 | int ptr; | |
644 | ||
d9a3bfbd HS |
645 | armdiv = divs; |
646 | nr_armdiv = nr_divs; | |
647 | armdivmask = divmask; | |
648 | ||
9edc12a1 | 649 | /* s3c2443 parents h clock from prediv */ |
af337f3e | 650 | clk_h.parent = &clk_prediv; |
b681bfcf HS |
651 | clk_h.ops = &clk_h_ops; |
652 | ||
9edc12a1 HS |
653 | /* and p clock from h clock */ |
654 | clk_p.parent = &clk_h; | |
655 | clk_p.ops = &clk_p_ops; | |
af337f3e BD |
656 | |
657 | clk_usb_bus.parent = &clk_usb_bus_host.clk; | |
658 | clk_epll.parent = &clk_epllref.clk; | |
659 | ||
660 | s3c24xx_register_baseclocks(xtal); | |
661 | s3c24xx_register_clocks(clks, ARRAY_SIZE(clks)); | |
662 | ||
663 | for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++) | |
664 | s3c_register_clksrc(clksrcs[ptr], 1); | |
665 | ||
666 | s3c_register_clksrc(clksrc_clks, ARRAY_SIZE(clksrc_clks)); | |
667 | s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks)); | |
668 | ||
669 | /* See s3c2443/etc notes on disabling clocks at init time */ | |
670 | s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); | |
671 | s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); | |
0cfb26e1 | 672 | clkdev_add_table(s3c2443_clk_lookup, ARRAY_SIZE(s3c2443_clk_lookup)); |
af337f3e | 673 | |
33ccedfd | 674 | s3c2443_common_setup_clocks(get_mpll); |
af337f3e | 675 | } |