Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
[pandora-kernel.git] / arch / arm / mach-s5p6440 / clock.c
1 /* linux/arch/arm/mach-s5p6440/clock.c
2  *
3  * Copyright (c) 2009 Samsung Electronics Co., Ltd.
4  *              http://www.samsung.com/
5  *
6  * S5P6440 - Clock 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 version 2 as
10  * published by the Free Software Foundation.
11 */
12
13 #include <linux/init.h>
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/list.h>
17 #include <linux/errno.h>
18 #include <linux/err.h>
19 #include <linux/clk.h>
20 #include <linux/sysdev.h>
21 #include <linux/io.h>
22
23 #include <mach/hardware.h>
24 #include <mach/map.h>
25
26 #include <plat/cpu-freq.h>
27 #include <mach/regs-clock.h>
28 #include <plat/clock.h>
29 #include <plat/cpu.h>
30 #include <plat/clock-clksrc.h>
31 #include <plat/s5p-clock.h>
32 #include <plat/pll.h>
33 #include <plat/s5p6440.h>
34
35 /* APLL Mux output clock */
36 static struct clksrc_clk clk_mout_apll = {
37         .clk    = {
38                 .name           = "mout_apll",
39                 .id             = -1,
40         },
41         .sources        = &clk_src_apll,
42         .reg_src        = { .reg = S5P_CLK_SRC0, .shift = 0, .size = 1 },
43 };
44
45 static int s5p6440_epll_enable(struct clk *clk, int enable)
46 {
47         unsigned int ctrlbit = clk->ctrlbit;
48         unsigned int epll_con = __raw_readl(S5P_EPLL_CON) & ~ctrlbit;
49
50         if (enable)
51                 __raw_writel(epll_con | ctrlbit, S5P_EPLL_CON);
52         else
53                 __raw_writel(epll_con, S5P_EPLL_CON);
54
55         return 0;
56 }
57
58 static unsigned long s5p6440_epll_get_rate(struct clk *clk)
59 {
60         return clk->rate;
61 }
62
63 static u32 epll_div[][5] = {
64         { 36000000,     0,      48, 1, 4 },
65         { 48000000,     0,      32, 1, 3 },
66         { 60000000,     0,      40, 1, 3 },
67         { 72000000,     0,      48, 1, 3 },
68         { 84000000,     0,      28, 1, 2 },
69         { 96000000,     0,      32, 1, 2 },
70         { 32768000,     45264,  43, 1, 4 },
71         { 45158000,     6903,   30, 1, 3 },
72         { 49152000,     50332,  32, 1, 3 },
73         { 67738000,     10398,  45, 1, 3 },
74         { 73728000,     9961,   49, 1, 3 }
75 };
76
77 static int s5p6440_epll_set_rate(struct clk *clk, unsigned long rate)
78 {
79         unsigned int epll_con, epll_con_k;
80         unsigned int i;
81
82         if (clk->rate == rate)  /* Return if nothing changed */
83                 return 0;
84
85         epll_con = __raw_readl(S5P_EPLL_CON);
86         epll_con_k = __raw_readl(S5P_EPLL_CON_K);
87
88         epll_con_k &= ~(PLL90XX_KDIV_MASK);
89         epll_con &= ~(PLL90XX_MDIV_MASK | PLL90XX_PDIV_MASK | PLL90XX_SDIV_MASK);
90
91         for (i = 0; i < ARRAY_SIZE(epll_div); i++) {
92                  if (epll_div[i][0] == rate) {
93                         epll_con_k |= (epll_div[i][1] << PLL90XX_KDIV_SHIFT);
94                         epll_con |= (epll_div[i][2] << PLL90XX_MDIV_SHIFT) |
95                                     (epll_div[i][3] << PLL90XX_PDIV_SHIFT) |
96                                     (epll_div[i][4] << PLL90XX_SDIV_SHIFT);
97                         break;
98                 }
99         }
100
101         if (i == ARRAY_SIZE(epll_div)) {
102                 printk(KERN_ERR "%s: Invalid Clock EPLL Frequency\n", __func__);
103                 return -EINVAL;
104         }
105
106         __raw_writel(epll_con, S5P_EPLL_CON);
107         __raw_writel(epll_con_k, S5P_EPLL_CON_K);
108
109         clk->rate = rate;
110
111         return 0;
112 }
113
114 static struct clk_ops s5p6440_epll_ops = {
115         .get_rate = s5p6440_epll_get_rate,
116         .set_rate = s5p6440_epll_set_rate,
117 };
118
119 static struct clksrc_clk clk_mout_epll = {
120         .clk    = {
121                 .name           = "mout_epll",
122                 .id             = -1,
123         },
124         .sources        = &clk_src_epll,
125         .reg_src        = { .reg = S5P_CLK_SRC0, .shift = 2, .size = 1 },
126 };
127
128 static struct clksrc_clk clk_mout_mpll = {
129         .clk = {
130                 .name           = "mout_mpll",
131                 .id             = -1,
132         },
133         .sources        = &clk_src_mpll,
134         .reg_src        = { .reg = S5P_CLK_SRC0, .shift = 1, .size = 1 },
135 };
136
137 static struct clk clk_h_low = {
138         .name           = "hclk_low",
139         .id             = -1,
140         .rate           = 0,
141         .parent         = NULL,
142         .ctrlbit        = 0,
143         .ops            = &clk_ops_def_setrate,
144 };
145
146 static struct clk clk_p_low = {
147         .name           = "pclk_low",
148         .id             = -1,
149         .rate           = 0,
150         .parent         = NULL,
151         .ctrlbit        = 0,
152         .ops            = &clk_ops_def_setrate,
153 };
154
155 enum perf_level {
156         L0 = 532*1000,
157         L1 = 266*1000,
158         L2 = 133*1000,
159 };
160
161 static const u32 clock_table[][3] = {
162         /*{ARM_CLK, DIVarm, DIVhclk}*/
163         {L0 * 1000, (0 << ARM_DIV_RATIO_SHIFT), (3 << S5P_CLKDIV0_HCLK_SHIFT)},
164         {L1 * 1000, (1 << ARM_DIV_RATIO_SHIFT), (1 << S5P_CLKDIV0_HCLK_SHIFT)},
165         {L2 * 1000, (3 << ARM_DIV_RATIO_SHIFT), (0 << S5P_CLKDIV0_HCLK_SHIFT)},
166 };
167
168 static unsigned long s5p6440_armclk_get_rate(struct clk *clk)
169 {
170         unsigned long rate = clk_get_rate(clk->parent);
171         u32 clkdiv;
172
173         /* divisor mask starts at bit0, so no need to shift */
174         clkdiv = __raw_readl(ARM_CLK_DIV) & ARM_DIV_MASK;
175
176         return rate / (clkdiv + 1);
177 }
178
179 static unsigned long s5p6440_armclk_round_rate(struct clk *clk,
180                                                 unsigned long rate)
181 {
182         u32 iter;
183
184         for (iter = 1 ; iter < ARRAY_SIZE(clock_table) ; iter++) {
185                 if (rate > clock_table[iter][0])
186                         return clock_table[iter-1][0];
187         }
188
189         return clock_table[ARRAY_SIZE(clock_table) - 1][0];
190 }
191
192 static int s5p6440_armclk_set_rate(struct clk *clk, unsigned long rate)
193 {
194         u32 round_tmp;
195         u32 iter;
196         u32 clk_div0_tmp;
197         u32 cur_rate = clk->ops->get_rate(clk);
198         unsigned long flags;
199
200         round_tmp = clk->ops->round_rate(clk, rate);
201         if (round_tmp == cur_rate)
202                 return 0;
203
204
205         for (iter = 0 ; iter < ARRAY_SIZE(clock_table) ; iter++) {
206                 if (round_tmp == clock_table[iter][0])
207                         break;
208         }
209
210         if (iter >= ARRAY_SIZE(clock_table))
211                 iter = ARRAY_SIZE(clock_table) - 1;
212
213         local_irq_save(flags);
214         if (cur_rate > round_tmp) {
215                 /* Frequency Down */
216                 clk_div0_tmp = __raw_readl(ARM_CLK_DIV) & ~(ARM_DIV_MASK);
217                 clk_div0_tmp |= clock_table[iter][1];
218                 __raw_writel(clk_div0_tmp, ARM_CLK_DIV);
219
220                 clk_div0_tmp = __raw_readl(ARM_CLK_DIV) &
221                                 ~(S5P_CLKDIV0_HCLK_MASK);
222                 clk_div0_tmp |= clock_table[iter][2];
223                 __raw_writel(clk_div0_tmp, ARM_CLK_DIV);
224
225
226         } else {
227                 /* Frequency Up */
228                 clk_div0_tmp = __raw_readl(ARM_CLK_DIV) &
229                                 ~(S5P_CLKDIV0_HCLK_MASK);
230                 clk_div0_tmp |= clock_table[iter][2];
231                 __raw_writel(clk_div0_tmp, ARM_CLK_DIV);
232
233                 clk_div0_tmp = __raw_readl(ARM_CLK_DIV) & ~(ARM_DIV_MASK);
234                 clk_div0_tmp |= clock_table[iter][1];
235                 __raw_writel(clk_div0_tmp, ARM_CLK_DIV);
236                 }
237         local_irq_restore(flags);
238
239         clk->rate = clock_table[iter][0];
240
241         return 0;
242 }
243
244 static struct clk_ops s5p6440_clkarm_ops = {
245         .get_rate       = s5p6440_armclk_get_rate,
246         .set_rate       = s5p6440_armclk_set_rate,
247         .round_rate     = s5p6440_armclk_round_rate,
248 };
249
250 static unsigned long s5p6440_clk_doutmpll_get_rate(struct clk *clk)
251 {
252         unsigned long rate = clk_get_rate(clk->parent);
253
254         if (__raw_readl(S5P_CLK_DIV0) & S5P_CLKDIV0_MPLL_MASK)
255                 rate /= 2;
256
257         return rate;
258 }
259
260 static struct clk clk_dout_mpll = {
261         .name           = "dout_mpll",
262         .id             = -1,
263         .parent         = &clk_mout_mpll.clk,
264         .ops            = &(struct clk_ops) {
265                 .get_rate       = s5p6440_clk_doutmpll_get_rate,
266         },
267 };
268
269 int s5p6440_clk48m_ctrl(struct clk *clk, int enable)
270 {
271         unsigned long flags;
272         u32 val;
273
274         /* can't rely on clock lock, this register has other usages */
275         local_irq_save(flags);
276
277         val = __raw_readl(S5P_OTHERS);
278         if (enable)
279                 val |= S5P_OTHERS_USB_SIG_MASK;
280         else
281                 val &= ~S5P_OTHERS_USB_SIG_MASK;
282
283         __raw_writel(val, S5P_OTHERS);
284
285         local_irq_restore(flags);
286
287         return 0;
288 }
289
290 static int s5p6440_pclk_ctrl(struct clk *clk, int enable)
291 {
292         return s5p_gatectrl(S5P_CLK_GATE_PCLK, clk, enable);
293 }
294
295 static int s5p6440_hclk0_ctrl(struct clk *clk, int enable)
296 {
297         return s5p_gatectrl(S5P_CLK_GATE_HCLK0, clk, enable);
298 }
299
300 static int s5p6440_hclk1_ctrl(struct clk *clk, int enable)
301 {
302         return s5p_gatectrl(S5P_CLK_GATE_HCLK1, clk, enable);
303 }
304
305 static int s5p6440_sclk_ctrl(struct clk *clk, int enable)
306 {
307         return s5p_gatectrl(S5P_CLK_GATE_SCLK0, clk, enable);
308 }
309
310 static int s5p6440_mem_ctrl(struct clk *clk, int enable)
311 {
312         return s5p_gatectrl(S5P_CLK_GATE_MEM0, clk, enable);
313 }
314
315 /*
316  * The following clocks will be disabled during clock initialization. It is
317  * recommended to keep the following clocks disabled until the driver requests
318  * for enabling the clock.
319  */
320 static struct clk init_clocks_disable[] = {
321         {
322                 .name           = "nand",
323                 .id             = -1,
324                 .parent         = &clk_h,
325                 .enable         = s5p6440_mem_ctrl,
326                 .ctrlbit        = S5P_CLKCON_MEM0_HCLK_NFCON,
327         }, {
328                 .name           = "adc",
329                 .id             = -1,
330                 .parent         = &clk_p_low,
331                 .enable         = s5p6440_pclk_ctrl,
332                 .ctrlbit        = S5P_CLKCON_PCLK_TSADC,
333         }, {
334                 .name           = "i2c",
335                 .id             = -1,
336                 .parent         = &clk_p_low,
337                 .enable         = s5p6440_pclk_ctrl,
338                 .ctrlbit        = S5P_CLKCON_PCLK_IIC0,
339         }, {
340                 .name           = "i2s_v40",
341                 .id             = 0,
342                 .parent         = &clk_p_low,
343                 .enable         = s5p6440_pclk_ctrl,
344                 .ctrlbit        = S5P_CLKCON_PCLK_IIS2,
345         }, {
346                 .name           = "spi",
347                 .id             = 0,
348                 .parent         = &clk_p_low,
349                 .enable         = s5p6440_pclk_ctrl,
350                 .ctrlbit        = S5P_CLKCON_PCLK_SPI0,
351         }, {
352                 .name           = "spi",
353                 .id             = 1,
354                 .parent         = &clk_p_low,
355                 .enable         = s5p6440_pclk_ctrl,
356                 .ctrlbit        = S5P_CLKCON_PCLK_SPI1,
357         }, {
358                 .name           = "sclk_spi_48",
359                 .id             = 0,
360                 .parent         = &clk_48m,
361                 .enable         = s5p6440_sclk_ctrl,
362                 .ctrlbit        = S5P_CLKCON_SCLK0_SPI0_48,
363         }, {
364                 .name           = "sclk_spi_48",
365                 .id             = 1,
366                 .parent         = &clk_48m,
367                 .enable         = s5p6440_sclk_ctrl,
368                 .ctrlbit        = S5P_CLKCON_SCLK0_SPI1_48,
369         }, {
370                 .name           = "mmc_48m",
371                 .id             = 0,
372                 .parent         = &clk_48m,
373                 .enable         = s5p6440_sclk_ctrl,
374                 .ctrlbit        = S5P_CLKCON_SCLK0_MMC0_48,
375         }, {
376                 .name           = "mmc_48m",
377                 .id             = 1,
378                 .parent         = &clk_48m,
379                 .enable         = s5p6440_sclk_ctrl,
380                 .ctrlbit        = S5P_CLKCON_SCLK0_MMC1_48,
381         }, {
382                 .name           = "mmc_48m",
383                 .id             = 2,
384                 .parent         = &clk_48m,
385                 .enable         = s5p6440_sclk_ctrl,
386                 .ctrlbit        = S5P_CLKCON_SCLK0_MMC2_48,
387         }, {
388                 .name           = "otg",
389                 .id             = -1,
390                 .parent         = &clk_h_low,
391                 .enable         = s5p6440_hclk0_ctrl,
392                 .ctrlbit        = S5P_CLKCON_HCLK0_USB
393         }, {
394                 .name           = "post",
395                 .id             = -1,
396                 .parent         = &clk_h_low,
397                 .enable         = s5p6440_hclk0_ctrl,
398                 .ctrlbit        = S5P_CLKCON_HCLK0_POST0
399         }, {
400                 .name           = "lcd",
401                 .id             = -1,
402                 .parent         = &clk_h_low,
403                 .enable         = s5p6440_hclk1_ctrl,
404                 .ctrlbit        = S5P_CLKCON_HCLK1_DISPCON,
405         }, {
406                 .name           = "hsmmc",
407                 .id             = 0,
408                 .parent         = &clk_h_low,
409                 .enable         = s5p6440_hclk0_ctrl,
410                 .ctrlbit        = S5P_CLKCON_HCLK0_HSMMC0,
411         }, {
412                 .name           = "hsmmc",
413                 .id             = 1,
414                 .parent         = &clk_h_low,
415                 .enable         = s5p6440_hclk0_ctrl,
416                 .ctrlbit        = S5P_CLKCON_HCLK0_HSMMC1,
417         }, {
418                 .name           = "hsmmc",
419                 .id             = 2,
420                 .parent         = &clk_h_low,
421                 .enable         = s5p6440_hclk0_ctrl,
422                 .ctrlbit        = S5P_CLKCON_HCLK0_HSMMC2,
423         }, {
424                 .name           = "rtc",
425                 .id             = -1,
426                 .parent         = &clk_p_low,
427                 .enable         = s5p6440_pclk_ctrl,
428                 .ctrlbit        = S5P_CLKCON_PCLK_RTC,
429         }, {
430                 .name           = "watchdog",
431                 .id             = -1,
432                 .parent         = &clk_p_low,
433                 .enable         = s5p6440_pclk_ctrl,
434                 .ctrlbit        = S5P_CLKCON_PCLK_WDT,
435         }, {
436                 .name           = "timers",
437                 .id             = -1,
438                 .parent         = &clk_p_low,
439                 .enable         = s5p6440_pclk_ctrl,
440                 .ctrlbit        = S5P_CLKCON_PCLK_PWM,
441         }
442 };
443
444 /*
445  * The following clocks will be enabled during clock initialization.
446  */
447 static struct clk init_clocks[] = {
448         {
449                 .name           = "gpio",
450                 .id             = -1,
451                 .parent         = &clk_p_low,
452                 .enable         = s5p6440_pclk_ctrl,
453                 .ctrlbit        = S5P_CLKCON_PCLK_GPIO,
454         }, {
455                 .name           = "uart",
456                 .id             = 0,
457                 .parent         = &clk_p_low,
458                 .enable         = s5p6440_pclk_ctrl,
459                 .ctrlbit        = S5P_CLKCON_PCLK_UART0,
460         }, {
461                 .name           = "uart",
462                 .id             = 1,
463                 .parent         = &clk_p_low,
464                 .enable         = s5p6440_pclk_ctrl,
465                 .ctrlbit        = S5P_CLKCON_PCLK_UART1,
466         }, {
467                 .name           = "uart",
468                 .id             = 2,
469                 .parent         = &clk_p_low,
470                 .enable         = s5p6440_pclk_ctrl,
471                 .ctrlbit        = S5P_CLKCON_PCLK_UART2,
472         }, {
473                 .name           = "uart",
474                 .id             = 3,
475                 .parent         = &clk_p_low,
476                 .enable         = s5p6440_pclk_ctrl,
477                 .ctrlbit        = S5P_CLKCON_PCLK_UART3,
478         }
479 };
480
481 static struct clk clk_iis_cd_v40 = {
482         .name           = "iis_cdclk_v40",
483         .id             = -1,
484 };
485
486 static struct clk clk_pcm_cd = {
487         .name           = "pcm_cdclk",
488         .id             = -1,
489 };
490
491 static struct clk *clkset_spi_mmc_list[] = {
492         &clk_mout_epll.clk,
493         &clk_dout_mpll,
494         &clk_fin_epll,
495 };
496
497 static struct clksrc_sources clkset_spi_mmc = {
498         .sources        = clkset_spi_mmc_list,
499         .nr_sources     = ARRAY_SIZE(clkset_spi_mmc_list),
500 };
501
502 static struct clk *clkset_uart_list[] = {
503         &clk_mout_epll.clk,
504         &clk_dout_mpll
505 };
506
507 static struct clksrc_sources clkset_uart = {
508         .sources        = clkset_uart_list,
509         .nr_sources     = ARRAY_SIZE(clkset_uart_list),
510 };
511
512 static struct clksrc_clk clksrcs[] = {
513         {
514                 .clk    = {
515                         .name           = "mmc_bus",
516                         .id             = 0,
517                         .ctrlbit        = S5P_CLKCON_SCLK0_MMC0,
518                         .enable         = s5p6440_sclk_ctrl,
519                 },
520                 .sources = &clkset_spi_mmc,
521                 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 18, .size = 2 },
522                 .reg_div = { .reg = S5P_CLK_DIV1, .shift = 0, .size = 4 },
523         }, {
524                 .clk    = {
525                         .name           = "mmc_bus",
526                         .id             = 1,
527                         .ctrlbit        = S5P_CLKCON_SCLK0_MMC1,
528                         .enable         = s5p6440_sclk_ctrl,
529                 },
530                 .sources = &clkset_spi_mmc,
531                 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 20, .size = 2 },
532                 .reg_div = { .reg = S5P_CLK_DIV1, .shift = 4, .size = 4 },
533         }, {
534                 .clk    = {
535                         .name           = "mmc_bus",
536                         .id             = 2,
537                         .ctrlbit        = S5P_CLKCON_SCLK0_MMC2,
538                         .enable         = s5p6440_sclk_ctrl,
539                 },
540                 .sources = &clkset_spi_mmc,
541                 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 22, .size = 2 },
542                 .reg_div = { .reg = S5P_CLK_DIV1, .shift = 8, .size = 4 },
543         }, {
544                 .clk    = {
545                         .name           = "uclk1",
546                         .id             = -1,
547                         .ctrlbit        = S5P_CLKCON_SCLK0_UART,
548                         .enable         = s5p6440_sclk_ctrl,
549                 },
550                 .sources = &clkset_uart,
551                 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 13, .size = 1 },
552                 .reg_div = { .reg = S5P_CLK_DIV2, .shift = 16, .size = 4 },
553         }, {
554                 .clk    = {
555                         .name           = "spi_epll",
556                         .id             = 0,
557                         .ctrlbit        = S5P_CLKCON_SCLK0_SPI0,
558                         .enable         = s5p6440_sclk_ctrl,
559                 },
560                 .sources = &clkset_spi_mmc,
561                 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 14, .size = 2 },
562                 .reg_div = { .reg = S5P_CLK_DIV2, .shift = 0, .size = 4 },
563         }, {
564                 .clk    = {
565                         .name           = "spi_epll",
566                         .id             = 1,
567                         .ctrlbit        = S5P_CLKCON_SCLK0_SPI1,
568                         .enable         = s5p6440_sclk_ctrl,
569                 },
570                 .sources = &clkset_spi_mmc,
571                 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 16, .size = 2 },
572                 .reg_div = { .reg = S5P_CLK_DIV2, .shift = 4, .size = 4 },
573         }
574 };
575
576 /* Clock initialisation code */
577 static struct clksrc_clk *init_parents[] = {
578         &clk_mout_apll,
579         &clk_mout_epll,
580         &clk_mout_mpll,
581 };
582
583 void __init_or_cpufreq s5p6440_setup_clocks(void)
584 {
585         struct clk *xtal_clk;
586         unsigned long xtal;
587         unsigned long fclk;
588         unsigned long hclk;
589         unsigned long hclk_low;
590         unsigned long pclk;
591         unsigned long pclk_low;
592         unsigned long epll;
593         unsigned long apll;
594         unsigned long mpll;
595         unsigned int ptr;
596         u32 clkdiv0;
597         u32 clkdiv3;
598
599         /* Set S5P6440 functions for clk_fout_epll */
600         clk_fout_epll.enable = s5p6440_epll_enable;
601         clk_fout_epll.ops = &s5p6440_epll_ops;
602
603         /* Set S5P6440 functions for arm clock */
604         clk_arm.parent = &clk_mout_apll.clk;
605         clk_arm.ops = &s5p6440_clkarm_ops;
606         clk_48m.enable = s5p6440_clk48m_ctrl;
607
608         clkdiv0 = __raw_readl(S5P_CLK_DIV0);
609         clkdiv3 = __raw_readl(S5P_CLK_DIV3);
610
611         xtal_clk = clk_get(NULL, "ext_xtal");
612         BUG_ON(IS_ERR(xtal_clk));
613
614         xtal = clk_get_rate(xtal_clk);
615         clk_put(xtal_clk);
616
617         epll = s5p_get_pll90xx(xtal, __raw_readl(S5P_EPLL_CON),
618                                 __raw_readl(S5P_EPLL_CON_K));
619         mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P_MPLL_CON), pll_4502);
620         apll = s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON), pll_4502);
621
622         printk(KERN_INFO "S5P6440: PLL settings, A=%ld.%ldMHz, M=%ld.%ldMHz," \
623                         " E=%ld.%ldMHz\n",
624                         print_mhz(apll), print_mhz(mpll), print_mhz(epll));
625
626         fclk = apll / GET_DIV(clkdiv0, S5P_CLKDIV0_ARM);
627         hclk = fclk / GET_DIV(clkdiv0, S5P_CLKDIV0_HCLK);
628         pclk = hclk / GET_DIV(clkdiv0, S5P_CLKDIV0_PCLK);
629
630         if (__raw_readl(S5P_OTHERS) & S5P_OTHERS_HCLK_LOW_SEL_MPLL) {
631                 /* Asynchronous mode */
632                 hclk_low = mpll / GET_DIV(clkdiv3, S5P_CLKDIV3_HCLK_LOW);
633         } else {
634                 /* Synchronous mode */
635                 hclk_low = apll / GET_DIV(clkdiv3, S5P_CLKDIV3_HCLK_LOW);
636         }
637
638         pclk_low = hclk_low / GET_DIV(clkdiv3, S5P_CLKDIV3_PCLK_LOW);
639
640         printk(KERN_INFO "S5P6440: HCLK=%ld.%ldMHz, HCLK_LOW=%ld.%ldMHz," \
641                         " PCLK=%ld.%ldMHz, PCLK_LOW=%ld.%ldMHz\n",
642                         print_mhz(hclk), print_mhz(hclk_low),
643                         print_mhz(pclk), print_mhz(pclk_low));
644
645         clk_fout_mpll.rate = mpll;
646         clk_fout_epll.rate = epll;
647         clk_fout_apll.rate = apll;
648
649         clk_f.rate = fclk;
650         clk_h.rate = hclk;
651         clk_p.rate = pclk;
652         clk_h_low.rate = hclk_low;
653         clk_p_low.rate = pclk_low;
654
655         for (ptr = 0; ptr < ARRAY_SIZE(init_parents); ptr++)
656                 s3c_set_clksrc(init_parents[ptr], true);
657
658         for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
659                 s3c_set_clksrc(&clksrcs[ptr], true);
660 }
661
662 static struct clk *clks[] __initdata = {
663         &clk_ext,
664         &clk_mout_epll.clk,
665         &clk_mout_mpll.clk,
666         &clk_dout_mpll,
667         &clk_iis_cd_v40,
668         &clk_pcm_cd,
669         &clk_p_low,
670         &clk_h_low,
671 };
672
673 void __init s5p6440_register_clocks(void)
674 {
675         struct clk *clkp;
676         int ret;
677         int ptr;
678
679         ret = s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
680         if (ret > 0)
681                 printk(KERN_ERR "Failed to register %u clocks\n", ret);
682
683         s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
684         s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
685
686         clkp = init_clocks_disable;
687         for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
688
689                 ret = s3c24xx_register_clock(clkp);
690                 if (ret < 0) {
691                         printk(KERN_ERR "Failed to register clock %s (%d)\n",
692                                clkp->name, ret);
693                 }
694                 (clkp->enable)(clkp, 0);
695         }
696
697         s3c_pwmclk_init();
698 }