aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-s5p64x0
diff options
context:
space:
mode:
authorKukjin Kim <kgene.kim@samsung.com>2010-09-01 02:35:30 -0400
committerKukjin Kim <kgene.kim@samsung.com>2010-10-18 05:33:02 -0400
commit3109e55099cb013f9e1b63d39606dc5d7ecf25bd (patch)
tree46fc9d0af9f08df90b079f953b4c0015e7f6134a /arch/arm/mach-s5p64x0
parenta2e0d6249fa866ce7f5a8fe08a4d75511e4701c6 (diff)
ARM: S5P64X0: Update Clock for S5P6440 and S5P6450
This patch updates regarding clock files for supporting S5P6440 and S5P6450 with one kernel image. The mach-s5p64x0/clock.c is for common of them and there are specific clock files for each SoCs. Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
Diffstat (limited to 'arch/arm/mach-s5p64x0')
-rw-r--r--arch/arm/mach-s5p64x0/clock-s5p6440.c626
-rw-r--r--arch/arm/mach-s5p64x0/clock-s5p6450.c655
-rw-r--r--arch/arm/mach-s5p64x0/clock.c253
-rw-r--r--arch/arm/mach-s5p64x0/include/mach/regs-clock.h63
-rw-r--r--arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h46
5 files changed, 1643 insertions, 0 deletions
diff --git a/arch/arm/mach-s5p64x0/clock-s5p6440.c b/arch/arm/mach-s5p64x0/clock-s5p6440.c
new file mode 100644
index 000000000000..f93dcd8b4d6a
--- /dev/null
+++ b/arch/arm/mach-s5p64x0/clock-s5p6440.c
@@ -0,0 +1,626 @@
1/* linux/arch/arm/mach-s5p64x0/clock-s5p6440.c
2 *
3 * Copyright (c) 2009-2010 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#include <mach/regs-clock.h>
26#include <mach/s5p64x0-clock.h>
27
28#include <plat/cpu-freq.h>
29#include <plat/clock.h>
30#include <plat/cpu.h>
31#include <plat/pll.h>
32#include <plat/s5p-clock.h>
33#include <plat/clock-clksrc.h>
34#include <plat/s5p6440.h>
35
36static u32 epll_div[][5] = {
37 { 36000000, 0, 48, 1, 4 },
38 { 48000000, 0, 32, 1, 3 },
39 { 60000000, 0, 40, 1, 3 },
40 { 72000000, 0, 48, 1, 3 },
41 { 84000000, 0, 28, 1, 2 },
42 { 96000000, 0, 32, 1, 2 },
43 { 32768000, 45264, 43, 1, 4 },
44 { 45158000, 6903, 30, 1, 3 },
45 { 49152000, 50332, 32, 1, 3 },
46 { 67738000, 10398, 45, 1, 3 },
47 { 73728000, 9961, 49, 1, 3 }
48};
49
50static int s5p6440_epll_set_rate(struct clk *clk, unsigned long rate)
51{
52 unsigned int epll_con, epll_con_k;
53 unsigned int i;
54
55 if (clk->rate == rate) /* Return if nothing changed */
56 return 0;
57
58 epll_con = __raw_readl(S5P64X0_EPLL_CON);
59 epll_con_k = __raw_readl(S5P64X0_EPLL_CON_K);
60
61 epll_con_k &= ~(PLL90XX_KDIV_MASK);
62 epll_con &= ~(PLL90XX_MDIV_MASK | PLL90XX_PDIV_MASK | PLL90XX_SDIV_MASK);
63
64 for (i = 0; i < ARRAY_SIZE(epll_div); i++) {
65 if (epll_div[i][0] == rate) {
66 epll_con_k |= (epll_div[i][1] << PLL90XX_KDIV_SHIFT);
67 epll_con |= (epll_div[i][2] << PLL90XX_MDIV_SHIFT) |
68 (epll_div[i][3] << PLL90XX_PDIV_SHIFT) |
69 (epll_div[i][4] << PLL90XX_SDIV_SHIFT);
70 break;
71 }
72 }
73
74 if (i == ARRAY_SIZE(epll_div)) {
75 printk(KERN_ERR "%s: Invalid Clock EPLL Frequency\n", __func__);
76 return -EINVAL;
77 }
78
79 __raw_writel(epll_con, S5P64X0_EPLL_CON);
80 __raw_writel(epll_con_k, S5P64X0_EPLL_CON_K);
81
82 clk->rate = rate;
83
84 return 0;
85}
86
87static struct clk_ops s5p6440_epll_ops = {
88 .get_rate = s5p64x0_epll_get_rate,
89 .set_rate = s5p6440_epll_set_rate,
90};
91
92static struct clksrc_clk clk_hclk = {
93 .clk = {
94 .name = "clk_hclk",
95 .id = -1,
96 .parent = &clk_armclk.clk,
97 },
98 .reg_div = { .reg = S5P64X0_CLK_DIV0, .shift = 8, .size = 4 },
99};
100
101static struct clksrc_clk clk_pclk = {
102 .clk = {
103 .name = "clk_pclk",
104 .id = -1,
105 .parent = &clk_hclk.clk,
106 },
107 .reg_div = { .reg = S5P64X0_CLK_DIV0, .shift = 12, .size = 4 },
108};
109static struct clksrc_clk clk_hclk_low = {
110 .clk = {
111 .name = "clk_hclk_low",
112 .id = -1,
113 },
114 .sources = &clkset_hclk_low,
115 .reg_src = { .reg = S5P64X0_SYS_OTHERS, .shift = 6, .size = 1 },
116 .reg_div = { .reg = S5P64X0_CLK_DIV3, .shift = 8, .size = 4 },
117};
118
119static struct clksrc_clk clk_pclk_low = {
120 .clk = {
121 .name = "clk_pclk_low",
122 .id = -1,
123 .parent = &clk_hclk_low.clk,
124 },
125 .reg_div = { .reg = S5P64X0_CLK_DIV3, .shift = 12, .size = 4 },
126};
127
128/*
129 * The following clocks will be disabled during clock initialization. It is
130 * recommended to keep the following clocks disabled until the driver requests
131 * for enabling the clock.
132 */
133static struct clk init_clocks_disable[] = {
134 {
135 .name = "nand",
136 .id = -1,
137 .parent = &clk_hclk.clk,
138 .enable = s5p64x0_mem_ctrl,
139 .ctrlbit = (1 << 2),
140 }, {
141 .name = "post",
142 .id = -1,
143 .parent = &clk_hclk_low.clk,
144 .enable = s5p64x0_hclk0_ctrl,
145 .ctrlbit = (1 << 5)
146 }, {
147 .name = "2d",
148 .id = -1,
149 .parent = &clk_hclk.clk,
150 .enable = s5p64x0_hclk0_ctrl,
151 .ctrlbit = (1 << 8),
152 }, {
153 .name = "hsmmc",
154 .id = 0,
155 .parent = &clk_hclk_low.clk,
156 .enable = s5p64x0_hclk0_ctrl,
157 .ctrlbit = (1 << 17),
158 }, {
159 .name = "hsmmc",
160 .id = 1,
161 .parent = &clk_hclk_low.clk,
162 .enable = s5p64x0_hclk0_ctrl,
163 .ctrlbit = (1 << 18),
164 }, {
165 .name = "hsmmc",
166 .id = 2,
167 .parent = &clk_hclk_low.clk,
168 .enable = s5p64x0_hclk0_ctrl,
169 .ctrlbit = (1 << 19),
170 }, {
171 .name = "otg",
172 .id = -1,
173 .parent = &clk_hclk_low.clk,
174 .enable = s5p64x0_hclk0_ctrl,
175 .ctrlbit = (1 << 20)
176 }, {
177 .name = "irom",
178 .id = -1,
179 .parent = &clk_hclk.clk,
180 .enable = s5p64x0_hclk0_ctrl,
181 .ctrlbit = (1 << 25),
182 }, {
183 .name = "lcd",
184 .id = -1,
185 .parent = &clk_hclk_low.clk,
186 .enable = s5p64x0_hclk1_ctrl,
187 .ctrlbit = (1 << 1),
188 }, {
189 .name = "hclk_fimgvg",
190 .id = -1,
191 .parent = &clk_hclk.clk,
192 .enable = s5p64x0_hclk1_ctrl,
193 .ctrlbit = (1 << 2),
194 }, {
195 .name = "tsi",
196 .id = -1,
197 .parent = &clk_hclk_low.clk,
198 .enable = s5p64x0_hclk1_ctrl,
199 .ctrlbit = (1 << 0),
200 }, {
201 .name = "watchdog",
202 .id = -1,
203 .parent = &clk_pclk_low.clk,
204 .enable = s5p64x0_pclk_ctrl,
205 .ctrlbit = (1 << 5),
206 }, {
207 .name = "rtc",
208 .id = -1,
209 .parent = &clk_pclk_low.clk,
210 .enable = s5p64x0_pclk_ctrl,
211 .ctrlbit = (1 << 6),
212 }, {
213 .name = "timers",
214 .id = -1,
215 .parent = &clk_pclk_low.clk,
216 .enable = s5p64x0_pclk_ctrl,
217 .ctrlbit = (1 << 7),
218 }, {
219 .name = "pcm",
220 .id = -1,
221 .parent = &clk_pclk_low.clk,
222 .enable = s5p64x0_pclk_ctrl,
223 .ctrlbit = (1 << 8),
224 }, {
225 .name = "adc",
226 .id = -1,
227 .parent = &clk_pclk_low.clk,
228 .enable = s5p64x0_pclk_ctrl,
229 .ctrlbit = (1 << 12),
230 }, {
231 .name = "i2c",
232 .id = -1,
233 .parent = &clk_pclk_low.clk,
234 .enable = s5p64x0_pclk_ctrl,
235 .ctrlbit = (1 << 17),
236 }, {
237 .name = "spi",
238 .id = 0,
239 .parent = &clk_pclk_low.clk,
240 .enable = s5p64x0_pclk_ctrl,
241 .ctrlbit = (1 << 21),
242 }, {
243 .name = "spi",
244 .id = 1,
245 .parent = &clk_pclk_low.clk,
246 .enable = s5p64x0_pclk_ctrl,
247 .ctrlbit = (1 << 22),
248 }, {
249 .name = "gps",
250 .id = -1,
251 .parent = &clk_pclk_low.clk,
252 .enable = s5p64x0_pclk_ctrl,
253 .ctrlbit = (1 << 25),
254 }, {
255 .name = "i2s_v40",
256 .id = 0,
257 .parent = &clk_pclk_low.clk,
258 .enable = s5p64x0_pclk_ctrl,
259 .ctrlbit = (1 << 26),
260 }, {
261 .name = "dsim",
262 .id = -1,
263 .parent = &clk_pclk_low.clk,
264 .enable = s5p64x0_pclk_ctrl,
265 .ctrlbit = (1 << 28),
266 }, {
267 .name = "etm",
268 .id = -1,
269 .parent = &clk_pclk.clk,
270 .enable = s5p64x0_pclk_ctrl,
271 .ctrlbit = (1 << 29),
272 }, {
273 .name = "dmc0",
274 .id = -1,
275 .parent = &clk_pclk.clk,
276 .enable = s5p64x0_pclk_ctrl,
277 .ctrlbit = (1 << 30),
278 }, {
279 .name = "pclk_fimgvg",
280 .id = -1,
281 .parent = &clk_pclk.clk,
282 .enable = s5p64x0_pclk_ctrl,
283 .ctrlbit = (1 << 31),
284 }, {
285 .name = "sclk_spi_48",
286 .id = 0,
287 .parent = &clk_48m,
288 .enable = s5p64x0_sclk_ctrl,
289 .ctrlbit = (1 << 22),
290 }, {
291 .name = "sclk_spi_48",
292 .id = 1,
293 .parent = &clk_48m,
294 .enable = s5p64x0_sclk_ctrl,
295 .ctrlbit = (1 << 23),
296 }, {
297 .name = "mmc_48m",
298 .id = 0,
299 .parent = &clk_48m,
300 .enable = s5p64x0_sclk_ctrl,
301 .ctrlbit = (1 << 27),
302 }, {
303 .name = "mmc_48m",
304 .id = 1,
305 .parent = &clk_48m,
306 .enable = s5p64x0_sclk_ctrl,
307 .ctrlbit = (1 << 28),
308 }, {
309 .name = "mmc_48m",
310 .id = 2,
311 .parent = &clk_48m,
312 .enable = s5p64x0_sclk_ctrl,
313 .ctrlbit = (1 << 29),
314 },
315};
316
317/*
318 * The following clocks will be enabled during clock initialization.
319 */
320static struct clk init_clocks[] = {
321 {
322 .name = "intc",
323 .id = -1,
324 .parent = &clk_hclk.clk,
325 .enable = s5p64x0_hclk0_ctrl,
326 .ctrlbit = (1 << 1),
327 }, {
328 .name = "mem",
329 .id = -1,
330 .parent = &clk_hclk.clk,
331 .enable = s5p64x0_hclk0_ctrl,
332 .ctrlbit = (1 << 21),
333 }, {
334 .name = "dma",
335 .id = -1,
336 .parent = &clk_hclk_low.clk,
337 .enable = s5p64x0_hclk0_ctrl,
338 .ctrlbit = (1 << 12),
339 }, {
340 .name = "uart",
341 .id = 0,
342 .parent = &clk_pclk_low.clk,
343 .enable = s5p64x0_pclk_ctrl,
344 .ctrlbit = (1 << 1),
345 }, {
346 .name = "uart",
347 .id = 1,
348 .parent = &clk_pclk_low.clk,
349 .enable = s5p64x0_pclk_ctrl,
350 .ctrlbit = (1 << 2),
351 }, {
352 .name = "uart",
353 .id = 2,
354 .parent = &clk_pclk_low.clk,
355 .enable = s5p64x0_pclk_ctrl,
356 .ctrlbit = (1 << 3),
357 }, {
358 .name = "uart",
359 .id = 3,
360 .parent = &clk_pclk_low.clk,
361 .enable = s5p64x0_pclk_ctrl,
362 .ctrlbit = (1 << 4),
363 }, {
364 .name = "gpio",
365 .id = -1,
366 .parent = &clk_pclk_low.clk,
367 .enable = s5p64x0_pclk_ctrl,
368 .ctrlbit = (1 << 18),
369 },
370};
371
372static struct clk clk_iis_cd_v40 = {
373 .name = "iis_cdclk_v40",
374 .id = -1,
375};
376
377static struct clk clk_pcm_cd = {
378 .name = "pcm_cdclk",
379 .id = -1,
380};
381
382static struct clk *clkset_group1_list[] = {
383 &clk_mout_epll.clk,
384 &clk_dout_mpll.clk,
385 &clk_fin_epll,
386};
387
388static struct clksrc_sources clkset_group1 = {
389 .sources = clkset_group1_list,
390 .nr_sources = ARRAY_SIZE(clkset_group1_list),
391};
392
393static struct clk *clkset_uart_list[] = {
394 &clk_mout_epll.clk,
395 &clk_dout_mpll.clk,
396};
397
398static struct clksrc_sources clkset_uart = {
399 .sources = clkset_uart_list,
400 .nr_sources = ARRAY_SIZE(clkset_uart_list),
401};
402
403static struct clk *clkset_audio_list[] = {
404 &clk_mout_epll.clk,
405 &clk_dout_mpll.clk,
406 &clk_fin_epll,
407 &clk_iis_cd_v40,
408 &clk_pcm_cd,
409};
410
411static struct clksrc_sources clkset_audio = {
412 .sources = clkset_audio_list,
413 .nr_sources = ARRAY_SIZE(clkset_audio_list),
414};
415
416static struct clksrc_clk clksrcs[] = {
417 {
418 .clk = {
419 .name = "mmc_bus",
420 .id = 0,
421 .ctrlbit = (1 << 24),
422 .enable = s5p64x0_sclk_ctrl,
423 },
424 .sources = &clkset_group1,
425 .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 18, .size = 2 },
426 .reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 0, .size = 4 },
427 }, {
428 .clk = {
429 .name = "mmc_bus",
430 .id = 1,
431 .ctrlbit = (1 << 25),
432 .enable = s5p64x0_sclk_ctrl,
433 },
434 .sources = &clkset_group1,
435 .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 20, .size = 2 },
436 .reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 4, .size = 4 },
437 }, {
438 .clk = {
439 .name = "mmc_bus",
440 .id = 2,
441 .ctrlbit = (1 << 26),
442 .enable = s5p64x0_sclk_ctrl,
443 },
444 .sources = &clkset_group1,
445 .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 22, .size = 2 },
446 .reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 8, .size = 4 },
447 }, {
448 .clk = {
449 .name = "uclk1",
450 .id = -1,
451 .ctrlbit = (1 << 5),
452 .enable = s5p64x0_sclk_ctrl,
453 },
454 .sources = &clkset_uart,
455 .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 13, .size = 1 },
456 .reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 16, .size = 4 },
457 }, {
458 .clk = {
459 .name = "sclk_spi",
460 .id = 0,
461 .ctrlbit = (1 << 20),
462 .enable = s5p64x0_sclk_ctrl,
463 },
464 .sources = &clkset_group1,
465 .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 14, .size = 2 },
466 .reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 0, .size = 4 },
467 }, {
468 .clk = {
469 .name = "sclk_spi",
470 .id = 1,
471 .ctrlbit = (1 << 21),
472 .enable = s5p64x0_sclk_ctrl,
473 },
474 .sources = &clkset_group1,
475 .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 16, .size = 2 },
476 .reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 4, .size = 4 },
477 }, {
478 .clk = {
479 .name = "sclk_post",
480 .id = -1,
481 .ctrlbit = (1 << 10),
482 .enable = s5p64x0_sclk_ctrl,
483 },
484 .sources = &clkset_group1,
485 .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 26, .size = 2 },
486 .reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 12, .size = 4 },
487 }, {
488 .clk = {
489 .name = "sclk_dispcon",
490 .id = -1,
491 .ctrlbit = (1 << 1),
492 .enable = s5p64x0_sclk1_ctrl,
493 },
494 .sources = &clkset_group1,
495 .reg_src = { .reg = S5P64X0_CLK_SRC1, .shift = 4, .size = 2 },
496 .reg_div = { .reg = S5P64X0_CLK_DIV3, .shift = 0, .size = 4 },
497 }, {
498 .clk = {
499 .name = "sclk_fimgvg",
500 .id = -1,
501 .ctrlbit = (1 << 2),
502 .enable = s5p64x0_sclk1_ctrl,
503 },
504 .sources = &clkset_group1,
505 .reg_src = { .reg = S5P64X0_CLK_SRC1, .shift = 8, .size = 2 },
506 .reg_div = { .reg = S5P64X0_CLK_DIV3, .shift = 4, .size = 4 },
507 }, {
508 .clk = {
509 .name = "sclk_audio2",
510 .id = -1,
511 .ctrlbit = (1 << 11),
512 .enable = s5p64x0_sclk_ctrl,
513 },
514 .sources = &clkset_audio,
515 .reg_src = { .reg = S5P64X0_CLK_SRC1, .shift = 0, .size = 3 },
516 .reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 24, .size = 4 },
517 },
518};
519
520/* Clock initialization code */
521static struct clksrc_clk *sysclks[] = {
522 &clk_mout_apll,
523 &clk_mout_epll,
524 &clk_mout_mpll,
525 &clk_dout_mpll,
526 &clk_armclk,
527 &clk_hclk,
528 &clk_pclk,
529 &clk_hclk_low,
530 &clk_pclk_low,
531};
532
533void __init_or_cpufreq s5p6440_setup_clocks(void)
534{
535 struct clk *xtal_clk;
536
537 unsigned long xtal;
538 unsigned long fclk;
539 unsigned long hclk;
540 unsigned long hclk_low;
541 unsigned long pclk;
542 unsigned long pclk_low;
543
544 unsigned long apll;
545 unsigned long mpll;
546 unsigned long epll;
547 unsigned int ptr;
548
549 /* Set S5P6440 functions for clk_fout_epll */
550
551 clk_fout_epll.enable = s5p64x0_epll_enable;
552 clk_fout_epll.ops = &s5p6440_epll_ops;
553
554 clk_48m.enable = s5p64x0_clk48m_ctrl;
555
556 xtal_clk = clk_get(NULL, "ext_xtal");
557 BUG_ON(IS_ERR(xtal_clk));
558
559 xtal = clk_get_rate(xtal_clk);
560 clk_put(xtal_clk);
561
562 apll = s5p_get_pll45xx(xtal, __raw_readl(S5P64X0_APLL_CON), pll_4502);
563 mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P64X0_MPLL_CON), pll_4502);
564 epll = s5p_get_pll90xx(xtal, __raw_readl(S5P64X0_EPLL_CON),
565 __raw_readl(S5P64X0_EPLL_CON_K));
566
567 clk_fout_apll.rate = apll;
568 clk_fout_mpll.rate = mpll;
569 clk_fout_epll.rate = epll;
570
571 printk(KERN_INFO "S5P6440: PLL settings, A=%ld.%ldMHz, M=%ld.%ldMHz," \
572 " E=%ld.%ldMHz\n",
573 print_mhz(apll), print_mhz(mpll), print_mhz(epll));
574
575 fclk = clk_get_rate(&clk_armclk.clk);
576 hclk = clk_get_rate(&clk_hclk.clk);
577 pclk = clk_get_rate(&clk_pclk.clk);
578 hclk_low = clk_get_rate(&clk_hclk_low.clk);
579 pclk_low = clk_get_rate(&clk_pclk_low.clk);
580
581 printk(KERN_INFO "S5P6440: HCLK=%ld.%ldMHz, HCLK_LOW=%ld.%ldMHz," \
582 " PCLK=%ld.%ldMHz, PCLK_LOW=%ld.%ldMHz\n",
583 print_mhz(hclk), print_mhz(hclk_low),
584 print_mhz(pclk), print_mhz(pclk_low));
585
586 clk_f.rate = fclk;
587 clk_h.rate = hclk;
588 clk_p.rate = pclk;
589
590 for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
591 s3c_set_clksrc(&clksrcs[ptr], true);
592}
593
594static struct clk *clks[] __initdata = {
595 &clk_ext,
596 &clk_iis_cd_v40,
597 &clk_pcm_cd,
598};
599
600void __init s5p6440_register_clocks(void)
601{
602 struct clk *clkp;
603 int ret;
604 int ptr;
605
606 s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
607
608 for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++)
609 s3c_register_clksrc(sysclks[ptr], 1);
610
611 s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
612 s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
613
614 clkp = init_clocks_disable;
615 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
616
617 ret = s3c24xx_register_clock(clkp);
618 if (ret < 0) {
619 printk(KERN_ERR "Failed to register clock %s (%d)\n",
620 clkp->name, ret);
621 }
622 (clkp->enable)(clkp, 0);
623 }
624
625 s3c_pwmclk_init();
626}
diff --git a/arch/arm/mach-s5p64x0/clock-s5p6450.c b/arch/arm/mach-s5p64x0/clock-s5p6450.c
new file mode 100644
index 000000000000..f9afb05b217c
--- /dev/null
+++ b/arch/arm/mach-s5p64x0/clock-s5p6450.c
@@ -0,0 +1,655 @@
1/* linux/arch/arm/mach-s5p64x0/clock-s5p6450.c
2 *
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * S5P6450 - 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#include <mach/regs-clock.h>
26#include <mach/s5p64x0-clock.h>
27
28#include <plat/cpu-freq.h>
29#include <plat/clock.h>
30#include <plat/cpu.h>
31#include <plat/pll.h>
32#include <plat/s5p-clock.h>
33#include <plat/clock-clksrc.h>
34#include <plat/s5p6450.h>
35
36static struct clksrc_clk clk_mout_dpll = {
37 .clk = {
38 .name = "mout_dpll",
39 .id = -1,
40 },
41 .sources = &clk_src_dpll,
42 .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 5, .size = 1 },
43};
44
45static u32 epll_div[][5] = {
46 { 133000000, 27307, 55, 2, 2 },
47 { 100000000, 43691, 41, 2, 2 },
48 { 480000000, 0, 80, 2, 0 },
49};
50
51static int s5p6450_epll_set_rate(struct clk *clk, unsigned long rate)
52{
53 unsigned int epll_con, epll_con_k;
54 unsigned int i;
55
56 if (clk->rate == rate) /* Return if nothing changed */
57 return 0;
58
59 epll_con = __raw_readl(S5P64X0_EPLL_CON);
60 epll_con_k = __raw_readl(S5P64X0_EPLL_CON_K);
61
62 epll_con_k &= ~(PLL90XX_KDIV_MASK);
63 epll_con &= ~(PLL90XX_MDIV_MASK | PLL90XX_PDIV_MASK | PLL90XX_SDIV_MASK);
64
65 for (i = 0; i < ARRAY_SIZE(epll_div); i++) {
66 if (epll_div[i][0] == rate) {
67 epll_con_k |= (epll_div[i][1] << PLL90XX_KDIV_SHIFT);
68 epll_con |= (epll_div[i][2] << PLL90XX_MDIV_SHIFT) |
69 (epll_div[i][3] << PLL90XX_PDIV_SHIFT) |
70 (epll_div[i][4] << PLL90XX_SDIV_SHIFT);
71 break;
72 }
73 }
74
75 if (i == ARRAY_SIZE(epll_div)) {
76 printk(KERN_ERR "%s: Invalid Clock EPLL Frequency\n", __func__);
77 return -EINVAL;
78 }
79
80 __raw_writel(epll_con, S5P64X0_EPLL_CON);
81 __raw_writel(epll_con_k, S5P64X0_EPLL_CON_K);
82
83 clk->rate = rate;
84
85 return 0;
86}
87
88static struct clk_ops s5p6450_epll_ops = {
89 .get_rate = s5p64x0_epll_get_rate,
90 .set_rate = s5p6450_epll_set_rate,
91};
92
93static struct clksrc_clk clk_dout_epll = {
94 .clk = {
95 .name = "dout_epll",
96 .id = -1,
97 .parent = &clk_mout_epll.clk,
98 },
99 .reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 24, .size = 4 },
100};
101
102static struct clksrc_clk clk_mout_hclk_sel = {
103 .clk = {
104 .name = "mout_hclk_sel",
105 .id = -1,
106 },
107 .sources = &clkset_hclk_low,
108 .reg_src = { .reg = S5P64X0_OTHERS, .shift = 15, .size = 1 },
109};
110
111static struct clk *clkset_hclk_list[] = {
112 &clk_mout_hclk_sel.clk,
113 &clk_armclk.clk,
114};
115
116static struct clksrc_sources clkset_hclk = {
117 .sources = clkset_hclk_list,
118 .nr_sources = ARRAY_SIZE(clkset_hclk_list),
119};
120
121static struct clksrc_clk clk_hclk = {
122 .clk = {
123 .name = "clk_hclk",
124 .id = -1,
125 },
126 .sources = &clkset_hclk,
127 .reg_src = { .reg = S5P64X0_OTHERS, .shift = 14, .size = 1 },
128 .reg_div = { .reg = S5P64X0_CLK_DIV0, .shift = 8, .size = 4 },
129};
130
131static struct clksrc_clk clk_pclk = {
132 .clk = {
133 .name = "clk_pclk",
134 .id = -1,
135 .parent = &clk_hclk.clk,
136 },
137 .reg_div = { .reg = S5P64X0_CLK_DIV0, .shift = 12, .size = 4 },
138};
139static struct clksrc_clk clk_dout_pwm_ratio0 = {
140 .clk = {
141 .name = "clk_dout_pwm_ratio0",
142 .id = -1,
143 .parent = &clk_mout_hclk_sel.clk,
144 },
145 .reg_div = { .reg = S5P64X0_CLK_DIV3, .shift = 16, .size = 4 },
146};
147
148static struct clksrc_clk clk_pclk_to_wdt_pwm = {
149 .clk = {
150 .name = "clk_pclk_to_wdt_pwm",
151 .id = -1,
152 .parent = &clk_dout_pwm_ratio0.clk,
153 },
154 .reg_div = { .reg = S5P64X0_CLK_DIV3, .shift = 20, .size = 4 },
155};
156
157static struct clksrc_clk clk_hclk_low = {
158 .clk = {
159 .name = "clk_hclk_low",
160 .id = -1,
161 },
162 .sources = &clkset_hclk_low,
163 .reg_src = { .reg = S5P64X0_OTHERS, .shift = 6, .size = 1 },
164 .reg_div = { .reg = S5P64X0_CLK_DIV3, .shift = 8, .size = 4 },
165};
166
167static struct clksrc_clk clk_pclk_low = {
168 .clk = {
169 .name = "clk_pclk_low",
170 .id = -1,
171 .parent = &clk_hclk_low.clk,
172 },
173 .reg_div = { .reg = S5P64X0_CLK_DIV3, .shift = 12, .size = 4 },
174};
175
176/*
177 * The following clocks will be disabled during clock initialization. It is
178 * recommended to keep the following clocks disabled until the driver requests
179 * for enabling the clock.
180 */
181static struct clk init_clocks_disable[] = {
182 {
183 .name = "usbhost",
184 .id = -1,
185 .parent = &clk_hclk_low.clk,
186 .enable = s5p64x0_hclk0_ctrl,
187 .ctrlbit = (1 << 3),
188 }, {
189 .name = "hsmmc",
190 .id = 0,
191 .parent = &clk_hclk_low.clk,
192 .enable = s5p64x0_hclk0_ctrl,
193 .ctrlbit = (1 << 17),
194 }, {
195 .name = "hsmmc",
196 .id = 1,
197 .parent = &clk_hclk_low.clk,
198 .enable = s5p64x0_hclk0_ctrl,
199 .ctrlbit = (1 << 18),
200 }, {
201 .name = "hsmmc",
202 .id = 2,
203 .parent = &clk_hclk_low.clk,
204 .enable = s5p64x0_hclk0_ctrl,
205 .ctrlbit = (1 << 19),
206 }, {
207 .name = "usbotg",
208 .id = -1,
209 .parent = &clk_hclk_low.clk,
210 .enable = s5p64x0_hclk0_ctrl,
211 .ctrlbit = (1 << 20),
212 }, {
213 .name = "lcd",
214 .id = -1,
215 .parent = &clk_h,
216 .enable = s5p64x0_hclk1_ctrl,
217 .ctrlbit = (1 << 1),
218 }, {
219 .name = "watchdog",
220 .id = -1,
221 .parent = &clk_pclk_low.clk,
222 .enable = s5p64x0_pclk_ctrl,
223 .ctrlbit = (1 << 5),
224 }, {
225 .name = "adc",
226 .id = -1,
227 .parent = &clk_pclk_low.clk,
228 .enable = s5p64x0_pclk_ctrl,
229 .ctrlbit = (1 << 12),
230 }, {
231 .name = "i2c",
232 .id = 0,
233 .parent = &clk_pclk_low.clk,
234 .enable = s5p64x0_pclk_ctrl,
235 .ctrlbit = (1 << 17),
236 }, {
237 .name = "spi",
238 .id = 0,
239 .parent = &clk_pclk_low.clk,
240 .enable = s5p64x0_pclk_ctrl,
241 .ctrlbit = (1 << 21),
242 }, {
243 .name = "spi",
244 .id = 1,
245 .parent = &clk_pclk_low.clk,
246 .enable = s5p64x0_pclk_ctrl,
247 .ctrlbit = (1 << 22),
248 }, {
249 .name = "iis",
250 .id = -1,
251 .parent = &clk_pclk_low.clk,
252 .enable = s5p64x0_pclk_ctrl,
253 .ctrlbit = (1 << 26),
254 }, {
255 .name = "i2c",
256 .id = 1,
257 .parent = &clk_pclk_low.clk,
258 .enable = s5p64x0_pclk_ctrl,
259 .ctrlbit = (1 << 27),
260 }, {
261 .name = "dmc0",
262 .id = -1,
263 .parent = &clk_pclk.clk,
264 .enable = s5p64x0_pclk_ctrl,
265 .ctrlbit = (1 << 30),
266 }
267};
268
269/*
270 * The following clocks will be enabled during clock initialization.
271 */
272static struct clk init_clocks[] = {
273 {
274 .name = "intc",
275 .id = -1,
276 .parent = &clk_hclk.clk,
277 .enable = s5p64x0_hclk0_ctrl,
278 .ctrlbit = (1 << 1),
279 }, {
280 .name = "mem",
281 .id = -1,
282 .parent = &clk_hclk.clk,
283 .enable = s5p64x0_hclk0_ctrl,
284 .ctrlbit = (1 << 21),
285 }, {
286 .name = "dma",
287 .id = -1,
288 .parent = &clk_hclk_low.clk,
289 .enable = s5p64x0_hclk0_ctrl,
290 .ctrlbit = (1 << 12),
291 }, {
292 .name = "uart",
293 .id = 0,
294 .parent = &clk_pclk_low.clk,
295 .enable = s5p64x0_pclk_ctrl,
296 .ctrlbit = (1 << 1),
297 }, {
298 .name = "uart",
299 .id = 1,
300 .parent = &clk_pclk_low.clk,
301 .enable = s5p64x0_pclk_ctrl,
302 .ctrlbit = (1 << 2),
303 }, {
304 .name = "uart",
305 .id = 2,
306 .parent = &clk_pclk_low.clk,
307 .enable = s5p64x0_pclk_ctrl,
308 .ctrlbit = (1 << 3),
309 }, {
310 .name = "uart",
311 .id = 3,
312 .parent = &clk_pclk_low.clk,
313 .enable = s5p64x0_pclk_ctrl,
314 .ctrlbit = (1 << 4),
315 }, {
316 .name = "timers",
317 .id = -1,
318 .parent = &clk_pclk_to_wdt_pwm.clk,
319 .enable = s5p64x0_pclk_ctrl,
320 .ctrlbit = (1 << 7),
321 }, {
322 .name = "gpio",
323 .id = -1,
324 .parent = &clk_pclk_low.clk,
325 .enable = s5p64x0_pclk_ctrl,
326 .ctrlbit = (1 << 18),
327 },
328};
329
330static struct clk *clkset_uart_list[] = {
331 &clk_dout_epll.clk,
332 &clk_dout_mpll.clk,
333};
334
335static struct clksrc_sources clkset_uart = {
336 .sources = clkset_uart_list,
337 .nr_sources = ARRAY_SIZE(clkset_uart_list),
338};
339
340static struct clk *clkset_mali_list[] = {
341 &clk_mout_epll.clk,
342 &clk_mout_apll.clk,
343 &clk_mout_mpll.clk,
344};
345
346static struct clksrc_sources clkset_mali = {
347 .sources = clkset_mali_list,
348 .nr_sources = ARRAY_SIZE(clkset_mali_list),
349};
350
351static struct clk *clkset_group2_list[] = {
352 &clk_dout_epll.clk,
353 &clk_dout_mpll.clk,
354 &clk_ext_xtal_mux,
355};
356
357static struct clksrc_sources clkset_group2 = {
358 .sources = clkset_group2_list,
359 .nr_sources = ARRAY_SIZE(clkset_group2_list),
360};
361
362static struct clk *clkset_dispcon_list[] = {
363 &clk_dout_epll.clk,
364 &clk_dout_mpll.clk,
365 &clk_ext_xtal_mux,
366 &clk_mout_dpll.clk,
367};
368
369static struct clksrc_sources clkset_dispcon = {
370 .sources = clkset_dispcon_list,
371 .nr_sources = ARRAY_SIZE(clkset_dispcon_list),
372};
373
374static struct clk *clkset_hsmmc44_list[] = {
375 &clk_dout_epll.clk,
376 &clk_dout_mpll.clk,
377 &clk_ext_xtal_mux,
378 &s5p_clk_27m,
379 &clk_48m,
380};
381
382static struct clksrc_sources clkset_hsmmc44 = {
383 .sources = clkset_hsmmc44_list,
384 .nr_sources = ARRAY_SIZE(clkset_hsmmc44_list),
385};
386
387static struct clk *clkset_sclk_audio0_list[] = {
388 [0] = &clk_dout_epll.clk,
389 [1] = &clk_dout_mpll.clk,
390 [2] = &clk_ext_xtal_mux,
391 [3] = NULL,
392 [4] = NULL,
393};
394
395static struct clksrc_sources clkset_sclk_audio0 = {
396 .sources = clkset_sclk_audio0_list,
397 .nr_sources = ARRAY_SIZE(clkset_sclk_audio0_list),
398};
399
400static struct clksrc_clk clk_sclk_audio0 = {
401 .clk = {
402 .name = "audio-bus",
403 .id = -1,
404 .enable = s5p64x0_sclk_ctrl,
405 .ctrlbit = (1 << 8),
406 .parent = &clk_dout_epll.clk,
407 },
408 .sources = &clkset_sclk_audio0,
409 .reg_src = { .reg = S5P64X0_CLK_SRC1, .shift = 10, .size = 3 },
410 .reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 8, .size = 4 },
411};
412
413static struct clksrc_clk clksrcs[] = {
414 {
415 .clk = {
416 .name = "sclk_mmc",
417 .id = 0,
418 .ctrlbit = (1 << 24),
419 .enable = s5p64x0_sclk_ctrl,
420 },
421 .sources = &clkset_group2,
422 .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 18, .size = 2 },
423 .reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 0, .size = 4 },
424 }, {
425 .clk = {
426 .name = "sclk_mmc",
427 .id = 1,
428 .ctrlbit = (1 << 25),
429 .enable = s5p64x0_sclk_ctrl,
430 },
431 .sources = &clkset_group2,
432 .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 20, .size = 2 },
433 .reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 4, .size = 4 },
434 }, {
435 .clk = {
436 .name = "sclk_mmc",
437 .id = 2,
438 .ctrlbit = (1 << 26),
439 .enable = s5p64x0_sclk_ctrl,
440 },
441 .sources = &clkset_group2,
442 .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 22, .size = 2 },
443 .reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 8, .size = 4 },
444 }, {
445 .clk = {
446 .name = "uclk1",
447 .id = -1,
448 .ctrlbit = (1 << 5),
449 .enable = s5p64x0_sclk_ctrl,
450 },
451 .sources = &clkset_uart,
452 .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 13, .size = 1 },
453 .reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 16, .size = 4 },
454 }, {
455 .clk = {
456 .name = "sclk_spi",
457 .id = 0,
458 .ctrlbit = (1 << 20),
459 .enable = s5p64x0_sclk_ctrl,
460 },
461 .sources = &clkset_group2,
462 .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 14, .size = 2 },
463 .reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 0, .size = 4 },
464 }, {
465 .clk = {
466 .name = "sclk_spi",
467 .id = 1,
468 .ctrlbit = (1 << 21),
469 .enable = s5p64x0_sclk_ctrl,
470 },
471 .sources = &clkset_group2,
472 .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 16, .size = 2 },
473 .reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 4, .size = 4 },
474 }, {
475 .clk = {
476 .name = "sclk_fimc",
477 .id = -1,
478 .ctrlbit = (1 << 10),
479 .enable = s5p64x0_sclk_ctrl,
480 },
481 .sources = &clkset_group2,
482 .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 26, .size = 2 },
483 .reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 12, .size = 4 },
484 }, {
485 .clk = {
486 .name = "aclk_mali",
487 .id = -1,
488 .ctrlbit = (1 << 2),
489 .enable = s5p64x0_sclk1_ctrl,
490 },
491 .sources = &clkset_mali,
492 .reg_src = { .reg = S5P64X0_CLK_SRC1, .shift = 8, .size = 2 },
493 .reg_div = { .reg = S5P64X0_CLK_DIV3, .shift = 4, .size = 4 },
494 }, {
495 .clk = {
496 .name = "sclk_2d",
497 .id = -1,
498 .ctrlbit = (1 << 12),
499 .enable = s5p64x0_sclk_ctrl,
500 },
501 .sources = &clkset_mali,
502 .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 30, .size = 2 },
503 .reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 20, .size = 4 },
504 }, {
505 .clk = {
506 .name = "sclk_usi",
507 .id = -1,
508 .ctrlbit = (1 << 7),
509 .enable = s5p64x0_sclk_ctrl,
510 },
511 .sources = &clkset_group2,
512 .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 10, .size = 2 },
513 .reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 16, .size = 4 },
514 }, {
515 .clk = {
516 .name = "sclk_camif",
517 .id = -1,
518 .ctrlbit = (1 << 6),
519 .enable = s5p64x0_sclk_ctrl,
520 },
521 .sources = &clkset_group2,
522 .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 28, .size = 2 },
523 .reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 20, .size = 4 },
524 }, {
525 .clk = {
526 .name = "sclk_dispcon",
527 .id = -1,
528 .ctrlbit = (1 << 1),
529 .enable = s5p64x0_sclk1_ctrl,
530 },
531 .sources = &clkset_dispcon,
532 .reg_src = { .reg = S5P64X0_CLK_SRC1, .shift = 4, .size = 2 },
533 .reg_div = { .reg = S5P64X0_CLK_DIV3, .shift = 0, .size = 4 },
534 }, {
535 .clk = {
536 .name = "sclk_hsmmc44",
537 .id = -1,
538 .ctrlbit = (1 << 30),
539 .enable = s5p64x0_sclk_ctrl,
540 },
541 .sources = &clkset_hsmmc44,
542 .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 6, .size = 3 },
543 .reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 28, .size = 4 },
544 },
545};
546
547/* Clock initialization code */
548static struct clksrc_clk *sysclks[] = {
549 &clk_mout_apll,
550 &clk_mout_epll,
551 &clk_dout_epll,
552 &clk_mout_mpll,
553 &clk_dout_mpll,
554 &clk_armclk,
555 &clk_mout_hclk_sel,
556 &clk_dout_pwm_ratio0,
557 &clk_pclk_to_wdt_pwm,
558 &clk_hclk,
559 &clk_pclk,
560 &clk_hclk_low,
561 &clk_pclk_low,
562 &clk_sclk_audio0,
563};
564
565void __init_or_cpufreq s5p6450_setup_clocks(void)
566{
567 struct clk *xtal_clk;
568
569 unsigned long xtal;
570 unsigned long fclk;
571 unsigned long hclk;
572 unsigned long hclk_low;
573 unsigned long pclk;
574 unsigned long pclk_low;
575
576 unsigned long apll;
577 unsigned long mpll;
578 unsigned long epll;
579 unsigned long dpll;
580 unsigned int ptr;
581
582 /* Set S5P6450 functions for clk_fout_epll */
583
584 clk_fout_epll.enable = s5p64x0_epll_enable;
585 clk_fout_epll.ops = &s5p6450_epll_ops;
586
587 clk_48m.enable = s5p64x0_clk48m_ctrl;
588
589 xtal_clk = clk_get(NULL, "ext_xtal");
590 BUG_ON(IS_ERR(xtal_clk));
591
592 xtal = clk_get_rate(xtal_clk);
593 clk_put(xtal_clk);
594
595 apll = s5p_get_pll45xx(xtal, __raw_readl(S5P64X0_APLL_CON), pll_4502);
596 mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P64X0_MPLL_CON), pll_4502);
597 epll = s5p_get_pll90xx(xtal, __raw_readl(S5P64X0_EPLL_CON),
598 __raw_readl(S5P64X0_EPLL_CON_K));
599 dpll = s5p_get_pll46xx(xtal, __raw_readl(S5P6450_DPLL_CON),
600 __raw_readl(S5P6450_DPLL_CON_K), pll_4650c);
601
602 clk_fout_apll.rate = apll;
603 clk_fout_mpll.rate = mpll;
604 clk_fout_epll.rate = epll;
605 clk_fout_dpll.rate = dpll;
606
607 printk(KERN_INFO "S5P6450: PLL settings, A=%ld.%ldMHz, M=%ld.%ldMHz," \
608 " E=%ld.%ldMHz, D=%ld.%ldMHz\n",
609 print_mhz(apll), print_mhz(mpll), print_mhz(epll),
610 print_mhz(dpll));
611
612 fclk = clk_get_rate(&clk_armclk.clk);
613 hclk = clk_get_rate(&clk_hclk.clk);
614 pclk = clk_get_rate(&clk_pclk.clk);
615 hclk_low = clk_get_rate(&clk_hclk_low.clk);
616 pclk_low = clk_get_rate(&clk_pclk_low.clk);
617
618 printk(KERN_INFO "S5P6450: HCLK=%ld.%ldMHz, HCLK_LOW=%ld.%ldMHz," \
619 " PCLK=%ld.%ldMHz, PCLK_LOW=%ld.%ldMHz\n",
620 print_mhz(hclk), print_mhz(hclk_low),
621 print_mhz(pclk), print_mhz(pclk_low));
622
623 clk_f.rate = fclk;
624 clk_h.rate = hclk;
625 clk_p.rate = pclk;
626
627 for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
628 s3c_set_clksrc(&clksrcs[ptr], true);
629}
630
631void __init s5p6450_register_clocks(void)
632{
633 struct clk *clkp;
634 int ret;
635 int ptr;
636
637 for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++)
638 s3c_register_clksrc(sysclks[ptr], 1);
639
640 s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
641 s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
642
643 clkp = init_clocks_disable;
644 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
645
646 ret = s3c24xx_register_clock(clkp);
647 if (ret < 0) {
648 printk(KERN_ERR "Failed to register clock %s (%d)\n",
649 clkp->name, ret);
650 }
651 (clkp->enable)(clkp, 0);
652 }
653
654 s3c_pwmclk_init();
655}
diff --git a/arch/arm/mach-s5p64x0/clock.c b/arch/arm/mach-s5p64x0/clock.c
new file mode 100644
index 000000000000..523ba8039ac2
--- /dev/null
+++ b/arch/arm/mach-s5p64x0/clock.c
@@ -0,0 +1,253 @@
1/* linux/arch/arm/mach-s5p64x0/clock.c
2 *
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * S5P64X0 - 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#include <mach/regs-clock.h>
26
27#include <plat/cpu-freq.h>
28#include <plat/clock.h>
29#include <plat/cpu.h>
30#include <plat/pll.h>
31#include <plat/s5p-clock.h>
32#include <plat/clock-clksrc.h>
33#include <plat/s5p6440.h>
34#include <plat/s5p6450.h>
35
36struct clksrc_clk clk_mout_apll = {
37 .clk = {
38 .name = "mout_apll",
39 .id = -1,
40 },
41 .sources = &clk_src_apll,
42 .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 0, .size = 1 },
43};
44
45struct clksrc_clk clk_mout_mpll = {
46 .clk = {
47 .name = "mout_mpll",
48 .id = -1,
49 },
50 .sources = &clk_src_mpll,
51 .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 1, .size = 1 },
52};
53
54struct clksrc_clk clk_mout_epll = {
55 .clk = {
56 .name = "mout_epll",
57 .id = -1,
58 },
59 .sources = &clk_src_epll,
60 .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 2, .size = 1 },
61};
62
63enum perf_level {
64 L0 = 532*1000,
65 L1 = 266*1000,
66 L2 = 133*1000,
67};
68
69static const u32 clock_table[][3] = {
70 /*{ARM_CLK, DIVarm, DIVhclk}*/
71 {L0 * 1000, (0 << ARM_DIV_RATIO_SHIFT), (3 << S5P64X0_CLKDIV0_HCLK_SHIFT)},
72 {L1 * 1000, (1 << ARM_DIV_RATIO_SHIFT), (1 << S5P64X0_CLKDIV0_HCLK_SHIFT)},
73 {L2 * 1000, (3 << ARM_DIV_RATIO_SHIFT), (0 << S5P64X0_CLKDIV0_HCLK_SHIFT)},
74};
75
76int s5p64x0_epll_enable(struct clk *clk, int enable)
77{
78 unsigned int ctrlbit = clk->ctrlbit;
79 unsigned int epll_con = __raw_readl(S5P64X0_EPLL_CON) & ~ctrlbit;
80
81 if (enable)
82 __raw_writel(epll_con | ctrlbit, S5P64X0_EPLL_CON);
83 else
84 __raw_writel(epll_con, S5P64X0_EPLL_CON);
85
86 return 0;
87}
88
89unsigned long s5p64x0_epll_get_rate(struct clk *clk)
90{
91 return clk->rate;
92}
93
94unsigned long s5p64x0_armclk_get_rate(struct clk *clk)
95{
96 unsigned long rate = clk_get_rate(clk->parent);
97 u32 clkdiv;
98
99 /* divisor mask starts at bit0, so no need to shift */
100 clkdiv = __raw_readl(ARM_CLK_DIV) & ARM_DIV_MASK;
101
102 return rate / (clkdiv + 1);
103}
104
105unsigned long s5p64x0_armclk_round_rate(struct clk *clk, unsigned long rate)
106{
107 u32 iter;
108
109 for (iter = 1 ; iter < ARRAY_SIZE(clock_table) ; iter++) {
110 if (rate > clock_table[iter][0])
111 return clock_table[iter-1][0];
112 }
113
114 return clock_table[ARRAY_SIZE(clock_table) - 1][0];
115}
116
117int s5p64x0_armclk_set_rate(struct clk *clk, unsigned long rate)
118{
119 u32 round_tmp;
120 u32 iter;
121 u32 clk_div0_tmp;
122 u32 cur_rate = clk->ops->get_rate(clk);
123 unsigned long flags;
124
125 round_tmp = clk->ops->round_rate(clk, rate);
126 if (round_tmp == cur_rate)
127 return 0;
128
129
130 for (iter = 0 ; iter < ARRAY_SIZE(clock_table) ; iter++) {
131 if (round_tmp == clock_table[iter][0])
132 break;
133 }
134
135 if (iter >= ARRAY_SIZE(clock_table))
136 iter = ARRAY_SIZE(clock_table) - 1;
137
138 local_irq_save(flags);
139 if (cur_rate > round_tmp) {
140 /* Frequency Down */
141 clk_div0_tmp = __raw_readl(ARM_CLK_DIV) & ~(ARM_DIV_MASK);
142 clk_div0_tmp |= clock_table[iter][1];
143 __raw_writel(clk_div0_tmp, ARM_CLK_DIV);
144
145 clk_div0_tmp = __raw_readl(ARM_CLK_DIV) &
146 ~(S5P64X0_CLKDIV0_HCLK_MASK);
147 clk_div0_tmp |= clock_table[iter][2];
148 __raw_writel(clk_div0_tmp, ARM_CLK_DIV);
149
150
151 } else {
152 /* Frequency Up */
153 clk_div0_tmp = __raw_readl(ARM_CLK_DIV) &
154 ~(S5P64X0_CLKDIV0_HCLK_MASK);
155 clk_div0_tmp |= clock_table[iter][2];
156 __raw_writel(clk_div0_tmp, ARM_CLK_DIV);
157
158 clk_div0_tmp = __raw_readl(ARM_CLK_DIV) & ~(ARM_DIV_MASK);
159 clk_div0_tmp |= clock_table[iter][1];
160 __raw_writel(clk_div0_tmp, ARM_CLK_DIV);
161 }
162 local_irq_restore(flags);
163
164 clk->rate = clock_table[iter][0];
165
166 return 0;
167}
168
169struct clk_ops s5p64x0_clkarm_ops = {
170 .get_rate = s5p64x0_armclk_get_rate,
171 .set_rate = s5p64x0_armclk_set_rate,
172 .round_rate = s5p64x0_armclk_round_rate,
173};
174
175struct clksrc_clk clk_armclk = {
176 .clk = {
177 .name = "armclk",
178 .id = 1,
179 .parent = &clk_mout_apll.clk,
180 .ops = &s5p64x0_clkarm_ops,
181 },
182 .reg_div = { .reg = S5P64X0_CLK_DIV0, .shift = 0, .size = 4 },
183};
184
185struct clksrc_clk clk_dout_mpll = {
186 .clk = {
187 .name = "dout_mpll",
188 .id = -1,
189 .parent = &clk_mout_mpll.clk,
190 },
191 .reg_div = { .reg = S5P64X0_CLK_DIV0, .shift = 4, .size = 1 },
192};
193
194struct clk *clkset_hclk_low_list[] = {
195 &clk_mout_apll.clk,
196 &clk_mout_mpll.clk,
197};
198
199struct clksrc_sources clkset_hclk_low = {
200 .sources = clkset_hclk_low_list,
201 .nr_sources = ARRAY_SIZE(clkset_hclk_low_list),
202};
203
204int s5p64x0_pclk_ctrl(struct clk *clk, int enable)
205{
206 return s5p_gatectrl(S5P64X0_CLK_GATE_PCLK, clk, enable);
207}
208
209int s5p64x0_hclk0_ctrl(struct clk *clk, int enable)
210{
211 return s5p_gatectrl(S5P64X0_CLK_GATE_HCLK0, clk, enable);
212}
213
214int s5p64x0_hclk1_ctrl(struct clk *clk, int enable)
215{
216 return s5p_gatectrl(S5P64X0_CLK_GATE_HCLK1, clk, enable);
217}
218
219int s5p64x0_sclk_ctrl(struct clk *clk, int enable)
220{
221 return s5p_gatectrl(S5P64X0_CLK_GATE_SCLK0, clk, enable);
222}
223
224int s5p64x0_sclk1_ctrl(struct clk *clk, int enable)
225{
226 return s5p_gatectrl(S5P64X0_CLK_GATE_SCLK1, clk, enable);
227}
228
229int s5p64x0_mem_ctrl(struct clk *clk, int enable)
230{
231 return s5p_gatectrl(S5P64X0_CLK_GATE_MEM0, clk, enable);
232}
233
234int s5p64x0_clk48m_ctrl(struct clk *clk, int enable)
235{
236 unsigned long flags;
237 u32 val;
238
239 /* can't rely on clock lock, this register has other usages */
240 local_irq_save(flags);
241
242 val = __raw_readl(S5P64X0_OTHERS);
243 if (enable)
244 val |= S5P64X0_OTHERS_USB_SIG_MASK;
245 else
246 val &= ~S5P64X0_OTHERS_USB_SIG_MASK;
247
248 __raw_writel(val, S5P64X0_OTHERS);
249
250 local_irq_restore(flags);
251
252 return 0;
253}
diff --git a/arch/arm/mach-s5p64x0/include/mach/regs-clock.h b/arch/arm/mach-s5p64x0/include/mach/regs-clock.h
new file mode 100644
index 000000000000..58e1bc813804
--- /dev/null
+++ b/arch/arm/mach-s5p64x0/include/mach/regs-clock.h
@@ -0,0 +1,63 @@
1/* linux/arch/arm/mach-s5p64x0/include/mach/regs-clock.h
2 *
3 * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * S5P64X0 - Clock register definitions
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#ifndef __ASM_ARCH_REGS_CLOCK_H
14#define __ASM_ARCH_REGS_CLOCK_H __FILE__
15
16#include <mach/map.h>
17
18#define S5P_CLKREG(x) (S3C_VA_SYS + (x))
19
20#define S5P64X0_APLL_CON S5P_CLKREG(0x0C)
21#define S5P64X0_MPLL_CON S5P_CLKREG(0x10)
22#define S5P64X0_EPLL_CON S5P_CLKREG(0x14)
23#define S5P64X0_EPLL_CON_K S5P_CLKREG(0x18)
24
25#define S5P64X0_CLK_SRC0 S5P_CLKREG(0x1C)
26
27#define S5P64X0_CLK_DIV0 S5P_CLKREG(0x20)
28#define S5P64X0_CLK_DIV1 S5P_CLKREG(0x24)
29#define S5P64X0_CLK_DIV2 S5P_CLKREG(0x28)
30
31#define S5P64X0_CLK_GATE_HCLK0 S5P_CLKREG(0x30)
32#define S5P64X0_CLK_GATE_PCLK S5P_CLKREG(0x34)
33#define S5P64X0_CLK_GATE_SCLK0 S5P_CLKREG(0x38)
34#define S5P64X0_CLK_GATE_MEM0 S5P_CLKREG(0x3C)
35
36#define S5P64X0_CLK_DIV3 S5P_CLKREG(0x40)
37
38#define S5P64X0_CLK_GATE_HCLK1 S5P_CLKREG(0x44)
39#define S5P64X0_CLK_GATE_SCLK1 S5P_CLKREG(0x48)
40
41#define S5P6450_DPLL_CON S5P_CLKREG(0x50)
42#define S5P6450_DPLL_CON_K S5P_CLKREG(0x54)
43
44#define S5P64X0_CLK_SRC1 S5P_CLKREG(0x10C)
45
46#define S5P64X0_SYS_ID S5P_CLKREG(0x118)
47#define S5P64X0_SYS_OTHERS S5P_CLKREG(0x11C)
48
49#define S5P64X0_PWR_CFG S5P_CLKREG(0x804)
50#define S5P64X0_OTHERS S5P_CLKREG(0x900)
51
52#define S5P64X0_CLKDIV0_HCLK_SHIFT (8)
53#define S5P64X0_CLKDIV0_HCLK_MASK (0xF << S5P64X0_CLKDIV0_HCLK_SHIFT)
54
55#define S5P64X0_OTHERS_USB_SIG_MASK (1 << 16)
56
57/* Compatibility defines */
58
59#define ARM_CLK_DIV S5P64X0_CLK_DIV0
60#define ARM_DIV_RATIO_SHIFT 0
61#define ARM_DIV_MASK (0xF << ARM_DIV_RATIO_SHIFT)
62
63#endif /* __ASM_ARCH_REGS_CLOCK_H */
diff --git a/arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h b/arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h
new file mode 100644
index 000000000000..ff85b4b6e8d9
--- /dev/null
+++ b/arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h
@@ -0,0 +1,46 @@
1/* linux/arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h
2 *
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * Header file for s5p64x0 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#ifndef __ASM_ARCH_CLOCK_H
14#define __ASM_ARCH_CLOCK_H __FILE__
15
16#include <linux/clk.h>
17
18extern struct clksrc_clk clk_mout_apll;
19extern struct clksrc_clk clk_mout_mpll;
20extern struct clksrc_clk clk_mout_epll;
21
22extern int s5p64x0_epll_enable(struct clk *clk, int enable);
23extern unsigned long s5p64x0_epll_get_rate(struct clk *clk);
24
25extern unsigned long s5p64x0_armclk_get_rate(struct clk *clk);
26extern unsigned long s5p64x0_armclk_round_rate(struct clk *clk, unsigned long rate);
27extern int s5p64x0_armclk_set_rate(struct clk *clk, unsigned long rate);
28
29extern struct clk_ops s5p64x0_clkarm_ops;
30
31extern struct clksrc_clk clk_armclk;
32extern struct clksrc_clk clk_dout_mpll;
33
34extern struct clk *clkset_hclk_low_list[];
35extern struct clksrc_sources clkset_hclk_low;
36
37extern int s5p64x0_pclk_ctrl(struct clk *clk, int enable);
38extern int s5p64x0_hclk0_ctrl(struct clk *clk, int enable);
39extern int s5p64x0_hclk1_ctrl(struct clk *clk, int enable);
40extern int s5p64x0_sclk_ctrl(struct clk *clk, int enable);
41extern int s5p64x0_sclk1_ctrl(struct clk *clk, int enable);
42extern int s5p64x0_mem_ctrl(struct clk *clk, int enable);
43
44extern int s5p64x0_clk48m_ctrl(struct clk *clk, int enable);
45
46#endif /* __ASM_ARCH_CLOCK_H */