ARM: S3C2443: Further clksrc-clk conversions
[profile/ivi/kernel-x86-ivi.git] / arch / arm / mach-s3c2443 / clock.c
1 /* linux/arch/arm/mach-s3c2443/clock.c
2  *
3  * Copyright (c) 2007, 2010 Simtec Electronics
4  *      Ben Dooks <ben@simtec.co.uk>
5  *
6  * S3C2443 Clock control support
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21 */
22
23 #include <linux/init.h>
24 #include <linux/module.h>
25 #include <linux/kernel.h>
26 #include <linux/list.h>
27 #include <linux/errno.h>
28 #include <linux/err.h>
29 #include <linux/sysdev.h>
30 #include <linux/clk.h>
31 #include <linux/mutex.h>
32 #include <linux/serial_core.h>
33 #include <linux/io.h>
34
35 #include <asm/mach/map.h>
36
37 #include <mach/hardware.h>
38
39 #include <mach/regs-s3c2443-clock.h>
40
41 #include <plat/cpu-freq.h>
42
43 #include <plat/s3c2443.h>
44 #include <plat/clock.h>
45 #include <plat/clock-clksrc.h>
46 #include <plat/cpu.h>
47
48 /* We currently have to assume that the system is running
49  * from the XTPll input, and that all ***REFCLKs are being
50  * fed from it, as we cannot read the state of OM[4] from
51  * software.
52  *
53  * It would be possible for each board initialisation to
54  * set the correct muxing at initialisation
55 */
56
57 static int s3c2443_gate(void __iomem *reg, struct clk *clk, int enable)
58 {
59         u32 ctrlbit = clk->ctrlbit;
60         u32 con = __raw_readl(reg);
61
62         if (enable)
63                 con |= ctrlbit;
64         else
65                 con &= ~ctrlbit;
66
67         __raw_writel(con, reg);
68         return 0;
69 }
70
71 static int s3c2443_clkcon_enable_h(struct clk *clk, int enable)
72 {
73         return s3c2443_gate(S3C2443_HCLKCON, clk, enable);
74 }
75
76 static int s3c2443_clkcon_enable_p(struct clk *clk, int enable)
77 {
78         return s3c2443_gate(S3C2443_PCLKCON, clk, enable);
79 }
80
81 static int s3c2443_clkcon_enable_s(struct clk *clk, int enable)
82 {
83         return s3c2443_gate(S3C2443_SCLKCON, clk, enable);
84 }
85
86 /* s3c2443_roundate_clksrc is close enough to s3c_roundate_clksrc */
87
88 /* clock selections */
89
90 static struct clk clk_mpllref = {
91         .name           = "mpllref",
92         .parent         = &clk_xtal,
93         .id             = -1,
94 };
95
96 #if 0
97 static struct clk clk_mpll = {
98         .name           = "mpll",
99         .parent         = &clk_mpllref,
100         .id             = -1,
101 };
102 #endif
103
104 static struct clk clk_i2s_ext = {
105         .name           = "i2s-ext",
106         .id             = -1,
107 };
108
109 static struct clk *clk_epllref_sources[] = {
110         [0] = &clk_mpllref,
111         [1] = &clk_mpllref,
112         [2] = &clk_xtal,
113         [3] = &clk_ext,
114 };
115
116 static struct clksrc_clk clk_epllref = {
117         .clk    = {
118                 .name           = "epllref",
119                 .id             = -1,
120         },
121         .sources = &(struct clksrc_sources) {
122                 .sources = clk_epllref_sources,
123                 .nr_sources = ARRAY_SIZE(clk_epllref_sources),
124         },
125         .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 7 },
126 };
127
128 static unsigned long s3c2443_getrate_mdivclk(struct clk *clk)
129 {
130         unsigned long parent_rate = clk_get_rate(clk->parent);
131         unsigned long div = __raw_readl(S3C2443_CLKDIV0);
132
133         div  &= S3C2443_CLKDIV0_EXTDIV_MASK;
134         div >>= (S3C2443_CLKDIV0_EXTDIV_SHIFT-1);       /* x2 */
135
136         return parent_rate / (div + 1);
137 }
138
139 static struct clk clk_mdivclk = {
140         .name           = "mdivclk",
141         .parent         = &clk_mpllref,
142         .id             = -1,
143         .ops            = &(struct clk_ops) {
144                 .get_rate       = s3c2443_getrate_mdivclk,
145         },
146 };
147
148 static struct clk *clk_msysclk_sources[] = {
149         [0] = &clk_mpllref,
150         [1] = &clk_mpll,
151         [2] = &clk_mdivclk,
152         [3] = &clk_mpllref,
153 };
154
155 static struct clksrc_clk clk_msysclk = {
156         .clk    = {
157                 .name           = "msysclk",
158                 .parent         = &clk_xtal,
159                 .id             = -1,
160         },
161         .sources = &(struct clksrc_sources) {
162                 .sources = clk_msysclk_sources,
163                 .nr_sources = ARRAY_SIZE(clk_msysclk_sources),
164         },
165         .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 3 },
166 };
167
168 /* armdiv
169  *
170  * this clock is sourced from msysclk and can have a number of
171  * divider values applied to it to then be fed into armclk.
172 */
173
174 static struct clk clk_armdiv = {
175         .name           = "armdiv",
176         .id             = -1,
177         .parent         = &clk_msysclk.clk,
178 };
179
180 /* armclk
181  *
182  * this is the clock fed into the ARM core itself, from armdiv or from hclk.
183  */
184
185 static struct clk *clk_arm_sources[] = {
186         [0] = &clk_armdiv,
187         [1] = &clk_h,
188 };
189
190 static struct clksrc_clk clk_arm = {
191         .clk    = {
192                 .name           = "armclk",
193                 .id             = -1,
194         },
195         .sources = &(struct clksrc_sources) {
196                 .sources = clk_arm_sources,
197                 .nr_sources = ARRAY_SIZE(clk_arm_sources),
198         },
199         .reg_src = { .reg = S3C2443_CLKDIV0, .size = 1, .shift = 13 },
200 };
201
202 /* esysclk
203  *
204  * this is sourced from either the EPLL or the EPLLref clock
205 */
206
207 static struct clk *clk_sysclk_sources[] = {
208         [0] = &clk_epllref.clk,
209         [1] = &clk_epll,
210 };
211
212 static struct clksrc_clk clk_esysclk = {
213         .clk    = {
214                 .name           = "esysclk",
215                 .parent         = &clk_epll,
216                 .id             = -1,
217         },
218         .sources = &(struct clksrc_sources) {
219                 .sources = clk_sysclk_sources,
220                 .nr_sources = ARRAY_SIZE(clk_sysclk_sources),
221         },
222         .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 6 },
223 };
224
225 /* uartclk
226  *
227  * UART baud-rate clock sourced from esysclk via a divisor
228 */
229
230 static struct clksrc_clk clk_uart = {
231         .clk    = {
232                 .name           = "uartclk",
233                 .id             = -1,
234                 .parent         = &clk_esysclk.clk,
235         },
236         .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 8 },
237 };
238
239
240 /* hsspi
241  *
242  * high-speed spi clock, sourced from esysclk
243 */
244
245 static struct clksrc_clk clk_hsspi = {
246         .clk    = {
247                 .name           = "hsspi",
248                 .id             = -1,
249                 .parent         = &clk_esysclk.clk,
250                 .ctrlbit        = S3C2443_SCLKCON_HSSPICLK,
251                 .enable         = s3c2443_clkcon_enable_s,
252         },
253         .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
254 };
255
256 /* usbhost
257  *
258  * usb host bus-clock, usually 48MHz to provide USB bus clock timing
259 */
260
261 static struct clksrc_clk clk_usb_bus_host = {
262         .clk    = {
263                 .name           = "usb-bus-host-parent",
264                 .id             = -1,
265                 .parent         = &clk_esysclk.clk,
266                 .ctrlbit        = S3C2443_SCLKCON_USBHOST,
267                 .enable         = s3c2443_clkcon_enable_s,
268         },
269         .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
270 };
271
272 /* clk_hsmcc_div
273  *
274  * this clock is sourced from epll, and is fed through a divider,
275  * to a mux controlled by sclkcon where either it or a extclk can
276  * be fed to the hsmmc block
277 */
278
279 static struct clksrc_clk clk_hsmmc_div = {
280         .clk    = {
281                 .name           = "hsmmc-div",
282                 .id             = -1,
283                 .parent         = &clk_esysclk.clk,
284         },
285         .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 },
286 };
287
288 static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent)
289 {
290         unsigned long clksrc = __raw_readl(S3C2443_SCLKCON);
291
292         clksrc &= ~(S3C2443_SCLKCON_HSMMCCLK_EXT |
293                     S3C2443_SCLKCON_HSMMCCLK_EPLL);
294
295         if (parent == &clk_epll)
296                 clksrc |= S3C2443_SCLKCON_HSMMCCLK_EPLL;
297         else if (parent == &clk_ext)
298                 clksrc |= S3C2443_SCLKCON_HSMMCCLK_EXT;
299         else
300                 return -EINVAL;
301
302         if (clk->usage > 0) {
303                 __raw_writel(clksrc, S3C2443_SCLKCON);
304         }
305
306         clk->parent = parent;
307         return 0;
308 }
309
310 static int s3c2443_enable_hsmmc(struct clk *clk, int enable)
311 {
312         return s3c2443_setparent_hsmmc(clk, clk->parent);
313 }
314
315 static struct clk clk_hsmmc = {
316         .name           = "hsmmc-if",
317         .id             = -1,
318         .parent         = &clk_hsmmc_div.clk,
319         .enable         = s3c2443_enable_hsmmc,
320         .ops            = &(struct clk_ops) {
321                 .set_parent     = s3c2443_setparent_hsmmc,
322         },
323 };
324
325 /* i2s_eplldiv
326  *
327  * This clock is the output from the I2S divisor of ESYSCLK, and is seperate
328  * from the mux that comes after it (cannot merge into one single clock)
329 */
330
331 static struct clksrc_clk clk_i2s_eplldiv = {
332         .clk    = {
333                 .name           = "i2s-eplldiv",
334                 .id             = -1,
335                 .parent         = &clk_esysclk.clk,
336         },
337         .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 12, },
338 };
339
340 /* i2s-ref
341  *
342  * i2s bus reference clock, selectable from external, esysclk or epllref
343  *
344  * Note, this used to be two clocks, but was compressed into one.
345 */
346
347 struct clk *clk_i2s_srclist[] = {
348         [0] = &clk_i2s_eplldiv.clk,
349         [1] = &clk_i2s_ext,
350         [2] = &clk_epllref.clk,
351         [3] = &clk_epllref.clk,
352 };
353
354 static struct clksrc_clk clk_i2s = {
355         .clk    = {
356                 .name           = "i2s-if",
357                 .id             = -1,
358                 .ctrlbit        = S3C2443_SCLKCON_I2SCLK,
359                 .enable         = s3c2443_clkcon_enable_s,
360
361         },
362         .sources = &(struct clksrc_sources) {
363                 .sources = clk_i2s_srclist,
364                 .nr_sources = ARRAY_SIZE(clk_i2s_srclist),
365         },
366         .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 14 },
367 };
368
369 /* cam-if
370  *
371  * camera interface bus-clock, divided down from esysclk
372 */
373
374 static struct clksrc_clk clk_cam = {
375         .clk    = {
376                 .name           = "camif-upll", /* same as 2440 name */
377                 .id             = -1,
378                 .parent         = &clk_esysclk.clk,
379                 .ctrlbit        = S3C2443_SCLKCON_CAMCLK,
380                 .enable         = s3c2443_clkcon_enable_s,
381         },
382         .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 26 },
383 };
384
385 /* display-if
386  *
387  * display interface clock, divided from esysclk
388 */
389
390 static struct clksrc_clk clk_display = {
391         .clk    = {
392                 .name           = "display-if",
393                 .id             = -1,
394                 .parent         = &clk_esysclk.clk,
395                 .ctrlbit        = S3C2443_SCLKCON_DISPCLK,
396                 .enable         = s3c2443_clkcon_enable_s,
397         },
398         .reg_div = { .reg = S3C2443_CLKDIV1, .size = 8, .shift = 16 },
399 };
400
401 /* prediv
402  *
403  * this divides the msysclk down to pass to h/p/etc.
404  */
405
406 static unsigned long s3c2443_prediv_getrate(struct clk *clk)
407 {
408         unsigned long rate = clk_get_rate(clk->parent);
409         unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
410
411         clkdiv0 &= S3C2443_CLKDIV0_PREDIV_MASK;
412         clkdiv0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT;
413
414         return rate / (clkdiv0 + 1);
415 }
416
417 static struct clk clk_prediv = {
418         .name           = "prediv",
419         .id             = -1,
420         .parent         = &clk_msysclk.clk,
421         .ops            = &(struct clk_ops) {
422                 .get_rate       = s3c2443_prediv_getrate,
423         },
424 };
425
426 /* standard clock definitions */
427
428 static struct clk init_clocks_disable[] = {
429         {
430                 .name           = "nand",
431                 .id             = -1,
432                 .parent         = &clk_h,
433         }, {
434                 .name           = "sdi",
435                 .id             = -1,
436                 .parent         = &clk_p,
437                 .enable         = s3c2443_clkcon_enable_p,
438                 .ctrlbit        = S3C2443_PCLKCON_SDI,
439         }, {
440                 .name           = "adc",
441                 .id             = -1,
442                 .parent         = &clk_p,
443                 .enable         = s3c2443_clkcon_enable_p,
444                 .ctrlbit        = S3C2443_PCLKCON_ADC,
445         }, {
446                 .name           = "i2c",
447                 .id             = -1,
448                 .parent         = &clk_p,
449                 .enable         = s3c2443_clkcon_enable_p,
450                 .ctrlbit        = S3C2443_PCLKCON_IIC,
451         }, {
452                 .name           = "iis",
453                 .id             = -1,
454                 .parent         = &clk_p,
455                 .enable         = s3c2443_clkcon_enable_p,
456                 .ctrlbit        = S3C2443_PCLKCON_IIS,
457         }, {
458                 .name           = "spi",
459                 .id             = 0,
460                 .parent         = &clk_p,
461                 .enable         = s3c2443_clkcon_enable_p,
462                 .ctrlbit        = S3C2443_PCLKCON_SPI0,
463         }, {
464                 .name           = "spi",
465                 .id             = 1,
466                 .parent         = &clk_p,
467                 .enable         = s3c2443_clkcon_enable_p,
468                 .ctrlbit        = S3C2443_PCLKCON_SPI1,
469         }
470 };
471
472 static struct clk init_clocks[] = {
473         {
474                 .name           = "dma",
475                 .id             = 0,
476                 .parent         = &clk_h,
477                 .enable         = s3c2443_clkcon_enable_h,
478                 .ctrlbit        = S3C2443_HCLKCON_DMA0,
479         }, {
480                 .name           = "dma",
481                 .id             = 1,
482                 .parent         = &clk_h,
483                 .enable         = s3c2443_clkcon_enable_h,
484                 .ctrlbit        = S3C2443_HCLKCON_DMA1,
485         }, {
486                 .name           = "dma",
487                 .id             = 2,
488                 .parent         = &clk_h,
489                 .enable         = s3c2443_clkcon_enable_h,
490                 .ctrlbit        = S3C2443_HCLKCON_DMA2,
491         }, {
492                 .name           = "dma",
493                 .id             = 3,
494                 .parent         = &clk_h,
495                 .enable         = s3c2443_clkcon_enable_h,
496                 .ctrlbit        = S3C2443_HCLKCON_DMA3,
497         }, {
498                 .name           = "dma",
499                 .id             = 4,
500                 .parent         = &clk_h,
501                 .enable         = s3c2443_clkcon_enable_h,
502                 .ctrlbit        = S3C2443_HCLKCON_DMA4,
503         }, {
504                 .name           = "dma",
505                 .id             = 5,
506                 .parent         = &clk_h,
507                 .enable         = s3c2443_clkcon_enable_h,
508                 .ctrlbit        = S3C2443_HCLKCON_DMA5,
509         }, {
510                 .name           = "lcd",
511                 .id             = -1,
512                 .parent         = &clk_h,
513                 .enable         = s3c2443_clkcon_enable_h,
514                 .ctrlbit        = S3C2443_HCLKCON_LCDC,
515         }, {
516                 .name           = "gpio",
517                 .id             = -1,
518                 .parent         = &clk_p,
519                 .enable         = s3c2443_clkcon_enable_p,
520                 .ctrlbit        = S3C2443_PCLKCON_GPIO,
521         }, {
522                 .name           = "usb-host",
523                 .id             = -1,
524                 .parent         = &clk_h,
525                 .enable         = s3c2443_clkcon_enable_h,
526                 .ctrlbit        = S3C2443_HCLKCON_USBH,
527         }, {
528                 .name           = "usb-device",
529                 .id             = -1,
530                 .parent         = &clk_h,
531                 .enable         = s3c2443_clkcon_enable_h,
532                 .ctrlbit        = S3C2443_HCLKCON_USBD,
533         }, {
534                 .name           = "hsmmc",
535                 .id             = -1,
536                 .parent         = &clk_h,
537                 .enable         = s3c2443_clkcon_enable_h,
538                 .ctrlbit        = S3C2443_HCLKCON_HSMMC,
539         }, {
540                 .name           = "cfc",
541                 .id             = -1,
542                 .parent         = &clk_h,
543                 .enable         = s3c2443_clkcon_enable_h,
544                 .ctrlbit        = S3C2443_HCLKCON_CFC,
545         }, {
546                 .name           = "ssmc",
547                 .id             = -1,
548                 .parent         = &clk_h,
549                 .enable         = s3c2443_clkcon_enable_h,
550                 .ctrlbit        = S3C2443_HCLKCON_SSMC,
551         }, {
552                 .name           = "timers",
553                 .id             = -1,
554                 .parent         = &clk_p,
555                 .enable         = s3c2443_clkcon_enable_p,
556                 .ctrlbit        = S3C2443_PCLKCON_PWMT,
557         }, {
558                 .name           = "uart",
559                 .id             = 0,
560                 .parent         = &clk_p,
561                 .enable         = s3c2443_clkcon_enable_p,
562                 .ctrlbit        = S3C2443_PCLKCON_UART0,
563         }, {
564                 .name           = "uart",
565                 .id             = 1,
566                 .parent         = &clk_p,
567                 .enable         = s3c2443_clkcon_enable_p,
568                 .ctrlbit        = S3C2443_PCLKCON_UART1,
569         }, {
570                 .name           = "uart",
571                 .id             = 2,
572                 .parent         = &clk_p,
573                 .enable         = s3c2443_clkcon_enable_p,
574                 .ctrlbit        = S3C2443_PCLKCON_UART2,
575         }, {
576                 .name           = "uart",
577                 .id             = 3,
578                 .parent         = &clk_p,
579                 .enable         = s3c2443_clkcon_enable_p,
580                 .ctrlbit        = S3C2443_PCLKCON_UART3,
581         }, {
582                 .name           = "rtc",
583                 .id             = -1,
584                 .parent         = &clk_p,
585                 .enable         = s3c2443_clkcon_enable_p,
586                 .ctrlbit        = S3C2443_PCLKCON_RTC,
587         }, {
588                 .name           = "watchdog",
589                 .id             = -1,
590                 .parent         = &clk_p,
591                 .ctrlbit        = S3C2443_PCLKCON_WDT,
592         }, {
593                 .name           = "usb-bus-host",
594                 .id             = -1,
595                 .parent         = &clk_usb_bus_host.clk,
596         }, {
597                 .name           = "ac97",
598                 .id             = -1,
599                 .parent         = &clk_p,
600                 .ctrlbit        = S3C2443_PCLKCON_AC97,
601         }
602 };
603
604 /* clocks to add where we need to check their parentage */
605
606 static struct clksrc_clk __initdata *init_list[] = {
607         &clk_epllref, /* should be first */
608         &clk_esysclk,
609         &clk_msysclk,
610         &clk_arm,
611         &clk_i2s_eplldiv,
612         &clk_i2s,
613         &clk_cam,
614         &clk_uart,
615         &clk_display,
616         &clk_hsmmc_div,
617         &clk_usb_bus_host,
618 };
619
620 static void __init s3c2443_clk_initparents(void)
621 {
622         int ptr;
623
624         for (ptr = 0; ptr < ARRAY_SIZE(init_list); ptr++)
625                 s3c_set_clksrc(init_list[ptr], true);
626 }
627
628 /* armdiv divisor table */
629
630 static unsigned int armdiv[16] = {
631         [S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 1,
632         [S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 2,
633         [S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 3,
634         [S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 4,
635         [S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 6,
636         [S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 8,
637         [S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]     = 12,
638         [S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]     = 16,
639 };
640
641 static inline unsigned int s3c2443_fclk_div(unsigned long clkcon0)
642 {
643         clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK;
644
645         return armdiv[clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT];
646 }
647
648 static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0)
649 {
650         clkcon0 &= S3C2443_CLKDIV0_HCLKDIV_MASK;
651
652         return clkcon0 + 1;
653 }
654
655 /* clocks to add straight away */
656
657 static struct clksrc_clk *clksrcs[] __initdata = {
658         &clk_usb_bus_host,
659         &clk_epllref,
660         &clk_esysclk,
661         &clk_msysclk,
662         &clk_arm,
663         &clk_uart,
664         &clk_display,
665         &clk_cam,
666         &clk_i2s_eplldiv,
667         &clk_i2s,
668         &clk_hsspi,
669         &clk_hsmmc_div,
670 };
671
672 static struct clk *clks[] __initdata = {
673         &clk_ext,
674         &clk_epll,
675         &clk_usb_bus,
676         &clk_mpllref,
677         &clk_hsmmc,
678         &clk_armdiv,
679         &clk_prediv,
680 };
681
682 void __init_or_cpufreq s3c2443_setup_clocks(void)
683 {
684         unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON);
685         unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
686         struct clk *xtal_clk;
687         unsigned long xtal;
688         unsigned long pll;
689         unsigned long fclk;
690         unsigned long hclk;
691         unsigned long pclk;
692
693         xtal_clk = clk_get(NULL, "xtal");
694         xtal = clk_get_rate(xtal_clk);
695         clk_put(xtal_clk);
696
697         pll = s3c2443_get_mpll(mpllcon, xtal);
698         clk_msysclk.clk.rate = pll;
699
700         fclk = pll / s3c2443_fclk_div(clkdiv0);
701         hclk = s3c2443_prediv_getrate(&clk_prediv);
702         hclk /= s3c2443_get_hdiv(clkdiv0);
703         pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1);
704
705         s3c24xx_setup_clocks(fclk, hclk, pclk);
706
707         printk("S3C2443: mpll %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n",
708                (mpllcon & S3C2443_PLLCON_OFF) ? "off":"on",
709                print_mhz(pll), print_mhz(fclk),
710                print_mhz(hclk), print_mhz(pclk));
711
712         s3c24xx_setup_clocks(fclk, hclk, pclk);
713 }
714
715 void __init s3c2443_init_clocks(int xtal)
716 {
717         struct clk *clkp;
718         unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
719         int ret;
720         int ptr;
721
722         /* s3c2443 parents h and p clocks from prediv */
723         clk_h.parent = &clk_prediv;
724         clk_p.parent = &clk_prediv;
725
726         s3c24xx_register_baseclocks(xtal);
727         s3c2443_setup_clocks();
728         s3c2443_clk_initparents();
729
730         for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
731                 clkp = clks[ptr];
732
733                 ret = s3c24xx_register_clock(clkp);
734                 if (ret < 0) {
735                         printk(KERN_ERR "Failed to register clock %s (%d)\n",
736                                clkp->name, ret);
737                 }
738         }
739
740         for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
741                 s3c_register_clksrc(clksrcs[ptr], 1);
742
743         clk_epll.rate = s3c2443_get_epll(epllcon, xtal);
744         clk_epll.parent = &clk_epllref.clk;
745         clk_usb_bus.parent = &clk_usb_bus_host.clk;
746
747         /* ensure usb bus clock is within correct rate of 48MHz */
748
749         if (clk_get_rate(&clk_usb_bus_host.clk) != (48 * 1000 * 1000)) {
750                 printk(KERN_INFO "Warning: USB host bus not at 48MHz\n");
751                 clk_set_rate(&clk_usb_bus_host.clk, 48*1000*1000);
752         }
753
754         printk("S3C2443: epll %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
755                (epllcon & S3C2443_PLLCON_OFF) ? "off":"on",
756                print_mhz(clk_get_rate(&clk_epll)),
757                print_mhz(clk_get_rate(&clk_usb_bus)));
758
759         /* register clocks from clock array */
760
761         s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
762
763         /* We must be careful disabling the clocks we are not intending to
764          * be using at boot time, as subsystems such as the LCD which do
765          * their own DMA requests to the bus can cause the system to lockup
766          * if they where in the middle of requesting bus access.
767          *
768          * Disabling the LCD clock if the LCD is active is very dangerous,
769          * and therefore the bootloader should be careful to not enable
770          * the LCD clock if it is not needed.
771         */
772
773         /* install (and disable) the clocks we do not need immediately */
774
775         clkp = init_clocks_disable;
776         for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
777
778                 ret = s3c24xx_register_clock(clkp);
779                 if (ret < 0) {
780                         printk(KERN_ERR "Failed to register clock %s (%d)\n",
781                                clkp->name, ret);
782                 }
783
784                 (clkp->enable)(clkp, 0);
785         }
786
787         s3c_pwmclk_init();
788 }