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/device.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
35#include "common.h"
36
37static struct clksrc_clk clk_mout_dpll = {
38	.clk	= {
39		.name		= "mout_dpll",
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	printk(KERN_WARNING "EPLL Rate changes from %lu to %lu\n",
84			clk->rate, rate);
85
86	clk->rate = rate;
87
88	return 0;
89}
90
91static struct clk_ops s5p6450_epll_ops = {
92	.get_rate = s5p_epll_get_rate,
93	.set_rate = s5p6450_epll_set_rate,
94};
95
96static struct clksrc_clk clk_dout_epll = {
97	.clk	= {
98		.name		= "dout_epll",
99		.parent		= &clk_mout_epll.clk,
100	},
101	.reg_div	= { .reg = S5P64X0_CLK_DIV1, .shift = 24, .size = 4 },
102};
103
104static struct clksrc_clk clk_mout_hclk_sel = {
105	.clk	= {
106		.name		= "mout_hclk_sel",
107	},
108	.sources	= &clkset_hclk_low,
109	.reg_src	= { .reg = S5P64X0_OTHERS, .shift = 15, .size = 1 },
110};
111
112static struct clk *clkset_hclk_list[] = {
113	&clk_mout_hclk_sel.clk,
114	&clk_armclk.clk,
115};
116
117static struct clksrc_sources clkset_hclk = {
118	.sources	= clkset_hclk_list,
119	.nr_sources	= ARRAY_SIZE(clkset_hclk_list),
120};
121
122static struct clksrc_clk clk_hclk = {
123	.clk	= {
124		.name		= "clk_hclk",
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		.parent		= &clk_hclk.clk,
135	},
136	.reg_div = { .reg = S5P64X0_CLK_DIV0, .shift = 12, .size = 4 },
137};
138static struct clksrc_clk clk_dout_pwm_ratio0 = {
139	.clk	= {
140		.name		= "clk_dout_pwm_ratio0",
141		.parent		= &clk_mout_hclk_sel.clk,
142	},
143	.reg_div	= { .reg = S5P64X0_CLK_DIV3, .shift = 16, .size = 4 },
144};
145
146static struct clksrc_clk clk_pclk_to_wdt_pwm = {
147	.clk	= {
148		.name		= "clk_pclk_to_wdt_pwm",
149		.parent		= &clk_dout_pwm_ratio0.clk,
150	},
151	.reg_div	= { .reg = S5P64X0_CLK_DIV3, .shift = 20, .size = 4 },
152};
153
154static struct clksrc_clk clk_hclk_low = {
155	.clk	= {
156		.name		= "clk_hclk_low",
157	},
158	.sources	= &clkset_hclk_low,
159	.reg_src	= { .reg = S5P64X0_OTHERS, .shift = 6, .size = 1 },
160	.reg_div	= { .reg = S5P64X0_CLK_DIV3, .shift = 8, .size = 4 },
161};
162
163static struct clksrc_clk clk_pclk_low = {
164	.clk	= {
165		.name		= "clk_pclk_low",
166		.parent		= &clk_hclk_low.clk,
167	},
168	.reg_div	= { .reg = S5P64X0_CLK_DIV3, .shift = 12, .size = 4 },
169};
170
171/*
172 * The following clocks will be disabled during clock initialization. It is
173 * recommended to keep the following clocks disabled until the driver requests
174 * for enabling the clock.
175 */
176static struct clk init_clocks_off[] = {
177	{
178		.name		= "usbhost",
179		.parent		= &clk_hclk_low.clk,
180		.enable		= s5p64x0_hclk0_ctrl,
181		.ctrlbit	= (1 << 3),
182	}, {
183		.name		= "dma",
184		.devname	= "dma-pl330",
185		.parent		= &clk_hclk_low.clk,
186		.enable		= s5p64x0_hclk0_ctrl,
187		.ctrlbit	= (1 << 12),
188	}, {
189		.name		= "hsmmc",
190		.devname	= "s3c-sdhci.0",
191		.parent		= &clk_hclk_low.clk,
192		.enable		= s5p64x0_hclk0_ctrl,
193		.ctrlbit	= (1 << 17),
194	}, {
195		.name		= "hsmmc",
196		.devname	= "s3c-sdhci.1",
197		.parent		= &clk_hclk_low.clk,
198		.enable		= s5p64x0_hclk0_ctrl,
199		.ctrlbit	= (1 << 18),
200	}, {
201		.name		= "hsmmc",
202		.devname	= "s3c-sdhci.2",
203		.parent		= &clk_hclk_low.clk,
204		.enable		= s5p64x0_hclk0_ctrl,
205		.ctrlbit	= (1 << 19),
206	}, {
207		.name		= "usbotg",
208		.parent		= &clk_hclk_low.clk,
209		.enable		= s5p64x0_hclk0_ctrl,
210		.ctrlbit	= (1 << 20),
211	}, {
212		.name		= "lcd",
213		.parent		= &clk_h,
214		.enable		= s5p64x0_hclk1_ctrl,
215		.ctrlbit	= (1 << 1),
216	}, {
217		.name		= "watchdog",
218		.parent		= &clk_pclk_low.clk,
219		.enable		= s5p64x0_pclk_ctrl,
220		.ctrlbit	= (1 << 5),
221	}, {
222		.name		= "rtc",
223		.parent		= &clk_pclk_low.clk,
224		.enable		= s5p64x0_pclk_ctrl,
225		.ctrlbit	= (1 << 6),
226	}, {
227		.name		= "adc",
228		.parent		= &clk_pclk_low.clk,
229		.enable		= s5p64x0_pclk_ctrl,
230		.ctrlbit	= (1 << 12),
231	}, {
232		.name		= "i2c",
233		.devname	= "s3c2440-i2c.0",
234		.parent		= &clk_pclk_low.clk,
235		.enable		= s5p64x0_pclk_ctrl,
236		.ctrlbit	= (1 << 17),
237	}, {
238		.name		= "spi",
239		.devname	= "s3c64xx-spi.0",
240		.parent		= &clk_pclk_low.clk,
241		.enable		= s5p64x0_pclk_ctrl,
242		.ctrlbit	= (1 << 21),
243	}, {
244		.name		= "spi",
245		.devname	= "s3c64xx-spi.1",
246		.parent		= &clk_pclk_low.clk,
247		.enable		= s5p64x0_pclk_ctrl,
248		.ctrlbit	= (1 << 22),
249	}, {
250		.name		= "iis",
251		.devname	= "samsung-i2s.0",
252		.parent		= &clk_pclk_low.clk,
253		.enable		= s5p64x0_pclk_ctrl,
254		.ctrlbit	= (1 << 26),
255	}, {
256		.name		= "iis",
257		.devname	= "samsung-i2s.1",
258		.parent		= &clk_pclk_low.clk,
259		.enable		= s5p64x0_pclk_ctrl,
260		.ctrlbit	= (1 << 15),
261	}, {
262		.name		= "iis",
263		.devname	= "samsung-i2s.2",
264		.parent		= &clk_pclk_low.clk,
265		.enable		= s5p64x0_pclk_ctrl,
266		.ctrlbit	= (1 << 16),
267	}, {
268		.name		= "i2c",
269		.devname	= "s3c2440-i2c.1",
270		.parent		= &clk_pclk_low.clk,
271		.enable		= s5p64x0_pclk_ctrl,
272		.ctrlbit	= (1 << 27),
273	}, {
274		.name		= "dmc0",
275		.parent		= &clk_pclk.clk,
276		.enable		= s5p64x0_pclk_ctrl,
277		.ctrlbit	= (1 << 30),
278	}
279};
280
281/*
282 * The following clocks will be enabled during clock initialization.
283 */
284static struct clk init_clocks[] = {
285	{
286		.name		= "intc",
287		.parent		= &clk_hclk.clk,
288		.enable		= s5p64x0_hclk0_ctrl,
289		.ctrlbit	= (1 << 1),
290	}, {
291		.name		= "mem",
292		.parent		= &clk_hclk.clk,
293		.enable		= s5p64x0_hclk0_ctrl,
294		.ctrlbit	= (1 << 21),
295	}, {
296		.name		= "uart",
297		.devname	= "s3c6400-uart.0",
298		.parent		= &clk_pclk_low.clk,
299		.enable		= s5p64x0_pclk_ctrl,
300		.ctrlbit	= (1 << 1),
301	}, {
302		.name		= "uart",
303		.devname	= "s3c6400-uart.1",
304		.parent		= &clk_pclk_low.clk,
305		.enable		= s5p64x0_pclk_ctrl,
306		.ctrlbit	= (1 << 2),
307	}, {
308		.name		= "uart",
309		.devname	= "s3c6400-uart.2",
310		.parent		= &clk_pclk_low.clk,
311		.enable		= s5p64x0_pclk_ctrl,
312		.ctrlbit	= (1 << 3),
313	}, {
314		.name		= "uart",
315		.devname	= "s3c6400-uart.3",
316		.parent		= &clk_pclk_low.clk,
317		.enable		= s5p64x0_pclk_ctrl,
318		.ctrlbit	= (1 << 4),
319	}, {
320		.name		= "timers",
321		.parent		= &clk_pclk_to_wdt_pwm.clk,
322		.enable		= s5p64x0_pclk_ctrl,
323		.ctrlbit	= (1 << 7),
324	}, {
325		.name		= "gpio",
326		.parent		= &clk_pclk_low.clk,
327		.enable		= s5p64x0_pclk_ctrl,
328		.ctrlbit	= (1 << 18),
329	},
330};
331
332static struct clk *clkset_uart_list[] = {
333	&clk_dout_epll.clk,
334	&clk_dout_mpll.clk,
335};
336
337static struct clksrc_sources clkset_uart = {
338	.sources	= clkset_uart_list,
339	.nr_sources	= ARRAY_SIZE(clkset_uart_list),
340};
341
342static struct clk *clkset_mali_list[] = {
343	&clk_mout_epll.clk,
344	&clk_mout_apll.clk,
345	&clk_mout_mpll.clk,
346};
347
348static struct clksrc_sources clkset_mali = {
349	.sources	= clkset_mali_list,
350	.nr_sources	= ARRAY_SIZE(clkset_mali_list),
351};
352
353static struct clk *clkset_group2_list[] = {
354	&clk_dout_epll.clk,
355	&clk_dout_mpll.clk,
356	&clk_ext_xtal_mux,
357};
358
359static struct clksrc_sources clkset_group2 = {
360	.sources	= clkset_group2_list,
361	.nr_sources	= ARRAY_SIZE(clkset_group2_list),
362};
363
364static struct clk *clkset_dispcon_list[] = {
365	&clk_dout_epll.clk,
366	&clk_dout_mpll.clk,
367	&clk_ext_xtal_mux,
368	&clk_mout_dpll.clk,
369};
370
371static struct clksrc_sources clkset_dispcon = {
372	.sources	= clkset_dispcon_list,
373	.nr_sources	= ARRAY_SIZE(clkset_dispcon_list),
374};
375
376static struct clk *clkset_hsmmc44_list[] = {
377	&clk_dout_epll.clk,
378	&clk_dout_mpll.clk,
379	&clk_ext_xtal_mux,
380	&s5p_clk_27m,
381	&clk_48m,
382};
383
384static struct clksrc_sources clkset_hsmmc44 = {
385	.sources	= clkset_hsmmc44_list,
386	.nr_sources	= ARRAY_SIZE(clkset_hsmmc44_list),
387};
388
389static struct clk *clkset_sclk_audio0_list[] = {
390	[0] = &clk_dout_epll.clk,
391	[1] = &clk_dout_mpll.clk,
392	[2] = &clk_ext_xtal_mux,
393	[3] = NULL,
394	[4] = NULL,
395};
396
397static struct clksrc_sources clkset_sclk_audio0 = {
398	.sources	= clkset_sclk_audio0_list,
399	.nr_sources	= ARRAY_SIZE(clkset_sclk_audio0_list),
400};
401
402static struct clksrc_clk clk_sclk_audio0 = {
403	.clk		= {
404		.name		= "audio-bus",
405		.enable		= s5p64x0_sclk_ctrl,
406		.ctrlbit	= (1 << 8),
407		.parent		= &clk_dout_epll.clk,
408	},
409	.sources	= &clkset_sclk_audio0,
410	.reg_src	= { .reg = S5P64X0_CLK_SRC1, .shift = 10, .size = 3 },
411	.reg_div	= { .reg = S5P64X0_CLK_DIV2, .shift = 8, .size = 4 },
412};
413
414static struct clksrc_clk clksrcs[] = {
415	{
416		.clk	= {
417			.name		= "sclk_fimc",
418			.ctrlbit	= (1 << 10),
419			.enable		= s5p64x0_sclk_ctrl,
420		},
421		.sources = &clkset_group2,
422		.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 26, .size = 2 },
423		.reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 12, .size = 4 },
424	}, {
425		.clk	= {
426			.name		= "aclk_mali",
427			.ctrlbit	= (1 << 2),
428			.enable		= s5p64x0_sclk1_ctrl,
429		},
430		.sources = &clkset_mali,
431		.reg_src = { .reg = S5P64X0_CLK_SRC1, .shift = 8, .size = 2 },
432		.reg_div = { .reg = S5P64X0_CLK_DIV3, .shift = 4, .size = 4 },
433	}, {
434		.clk	= {
435			.name		= "sclk_2d",
436			.ctrlbit	= (1 << 12),
437			.enable		= s5p64x0_sclk_ctrl,
438		},
439		.sources = &clkset_mali,
440		.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 30, .size = 2 },
441		.reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 20, .size = 4 },
442	}, {
443		.clk	= {
444			.name		= "sclk_usi",
445			.ctrlbit	= (1 << 7),
446			.enable		= s5p64x0_sclk_ctrl,
447		},
448		.sources = &clkset_group2,
449		.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 10, .size = 2 },
450		.reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 16, .size = 4 },
451	}, {
452		.clk	= {
453			.name		= "sclk_camif",
454			.ctrlbit	= (1 << 6),
455			.enable		= s5p64x0_sclk_ctrl,
456		},
457		.sources = &clkset_group2,
458		.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 28, .size = 2 },
459		.reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 20, .size = 4 },
460	}, {
461		.clk	= {
462			.name		= "sclk_dispcon",
463			.ctrlbit	= (1 << 1),
464			.enable		= s5p64x0_sclk1_ctrl,
465		},
466		.sources = &clkset_dispcon,
467		.reg_src = { .reg = S5P64X0_CLK_SRC1, .shift = 4, .size = 2 },
468		.reg_div = { .reg = S5P64X0_CLK_DIV3, .shift = 0, .size = 4 },
469	}, {
470		.clk	= {
471			.name		= "sclk_hsmmc44",
472			.ctrlbit	= (1 << 30),
473			.enable		= s5p64x0_sclk_ctrl,
474		},
475		.sources = &clkset_hsmmc44,
476		.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 6, .size = 3 },
477		.reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 28, .size = 4 },
478	},
479};
480
481static struct clksrc_clk clk_sclk_mmc0 = {
482	.clk	= {
483		.name		= "sclk_mmc",
484		.devname	= "s3c-sdhci.0",
485		.ctrlbit	= (1 << 24),
486		.enable		= s5p64x0_sclk_ctrl,
487	},
488	.sources = &clkset_group2,
489	.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 18, .size = 2 },
490	.reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 0, .size = 4 },
491};
492
493static struct clksrc_clk clk_sclk_mmc1 = {
494	.clk	= {
495		.name		= "sclk_mmc",
496		.devname	= "s3c-sdhci.1",
497		.ctrlbit	= (1 << 25),
498		.enable		= s5p64x0_sclk_ctrl,
499	},
500	.sources = &clkset_group2,
501	.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 20, .size = 2 },
502	.reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 4, .size = 4 },
503};
504
505static struct clksrc_clk clk_sclk_mmc2 = {
506	.clk	= {
507		.name		= "sclk_mmc",
508		.devname	= "s3c-sdhci.2",
509		.ctrlbit	= (1 << 26),
510		.enable		= s5p64x0_sclk_ctrl,
511	},
512	.sources = &clkset_group2,
513	.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 22, .size = 2 },
514	.reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 8, .size = 4 },
515};
516
517static struct clksrc_clk clk_sclk_uclk = {
518	.clk	= {
519		.name		= "uclk1",
520		.ctrlbit	= (1 << 5),
521		.enable		= s5p64x0_sclk_ctrl,
522	},
523	.sources = &clkset_uart,
524	.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 13, .size = 1 },
525	.reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 16, .size = 4 },
526};
527
528static struct clksrc_clk clk_sclk_spi0 = {
529	.clk	= {
530		.name		= "sclk_spi",
531		.devname	= "s3c64xx-spi.0",
532		.ctrlbit	= (1 << 20),
533		.enable		= s5p64x0_sclk_ctrl,
534	},
535	.sources = &clkset_group2,
536	.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 14, .size = 2 },
537	.reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 0, .size = 4 },
538};
539
540static struct clksrc_clk clk_sclk_spi1 = {
541	.clk	= {
542		.name		= "sclk_spi",
543		.devname	= "s3c64xx-spi.1",
544		.ctrlbit	= (1 << 21),
545		.enable		= s5p64x0_sclk_ctrl,
546	},
547	.sources = &clkset_group2,
548	.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 16, .size = 2 },
549	.reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 4, .size = 4 },
550};
551
552static struct clksrc_clk *clksrc_cdev[] = {
553	&clk_sclk_uclk,
554	&clk_sclk_spi0,
555	&clk_sclk_spi1,
556	&clk_sclk_mmc0,
557	&clk_sclk_mmc1,
558	&clk_sclk_mmc2,
559};
560
561static struct clk_lookup s5p6450_clk_lookup[] = {
562	CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_pclk_low.clk),
563	CLKDEV_INIT(NULL, "clk_uart_baud3", &clk_sclk_uclk.clk),
564	CLKDEV_INIT(NULL, "spi_busclk0", &clk_p),
565	CLKDEV_INIT("s3c64xx-spi.0", "spi_busclk1", &clk_sclk_spi0.clk),
566	CLKDEV_INIT("s3c64xx-spi.1", "spi_busclk1", &clk_sclk_spi1.clk),
567	CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &clk_sclk_mmc0.clk),
568	CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &clk_sclk_mmc1.clk),
569	CLKDEV_INIT("s3c-sdhci.2", "mmc_busclk.2", &clk_sclk_mmc2.clk),
570};
571
572/* Clock initialization code */
573static struct clksrc_clk *sysclks[] = {
574	&clk_mout_apll,
575	&clk_mout_epll,
576	&clk_dout_epll,
577	&clk_mout_mpll,
578	&clk_dout_mpll,
579	&clk_armclk,
580	&clk_mout_hclk_sel,
581	&clk_dout_pwm_ratio0,
582	&clk_pclk_to_wdt_pwm,
583	&clk_hclk,
584	&clk_pclk,
585	&clk_hclk_low,
586	&clk_pclk_low,
587	&clk_sclk_audio0,
588};
589
590static struct clk dummy_apb_pclk = {
591	.name		= "apb_pclk",
592	.id		= -1,
593};
594
595void __init_or_cpufreq s5p6450_setup_clocks(void)
596{
597	struct clk *xtal_clk;
598
599	unsigned long xtal;
600	unsigned long fclk;
601	unsigned long hclk;
602	unsigned long hclk_low;
603	unsigned long pclk;
604	unsigned long pclk_low;
605
606	unsigned long apll;
607	unsigned long mpll;
608	unsigned long epll;
609	unsigned long dpll;
610	unsigned int ptr;
611
612	/* Set S5P6450 functions for clk_fout_epll */
613
614	clk_fout_epll.enable = s5p_epll_enable;
615	clk_fout_epll.ops = &s5p6450_epll_ops;
616
617	clk_48m.enable = s5p64x0_clk48m_ctrl;
618
619	xtal_clk = clk_get(NULL, "ext_xtal");
620	BUG_ON(IS_ERR(xtal_clk));
621
622	xtal = clk_get_rate(xtal_clk);
623	clk_put(xtal_clk);
624
625	apll = s5p_get_pll45xx(xtal, __raw_readl(S5P64X0_APLL_CON), pll_4502);
626	mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P64X0_MPLL_CON), pll_4502);
627	epll = s5p_get_pll90xx(xtal, __raw_readl(S5P64X0_EPLL_CON),
628				__raw_readl(S5P64X0_EPLL_CON_K));
629	dpll = s5p_get_pll46xx(xtal, __raw_readl(S5P6450_DPLL_CON),
630				__raw_readl(S5P6450_DPLL_CON_K), pll_4650c);
631
632	clk_fout_apll.rate = apll;
633	clk_fout_mpll.rate = mpll;
634	clk_fout_epll.rate = epll;
635	clk_fout_dpll.rate = dpll;
636
637	printk(KERN_INFO "S5P6450: PLL settings, A=%ld.%ldMHz, M=%ld.%ldMHz," \
638			" E=%ld.%ldMHz, D=%ld.%ldMHz\n",
639			print_mhz(apll), print_mhz(mpll), print_mhz(epll),
640			print_mhz(dpll));
641
642	fclk = clk_get_rate(&clk_armclk.clk);
643	hclk = clk_get_rate(&clk_hclk.clk);
644	pclk = clk_get_rate(&clk_pclk.clk);
645	hclk_low = clk_get_rate(&clk_hclk_low.clk);
646	pclk_low = clk_get_rate(&clk_pclk_low.clk);
647
648	printk(KERN_INFO "S5P6450: HCLK=%ld.%ldMHz, HCLK_LOW=%ld.%ldMHz," \
649			" PCLK=%ld.%ldMHz, PCLK_LOW=%ld.%ldMHz\n",
650			print_mhz(hclk), print_mhz(hclk_low),
651			print_mhz(pclk), print_mhz(pclk_low));
652
653	clk_f.rate = fclk;
654	clk_h.rate = hclk;
655	clk_p.rate = pclk;
656
657	for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
658		s3c_set_clksrc(&clksrcs[ptr], true);
659}
660
661void __init s5p6450_register_clocks(void)
662{
663	int ptr;
664
665	for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++)
666		s3c_register_clksrc(sysclks[ptr], 1);
667
668	s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
669	s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
670	for (ptr = 0; ptr < ARRAY_SIZE(clksrc_cdev); ptr++)
671		s3c_register_clksrc(clksrc_cdev[ptr], 1);
672
673	s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
674	s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
675	clkdev_add_table(s5p6450_clk_lookup, ARRAY_SIZE(s5p6450_clk_lookup));
676
677	s3c24xx_register_clock(&dummy_apb_pclk);
678
679	s3c_pwmclk_init();
680}
681