• 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-s3c64xx/
1/* linux/arch/arm/plat-s3c64xx/clock.c
2 *
3 * Copyright 2008 Openmoko, Inc.
4 * Copyright 2008 Simtec Electronics
5 *	Ben Dooks <ben@simtec.co.uk>
6 *	http://armlinux.simtec.co.uk/
7 *
8 * S3C64XX Base clock support
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13*/
14
15#include <linux/init.h>
16#include <linux/module.h>
17#include <linux/interrupt.h>
18#include <linux/ioport.h>
19#include <linux/clk.h>
20#include <linux/err.h>
21#include <linux/io.h>
22
23#include <mach/hardware.h>
24#include <mach/map.h>
25
26#include <mach/regs-sys.h>
27#include <mach/regs-clock.h>
28#include <mach/pll.h>
29
30#include <plat/cpu.h>
31#include <plat/devs.h>
32#include <plat/cpu-freq.h>
33#include <plat/clock.h>
34#include <plat/clock-clksrc.h>
35
36/* fin_apll, fin_mpll and fin_epll are all the same clock, which we call
37 * ext_xtal_mux for want of an actual name from the manual.
38*/
39
40static struct clk clk_ext_xtal_mux = {
41	.name		= "ext_xtal",
42	.id		= -1,
43};
44
45#define clk_fin_apll clk_ext_xtal_mux
46#define clk_fin_mpll clk_ext_xtal_mux
47#define clk_fin_epll clk_ext_xtal_mux
48
49#define clk_fout_mpll	clk_mpll
50#define clk_fout_epll	clk_epll
51
52struct clk clk_h2 = {
53	.name		= "hclk2",
54	.id		= -1,
55	.rate		= 0,
56};
57
58struct clk clk_27m = {
59	.name		= "clk_27m",
60	.id		= -1,
61	.rate		= 27000000,
62};
63
64static int clk_48m_ctrl(struct clk *clk, int enable)
65{
66	unsigned long flags;
67	u32 val;
68
69	/* can't rely on clock lock, this register has other usages */
70	local_irq_save(flags);
71
72	val = __raw_readl(S3C64XX_OTHERS);
73	if (enable)
74		val |= S3C64XX_OTHERS_USBMASK;
75	else
76		val &= ~S3C64XX_OTHERS_USBMASK;
77
78	__raw_writel(val, S3C64XX_OTHERS);
79	local_irq_restore(flags);
80
81	return 0;
82}
83
84struct clk clk_48m = {
85	.name		= "clk_48m",
86	.id		= -1,
87	.rate		= 48000000,
88	.enable		= clk_48m_ctrl,
89};
90
91struct clk clk_xusbxti = {
92	.name		= "xusbxti",
93	.id		= -1,
94	.rate		= 48000000,
95};
96
97static int inline s3c64xx_gate(void __iomem *reg,
98				struct clk *clk,
99				int enable)
100{
101	unsigned int ctrlbit = clk->ctrlbit;
102	u32 con;
103
104	con = __raw_readl(reg);
105
106	if (enable)
107		con |= ctrlbit;
108	else
109		con &= ~ctrlbit;
110
111	__raw_writel(con, reg);
112	return 0;
113}
114
115static int s3c64xx_pclk_ctrl(struct clk *clk, int enable)
116{
117	return s3c64xx_gate(S3C_PCLK_GATE, clk, enable);
118}
119
120static int s3c64xx_hclk_ctrl(struct clk *clk, int enable)
121{
122	return s3c64xx_gate(S3C_HCLK_GATE, clk, enable);
123}
124
125int s3c64xx_sclk_ctrl(struct clk *clk, int enable)
126{
127	return s3c64xx_gate(S3C_SCLK_GATE, clk, enable);
128}
129
130static struct clk init_clocks_disable[] = {
131	{
132		.name		= "nand",
133		.id		= -1,
134		.parent		= &clk_h,
135	}, {
136		.name		= "rtc",
137		.id		= -1,
138		.parent		= &clk_p,
139		.enable		= s3c64xx_pclk_ctrl,
140		.ctrlbit	= S3C_CLKCON_PCLK_RTC,
141	}, {
142		.name		= "adc",
143		.id		= -1,
144		.parent		= &clk_p,
145		.enable		= s3c64xx_pclk_ctrl,
146		.ctrlbit	= S3C_CLKCON_PCLK_TSADC,
147	}, {
148		.name		= "i2c",
149		.id		= -1,
150		.parent		= &clk_p,
151		.enable		= s3c64xx_pclk_ctrl,
152		.ctrlbit	= S3C_CLKCON_PCLK_IIC,
153	}, {
154		.name		= "iis",
155		.id		= 0,
156		.parent		= &clk_p,
157		.enable		= s3c64xx_pclk_ctrl,
158		.ctrlbit	= S3C_CLKCON_PCLK_IIS0,
159	}, {
160		.name		= "iis",
161		.id		= 1,
162		.parent		= &clk_p,
163		.enable		= s3c64xx_pclk_ctrl,
164		.ctrlbit	= S3C_CLKCON_PCLK_IIS1,
165	}, {
166#ifdef CONFIG_CPU_S3C6410
167		.name		= "iis",
168		.id		= -1,  /* There's only one IISv4 port */
169		.parent		= &clk_p,
170		.enable		= s3c64xx_pclk_ctrl,
171		.ctrlbit	= S3C6410_CLKCON_PCLK_IIS2,
172	}, {
173#endif
174		.name		= "keypad",
175		.id		= -1,
176		.parent		= &clk_p,
177		.enable		= s3c64xx_pclk_ctrl,
178		.ctrlbit	= S3C_CLKCON_PCLK_KEYPAD,
179	}, {
180		.name		= "spi",
181		.id		= 0,
182		.parent		= &clk_p,
183		.enable		= s3c64xx_pclk_ctrl,
184		.ctrlbit	= S3C_CLKCON_PCLK_SPI0,
185	}, {
186		.name		= "spi",
187		.id		= 1,
188		.parent		= &clk_p,
189		.enable		= s3c64xx_pclk_ctrl,
190		.ctrlbit	= S3C_CLKCON_PCLK_SPI1,
191	}, {
192		.name		= "spi_48m",
193		.id		= 0,
194		.parent		= &clk_48m,
195		.enable		= s3c64xx_sclk_ctrl,
196		.ctrlbit	= S3C_CLKCON_SCLK_SPI0_48,
197	}, {
198		.name		= "spi_48m",
199		.id		= 1,
200		.parent		= &clk_48m,
201		.enable		= s3c64xx_sclk_ctrl,
202		.ctrlbit	= S3C_CLKCON_SCLK_SPI1_48,
203	}, {
204		.name		= "48m",
205		.id		= 0,
206		.parent		= &clk_48m,
207		.enable		= s3c64xx_sclk_ctrl,
208		.ctrlbit	= S3C_CLKCON_SCLK_MMC0_48,
209	}, {
210		.name		= "48m",
211		.id		= 1,
212		.parent		= &clk_48m,
213		.enable		= s3c64xx_sclk_ctrl,
214		.ctrlbit	= S3C_CLKCON_SCLK_MMC1_48,
215	}, {
216		.name		= "48m",
217		.id		= 2,
218		.parent		= &clk_48m,
219		.enable		= s3c64xx_sclk_ctrl,
220		.ctrlbit	= S3C_CLKCON_SCLK_MMC2_48,
221	}, {
222		.name		= "dma0",
223		.id		= -1,
224		.parent		= &clk_h,
225		.enable		= s3c64xx_hclk_ctrl,
226		.ctrlbit	= S3C_CLKCON_HCLK_DMA0,
227	}, {
228		.name		= "dma1",
229		.id		= -1,
230		.parent		= &clk_h,
231		.enable		= s3c64xx_hclk_ctrl,
232		.ctrlbit	= S3C_CLKCON_HCLK_DMA1,
233	},
234};
235
236static struct clk init_clocks[] = {
237	{
238		.name		= "lcd",
239		.id		= -1,
240		.parent		= &clk_h,
241		.enable		= s3c64xx_hclk_ctrl,
242		.ctrlbit	= S3C_CLKCON_HCLK_LCD,
243	}, {
244		.name		= "gpio",
245		.id		= -1,
246		.parent		= &clk_p,
247		.enable		= s3c64xx_pclk_ctrl,
248		.ctrlbit	= S3C_CLKCON_PCLK_GPIO,
249	}, {
250		.name		= "usb-host",
251		.id		= -1,
252		.parent		= &clk_h,
253		.enable		= s3c64xx_hclk_ctrl,
254		.ctrlbit	= S3C_CLKCON_HCLK_UHOST,
255	}, {
256		.name		= "hsmmc",
257		.id		= 0,
258		.parent		= &clk_h,
259		.enable		= s3c64xx_hclk_ctrl,
260		.ctrlbit	= S3C_CLKCON_HCLK_HSMMC0,
261	}, {
262		.name		= "hsmmc",
263		.id		= 1,
264		.parent		= &clk_h,
265		.enable		= s3c64xx_hclk_ctrl,
266		.ctrlbit	= S3C_CLKCON_HCLK_HSMMC1,
267	}, {
268		.name		= "hsmmc",
269		.id		= 2,
270		.parent		= &clk_h,
271		.enable		= s3c64xx_hclk_ctrl,
272		.ctrlbit	= S3C_CLKCON_HCLK_HSMMC2,
273	}, {
274		.name		= "otg",
275		.id		= -1,
276		.parent		= &clk_h,
277		.enable		= s3c64xx_hclk_ctrl,
278		.ctrlbit	= S3C_CLKCON_HCLK_USB,
279	}, {
280		.name		= "timers",
281		.id		= -1,
282		.parent		= &clk_p,
283		.enable		= s3c64xx_pclk_ctrl,
284		.ctrlbit	= S3C_CLKCON_PCLK_PWM,
285	}, {
286		.name		= "uart",
287		.id		= 0,
288		.parent		= &clk_p,
289		.enable		= s3c64xx_pclk_ctrl,
290		.ctrlbit	= S3C_CLKCON_PCLK_UART0,
291	}, {
292		.name		= "uart",
293		.id		= 1,
294		.parent		= &clk_p,
295		.enable		= s3c64xx_pclk_ctrl,
296		.ctrlbit	= S3C_CLKCON_PCLK_UART1,
297	}, {
298		.name		= "uart",
299		.id		= 2,
300		.parent		= &clk_p,
301		.enable		= s3c64xx_pclk_ctrl,
302		.ctrlbit	= S3C_CLKCON_PCLK_UART2,
303	}, {
304		.name		= "uart",
305		.id		= 3,
306		.parent		= &clk_p,
307		.enable		= s3c64xx_pclk_ctrl,
308		.ctrlbit	= S3C_CLKCON_PCLK_UART3,
309	}, {
310		.name		= "watchdog",
311		.id		= -1,
312		.parent		= &clk_p,
313		.ctrlbit	= S3C_CLKCON_PCLK_WDT,
314	}, {
315		.name		= "ac97",
316		.id		= -1,
317		.parent		= &clk_p,
318		.ctrlbit	= S3C_CLKCON_PCLK_AC97,
319	}, {
320		.name		= "cfcon",
321		.id		= -1,
322		.parent		= &clk_h,
323		.enable		= s3c64xx_hclk_ctrl,
324		.ctrlbit	= S3C_CLKCON_HCLK_IHOST,
325	}
326};
327
328
329static struct clk clk_fout_apll = {
330	.name		= "fout_apll",
331	.id		= -1,
332};
333
334static struct clk *clk_src_apll_list[] = {
335	[0] = &clk_fin_apll,
336	[1] = &clk_fout_apll,
337};
338
339static struct clksrc_sources clk_src_apll = {
340	.sources	= clk_src_apll_list,
341	.nr_sources	= ARRAY_SIZE(clk_src_apll_list),
342};
343
344static struct clksrc_clk clk_mout_apll = {
345	.clk	= {
346		.name		= "mout_apll",
347		.id		= -1,
348	},
349	.reg_src	= { .reg = S3C_CLK_SRC, .shift = 0, .size = 1  },
350	.sources	= &clk_src_apll,
351};
352
353static struct clk *clk_src_epll_list[] = {
354	[0] = &clk_fin_epll,
355	[1] = &clk_fout_epll,
356};
357
358static struct clksrc_sources clk_src_epll = {
359	.sources	= clk_src_epll_list,
360	.nr_sources	= ARRAY_SIZE(clk_src_epll_list),
361};
362
363static struct clksrc_clk clk_mout_epll = {
364	.clk	= {
365		.name		= "mout_epll",
366		.id		= -1,
367	},
368	.reg_src	= { .reg = S3C_CLK_SRC, .shift = 2, .size = 1  },
369	.sources	= &clk_src_epll,
370};
371
372static struct clk *clk_src_mpll_list[] = {
373	[0] = &clk_fin_mpll,
374	[1] = &clk_fout_mpll,
375};
376
377static struct clksrc_sources clk_src_mpll = {
378	.sources	= clk_src_mpll_list,
379	.nr_sources	= ARRAY_SIZE(clk_src_mpll_list),
380};
381
382static struct clksrc_clk clk_mout_mpll = {
383	.clk = {
384		.name		= "mout_mpll",
385		.id		= -1,
386	},
387	.reg_src	= { .reg = S3C_CLK_SRC, .shift = 1, .size = 1  },
388	.sources	= &clk_src_mpll,
389};
390
391static unsigned int armclk_mask;
392
393static unsigned long s3c64xx_clk_arm_get_rate(struct clk *clk)
394{
395	unsigned long rate = clk_get_rate(clk->parent);
396	u32 clkdiv;
397
398	/* divisor mask starts at bit0, so no need to shift */
399	clkdiv = __raw_readl(S3C_CLK_DIV0) & armclk_mask;
400
401	return rate / (clkdiv + 1);
402}
403
404static unsigned long s3c64xx_clk_arm_round_rate(struct clk *clk,
405						unsigned long rate)
406{
407	unsigned long parent = clk_get_rate(clk->parent);
408	u32 div;
409
410	if (parent < rate)
411		return parent;
412
413	div = (parent / rate) - 1;
414	if (div > armclk_mask)
415		div = armclk_mask;
416
417	return parent / (div + 1);
418}
419
420static int s3c64xx_clk_arm_set_rate(struct clk *clk, unsigned long rate)
421{
422	unsigned long parent = clk_get_rate(clk->parent);
423	u32 div;
424	u32 val;
425
426	if (rate < parent / (armclk_mask + 1))
427		return -EINVAL;
428
429	rate = clk_round_rate(clk, rate);
430	div = clk_get_rate(clk->parent) / rate;
431
432	val = __raw_readl(S3C_CLK_DIV0);
433	val &= ~armclk_mask;
434	val |= (div - 1);
435	__raw_writel(val, S3C_CLK_DIV0);
436
437	return 0;
438
439}
440
441static struct clk clk_arm = {
442	.name		= "armclk",
443	.id		= -1,
444	.parent		= &clk_mout_apll.clk,
445	.ops		= &(struct clk_ops) {
446		.get_rate	= s3c64xx_clk_arm_get_rate,
447		.set_rate	= s3c64xx_clk_arm_set_rate,
448		.round_rate	= s3c64xx_clk_arm_round_rate,
449	},
450};
451
452static unsigned long s3c64xx_clk_doutmpll_get_rate(struct clk *clk)
453{
454	unsigned long rate = clk_get_rate(clk->parent);
455
456	printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
457
458	if (__raw_readl(S3C_CLK_DIV0) & S3C6400_CLKDIV0_MPLL_MASK)
459		rate /= 2;
460
461	return rate;
462}
463
464static struct clk_ops clk_dout_ops = {
465	.get_rate	= s3c64xx_clk_doutmpll_get_rate,
466};
467
468static struct clk clk_dout_mpll = {
469	.name		= "dout_mpll",
470	.id		= -1,
471	.parent		= &clk_mout_mpll.clk,
472	.ops		= &clk_dout_ops,
473};
474
475static struct clk *clkset_spi_mmc_list[] = {
476	&clk_mout_epll.clk,
477	&clk_dout_mpll,
478	&clk_fin_epll,
479	&clk_27m,
480};
481
482static struct clksrc_sources clkset_spi_mmc = {
483	.sources	= clkset_spi_mmc_list,
484	.nr_sources	= ARRAY_SIZE(clkset_spi_mmc_list),
485};
486
487static struct clk *clkset_irda_list[] = {
488	&clk_mout_epll.clk,
489	&clk_dout_mpll,
490	NULL,
491	&clk_27m,
492};
493
494static struct clksrc_sources clkset_irda = {
495	.sources	= clkset_irda_list,
496	.nr_sources	= ARRAY_SIZE(clkset_irda_list),
497};
498
499static struct clk *clkset_uart_list[] = {
500	&clk_mout_epll.clk,
501	&clk_dout_mpll,
502	NULL,
503	NULL
504};
505
506static struct clksrc_sources clkset_uart = {
507	.sources	= clkset_uart_list,
508	.nr_sources	= ARRAY_SIZE(clkset_uart_list),
509};
510
511static struct clk *clkset_uhost_list[] = {
512	&clk_48m,
513	&clk_mout_epll.clk,
514	&clk_dout_mpll,
515	&clk_fin_epll,
516};
517
518static struct clksrc_sources clkset_uhost = {
519	.sources	= clkset_uhost_list,
520	.nr_sources	= ARRAY_SIZE(clkset_uhost_list),
521};
522
523/* The peripheral clocks are all controlled via clocksource followed
524 * by an optional divider and gate stage. We currently roll this into
525 * one clock which hides the intermediate clock from the mux.
526 *
527 * Note, the JPEG clock can only be an even divider...
528 *
529 * The scaler and LCD clocks depend on the S3C64XX version, and also
530 * have a common parent divisor so are not included here.
531 */
532
533/* clocks that feed other parts of the clock source tree */
534
535static struct clk clk_iis_cd0 = {
536	.name		= "iis_cdclk0",
537	.id		= -1,
538};
539
540static struct clk clk_iis_cd1 = {
541	.name		= "iis_cdclk1",
542	.id		= -1,
543};
544
545static struct clk clk_iisv4_cd = {
546	.name		= "iis_cdclk_v4",
547	.id		= -1,
548};
549
550static struct clk clk_pcm_cd = {
551	.name		= "pcm_cdclk",
552	.id		= -1,
553};
554
555static struct clk *clkset_audio0_list[] = {
556	[0] = &clk_mout_epll.clk,
557	[1] = &clk_dout_mpll,
558	[2] = &clk_fin_epll,
559	[3] = &clk_iis_cd0,
560	[4] = &clk_pcm_cd,
561};
562
563static struct clksrc_sources clkset_audio0 = {
564	.sources	= clkset_audio0_list,
565	.nr_sources	= ARRAY_SIZE(clkset_audio0_list),
566};
567
568static struct clk *clkset_audio1_list[] = {
569	[0] = &clk_mout_epll.clk,
570	[1] = &clk_dout_mpll,
571	[2] = &clk_fin_epll,
572	[3] = &clk_iis_cd1,
573	[4] = &clk_pcm_cd,
574};
575
576static struct clksrc_sources clkset_audio1 = {
577	.sources	= clkset_audio1_list,
578	.nr_sources	= ARRAY_SIZE(clkset_audio1_list),
579};
580
581static struct clk *clkset_audio2_list[] = {
582	[0] = &clk_mout_epll.clk,
583	[1] = &clk_dout_mpll,
584	[2] = &clk_fin_epll,
585	[3] = &clk_iisv4_cd,
586	[4] = &clk_pcm_cd,
587};
588
589static struct clksrc_sources clkset_audio2 = {
590	.sources	= clkset_audio2_list,
591	.nr_sources	= ARRAY_SIZE(clkset_audio2_list),
592};
593
594static struct clk *clkset_camif_list[] = {
595	&clk_h2,
596};
597
598static struct clksrc_sources clkset_camif = {
599	.sources	= clkset_camif_list,
600	.nr_sources	= ARRAY_SIZE(clkset_camif_list),
601};
602
603static struct clksrc_clk clksrcs[] = {
604	{
605		.clk	= {
606			.name		= "mmc_bus",
607			.id		= 0,
608			.ctrlbit        = S3C_CLKCON_SCLK_MMC0,
609			.enable		= s3c64xx_sclk_ctrl,
610		},
611		.reg_src	= { .reg = S3C_CLK_SRC, .shift = 18, .size = 2  },
612		.reg_div	= { .reg = S3C_CLK_DIV1, .shift = 0, .size = 4  },
613		.sources	= &clkset_spi_mmc,
614	}, {
615		.clk	= {
616			.name		= "mmc_bus",
617			.id		= 1,
618			.ctrlbit        = S3C_CLKCON_SCLK_MMC1,
619			.enable		= s3c64xx_sclk_ctrl,
620		},
621		.reg_src	= { .reg = S3C_CLK_SRC, .shift = 20, .size = 2  },
622		.reg_div	= { .reg = S3C_CLK_DIV1, .shift = 4, .size = 4  },
623		.sources	= &clkset_spi_mmc,
624	}, {
625		.clk	= {
626			.name		= "mmc_bus",
627			.id		= 2,
628			.ctrlbit        = S3C_CLKCON_SCLK_MMC2,
629			.enable		= s3c64xx_sclk_ctrl,
630		},
631		.reg_src	= { .reg = S3C_CLK_SRC, .shift = 22, .size = 2  },
632		.reg_div 	= { .reg = S3C_CLK_DIV1, .shift = 8, .size = 4  },
633		.sources	= &clkset_spi_mmc,
634	}, {
635		.clk	= {
636			.name		= "usb-bus-host",
637			.id		= -1,
638			.ctrlbit        = S3C_CLKCON_SCLK_UHOST,
639			.enable		= s3c64xx_sclk_ctrl,
640		},
641		.reg_src 	= { .reg = S3C_CLK_SRC, .shift = 5, .size = 2  },
642		.reg_div	= { .reg = S3C_CLK_DIV1, .shift = 20, .size = 4  },
643		.sources	= &clkset_uhost,
644	}, {
645		.clk	= {
646			.name		= "uclk1",
647			.id		= -1,
648			.ctrlbit        = S3C_CLKCON_SCLK_UART,
649			.enable		= s3c64xx_sclk_ctrl,
650		},
651		.reg_src	= { .reg = S3C_CLK_SRC, .shift = 13, .size = 1  },
652		.reg_div	= { .reg = S3C_CLK_DIV2, .shift = 16, .size = 4  },
653		.sources	= &clkset_uart,
654	}, {
655/* Where does UCLK0 come from? */
656		.clk	= {
657			.name		= "spi-bus",
658			.id		= 0,
659			.ctrlbit        = S3C_CLKCON_SCLK_SPI0,
660			.enable		= s3c64xx_sclk_ctrl,
661		},
662		.reg_src	= { .reg = S3C_CLK_SRC, .shift = 14, .size = 2  },
663		.reg_div	= { .reg = S3C_CLK_DIV2, .shift = 0, .size = 4  },
664		.sources	= &clkset_spi_mmc,
665	}, {
666		.clk	= {
667			.name		= "spi-bus",
668			.id		= 1,
669			.ctrlbit        = S3C_CLKCON_SCLK_SPI1,
670			.enable		= s3c64xx_sclk_ctrl,
671		},
672		.reg_src	= { .reg = S3C_CLK_SRC, .shift = 16, .size = 2  },
673		.reg_div	= { .reg = S3C_CLK_DIV2, .shift = 4, .size = 4  },
674		.sources	= &clkset_spi_mmc,
675	}, {
676		.clk	= {
677			.name		= "audio-bus",
678			.id		= 0,
679			.ctrlbit        = S3C_CLKCON_SCLK_AUDIO0,
680			.enable		= s3c64xx_sclk_ctrl,
681		},
682		.reg_src	= { .reg = S3C_CLK_SRC, .shift = 7, .size = 3  },
683		.reg_div	= { .reg = S3C_CLK_DIV2, .shift = 8, .size = 4  },
684		.sources	= &clkset_audio0,
685	}, {
686		.clk	= {
687			.name		= "audio-bus",
688			.id		= 1,
689			.ctrlbit        = S3C_CLKCON_SCLK_AUDIO1,
690			.enable		= s3c64xx_sclk_ctrl,
691		},
692		.reg_src	= { .reg = S3C_CLK_SRC, .shift = 10, .size = 3  },
693		.reg_div	= { .reg = S3C_CLK_DIV2, .shift = 12, .size = 4  },
694		.sources	= &clkset_audio1,
695	}, {
696		.clk	= {
697			.name		= "audio-bus",
698			.id		= -1,  /* There's only one IISv4 port */
699			.ctrlbit        = S3C6410_CLKCON_SCLK_AUDIO2,
700			.enable		= s3c64xx_sclk_ctrl,
701		},
702		.reg_src	= { .reg = S3C6410_CLK_SRC2, .shift = 0, .size = 3  },
703		.reg_div	= { .reg = S3C_CLK_DIV2, .shift = 24, .size = 4  },
704		.sources	= &clkset_audio2,
705	}, {
706		.clk	= {
707			.name		= "irda-bus",
708			.id		= 0,
709			.ctrlbit        = S3C_CLKCON_SCLK_IRDA,
710			.enable		= s3c64xx_sclk_ctrl,
711		},
712		.reg_src	= { .reg = S3C_CLK_SRC, .shift = 24, .size = 2  },
713		.reg_div	= { .reg = S3C_CLK_DIV2, .shift = 20, .size = 4  },
714		.sources	= &clkset_irda,
715	}, {
716		.clk	= {
717			.name		= "camera",
718			.id		= -1,
719			.ctrlbit        = S3C_CLKCON_SCLK_CAM,
720			.enable		= s3c64xx_sclk_ctrl,
721		},
722		.reg_div	= { .reg = S3C_CLK_DIV0, .shift = 20, .size = 4  },
723		.reg_src	= { .reg = NULL, .shift = 0, .size = 0  },
724		.sources	= &clkset_camif,
725	},
726};
727
728/* Clock initialisation code */
729
730static struct clksrc_clk *init_parents[] = {
731	&clk_mout_apll,
732	&clk_mout_epll,
733	&clk_mout_mpll,
734};
735
736#define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
737
738void __init_or_cpufreq s3c6400_setup_clocks(void)
739{
740	struct clk *xtal_clk;
741	unsigned long xtal;
742	unsigned long fclk;
743	unsigned long hclk;
744	unsigned long hclk2;
745	unsigned long pclk;
746	unsigned long epll;
747	unsigned long apll;
748	unsigned long mpll;
749	unsigned int ptr;
750	u32 clkdiv0;
751
752	printk(KERN_DEBUG "%s: registering clocks\n", __func__);
753
754	clkdiv0 = __raw_readl(S3C_CLK_DIV0);
755	printk(KERN_DEBUG "%s: clkdiv0 = %08x\n", __func__, clkdiv0);
756
757	xtal_clk = clk_get(NULL, "xtal");
758	BUG_ON(IS_ERR(xtal_clk));
759
760	xtal = clk_get_rate(xtal_clk);
761	clk_put(xtal_clk);
762
763	printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
764
765	/* For now assume the mux always selects the crystal */
766	clk_ext_xtal_mux.parent = xtal_clk;
767
768	epll = s3c6400_get_epll(xtal);
769	mpll = s3c6400_get_pll(xtal, __raw_readl(S3C_MPLL_CON));
770	apll = s3c6400_get_pll(xtal, __raw_readl(S3C_APLL_CON));
771
772	fclk = mpll;
773
774	printk(KERN_INFO "S3C64XX: PLL settings, A=%ld, M=%ld, E=%ld\n",
775	       apll, mpll, epll);
776
777	hclk2 = mpll / GET_DIV(clkdiv0, S3C6400_CLKDIV0_HCLK2);
778	hclk = hclk2 / GET_DIV(clkdiv0, S3C6400_CLKDIV0_HCLK);
779	pclk = hclk2 / GET_DIV(clkdiv0, S3C6400_CLKDIV0_PCLK);
780
781	printk(KERN_INFO "S3C64XX: HCLK2=%ld, HCLK=%ld, PCLK=%ld\n",
782	       hclk2, hclk, pclk);
783
784	clk_fout_mpll.rate = mpll;
785	clk_fout_epll.rate = epll;
786	clk_fout_apll.rate = apll;
787
788	clk_h2.rate = hclk2;
789	clk_h.rate = hclk;
790	clk_p.rate = pclk;
791	clk_f.rate = fclk;
792
793	for (ptr = 0; ptr < ARRAY_SIZE(init_parents); ptr++)
794		s3c_set_clksrc(init_parents[ptr], true);
795
796	for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
797		s3c_set_clksrc(&clksrcs[ptr], true);
798}
799
800static struct clk *clks1[] __initdata = {
801	&clk_ext_xtal_mux,
802	&clk_iis_cd0,
803	&clk_iis_cd1,
804	&clk_iisv4_cd,
805	&clk_pcm_cd,
806	&clk_mout_epll.clk,
807	&clk_mout_mpll.clk,
808	&clk_dout_mpll,
809	&clk_arm,
810};
811
812static struct clk *clks[] __initdata = {
813	&clk_ext,
814	&clk_epll,
815	&clk_27m,
816	&clk_48m,
817	&clk_h2,
818	&clk_xusbxti,
819};
820
821/**
822 * s3c64xx_register_clocks - register clocks for s3c6400 and s3c6410
823 * @xtal: The rate for the clock crystal feeding the PLLs.
824 * @armclk_divlimit: Divisor mask for ARMCLK.
825 *
826 * Register the clocks for the S3C6400 and S3C6410 SoC range, such
827 * as ARMCLK as well as the necessary parent clocks.
828 *
829 * This call does not setup the clocks, which is left to the
830 * s3c6400_setup_clocks() call which may be needed by the cpufreq
831 * or resume code to re-set the clocks if the bootloader has changed
832 * them.
833 */
834void __init s3c64xx_register_clocks(unsigned long xtal,
835				    unsigned armclk_divlimit)
836{
837	struct clk *clkp;
838	int ret;
839	int ptr;
840
841	armclk_mask = armclk_divlimit;
842
843	s3c24xx_register_baseclocks(xtal);
844	s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
845
846	s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
847
848	clkp = init_clocks_disable;
849	for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
850
851		ret = s3c24xx_register_clock(clkp);
852		if (ret < 0) {
853			printk(KERN_ERR "Failed to register clock %s (%d)\n",
854			       clkp->name, ret);
855		}
856
857		(clkp->enable)(clkp, 0);
858	}
859
860	s3c24xx_register_clocks(clks1, ARRAY_SIZE(clks1));
861	s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
862	s3c_pwmclk_init();
863}
864