ca6e48dce77793b0a846a26ca5dd9a5429524c74
[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 enum perf_level {
138         L0 = 532*1000,
139         L1 = 266*1000,
140         L2 = 133*1000,
141 };
142
143 static const u32 clock_table[][3] = {
144         /*{ARM_CLK, DIVarm, DIVhclk}*/
145         {L0 * 1000, (0 << ARM_DIV_RATIO_SHIFT), (3 << S5P_CLKDIV0_HCLK_SHIFT)},
146         {L1 * 1000, (1 << ARM_DIV_RATIO_SHIFT), (1 << S5P_CLKDIV0_HCLK_SHIFT)},
147         {L2 * 1000, (3 << ARM_DIV_RATIO_SHIFT), (0 << S5P_CLKDIV0_HCLK_SHIFT)},
148 };
149
150 static unsigned long s5p6440_armclk_get_rate(struct clk *clk)
151 {
152         unsigned long rate = clk_get_rate(clk->parent);
153         u32 clkdiv;
154
155         /* divisor mask starts at bit0, so no need to shift */
156         clkdiv = __raw_readl(ARM_CLK_DIV) & ARM_DIV_MASK;
157
158         return rate / (clkdiv + 1);
159 }
160
161 static unsigned long s5p6440_armclk_round_rate(struct clk *clk,
162                                                 unsigned long rate)
163 {
164         u32 iter;
165
166         for (iter = 1 ; iter < ARRAY_SIZE(clock_table) ; iter++) {
167                 if (rate > clock_table[iter][0])
168                         return clock_table[iter-1][0];
169         }
170
171         return clock_table[ARRAY_SIZE(clock_table) - 1][0];
172 }
173
174 static int s5p6440_armclk_set_rate(struct clk *clk, unsigned long rate)
175 {
176         u32 round_tmp;
177         u32 iter;
178         u32 clk_div0_tmp;
179         u32 cur_rate = clk->ops->get_rate(clk);
180         unsigned long flags;
181
182         round_tmp = clk->ops->round_rate(clk, rate);
183         if (round_tmp == cur_rate)
184                 return 0;
185
186
187         for (iter = 0 ; iter < ARRAY_SIZE(clock_table) ; iter++) {
188                 if (round_tmp == clock_table[iter][0])
189                         break;
190         }
191
192         if (iter >= ARRAY_SIZE(clock_table))
193                 iter = ARRAY_SIZE(clock_table) - 1;
194
195         local_irq_save(flags);
196         if (cur_rate > round_tmp) {
197                 /* Frequency Down */
198                 clk_div0_tmp = __raw_readl(ARM_CLK_DIV) & ~(ARM_DIV_MASK);
199                 clk_div0_tmp |= clock_table[iter][1];
200                 __raw_writel(clk_div0_tmp, ARM_CLK_DIV);
201
202                 clk_div0_tmp = __raw_readl(ARM_CLK_DIV) &
203                                 ~(S5P_CLKDIV0_HCLK_MASK);
204                 clk_div0_tmp |= clock_table[iter][2];
205                 __raw_writel(clk_div0_tmp, ARM_CLK_DIV);
206
207
208         } else {
209                 /* Frequency Up */
210                 clk_div0_tmp = __raw_readl(ARM_CLK_DIV) &
211                                 ~(S5P_CLKDIV0_HCLK_MASK);
212                 clk_div0_tmp |= clock_table[iter][2];
213                 __raw_writel(clk_div0_tmp, ARM_CLK_DIV);
214
215                 clk_div0_tmp = __raw_readl(ARM_CLK_DIV) & ~(ARM_DIV_MASK);
216                 clk_div0_tmp |= clock_table[iter][1];
217                 __raw_writel(clk_div0_tmp, ARM_CLK_DIV);
218                 }
219         local_irq_restore(flags);
220
221         clk->rate = clock_table[iter][0];
222
223         return 0;
224 }
225
226 static struct clk_ops s5p6440_clkarm_ops = {
227         .get_rate       = s5p6440_armclk_get_rate,
228         .set_rate       = s5p6440_armclk_set_rate,
229         .round_rate     = s5p6440_armclk_round_rate,
230 };
231
232 static struct clksrc_clk clk_armclk = {
233         .clk    = {
234                 .name   = "armclk",
235                 .id     = 1,
236                 .parent = &clk_mout_apll.clk,
237                 .ops    = &s5p6440_clkarm_ops,
238         },
239         .reg_div        = { .reg = S5P_CLK_DIV0, .shift = 0, .size = 4 },
240 };
241
242 static struct clksrc_clk clk_dout_mpll = {
243         .clk    = {
244                 .name   = "dout_mpll",
245                 .id     = -1,
246                 .parent = &clk_mout_mpll.clk,
247         },
248         .reg_div        = { .reg = S5P_CLK_DIV0, .shift = 4, .size = 1 },
249 };
250
251 static struct clksrc_clk clk_hclk = {
252         .clk    = {
253                 .name   = "clk_hclk",
254                 .id     = -1,
255                 .parent = &clk_armclk.clk,
256         },
257         .reg_div        = { .reg = S5P_CLK_DIV0, .shift = 8, .size = 4 },
258 };
259
260 static struct clksrc_clk clk_pclk = {
261         .clk    = {
262                 .name   = "clk_pclk",
263                 .id     = -1,
264                 .parent = &clk_hclk.clk,
265         },
266         .reg_div = { .reg = S5P_CLK_DIV0, .shift = 12, .size = 4 },
267 };
268
269 static struct clk *clkset_hclklow_list[] = {
270         &clk_mout_apll.clk,
271         &clk_mout_mpll.clk,
272 };
273
274 static struct clksrc_sources clkset_hclklow = {
275         .sources        = clkset_hclklow_list,
276         .nr_sources     = ARRAY_SIZE(clkset_hclklow_list),
277 };
278
279 static struct clksrc_clk clk_hclk_low = {
280         .clk = {
281                 .name   = "hclk_low",
282                 .id     = -1,
283         },
284         .sources        = &clkset_hclklow,
285         .reg_src        = { .reg = S5P_SYS_OTHERS, .shift = 6, .size = 1 },
286         .reg_div        = { .reg = S5P_CLK_DIV3, .shift = 8, .size = 4 },
287 };
288
289 static struct clksrc_clk clk_pclk_low = {
290         .clk    = {
291                 .name   = "pclk_low",
292                 .id     = -1,
293                 .parent = &clk_hclk_low.clk,
294         },
295         .reg_div = { .reg = S5P_CLK_DIV3, .shift = 12, .size = 4 },
296 };
297
298 int s5p6440_clk48m_ctrl(struct clk *clk, int enable)
299 {
300         unsigned long flags;
301         u32 val;
302
303         /* can't rely on clock lock, this register has other usages */
304         local_irq_save(flags);
305
306         val = __raw_readl(S5P_OTHERS);
307         if (enable)
308                 val |= S5P_OTHERS_USB_SIG_MASK;
309         else
310                 val &= ~S5P_OTHERS_USB_SIG_MASK;
311
312         __raw_writel(val, S5P_OTHERS);
313
314         local_irq_restore(flags);
315
316         return 0;
317 }
318
319 static int s5p6440_pclk_ctrl(struct clk *clk, int enable)
320 {
321         return s5p_gatectrl(S5P_CLK_GATE_PCLK, clk, enable);
322 }
323
324 static int s5p6440_hclk0_ctrl(struct clk *clk, int enable)
325 {
326         return s5p_gatectrl(S5P_CLK_GATE_HCLK0, clk, enable);
327 }
328
329 static int s5p6440_hclk1_ctrl(struct clk *clk, int enable)
330 {
331         return s5p_gatectrl(S5P_CLK_GATE_HCLK1, clk, enable);
332 }
333
334 static int s5p6440_sclk_ctrl(struct clk *clk, int enable)
335 {
336         return s5p_gatectrl(S5P_CLK_GATE_SCLK0, clk, enable);
337 }
338
339 static int s5p6440_sclk1_ctrl(struct clk *clk, int enable)
340 {
341         return s5p_gatectrl(S5P_CLK_GATE_SCLK1, clk, enable);
342 }
343
344 static int s5p6440_mem_ctrl(struct clk *clk, int enable)
345 {
346         return s5p_gatectrl(S5P_CLK_GATE_MEM0, clk, enable);
347 }
348
349 /*
350  * The following clocks will be disabled during clock initialization. It is
351  * recommended to keep the following clocks disabled until the driver requests
352  * for enabling the clock.
353  */
354 static struct clk init_clocks_disable[] = {
355         {
356                 .name           = "nand",
357                 .id             = -1,
358                 .parent         = &clk_hclk.clk,
359                 .enable         = s5p6440_mem_ctrl,
360                 .ctrlbit        = S5P_CLKCON_MEM0_HCLK_NFCON,
361         }, {
362                 .name           = "adc",
363                 .id             = -1,
364                 .parent         = &clk_pclk_low.clk,
365                 .enable         = s5p6440_pclk_ctrl,
366                 .ctrlbit        = S5P_CLKCON_PCLK_TSADC,
367         }, {
368                 .name           = "i2c",
369                 .id             = -1,
370                 .parent         = &clk_pclk_low.clk,
371                 .enable         = s5p6440_pclk_ctrl,
372                 .ctrlbit        = S5P_CLKCON_PCLK_IIC0,
373         }, {
374                 .name           = "i2s_v40",
375                 .id             = 0,
376                 .parent         = &clk_pclk_low.clk,
377                 .enable         = s5p6440_pclk_ctrl,
378                 .ctrlbit        = S5P_CLKCON_PCLK_IIS2,
379         }, {
380                 .name           = "spi",
381                 .id             = 0,
382                 .parent         = &clk_pclk_low.clk,
383                 .enable         = s5p6440_pclk_ctrl,
384                 .ctrlbit        = S5P_CLKCON_PCLK_SPI0,
385         }, {
386                 .name           = "spi",
387                 .id             = 1,
388                 .parent         = &clk_pclk_low.clk,
389                 .enable         = s5p6440_pclk_ctrl,
390                 .ctrlbit        = S5P_CLKCON_PCLK_SPI1,
391         }, {
392                 .name           = "sclk_spi_48",
393                 .id             = 0,
394                 .parent         = &clk_48m,
395                 .enable         = s5p6440_sclk_ctrl,
396                 .ctrlbit        = S5P_CLKCON_SCLK0_SPI0_48,
397         }, {
398                 .name           = "sclk_spi_48",
399                 .id             = 1,
400                 .parent         = &clk_48m,
401                 .enable         = s5p6440_sclk_ctrl,
402                 .ctrlbit        = S5P_CLKCON_SCLK0_SPI1_48,
403         }, {
404                 .name           = "mmc_48m",
405                 .id             = 0,
406                 .parent         = &clk_48m,
407                 .enable         = s5p6440_sclk_ctrl,
408                 .ctrlbit        = S5P_CLKCON_SCLK0_MMC0_48,
409         }, {
410                 .name           = "mmc_48m",
411                 .id             = 1,
412                 .parent         = &clk_48m,
413                 .enable         = s5p6440_sclk_ctrl,
414                 .ctrlbit        = S5P_CLKCON_SCLK0_MMC1_48,
415         }, {
416                 .name           = "mmc_48m",
417                 .id             = 2,
418                 .parent         = &clk_48m,
419                 .enable         = s5p6440_sclk_ctrl,
420                 .ctrlbit        = S5P_CLKCON_SCLK0_MMC2_48,
421         }, {
422                 .name           = "otg",
423                 .id             = -1,
424                 .parent         = &clk_hclk_low.clk,
425                 .enable         = s5p6440_hclk0_ctrl,
426                 .ctrlbit        = S5P_CLKCON_HCLK0_USB
427         }, {
428                 .name           = "post",
429                 .id             = -1,
430                 .parent         = &clk_hclk_low.clk,
431                 .enable         = s5p6440_hclk0_ctrl,
432                 .ctrlbit        = S5P_CLKCON_HCLK0_POST0
433         }, {
434                 .name           = "lcd",
435                 .id             = -1,
436                 .parent         = &clk_hclk_low.clk,
437                 .enable         = s5p6440_hclk1_ctrl,
438                 .ctrlbit        = S5P_CLKCON_HCLK1_DISPCON,
439         }, {
440                 .name           = "hsmmc",
441                 .id             = 0,
442                 .parent         = &clk_hclk_low.clk,
443                 .enable         = s5p6440_hclk0_ctrl,
444                 .ctrlbit        = S5P_CLKCON_HCLK0_HSMMC0,
445         }, {
446                 .name           = "hsmmc",
447                 .id             = 1,
448                 .parent         = &clk_hclk_low.clk,
449                 .enable         = s5p6440_hclk0_ctrl,
450                 .ctrlbit        = S5P_CLKCON_HCLK0_HSMMC1,
451         }, {
452                 .name           = "hsmmc",
453                 .id             = 2,
454                 .parent         = &clk_hclk_low.clk,
455                 .enable         = s5p6440_hclk0_ctrl,
456                 .ctrlbit        = S5P_CLKCON_HCLK0_HSMMC2,
457         }, {
458                 .name           = "rtc",
459                 .id             = -1,
460                 .parent         = &clk_pclk_low.clk,
461                 .enable         = s5p6440_pclk_ctrl,
462                 .ctrlbit        = S5P_CLKCON_PCLK_RTC,
463         }, {
464                 .name           = "watchdog",
465                 .id             = -1,
466                 .parent         = &clk_pclk_low.clk,
467                 .enable         = s5p6440_pclk_ctrl,
468                 .ctrlbit        = S5P_CLKCON_PCLK_WDT,
469         }, {
470                 .name           = "timers",
471                 .id             = -1,
472                 .parent         = &clk_pclk_low.clk,
473                 .enable         = s5p6440_pclk_ctrl,
474                 .ctrlbit        = S5P_CLKCON_PCLK_PWM,
475         }, {
476                 .name           = "hclk_fimgvg",
477                 .id             = -1,
478                 .parent         = &clk_hclk.clk,
479                 .enable         = s5p6440_hclk1_ctrl,
480                 .ctrlbit        = (1 << 2),
481         }, {
482                 .name           = "tsi",
483                 .id             = -1,
484                 .parent         = &clk_hclk_low.clk,
485                 .enable         = s5p6440_hclk1_ctrl,
486                 .ctrlbit        = (1 << 0),
487         }, {
488                 .name           = "pclk_fimgvg",
489                 .id             = -1,
490                 .parent         = &clk_pclk.clk,
491                 .enable         = s5p6440_pclk_ctrl,
492                 .ctrlbit        = (1 << 31),
493         }, {
494                 .name           = "dmc0",
495                 .id             = -1,
496                 .parent         = &clk_pclk.clk,
497                 .enable         = s5p6440_pclk_ctrl,
498                 .ctrlbit        = (1 << 30),
499         }, {
500                 .name           = "etm",
501                 .id             = -1,
502                 .parent         = &clk_pclk.clk,
503                 .enable         = s5p6440_pclk_ctrl,
504                 .ctrlbit        = (1 << 29),
505         }, {
506                 .name           = "dsim",
507                 .id             = -1,
508                 .parent         = &clk_pclk_low.clk,
509                 .enable         = s5p6440_pclk_ctrl,
510                 .ctrlbit        = (1 << 28),
511         }, {
512                 .name           = "gps",
513                 .id             = -1,
514                 .parent         = &clk_pclk_low.clk,
515                 .enable         = s5p6440_pclk_ctrl,
516                 .ctrlbit        = (1 << 25),
517         }, {
518                 .name           = "pcm",
519                 .id             = -1,
520                 .parent         = &clk_pclk_low.clk,
521                 .enable         = s5p6440_pclk_ctrl,
522                 .ctrlbit        = (1 << 8),
523         }, {
524                 .name           = "irom",
525                 .id             = -1,
526                 .parent         = &clk_hclk.clk,
527                 .enable         = s5p6440_hclk0_ctrl,
528                 .ctrlbit        = (1 << 25),
529         }, {
530                 .name           = "dma",
531                 .id             = -1,
532                 .parent         = &clk_hclk_low.clk,
533                 .enable         = s5p6440_hclk0_ctrl,
534                 .ctrlbit        = (1 << 12),
535         }, {
536                 .name           = "2d",
537                 .id             = -1,
538                 .parent         = &clk_hclk.clk,
539                 .enable         = s5p6440_hclk0_ctrl,
540                 .ctrlbit        = (1 << 8),
541         },
542 };
543
544 /*
545  * The following clocks will be enabled during clock initialization.
546  */
547 static struct clk init_clocks[] = {
548         {
549                 .name           = "gpio",
550                 .id             = -1,
551                 .parent         = &clk_pclk_low.clk,
552                 .enable         = s5p6440_pclk_ctrl,
553                 .ctrlbit        = S5P_CLKCON_PCLK_GPIO,
554         }, {
555                 .name           = "uart",
556                 .id             = 0,
557                 .parent         = &clk_pclk_low.clk,
558                 .enable         = s5p6440_pclk_ctrl,
559                 .ctrlbit        = S5P_CLKCON_PCLK_UART0,
560         }, {
561                 .name           = "uart",
562                 .id             = 1,
563                 .parent         = &clk_pclk_low.clk,
564                 .enable         = s5p6440_pclk_ctrl,
565                 .ctrlbit        = S5P_CLKCON_PCLK_UART1,
566         }, {
567                 .name           = "uart",
568                 .id             = 2,
569                 .parent         = &clk_pclk_low.clk,
570                 .enable         = s5p6440_pclk_ctrl,
571                 .ctrlbit        = S5P_CLKCON_PCLK_UART2,
572         }, {
573                 .name           = "uart",
574                 .id             = 3,
575                 .parent         = &clk_pclk_low.clk,
576                 .enable         = s5p6440_pclk_ctrl,
577                 .ctrlbit        = S5P_CLKCON_PCLK_UART3,
578         }, {
579                 .name           = "mem",
580                 .id             = -1,
581                 .parent         = &clk_hclk.clk,
582                 .enable         = s5p6440_hclk0_ctrl,
583                 .ctrlbit        = (1 << 21),
584         }, {
585                 .name           = "intc",
586                 .id             = -1,
587                 .parent         = &clk_hclk.clk,
588                 .enable         = s5p6440_hclk0_ctrl,
589                 .ctrlbit        = (1 << 1),
590         },
591 };
592
593 static struct clk clk_iis_cd_v40 = {
594         .name           = "iis_cdclk_v40",
595         .id             = -1,
596 };
597
598 static struct clk clk_pcm_cd = {
599         .name           = "pcm_cdclk",
600         .id             = -1,
601 };
602
603 static struct clk *clkset_group1_list[] = {
604         &clk_mout_epll.clk,
605         &clk_dout_mpll.clk,
606         &clk_fin_epll,
607 };
608
609 static struct clksrc_sources clkset_group1 = {
610         .sources        = clkset_group1_list,
611         .nr_sources     = ARRAY_SIZE(clkset_group1_list),
612 };
613
614 static struct clk *clkset_uart_list[] = {
615         &clk_mout_epll.clk,
616         &clk_dout_mpll.clk,
617 };
618
619 static struct clksrc_sources clkset_uart = {
620         .sources        = clkset_uart_list,
621         .nr_sources     = ARRAY_SIZE(clkset_uart_list),
622 };
623
624 static struct clk *clkset_audio_list[] = {
625         &clk_mout_epll.clk,
626         &clk_dout_mpll.clk,
627         &clk_fin_epll,
628         &clk_iis_cd_v40,
629         &clk_pcm_cd,
630 };
631
632 static struct clksrc_sources clkset_audio = {
633         .sources        = clkset_audio_list,
634         .nr_sources     = ARRAY_SIZE(clkset_audio_list),
635 };
636
637 static struct clksrc_clk clksrcs[] = {
638         {
639                 .clk    = {
640                         .name           = "mmc_bus",
641                         .id             = 0,
642                         .ctrlbit        = S5P_CLKCON_SCLK0_MMC0,
643                         .enable         = s5p6440_sclk_ctrl,
644                 },
645                 .sources = &clkset_group1,
646                 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 18, .size = 2 },
647                 .reg_div = { .reg = S5P_CLK_DIV1, .shift = 0, .size = 4 },
648         }, {
649                 .clk    = {
650                         .name           = "mmc_bus",
651                         .id             = 1,
652                         .ctrlbit        = S5P_CLKCON_SCLK0_MMC1,
653                         .enable         = s5p6440_sclk_ctrl,
654                 },
655                 .sources = &clkset_group1,
656                 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 20, .size = 2 },
657                 .reg_div = { .reg = S5P_CLK_DIV1, .shift = 4, .size = 4 },
658         }, {
659                 .clk    = {
660                         .name           = "mmc_bus",
661                         .id             = 2,
662                         .ctrlbit        = S5P_CLKCON_SCLK0_MMC2,
663                         .enable         = s5p6440_sclk_ctrl,
664                 },
665                 .sources = &clkset_group1,
666                 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 22, .size = 2 },
667                 .reg_div = { .reg = S5P_CLK_DIV1, .shift = 8, .size = 4 },
668         }, {
669                 .clk    = {
670                         .name           = "uclk1",
671                         .id             = -1,
672                         .ctrlbit        = S5P_CLKCON_SCLK0_UART,
673                         .enable         = s5p6440_sclk_ctrl,
674                 },
675                 .sources = &clkset_uart,
676                 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 13, .size = 1 },
677                 .reg_div = { .reg = S5P_CLK_DIV2, .shift = 16, .size = 4 },
678         }, {
679                 .clk    = {
680                         .name           = "spi_epll",
681                         .id             = 0,
682                         .ctrlbit        = S5P_CLKCON_SCLK0_SPI0,
683                         .enable         = s5p6440_sclk_ctrl,
684                 },
685                 .sources = &clkset_group1,
686                 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 14, .size = 2 },
687                 .reg_div = { .reg = S5P_CLK_DIV2, .shift = 0, .size = 4 },
688         }, {
689                 .clk    = {
690                         .name           = "spi_epll",
691                         .id             = 1,
692                         .ctrlbit        = S5P_CLKCON_SCLK0_SPI1,
693                         .enable         = s5p6440_sclk_ctrl,
694                 },
695                 .sources = &clkset_group1,
696                 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 16, .size = 2 },
697                 .reg_div = { .reg = S5P_CLK_DIV2, .shift = 4, .size = 4 },
698         }, {
699                 .clk    = {
700                         .name           = "sclk_post",
701                         .id             = -1,
702                         .ctrlbit        = (1 << 10),
703                         .enable         = s5p6440_sclk_ctrl,
704                 },
705                 .sources = &clkset_group1,
706                 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 26, .size = 2 },
707                 .reg_div = { .reg = S5P_CLK_DIV1, .shift = 12, .size = 4 },
708         }, {
709                 .clk    = {
710                         .name           = "sclk_dispcon",
711                         .id             = -1,
712                         .ctrlbit        = (1 << 1),
713                         .enable         = s5p6440_sclk1_ctrl,
714                 },
715                 .sources = &clkset_group1,
716                 .reg_src = { .reg = S5P_CLK_SRC1, .shift = 4, .size = 2 },
717                 .reg_div = { .reg = S5P_CLK_DIV3, .shift = 0, .size = 4 },
718         }, {
719                 .clk    = {
720                         .name           = "sclk_fimgvg",
721                         .id             = -1,
722                         .ctrlbit        = (1 << 2),
723                         .enable         = s5p6440_sclk1_ctrl,
724                 },
725                 .sources = &clkset_group1,
726                 .reg_src = { .reg = S5P_CLK_SRC1, .shift = 8, .size = 2 },
727                 .reg_div = { .reg = S5P_CLK_DIV3, .shift = 4, .size = 4 },
728         }, {
729                 .clk    = {
730                         .name           = "sclk_audio2",
731                         .id             = -1,
732                         .ctrlbit        = (1 << 11),
733                         .enable         = s5p6440_sclk_ctrl,
734                 },
735                 .sources = &clkset_audio,
736                 .reg_src = { .reg = S5P_CLK_SRC1, .shift = 0, .size = 3 },
737                 .reg_div = { .reg = S5P_CLK_DIV2, .shift = 24, .size = 4 },
738         },
739 };
740
741 /* Clock initialisation code */
742 static struct clksrc_clk *sysclks[] = {
743         &clk_mout_apll,
744         &clk_mout_epll,
745         &clk_mout_mpll,
746         &clk_dout_mpll,
747         &clk_armclk,
748         &clk_hclk,
749         &clk_pclk,
750         &clk_hclk_low,
751         &clk_pclk_low,
752 };
753
754 void __init_or_cpufreq s5p6440_setup_clocks(void)
755 {
756         struct clk *xtal_clk;
757         unsigned long xtal;
758         unsigned long fclk;
759         unsigned long hclk;
760         unsigned long hclk_low;
761         unsigned long pclk;
762         unsigned long pclk_low;
763         unsigned long epll;
764         unsigned long apll;
765         unsigned long mpll;
766         unsigned int ptr;
767
768         /* Set S5P6440 functions for clk_fout_epll */
769         clk_fout_epll.enable = s5p6440_epll_enable;
770         clk_fout_epll.ops = &s5p6440_epll_ops;
771
772         clk_48m.enable = s5p6440_clk48m_ctrl;
773
774         xtal_clk = clk_get(NULL, "ext_xtal");
775         BUG_ON(IS_ERR(xtal_clk));
776
777         xtal = clk_get_rate(xtal_clk);
778         clk_put(xtal_clk);
779
780         epll = s5p_get_pll90xx(xtal, __raw_readl(S5P_EPLL_CON),
781                                 __raw_readl(S5P_EPLL_CON_K));
782         mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P_MPLL_CON), pll_4502);
783         apll = s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON), pll_4502);
784
785         clk_fout_mpll.rate = mpll;
786         clk_fout_epll.rate = epll;
787         clk_fout_apll.rate = apll;
788
789         printk(KERN_INFO "S5P6440: PLL settings, A=%ld.%ldMHz, M=%ld.%ldMHz," \
790                         " E=%ld.%ldMHz\n",
791                         print_mhz(apll), print_mhz(mpll), print_mhz(epll));
792
793         fclk = clk_get_rate(&clk_armclk.clk);
794         hclk = clk_get_rate(&clk_hclk.clk);
795         pclk = clk_get_rate(&clk_pclk.clk);
796         hclk_low = clk_get_rate(&clk_hclk_low.clk);
797         pclk_low = clk_get_rate(&clk_pclk_low.clk);
798
799         printk(KERN_INFO "S5P6440: HCLK=%ld.%ldMHz, HCLK_LOW=%ld.%ldMHz," \
800                         " PCLK=%ld.%ldMHz, PCLK_LOW=%ld.%ldMHz\n",
801                         print_mhz(hclk), print_mhz(hclk_low),
802                         print_mhz(pclk), print_mhz(pclk_low));
803
804         clk_f.rate = fclk;
805         clk_h.rate = hclk;
806         clk_p.rate = pclk;
807
808         for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
809                 s3c_set_clksrc(&clksrcs[ptr], true);
810 }
811
812 static struct clk *clks[] __initdata = {
813         &clk_ext,
814         &clk_iis_cd_v40,
815         &clk_pcm_cd,
816 };
817
818 void __init s5p6440_register_clocks(void)
819 {
820         struct clk *clkp;
821         int ret;
822         int ptr;
823
824         ret = s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
825         if (ret > 0)
826                 printk(KERN_ERR "Failed to register %u clocks\n", ret);
827
828         for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++)
829                 s3c_register_clksrc(sysclks[ptr], 1);
830
831         s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
832         s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
833
834         clkp = init_clocks_disable;
835         for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
836
837                 ret = s3c24xx_register_clock(clkp);
838                 if (ret < 0) {
839                         printk(KERN_ERR "Failed to register clock %s (%d)\n",
840                                clkp->name, ret);
841                 }
842                 (clkp->enable)(clkp, 0);
843         }
844
845         s3c_pwmclk_init();
846 }