]>
Commit | Line | Data |
---|---|---|
b6f83757 KK |
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 | ||
32 | static 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 | ||
41 | static 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 | ||
50 | static 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 */ | |
60 | static struct clk *clk_src_arm_list[] = { | |
61 | [1] = &clk_mout_apll.clk, | |
62 | [2] = &clk_mout_mpll.clk, | |
63 | }; | |
64 | ||
65 | static struct clksrc_sources clk_src_arm = { | |
66 | .sources = clk_src_arm_list, | |
67 | .nr_sources = ARRAY_SIZE(clk_src_arm_list), | |
68 | }; | |
69 | ||
70 | static 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 | ||
79 | static 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 */ | |
86 | static struct clk *clk_src_d0_list[] = { | |
87 | [1] = &clk_mout_mpll.clk, | |
88 | [2] = &clk_dout_a2m, | |
89 | }; | |
90 | ||
91 | static struct clksrc_sources clk_src_d0 = { | |
92 | .sources = clk_src_d0_list, | |
93 | .nr_sources = ARRAY_SIZE(clk_src_d0_list), | |
94 | }; | |
95 | ||
96 | static 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 | ||
105 | static 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 */ | |
112 | static struct clk *clk_src_d0sync_list[] = { | |
113 | [1] = &clk_mout_d0.clk, | |
114 | [2] = &clk_dout_apll, | |
115 | }; | |
116 | ||
117 | static struct clksrc_sources clk_src_d0sync = { | |
118 | .sources = clk_src_d0sync_list, | |
119 | .nr_sources = ARRAY_SIZE(clk_src_d0sync_list), | |
120 | }; | |
121 | ||
122 | static 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 */ | |
132 | static struct clk *clk_src_d1_list[] = { | |
133 | [1] = &clk_mout_mpll.clk, | |
134 | [2] = &clk_dout_a2m, | |
135 | }; | |
136 | ||
137 | static struct clksrc_sources clk_src_d1 = { | |
138 | .sources = clk_src_d1_list, | |
139 | .nr_sources = ARRAY_SIZE(clk_src_d1_list), | |
140 | }; | |
141 | ||
142 | static 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 */ | |
152 | static struct clk *clk_src_d1sync_list[] = { | |
153 | [1] = &clk_mout_d1.clk, | |
154 | [2] = &clk_dout_apll, | |
155 | }; | |
156 | ||
157 | static struct clksrc_sources clk_src_d1sync = { | |
158 | .sources = clk_src_d1sync_list, | |
159 | .nr_sources = ARRAY_SIZE(clk_src_d1sync_list), | |
160 | }; | |
161 | ||
162 | static 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 | ||
171 | static struct clk clk_hclkd0 = { | |
172 | .name = "hclkd0", | |
173 | .id = -1, | |
174 | .parent = &clk_mout_d0sync.clk, | |
175 | }; | |
176 | ||
177 | static struct clk clk_hclkd1 = { | |
178 | .name = "hclkd1", | |
179 | .id = -1, | |
180 | .parent = &clk_mout_d1sync.clk, | |
181 | }; | |
182 | ||
183 | static struct clk clk_pclkd0 = { | |
184 | .name = "pclkd0", | |
185 | .id = -1, | |
186 | .parent = &clk_hclkd0, | |
187 | }; | |
188 | ||
189 | static struct clk clk_pclkd1 = { | |
190 | .name = "pclkd1", | |
191 | .id = -1, | |
192 | .parent = &clk_hclkd1, | |
193 | }; | |
194 | ||
06185c07 SY |
195 | int s5p6442_clk_ip0_ctrl(struct clk *clk, int enable) |
196 | { | |
197 | return s5p_gatectrl(S5P_CLKGATE_IP0, clk, enable); | |
198 | } | |
199 | ||
b6f83757 KK |
200 | int s5p6442_clk_ip3_ctrl(struct clk *clk, int enable) |
201 | { | |
202 | return s5p_gatectrl(S5P_CLKGATE_IP3, clk, enable); | |
203 | } | |
204 | ||
205 | static struct clksrc_clk clksrcs[] = { | |
206 | { | |
207 | .clk = { | |
208 | .name = "dout_a2m", | |
209 | .id = -1, | |
210 | .parent = &clk_mout_apll.clk, | |
211 | }, | |
212 | .sources = &clk_src_apll, | |
213 | .reg_src = { .reg = S5P_CLK_SRC0, .shift = 0, .size = 1 }, | |
214 | .reg_div = { .reg = S5P_CLK_DIV0, .shift = 4, .size = 3 }, | |
215 | }, { | |
216 | .clk = { | |
217 | .name = "dout_apll", | |
218 | .id = -1, | |
219 | .parent = &clk_mout_arm.clk, | |
220 | }, | |
221 | .sources = &clk_src_arm, | |
222 | .reg_src = { .reg = S5P_CLK_MUX_STAT0, .shift = 16, .size = 3 }, | |
223 | .reg_div = { .reg = S5P_CLK_DIV0, .shift = 0, .size = 3 }, | |
224 | }, { | |
225 | .clk = { | |
226 | .name = "hclkd1", | |
227 | .id = -1, | |
228 | .parent = &clk_mout_d1sync.clk, | |
229 | }, | |
230 | .sources = &clk_src_d1sync, | |
231 | .reg_src = { .reg = S5P_CLK_MUX_STAT1, .shift = 24, .size = 3 }, | |
232 | .reg_div = { .reg = S5P_CLK_DIV0, .shift = 24, .size = 4 }, | |
233 | }, { | |
234 | .clk = { | |
235 | .name = "hclkd0", | |
236 | .id = -1, | |
237 | .parent = &clk_mout_d0sync.clk, | |
238 | }, | |
239 | .sources = &clk_src_d0sync, | |
240 | .reg_src = { .reg = S5P_CLK_MUX_STAT1, .shift = 28, .size = 3 }, | |
241 | .reg_div = { .reg = S5P_CLK_DIV0, .shift = 16, .size = 4 }, | |
242 | }, { | |
243 | .clk = { | |
244 | .name = "pclkd0", | |
245 | .id = -1, | |
246 | .parent = &clk_hclkd0, | |
247 | }, | |
248 | .sources = &clk_src_d0sync, | |
249 | .reg_src = { .reg = S5P_CLK_MUX_STAT1, .shift = 28, .size = 3 }, | |
250 | .reg_div = { .reg = S5P_CLK_DIV0, .shift = 20, .size = 3 }, | |
251 | }, { | |
252 | .clk = { | |
253 | .name = "pclkd1", | |
254 | .id = -1, | |
255 | .parent = &clk_hclkd1, | |
256 | }, | |
257 | .sources = &clk_src_d1sync, | |
258 | .reg_src = { .reg = S5P_CLK_MUX_STAT1, .shift = 24, .size = 3 }, | |
259 | .reg_div = { .reg = S5P_CLK_DIV0, .shift = 28, .size = 3 }, | |
260 | } | |
261 | }; | |
262 | ||
263 | /* Clock initialisation code */ | |
264 | static struct clksrc_clk *init_parents[] = { | |
265 | &clk_mout_apll, | |
266 | &clk_mout_mpll, | |
267 | &clk_mout_epll, | |
268 | &clk_mout_arm, | |
269 | &clk_mout_d0, | |
270 | &clk_mout_d0sync, | |
271 | &clk_mout_d1, | |
272 | &clk_mout_d1sync, | |
273 | }; | |
274 | ||
275 | void __init_or_cpufreq s5p6442_setup_clocks(void) | |
276 | { | |
277 | struct clk *pclkd0_clk; | |
278 | struct clk *pclkd1_clk; | |
279 | ||
280 | unsigned long xtal; | |
281 | unsigned long arm; | |
282 | unsigned long hclkd0 = 0; | |
283 | unsigned long hclkd1 = 0; | |
284 | unsigned long pclkd0 = 0; | |
285 | unsigned long pclkd1 = 0; | |
286 | ||
287 | unsigned long apll; | |
288 | unsigned long mpll; | |
289 | unsigned long epll; | |
290 | unsigned int ptr; | |
291 | ||
292 | printk(KERN_DEBUG "%s: registering clocks\n", __func__); | |
293 | ||
294 | xtal = clk_get_rate(&clk_xtal); | |
295 | ||
296 | printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal); | |
297 | ||
298 | apll = s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON), pll_4508); | |
299 | mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P_MPLL_CON), pll_4502); | |
300 | epll = s5p_get_pll45xx(xtal, __raw_readl(S5P_EPLL_CON), pll_4500); | |
301 | ||
4164acaf | 302 | printk(KERN_INFO "S5P6442: PLL settings, A=%ld, M=%ld, E=%ld", |
b6f83757 KK |
303 | apll, mpll, epll); |
304 | ||
305 | clk_fout_apll.rate = apll; | |
306 | clk_fout_mpll.rate = mpll; | |
307 | clk_fout_epll.rate = epll; | |
308 | ||
309 | for (ptr = 0; ptr < ARRAY_SIZE(init_parents); ptr++) | |
310 | s3c_set_clksrc(init_parents[ptr], true); | |
311 | ||
312 | for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++) | |
313 | s3c_set_clksrc(&clksrcs[ptr], true); | |
314 | ||
315 | arm = clk_get_rate(&clk_dout_apll); | |
316 | hclkd0 = clk_get_rate(&clk_hclkd0); | |
317 | hclkd1 = clk_get_rate(&clk_hclkd1); | |
318 | ||
319 | pclkd0_clk = clk_get(NULL, "pclkd0"); | |
320 | BUG_ON(IS_ERR(pclkd0_clk)); | |
321 | ||
322 | pclkd0 = clk_get_rate(pclkd0_clk); | |
323 | clk_put(pclkd0_clk); | |
324 | ||
325 | pclkd1_clk = clk_get(NULL, "pclkd1"); | |
326 | BUG_ON(IS_ERR(pclkd1_clk)); | |
327 | ||
328 | pclkd1 = clk_get_rate(pclkd1_clk); | |
329 | clk_put(pclkd1_clk); | |
330 | ||
331 | printk(KERN_INFO "S5P6442: HCLKD0=%ld, HCLKD1=%ld, PCLKD0=%ld, PCLKD1=%ld\n", | |
332 | hclkd0, hclkd1, pclkd0, pclkd1); | |
333 | ||
334 | /* For backward compatibility */ | |
335 | clk_f.rate = arm; | |
336 | clk_h.rate = hclkd1; | |
337 | clk_p.rate = pclkd1; | |
338 | ||
339 | clk_pclkd0.rate = pclkd0; | |
340 | clk_pclkd1.rate = pclkd1; | |
341 | } | |
342 | ||
06185c07 SY |
343 | static struct clk init_clocks_disable[] = { |
344 | { | |
345 | .name = "pdma", | |
346 | .id = -1, | |
347 | .parent = &clk_pclkd1, | |
348 | .enable = s5p6442_clk_ip0_ctrl, | |
349 | .ctrlbit = (1 << 3), | |
350 | }, | |
351 | }; | |
352 | ||
b6f83757 KK |
353 | static struct clk init_clocks[] = { |
354 | { | |
355 | .name = "systimer", | |
356 | .id = -1, | |
357 | .parent = &clk_pclkd1, | |
358 | .enable = s5p6442_clk_ip3_ctrl, | |
359 | .ctrlbit = (1<<16), | |
360 | }, { | |
361 | .name = "uart", | |
362 | .id = 0, | |
363 | .parent = &clk_pclkd1, | |
364 | .enable = s5p6442_clk_ip3_ctrl, | |
365 | .ctrlbit = (1<<17), | |
366 | }, { | |
367 | .name = "uart", | |
368 | .id = 1, | |
369 | .parent = &clk_pclkd1, | |
370 | .enable = s5p6442_clk_ip3_ctrl, | |
371 | .ctrlbit = (1<<18), | |
372 | }, { | |
373 | .name = "uart", | |
374 | .id = 2, | |
375 | .parent = &clk_pclkd1, | |
376 | .enable = s5p6442_clk_ip3_ctrl, | |
377 | .ctrlbit = (1<<19), | |
b46de63d BG |
378 | }, { |
379 | .name = "watchdog", | |
380 | .id = -1, | |
381 | .parent = &clk_pclkd1, | |
382 | .enable = s5p6442_clk_ip3_ctrl, | |
383 | .ctrlbit = (1 << 22), | |
b6f83757 KK |
384 | }, { |
385 | .name = "timers", | |
386 | .id = -1, | |
387 | .parent = &clk_pclkd1, | |
388 | .enable = s5p6442_clk_ip3_ctrl, | |
389 | .ctrlbit = (1<<23), | |
390 | }, | |
391 | }; | |
392 | ||
393 | static struct clk *clks[] __initdata = { | |
394 | &clk_ext, | |
395 | &clk_epll, | |
396 | &clk_mout_apll.clk, | |
397 | &clk_mout_mpll.clk, | |
398 | &clk_mout_epll.clk, | |
399 | &clk_mout_d0.clk, | |
400 | &clk_mout_d0sync.clk, | |
401 | &clk_mout_d1.clk, | |
402 | &clk_mout_d1sync.clk, | |
403 | &clk_hclkd0, | |
404 | &clk_pclkd0, | |
405 | &clk_hclkd1, | |
406 | &clk_pclkd1, | |
407 | }; | |
408 | ||
409 | void __init s5p6442_register_clocks(void) | |
410 | { | |
06185c07 SY |
411 | struct clk *clkptr; |
412 | int i, ret; | |
413 | ||
b6f83757 KK |
414 | s3c24xx_register_clocks(clks, ARRAY_SIZE(clks)); |
415 | ||
416 | s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs)); | |
417 | s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks)); | |
418 | ||
06185c07 SY |
419 | clkptr = init_clocks_disable; |
420 | for (i = 0; i < ARRAY_SIZE(init_clocks_disable); i++, clkptr++) { | |
421 | ret = s3c24xx_register_clock(clkptr); | |
422 | if (ret < 0) { | |
423 | printk(KERN_ERR "Fail to register clock %s (%d)\n", | |
424 | clkptr->name, ret); | |
425 | } else | |
426 | (clkptr->enable)(clkptr, 0); | |
427 | } | |
428 | ||
b6f83757 KK |
429 | s3c_pwmclk_init(); |
430 | } |