ARM: S5P6440: Change dout_mpll clock type to clksrc_clk clock type.
[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 struct clksrc_clk clk_dout_mpll = {
251         .clk    = {
252                 .name   = "dout_mpll",
253                 .id     = -1,
254                 .parent = &clk_mout_mpll.clk,
255         },
256         .reg_div        = { .reg = S5P_CLK_DIV0, .shift = 4, .size = 1 },
257 };
258
259 int s5p6440_clk48m_ctrl(struct clk *clk, int enable)
260 {
261         unsigned long flags;
262         u32 val;
263
264         /* can't rely on clock lock, this register has other usages */
265         local_irq_save(flags);
266
267         val = __raw_readl(S5P_OTHERS);
268         if (enable)
269                 val |= S5P_OTHERS_USB_SIG_MASK;
270         else
271                 val &= ~S5P_OTHERS_USB_SIG_MASK;
272
273         __raw_writel(val, S5P_OTHERS);
274
275         local_irq_restore(flags);
276
277         return 0;
278 }
279
280 static int s5p6440_pclk_ctrl(struct clk *clk, int enable)
281 {
282         return s5p_gatectrl(S5P_CLK_GATE_PCLK, clk, enable);
283 }
284
285 static int s5p6440_hclk0_ctrl(struct clk *clk, int enable)
286 {
287         return s5p_gatectrl(S5P_CLK_GATE_HCLK0, clk, enable);
288 }
289
290 static int s5p6440_hclk1_ctrl(struct clk *clk, int enable)
291 {
292         return s5p_gatectrl(S5P_CLK_GATE_HCLK1, clk, enable);
293 }
294
295 static int s5p6440_sclk_ctrl(struct clk *clk, int enable)
296 {
297         return s5p_gatectrl(S5P_CLK_GATE_SCLK0, clk, enable);
298 }
299
300 static int s5p6440_mem_ctrl(struct clk *clk, int enable)
301 {
302         return s5p_gatectrl(S5P_CLK_GATE_MEM0, clk, enable);
303 }
304
305 /*
306  * The following clocks will be disabled during clock initialization. It is
307  * recommended to keep the following clocks disabled until the driver requests
308  * for enabling the clock.
309  */
310 static struct clk init_clocks_disable[] = {
311         {
312                 .name           = "nand",
313                 .id             = -1,
314                 .parent         = &clk_h,
315                 .enable         = s5p6440_mem_ctrl,
316                 .ctrlbit        = S5P_CLKCON_MEM0_HCLK_NFCON,
317         }, {
318                 .name           = "adc",
319                 .id             = -1,
320                 .parent         = &clk_p_low,
321                 .enable         = s5p6440_pclk_ctrl,
322                 .ctrlbit        = S5P_CLKCON_PCLK_TSADC,
323         }, {
324                 .name           = "i2c",
325                 .id             = -1,
326                 .parent         = &clk_p_low,
327                 .enable         = s5p6440_pclk_ctrl,
328                 .ctrlbit        = S5P_CLKCON_PCLK_IIC0,
329         }, {
330                 .name           = "i2s_v40",
331                 .id             = 0,
332                 .parent         = &clk_p_low,
333                 .enable         = s5p6440_pclk_ctrl,
334                 .ctrlbit        = S5P_CLKCON_PCLK_IIS2,
335         }, {
336                 .name           = "spi",
337                 .id             = 0,
338                 .parent         = &clk_p_low,
339                 .enable         = s5p6440_pclk_ctrl,
340                 .ctrlbit        = S5P_CLKCON_PCLK_SPI0,
341         }, {
342                 .name           = "spi",
343                 .id             = 1,
344                 .parent         = &clk_p_low,
345                 .enable         = s5p6440_pclk_ctrl,
346                 .ctrlbit        = S5P_CLKCON_PCLK_SPI1,
347         }, {
348                 .name           = "sclk_spi_48",
349                 .id             = 0,
350                 .parent         = &clk_48m,
351                 .enable         = s5p6440_sclk_ctrl,
352                 .ctrlbit        = S5P_CLKCON_SCLK0_SPI0_48,
353         }, {
354                 .name           = "sclk_spi_48",
355                 .id             = 1,
356                 .parent         = &clk_48m,
357                 .enable         = s5p6440_sclk_ctrl,
358                 .ctrlbit        = S5P_CLKCON_SCLK0_SPI1_48,
359         }, {
360                 .name           = "mmc_48m",
361                 .id             = 0,
362                 .parent         = &clk_48m,
363                 .enable         = s5p6440_sclk_ctrl,
364                 .ctrlbit        = S5P_CLKCON_SCLK0_MMC0_48,
365         }, {
366                 .name           = "mmc_48m",
367                 .id             = 1,
368                 .parent         = &clk_48m,
369                 .enable         = s5p6440_sclk_ctrl,
370                 .ctrlbit        = S5P_CLKCON_SCLK0_MMC1_48,
371         }, {
372                 .name           = "mmc_48m",
373                 .id             = 2,
374                 .parent         = &clk_48m,
375                 .enable         = s5p6440_sclk_ctrl,
376                 .ctrlbit        = S5P_CLKCON_SCLK0_MMC2_48,
377         }, {
378                 .name           = "otg",
379                 .id             = -1,
380                 .parent         = &clk_h_low,
381                 .enable         = s5p6440_hclk0_ctrl,
382                 .ctrlbit        = S5P_CLKCON_HCLK0_USB
383         }, {
384                 .name           = "post",
385                 .id             = -1,
386                 .parent         = &clk_h_low,
387                 .enable         = s5p6440_hclk0_ctrl,
388                 .ctrlbit        = S5P_CLKCON_HCLK0_POST0
389         }, {
390                 .name           = "lcd",
391                 .id             = -1,
392                 .parent         = &clk_h_low,
393                 .enable         = s5p6440_hclk1_ctrl,
394                 .ctrlbit        = S5P_CLKCON_HCLK1_DISPCON,
395         }, {
396                 .name           = "hsmmc",
397                 .id             = 0,
398                 .parent         = &clk_h_low,
399                 .enable         = s5p6440_hclk0_ctrl,
400                 .ctrlbit        = S5P_CLKCON_HCLK0_HSMMC0,
401         }, {
402                 .name           = "hsmmc",
403                 .id             = 1,
404                 .parent         = &clk_h_low,
405                 .enable         = s5p6440_hclk0_ctrl,
406                 .ctrlbit        = S5P_CLKCON_HCLK0_HSMMC1,
407         }, {
408                 .name           = "hsmmc",
409                 .id             = 2,
410                 .parent         = &clk_h_low,
411                 .enable         = s5p6440_hclk0_ctrl,
412                 .ctrlbit        = S5P_CLKCON_HCLK0_HSMMC2,
413         }, {
414                 .name           = "rtc",
415                 .id             = -1,
416                 .parent         = &clk_p_low,
417                 .enable         = s5p6440_pclk_ctrl,
418                 .ctrlbit        = S5P_CLKCON_PCLK_RTC,
419         }, {
420                 .name           = "watchdog",
421                 .id             = -1,
422                 .parent         = &clk_p_low,
423                 .enable         = s5p6440_pclk_ctrl,
424                 .ctrlbit        = S5P_CLKCON_PCLK_WDT,
425         }, {
426                 .name           = "timers",
427                 .id             = -1,
428                 .parent         = &clk_p_low,
429                 .enable         = s5p6440_pclk_ctrl,
430                 .ctrlbit        = S5P_CLKCON_PCLK_PWM,
431         }
432 };
433
434 /*
435  * The following clocks will be enabled during clock initialization.
436  */
437 static struct clk init_clocks[] = {
438         {
439                 .name           = "gpio",
440                 .id             = -1,
441                 .parent         = &clk_p_low,
442                 .enable         = s5p6440_pclk_ctrl,
443                 .ctrlbit        = S5P_CLKCON_PCLK_GPIO,
444         }, {
445                 .name           = "uart",
446                 .id             = 0,
447                 .parent         = &clk_p_low,
448                 .enable         = s5p6440_pclk_ctrl,
449                 .ctrlbit        = S5P_CLKCON_PCLK_UART0,
450         }, {
451                 .name           = "uart",
452                 .id             = 1,
453                 .parent         = &clk_p_low,
454                 .enable         = s5p6440_pclk_ctrl,
455                 .ctrlbit        = S5P_CLKCON_PCLK_UART1,
456         }, {
457                 .name           = "uart",
458                 .id             = 2,
459                 .parent         = &clk_p_low,
460                 .enable         = s5p6440_pclk_ctrl,
461                 .ctrlbit        = S5P_CLKCON_PCLK_UART2,
462         }, {
463                 .name           = "uart",
464                 .id             = 3,
465                 .parent         = &clk_p_low,
466                 .enable         = s5p6440_pclk_ctrl,
467                 .ctrlbit        = S5P_CLKCON_PCLK_UART3,
468         }
469 };
470
471 static struct clk clk_iis_cd_v40 = {
472         .name           = "iis_cdclk_v40",
473         .id             = -1,
474 };
475
476 static struct clk clk_pcm_cd = {
477         .name           = "pcm_cdclk",
478         .id             = -1,
479 };
480
481 static struct clk *clkset_spi_mmc_list[] = {
482         &clk_mout_epll.clk,
483         &clk_dout_mpll.clk,
484         &clk_fin_epll,
485 };
486
487 static struct clksrc_sources clkset_spi_mmc = {
488         .sources        = clkset_spi_mmc_list,
489         .nr_sources     = ARRAY_SIZE(clkset_spi_mmc_list),
490 };
491
492 static struct clk *clkset_uart_list[] = {
493         &clk_mout_epll.clk,
494         &clk_dout_mpll.clk,
495 };
496
497 static struct clksrc_sources clkset_uart = {
498         .sources        = clkset_uart_list,
499         .nr_sources     = ARRAY_SIZE(clkset_uart_list),
500 };
501
502 static struct clksrc_clk clksrcs[] = {
503         {
504                 .clk    = {
505                         .name           = "mmc_bus",
506                         .id             = 0,
507                         .ctrlbit        = S5P_CLKCON_SCLK0_MMC0,
508                         .enable         = s5p6440_sclk_ctrl,
509                 },
510                 .sources = &clkset_spi_mmc,
511                 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 18, .size = 2 },
512                 .reg_div = { .reg = S5P_CLK_DIV1, .shift = 0, .size = 4 },
513         }, {
514                 .clk    = {
515                         .name           = "mmc_bus",
516                         .id             = 1,
517                         .ctrlbit        = S5P_CLKCON_SCLK0_MMC1,
518                         .enable         = s5p6440_sclk_ctrl,
519                 },
520                 .sources = &clkset_spi_mmc,
521                 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 20, .size = 2 },
522                 .reg_div = { .reg = S5P_CLK_DIV1, .shift = 4, .size = 4 },
523         }, {
524                 .clk    = {
525                         .name           = "mmc_bus",
526                         .id             = 2,
527                         .ctrlbit        = S5P_CLKCON_SCLK0_MMC2,
528                         .enable         = s5p6440_sclk_ctrl,
529                 },
530                 .sources = &clkset_spi_mmc,
531                 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 22, .size = 2 },
532                 .reg_div = { .reg = S5P_CLK_DIV1, .shift = 8, .size = 4 },
533         }, {
534                 .clk    = {
535                         .name           = "uclk1",
536                         .id             = -1,
537                         .ctrlbit        = S5P_CLKCON_SCLK0_UART,
538                         .enable         = s5p6440_sclk_ctrl,
539                 },
540                 .sources = &clkset_uart,
541                 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 13, .size = 1 },
542                 .reg_div = { .reg = S5P_CLK_DIV2, .shift = 16, .size = 4 },
543         }, {
544                 .clk    = {
545                         .name           = "spi_epll",
546                         .id             = 0,
547                         .ctrlbit        = S5P_CLKCON_SCLK0_SPI0,
548                         .enable         = s5p6440_sclk_ctrl,
549                 },
550                 .sources = &clkset_spi_mmc,
551                 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 14, .size = 2 },
552                 .reg_div = { .reg = S5P_CLK_DIV2, .shift = 0, .size = 4 },
553         }, {
554                 .clk    = {
555                         .name           = "spi_epll",
556                         .id             = 1,
557                         .ctrlbit        = S5P_CLKCON_SCLK0_SPI1,
558                         .enable         = s5p6440_sclk_ctrl,
559                 },
560                 .sources = &clkset_spi_mmc,
561                 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 16, .size = 2 },
562                 .reg_div = { .reg = S5P_CLK_DIV2, .shift = 4, .size = 4 },
563         }
564 };
565
566 /* Clock initialisation code */
567 static struct clksrc_clk *sysclks[] = {
568         &clk_mout_apll,
569         &clk_mout_epll,
570         &clk_mout_mpll,
571         &clk_dout_mpll,
572 };
573
574 void __init_or_cpufreq s5p6440_setup_clocks(void)
575 {
576         struct clk *xtal_clk;
577         unsigned long xtal;
578         unsigned long fclk;
579         unsigned long hclk;
580         unsigned long hclk_low;
581         unsigned long pclk;
582         unsigned long pclk_low;
583         unsigned long epll;
584         unsigned long apll;
585         unsigned long mpll;
586         unsigned int ptr;
587         u32 clkdiv0;
588         u32 clkdiv3;
589
590         /* Set S5P6440 functions for clk_fout_epll */
591         clk_fout_epll.enable = s5p6440_epll_enable;
592         clk_fout_epll.ops = &s5p6440_epll_ops;
593
594         /* Set S5P6440 functions for arm clock */
595         clk_arm.parent = &clk_mout_apll.clk;
596         clk_arm.ops = &s5p6440_clkarm_ops;
597         clk_48m.enable = s5p6440_clk48m_ctrl;
598
599         clkdiv0 = __raw_readl(S5P_CLK_DIV0);
600         clkdiv3 = __raw_readl(S5P_CLK_DIV3);
601
602         xtal_clk = clk_get(NULL, "ext_xtal");
603         BUG_ON(IS_ERR(xtal_clk));
604
605         xtal = clk_get_rate(xtal_clk);
606         clk_put(xtal_clk);
607
608         epll = s5p_get_pll90xx(xtal, __raw_readl(S5P_EPLL_CON),
609                                 __raw_readl(S5P_EPLL_CON_K));
610         mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P_MPLL_CON), pll_4502);
611         apll = s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON), pll_4502);
612
613         printk(KERN_INFO "S5P6440: PLL settings, A=%ld.%ldMHz, M=%ld.%ldMHz," \
614                         " E=%ld.%ldMHz\n",
615                         print_mhz(apll), print_mhz(mpll), print_mhz(epll));
616
617         fclk = apll / GET_DIV(clkdiv0, S5P_CLKDIV0_ARM);
618         hclk = fclk / GET_DIV(clkdiv0, S5P_CLKDIV0_HCLK);
619         pclk = hclk / GET_DIV(clkdiv0, S5P_CLKDIV0_PCLK);
620
621         if (__raw_readl(S5P_OTHERS) & S5P_OTHERS_HCLK_LOW_SEL_MPLL) {
622                 /* Asynchronous mode */
623                 hclk_low = mpll / GET_DIV(clkdiv3, S5P_CLKDIV3_HCLK_LOW);
624         } else {
625                 /* Synchronous mode */
626                 hclk_low = apll / GET_DIV(clkdiv3, S5P_CLKDIV3_HCLK_LOW);
627         }
628
629         pclk_low = hclk_low / GET_DIV(clkdiv3, S5P_CLKDIV3_PCLK_LOW);
630
631         printk(KERN_INFO "S5P6440: HCLK=%ld.%ldMHz, HCLK_LOW=%ld.%ldMHz," \
632                         " PCLK=%ld.%ldMHz, PCLK_LOW=%ld.%ldMHz\n",
633                         print_mhz(hclk), print_mhz(hclk_low),
634                         print_mhz(pclk), print_mhz(pclk_low));
635
636         clk_fout_mpll.rate = mpll;
637         clk_fout_epll.rate = epll;
638         clk_fout_apll.rate = apll;
639
640         clk_f.rate = fclk;
641         clk_h.rate = hclk;
642         clk_p.rate = pclk;
643         clk_h_low.rate = hclk_low;
644         clk_p_low.rate = pclk_low;
645
646         for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
647                 s3c_set_clksrc(&clksrcs[ptr], true);
648 }
649
650 static struct clk *clks[] __initdata = {
651         &clk_ext,
652         &clk_iis_cd_v40,
653         &clk_pcm_cd,
654         &clk_p_low,
655         &clk_h_low,
656 };
657
658 void __init s5p6440_register_clocks(void)
659 {
660         struct clk *clkp;
661         int ret;
662         int ptr;
663
664         ret = s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
665         if (ret > 0)
666                 printk(KERN_ERR "Failed to register %u clocks\n", ret);
667
668         for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++)
669                 s3c_register_clksrc(sysclks[ptr], 1);
670
671         s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
672         s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
673
674         clkp = init_clocks_disable;
675         for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
676
677                 ret = s3c24xx_register_clock(clkp);
678                 if (ret < 0) {
679                         printk(KERN_ERR "Failed to register clock %s (%d)\n",
680                                clkp->name, ret);
681                 }
682                 (clkp->enable)(clkp, 0);
683         }
684
685         s3c_pwmclk_init();
686 }