aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-s5p6440
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-s5p6440')
-rw-r--r--arch/arm/mach-s5p6440/Kconfig2
-rw-r--r--arch/arm/mach-s5p6440/Makefile2
-rw-r--r--arch/arm/mach-s5p6440/clock.c698
-rw-r--r--arch/arm/mach-s5p6440/gpio.c (renamed from arch/arm/mach-s5p6440/s5p6440-gpio.c)2
-rw-r--r--arch/arm/mach-s5p6440/init.c52
5 files changed, 752 insertions, 4 deletions
diff --git a/arch/arm/mach-s5p6440/Kconfig b/arch/arm/mach-s5p6440/Kconfig
index 3aa246244dcf..4c29ff8b07de 100644
--- a/arch/arm/mach-s5p6440/Kconfig
+++ b/arch/arm/mach-s5p6440/Kconfig
@@ -9,8 +9,6 @@ if ARCH_S5P6440
9 9
10config CPU_S5P6440 10config CPU_S5P6440
11 bool 11 bool
12 select CPU_S5P6440_INIT
13 select CPU_S5P6440_CLOCK
14 help 12 help
15 Enable S5P6440 CPU support 13 Enable S5P6440 CPU support
16 14
diff --git a/arch/arm/mach-s5p6440/Makefile b/arch/arm/mach-s5p6440/Makefile
index a79b13011edc..1ad894b1d3ab 100644
--- a/arch/arm/mach-s5p6440/Makefile
+++ b/arch/arm/mach-s5p6440/Makefile
@@ -12,7 +12,7 @@ obj- :=
12 12
13# Core support for S5P6440 system 13# Core support for S5P6440 system
14 14
15obj-$(CONFIG_CPU_S5P6440) += cpu.o s5p6440-gpio.o 15obj-$(CONFIG_CPU_S5P6440) += cpu.o init.o clock.o gpio.o
16 16
17# machine support 17# machine support
18 18
diff --git a/arch/arm/mach-s5p6440/clock.c b/arch/arm/mach-s5p6440/clock.c
new file mode 100644
index 000000000000..b2672e16e7aa
--- /dev/null
+++ b/arch/arm/mach-s5p6440/clock.c
@@ -0,0 +1,698 @@
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 */
36static 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
45static 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
58static unsigned long s5p6440_epll_get_rate(struct clk *clk)
59{
60 return clk->rate;
61}
62
63static 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
77static 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
114static struct clk_ops s5p6440_epll_ops = {
115 .get_rate = s5p6440_epll_get_rate,
116 .set_rate = s5p6440_epll_set_rate,
117};
118
119static 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
128static 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
137static 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
146static 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
155enum perf_level {
156 L0 = 532*1000,
157 L1 = 266*1000,
158 L2 = 133*1000,
159};
160
161static 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
168static 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
179static 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
192static 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
244static 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
250static 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
260static 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
269int 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
290static int s5p6440_pclk_ctrl(struct clk *clk, int enable)
291{
292 return s5p_gatectrl(S5P_CLK_GATE_PCLK, clk, enable);
293}
294
295static int s5p6440_hclk0_ctrl(struct clk *clk, int enable)
296{
297 return s5p_gatectrl(S5P_CLK_GATE_HCLK0, clk, enable);
298}
299
300static int s5p6440_hclk1_ctrl(struct clk *clk, int enable)
301{
302 return s5p_gatectrl(S5P_CLK_GATE_HCLK1, clk, enable);
303}
304
305static int s5p6440_sclk_ctrl(struct clk *clk, int enable)
306{
307 return s5p_gatectrl(S5P_CLK_GATE_SCLK0, clk, enable);
308}
309
310static 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 */
320static 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 */
447static 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
481static struct clk clk_iis_cd_v40 = {
482 .name = "iis_cdclk_v40",
483 .id = -1,
484};
485
486static struct clk clk_pcm_cd = {
487 .name = "pcm_cdclk",
488 .id = -1,
489};
490
491static struct clk *clkset_spi_mmc_list[] = {
492 &clk_mout_epll.clk,
493 &clk_dout_mpll,
494 &clk_fin_epll,
495};
496
497static struct clksrc_sources clkset_spi_mmc = {
498 .sources = clkset_spi_mmc_list,
499 .nr_sources = ARRAY_SIZE(clkset_spi_mmc_list),
500};
501
502static struct clk *clkset_uart_list[] = {
503 &clk_mout_epll.clk,
504 &clk_dout_mpll
505};
506
507static struct clksrc_sources clkset_uart = {
508 .sources = clkset_uart_list,
509 .nr_sources = ARRAY_SIZE(clkset_uart_list),
510};
511
512static 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 */
577static struct clksrc_clk *init_parents[] = {
578 &clk_mout_apll,
579 &clk_mout_epll,
580 &clk_mout_mpll,
581};
582
583void __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
662static 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
673void __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}
diff --git a/arch/arm/mach-s5p6440/s5p6440-gpio.c b/arch/arm/mach-s5p6440/gpio.c
index 742264c29f2a..b0ea741177ad 100644
--- a/arch/arm/mach-s5p6440/s5p6440-gpio.c
+++ b/arch/arm/mach-s5p6440/gpio.c
@@ -1,4 +1,4 @@
1/* arch/arm/mach-s5p6440/s5p6440-gpio.c 1/* arch/arm/mach-s5p6440/gpio.c
2 * 2 *
3 * Copyright (c) 2009 Samsung Electronics Co., Ltd. 3 * Copyright (c) 2009 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/ 4 * http://www.samsung.com/
diff --git a/arch/arm/mach-s5p6440/init.c b/arch/arm/mach-s5p6440/init.c
new file mode 100644
index 000000000000..a1f3727e4021
--- /dev/null
+++ b/arch/arm/mach-s5p6440/init.c
@@ -0,0 +1,52 @@
1/* linux/arch/arm/mach-s5p6440/init.c
2 *
3 * Copyright (c) 2009 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
5 *
6 * S5P6440 - Init 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/kernel.h>
14#include <linux/types.h>
15#include <linux/init.h>
16#include <linux/serial_core.h>
17
18#include <plat/cpu.h>
19#include <plat/devs.h>
20#include <plat/s5p6440.h>
21#include <plat/regs-serial.h>
22
23static struct s3c24xx_uart_clksrc s5p6440_serial_clocks[] = {
24 [0] = {
25 .name = "pclk_low",
26 .divisor = 1,
27 .min_baud = 0,
28 .max_baud = 0,
29 },
30 [1] = {
31 .name = "uclk1",
32 .divisor = 1,
33 .min_baud = 0,
34 .max_baud = 0,
35 },
36};
37
38/* uart registration process */
39void __init s5p6440_common_init_uarts(struct s3c2410_uartcfg *cfg, int no)
40{
41 struct s3c2410_uartcfg *tcfg = cfg;
42 u32 ucnt;
43
44 for (ucnt = 0; ucnt < no; ucnt++, tcfg++) {
45 if (!tcfg->clocks) {
46 tcfg->clocks = s5p6440_serial_clocks;
47 tcfg->clocks_size = ARRAY_SIZE(s5p6440_serial_clocks);
48 }
49 }
50
51 s3c24xx_init_uartdevs("s3c6400-uart", s5p_uart_resources, cfg, no);
52}