• 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.36/arch/arm/mach-s5p6442/
1/* linux/arch/arm/mach-s5p6442/clock.c
2 *
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 *		http://www.samsung.com/
5 *
6 * S5P6442 - 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/err.h>
18#include <linux/clk.h>
19#include <linux/io.h>
20
21#include <mach/map.h>
22
23#include <plat/cpu-freq.h>
24#include <mach/regs-clock.h>
25#include <plat/clock.h>
26#include <plat/cpu.h>
27#include <plat/pll.h>
28#include <plat/s5p-clock.h>
29#include <plat/clock-clksrc.h>
30#include <plat/s5p6442.h>
31
32static struct clksrc_clk clk_mout_apll = {
33	.clk	= {
34		.name		= "mout_apll",
35		.id		= -1,
36	},
37	.sources	= &clk_src_apll,
38	.reg_src	= { .reg = S5P_CLK_SRC0, .shift = 0, .size = 1 },
39};
40
41static struct clksrc_clk clk_mout_mpll = {
42	.clk = {
43		.name		= "mout_mpll",
44		.id		= -1,
45	},
46	.sources	= &clk_src_mpll,
47	.reg_src	= { .reg = S5P_CLK_SRC0, .shift = 4, .size = 1 },
48};
49
50static struct clksrc_clk clk_mout_epll = {
51	.clk	= {
52		.name		= "mout_epll",
53		.id		= -1,
54	},
55	.sources	= &clk_src_epll,
56	.reg_src	= { .reg = S5P_CLK_SRC0, .shift = 8, .size = 1 },
57};
58
59/* Possible clock sources for ARM Mux */
60static struct clk *clk_src_arm_list[] = {
61	[1] = &clk_mout_apll.clk,
62	[2] = &clk_mout_mpll.clk,
63};
64
65static struct clksrc_sources clk_src_arm = {
66	.sources	= clk_src_arm_list,
67	.nr_sources	= ARRAY_SIZE(clk_src_arm_list),
68};
69
70static struct clksrc_clk clk_mout_arm = {
71	.clk	= {
72		.name		= "mout_arm",
73		.id		= -1,
74	},
75	.sources	= &clk_src_arm,
76	.reg_src	= { .reg = S5P_CLK_MUX_STAT0, .shift = 16, .size = 3 },
77};
78
79static struct clk clk_dout_a2m = {
80	.name		= "dout_a2m",
81	.id		= -1,
82	.parent		= &clk_mout_apll.clk,
83};
84
85/* Possible clock sources for D0 Mux */
86static struct clk *clk_src_d0_list[] = {
87	[1] = &clk_mout_mpll.clk,
88	[2] = &clk_dout_a2m,
89};
90
91static struct clksrc_sources clk_src_d0 = {
92	.sources	= clk_src_d0_list,
93	.nr_sources	= ARRAY_SIZE(clk_src_d0_list),
94};
95
96static struct clksrc_clk clk_mout_d0 = {
97	.clk = {
98		.name		= "mout_d0",
99		.id		= -1,
100	},
101	.sources	= &clk_src_d0,
102	.reg_src	= { .reg = S5P_CLK_MUX_STAT0, .shift = 20, .size = 3 },
103};
104
105static struct clk clk_dout_apll = {
106	.name		= "dout_apll",
107	.id		= -1,
108	.parent		= &clk_mout_arm.clk,
109};
110
111/* Possible clock sources for D0SYNC Mux */
112static struct clk *clk_src_d0sync_list[] = {
113	[1] = &clk_mout_d0.clk,
114	[2] = &clk_dout_apll,
115};
116
117static struct clksrc_sources clk_src_d0sync = {
118	.sources	= clk_src_d0sync_list,
119	.nr_sources	= ARRAY_SIZE(clk_src_d0sync_list),
120};
121
122static struct clksrc_clk clk_mout_d0sync = {
123	.clk	= {
124		.name		= "mout_d0sync",
125		.id		= -1,
126	},
127	.sources	= &clk_src_d0sync,
128	.reg_src	= { .reg = S5P_CLK_MUX_STAT1, .shift = 28, .size = 3 },
129};
130
131/* Possible clock sources for D1 Mux */
132static struct clk *clk_src_d1_list[] = {
133	[1] = &clk_mout_mpll.clk,
134	[2] = &clk_dout_a2m,
135};
136
137static struct clksrc_sources clk_src_d1 = {
138	.sources	= clk_src_d1_list,
139	.nr_sources	= ARRAY_SIZE(clk_src_d1_list),
140};
141
142static struct clksrc_clk clk_mout_d1 = {
143	.clk	= {
144		.name		= "mout_d1",
145		.id		= -1,
146	},
147	.sources	= &clk_src_d1,
148	.reg_src	= { .reg = S5P_CLK_MUX_STAT0, .shift = 24, .size = 3 },
149};
150
151/* Possible clock sources for D1SYNC Mux */
152static struct clk *clk_src_d1sync_list[] = {
153	[1] = &clk_mout_d1.clk,
154	[2] = &clk_dout_apll,
155};
156
157static struct clksrc_sources clk_src_d1sync = {
158	.sources	= clk_src_d1sync_list,
159	.nr_sources	= ARRAY_SIZE(clk_src_d1sync_list),
160};
161
162static struct clksrc_clk clk_mout_d1sync = {
163	.clk	= {
164		.name		= "mout_d1sync",
165		.id		= -1,
166	},
167	.sources	= &clk_src_d1sync,
168	.reg_src	= { .reg = S5P_CLK_MUX_STAT1, .shift = 24, .size = 3 },
169};
170
171static struct clk clk_hclkd0 = {
172	.name		= "hclkd0",
173	.id		= -1,
174	.parent		= &clk_mout_d0sync.clk,
175};
176
177static struct clk clk_hclkd1 = {
178	.name		= "hclkd1",
179	.id		= -1,
180	.parent		= &clk_mout_d1sync.clk,
181};
182
183static struct clk clk_pclkd0 = {
184	.name		= "pclkd0",
185	.id		= -1,
186	.parent		= &clk_hclkd0,
187};
188
189static struct clk clk_pclkd1 = {
190	.name		= "pclkd1",
191	.id		= -1,
192	.parent		= &clk_hclkd1,
193};
194
195int s5p6442_clk_ip3_ctrl(struct clk *clk, int enable)
196{
197	return s5p_gatectrl(S5P_CLKGATE_IP3, clk, enable);
198}
199
200static struct clksrc_clk clksrcs[] = {
201	{
202		.clk	= {
203			.name		= "dout_a2m",
204			.id		= -1,
205			.parent		= &clk_mout_apll.clk,
206		},
207		.sources = &clk_src_apll,
208		.reg_src = { .reg = S5P_CLK_SRC0, .shift = 0, .size = 1 },
209		.reg_div = { .reg = S5P_CLK_DIV0, .shift = 4, .size = 3 },
210	}, {
211		.clk	= {
212			.name		= "dout_apll",
213			.id		= -1,
214			.parent		= &clk_mout_arm.clk,
215		},
216		.sources = &clk_src_arm,
217		.reg_src = { .reg = S5P_CLK_MUX_STAT0, .shift = 16, .size = 3 },
218		.reg_div = { .reg = S5P_CLK_DIV0, .shift = 0, .size = 3 },
219	}, {
220		.clk	= {
221			.name		= "hclkd1",
222			.id		= -1,
223			.parent		= &clk_mout_d1sync.clk,
224		},
225		.sources = &clk_src_d1sync,
226		.reg_src = { .reg = S5P_CLK_MUX_STAT1, .shift = 24, .size = 3 },
227		.reg_div = { .reg = S5P_CLK_DIV0, .shift = 24, .size = 4 },
228	}, {
229		.clk	= {
230			.name		= "hclkd0",
231			.id		= -1,
232			.parent		= &clk_mout_d0sync.clk,
233		},
234		.sources = &clk_src_d0sync,
235		.reg_src = { .reg = S5P_CLK_MUX_STAT1, .shift = 28, .size = 3 },
236		.reg_div = { .reg = S5P_CLK_DIV0, .shift = 16, .size = 4 },
237	}, {
238		.clk	= {
239			.name		= "pclkd0",
240			.id		= -1,
241			.parent		= &clk_hclkd0,
242		},
243		.sources = &clk_src_d0sync,
244		.reg_src = { .reg = S5P_CLK_MUX_STAT1, .shift = 28, .size = 3 },
245		.reg_div = { .reg = S5P_CLK_DIV0, .shift = 20, .size = 3 },
246	}, {
247		.clk	= {
248			.name		= "pclkd1",
249			.id		= -1,
250			.parent		= &clk_hclkd1,
251		},
252		.sources = &clk_src_d1sync,
253		.reg_src = { .reg = S5P_CLK_MUX_STAT1, .shift = 24, .size = 3 },
254		.reg_div = { .reg = S5P_CLK_DIV0, .shift = 28, .size = 3 },
255	}
256};
257
258/* Clock initialisation code */
259static struct clksrc_clk *init_parents[] = {
260	&clk_mout_apll,
261	&clk_mout_mpll,
262	&clk_mout_epll,
263	&clk_mout_arm,
264	&clk_mout_d0,
265	&clk_mout_d0sync,
266	&clk_mout_d1,
267	&clk_mout_d1sync,
268};
269
270void __init_or_cpufreq s5p6442_setup_clocks(void)
271{
272	struct clk *pclkd0_clk;
273	struct clk *pclkd1_clk;
274
275	unsigned long xtal;
276	unsigned long arm;
277	unsigned long hclkd0 = 0;
278	unsigned long hclkd1 = 0;
279	unsigned long pclkd0 = 0;
280	unsigned long pclkd1 = 0;
281
282	unsigned long apll;
283	unsigned long mpll;
284	unsigned long epll;
285	unsigned int ptr;
286
287	printk(KERN_DEBUG "%s: registering clocks\n", __func__);
288
289	xtal = clk_get_rate(&clk_xtal);
290
291	printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
292
293	apll = s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON), pll_4508);
294	mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P_MPLL_CON), pll_4502);
295	epll = s5p_get_pll45xx(xtal, __raw_readl(S5P_EPLL_CON), pll_4500);
296
297	printk(KERN_INFO "S5P6442: PLL settings, A=%ld, M=%ld, E=%ld",
298			apll, mpll, epll);
299
300	clk_fout_apll.rate = apll;
301	clk_fout_mpll.rate = mpll;
302	clk_fout_epll.rate = epll;
303
304	for (ptr = 0; ptr < ARRAY_SIZE(init_parents); ptr++)
305		s3c_set_clksrc(init_parents[ptr], true);
306
307	for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
308		s3c_set_clksrc(&clksrcs[ptr], true);
309
310	arm = clk_get_rate(&clk_dout_apll);
311	hclkd0 = clk_get_rate(&clk_hclkd0);
312	hclkd1 = clk_get_rate(&clk_hclkd1);
313
314	pclkd0_clk = clk_get(NULL, "pclkd0");
315	BUG_ON(IS_ERR(pclkd0_clk));
316
317	pclkd0 = clk_get_rate(pclkd0_clk);
318	clk_put(pclkd0_clk);
319
320	pclkd1_clk = clk_get(NULL, "pclkd1");
321	BUG_ON(IS_ERR(pclkd1_clk));
322
323	pclkd1 = clk_get_rate(pclkd1_clk);
324	clk_put(pclkd1_clk);
325
326	printk(KERN_INFO "S5P6442: HCLKD0=%ld, HCLKD1=%ld, PCLKD0=%ld, PCLKD1=%ld\n",
327			hclkd0, hclkd1, pclkd0, pclkd1);
328
329	/* For backward compatibility */
330	clk_f.rate = arm;
331	clk_h.rate = hclkd1;
332	clk_p.rate = pclkd1;
333
334	clk_pclkd0.rate = pclkd0;
335	clk_pclkd1.rate = pclkd1;
336}
337
338static struct clk init_clocks[] = {
339	{
340		.name		= "systimer",
341		.id		= -1,
342		.parent		= &clk_pclkd1,
343		.enable		= s5p6442_clk_ip3_ctrl,
344		.ctrlbit	= (1<<16),
345	}, {
346		.name		= "uart",
347		.id		= 0,
348		.parent		= &clk_pclkd1,
349		.enable		= s5p6442_clk_ip3_ctrl,
350		.ctrlbit	= (1<<17),
351	}, {
352		.name		= "uart",
353		.id		= 1,
354		.parent		= &clk_pclkd1,
355		.enable		= s5p6442_clk_ip3_ctrl,
356		.ctrlbit	= (1<<18),
357	}, {
358		.name		= "uart",
359		.id		= 2,
360		.parent		= &clk_pclkd1,
361		.enable		= s5p6442_clk_ip3_ctrl,
362		.ctrlbit	= (1<<19),
363	}, {
364		.name		= "watchdog",
365		.id		= -1,
366		.parent		= &clk_pclkd1,
367		.enable		= s5p6442_clk_ip3_ctrl,
368		.ctrlbit	= (1 << 22),
369	}, {
370		.name		= "timers",
371		.id		= -1,
372		.parent		= &clk_pclkd1,
373		.enable		= s5p6442_clk_ip3_ctrl,
374		.ctrlbit	= (1<<23),
375	},
376};
377
378static struct clk *clks[] __initdata = {
379	&clk_ext,
380	&clk_epll,
381	&clk_mout_apll.clk,
382	&clk_mout_mpll.clk,
383	&clk_mout_epll.clk,
384	&clk_mout_d0.clk,
385	&clk_mout_d0sync.clk,
386	&clk_mout_d1.clk,
387	&clk_mout_d1sync.clk,
388	&clk_hclkd0,
389	&clk_pclkd0,
390	&clk_hclkd1,
391	&clk_pclkd1,
392};
393
394void __init s5p6442_register_clocks(void)
395{
396	s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
397
398	s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
399	s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
400
401	s3c_pwmclk_init();
402}
403