• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/arch/arm/mach-s5p6440/
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
137enum perf_level {
138	L0 = 532*1000,
139	L1 = 266*1000,
140	L2 = 133*1000,
141};
142
143static 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
150static 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
161static 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
174static 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
226static 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
232static 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
242static 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
251static 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
260static 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
269static struct clk *clkset_hclklow_list[] = {
270	&clk_mout_apll.clk,
271	&clk_mout_mpll.clk,
272};
273
274static struct clksrc_sources clkset_hclklow = {
275	.sources	= clkset_hclklow_list,
276	.nr_sources	= ARRAY_SIZE(clkset_hclklow_list),
277};
278
279static 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
289static 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
298int 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
319static int s5p6440_pclk_ctrl(struct clk *clk, int enable)
320{
321	return s5p_gatectrl(S5P_CLK_GATE_PCLK, clk, enable);
322}
323
324static int s5p6440_hclk0_ctrl(struct clk *clk, int enable)
325{
326	return s5p_gatectrl(S5P_CLK_GATE_HCLK0, clk, enable);
327}
328
329static int s5p6440_hclk1_ctrl(struct clk *clk, int enable)
330{
331	return s5p_gatectrl(S5P_CLK_GATE_HCLK1, clk, enable);
332}
333
334static int s5p6440_sclk_ctrl(struct clk *clk, int enable)
335{
336	return s5p_gatectrl(S5P_CLK_GATE_SCLK0, clk, enable);
337}
338
339static int s5p6440_sclk1_ctrl(struct clk *clk, int enable)
340{
341	return s5p_gatectrl(S5P_CLK_GATE_SCLK1, clk, enable);
342}
343
344static 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 */
354static 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 */
547static 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
593static struct clk clk_iis_cd_v40 = {
594	.name		= "iis_cdclk_v40",
595	.id		= -1,
596};
597
598static struct clk clk_pcm_cd = {
599	.name		= "pcm_cdclk",
600	.id		= -1,
601};
602
603static struct clk *clkset_group1_list[] = {
604	&clk_mout_epll.clk,
605	&clk_dout_mpll.clk,
606	&clk_fin_epll,
607};
608
609static struct clksrc_sources clkset_group1 = {
610	.sources	= clkset_group1_list,
611	.nr_sources	= ARRAY_SIZE(clkset_group1_list),
612};
613
614static struct clk *clkset_uart_list[] = {
615	&clk_mout_epll.clk,
616	&clk_dout_mpll.clk,
617};
618
619static struct clksrc_sources clkset_uart = {
620	.sources	= clkset_uart_list,
621	.nr_sources	= ARRAY_SIZE(clkset_uart_list),
622};
623
624static 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
632static struct clksrc_sources clkset_audio = {
633	.sources	= clkset_audio_list,
634	.nr_sources	= ARRAY_SIZE(clkset_audio_list),
635};
636
637static 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 */
742static 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
754void __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
812static struct clk *clks[] __initdata = {
813	&clk_ext,
814	&clk_iis_cd_v40,
815	&clk_pcm_cd,
816};
817
818void __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}
847