1 /* linux/arch/arm/mach-s5p6442/clock.c
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
6 * S5P6442 - Clock support
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.
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>
23 #include <plat/cpu-freq.h>
24 #include <mach/regs-clock.h>
25 #include <plat/clock.h>
28 #include <plat/s5p-clock.h>
29 #include <plat/clock-clksrc.h>
30 #include <plat/s5p6442.h>
32 static struct clksrc_clk clk_mout_apll
= {
37 .sources
= &clk_src_apll
,
38 .reg_src
= { .reg
= S5P_CLK_SRC0
, .shift
= 0, .size
= 1 },
41 static struct clksrc_clk clk_mout_mpll
= {
46 .sources
= &clk_src_mpll
,
47 .reg_src
= { .reg
= S5P_CLK_SRC0
, .shift
= 4, .size
= 1 },
50 static struct clksrc_clk clk_mout_epll
= {
55 .sources
= &clk_src_epll
,
56 .reg_src
= { .reg
= S5P_CLK_SRC0
, .shift
= 8, .size
= 1 },
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
,
65 static struct clksrc_sources clk_src_arm
= {
66 .sources
= clk_src_arm_list
,
67 .nr_sources
= ARRAY_SIZE(clk_src_arm_list
),
70 static struct clksrc_clk clk_mout_arm
= {
75 .sources
= &clk_src_arm
,
76 .reg_src
= { .reg
= S5P_CLK_MUX_STAT0
, .shift
= 16, .size
= 3 },
79 static struct clk clk_dout_a2m
= {
82 .parent
= &clk_mout_apll
.clk
,
85 /* Possible clock sources for D0 Mux */
86 static struct clk
*clk_src_d0_list
[] = {
87 [1] = &clk_mout_mpll
.clk
,
91 static struct clksrc_sources clk_src_d0
= {
92 .sources
= clk_src_d0_list
,
93 .nr_sources
= ARRAY_SIZE(clk_src_d0_list
),
96 static struct clksrc_clk clk_mout_d0
= {
101 .sources
= &clk_src_d0
,
102 .reg_src
= { .reg
= S5P_CLK_MUX_STAT0
, .shift
= 20, .size
= 3 },
105 static struct clk clk_dout_apll
= {
108 .parent
= &clk_mout_arm
.clk
,
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
,
117 static struct clksrc_sources clk_src_d0sync
= {
118 .sources
= clk_src_d0sync_list
,
119 .nr_sources
= ARRAY_SIZE(clk_src_d0sync_list
),
122 static struct clksrc_clk clk_mout_d0sync
= {
124 .name
= "mout_d0sync",
127 .sources
= &clk_src_d0sync
,
128 .reg_src
= { .reg
= S5P_CLK_MUX_STAT1
, .shift
= 28, .size
= 3 },
131 /* Possible clock sources for D1 Mux */
132 static struct clk
*clk_src_d1_list
[] = {
133 [1] = &clk_mout_mpll
.clk
,
137 static struct clksrc_sources clk_src_d1
= {
138 .sources
= clk_src_d1_list
,
139 .nr_sources
= ARRAY_SIZE(clk_src_d1_list
),
142 static struct clksrc_clk clk_mout_d1
= {
147 .sources
= &clk_src_d1
,
148 .reg_src
= { .reg
= S5P_CLK_MUX_STAT0
, .shift
= 24, .size
= 3 },
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
,
157 static struct clksrc_sources clk_src_d1sync
= {
158 .sources
= clk_src_d1sync_list
,
159 .nr_sources
= ARRAY_SIZE(clk_src_d1sync_list
),
162 static struct clksrc_clk clk_mout_d1sync
= {
164 .name
= "mout_d1sync",
167 .sources
= &clk_src_d1sync
,
168 .reg_src
= { .reg
= S5P_CLK_MUX_STAT1
, .shift
= 24, .size
= 3 },
171 static struct clk clk_hclkd0
= {
174 .parent
= &clk_mout_d0sync
.clk
,
177 static struct clk clk_hclkd1
= {
180 .parent
= &clk_mout_d1sync
.clk
,
183 static struct clk clk_pclkd0
= {
186 .parent
= &clk_hclkd0
,
189 static struct clk clk_pclkd1
= {
192 .parent
= &clk_hclkd1
,
195 int s5p6442_clk_ip0_ctrl(struct clk
*clk
, int enable
)
197 return s5p_gatectrl(S5P_CLKGATE_IP0
, clk
, enable
);
200 int s5p6442_clk_ip3_ctrl(struct clk
*clk
, int enable
)
202 return s5p_gatectrl(S5P_CLKGATE_IP3
, clk
, enable
);
205 static struct clksrc_clk clksrcs
[] = {
210 .parent
= &clk_mout_apll
.clk
,
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 },
219 .parent
= &clk_mout_arm
.clk
,
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 },
228 .parent
= &clk_mout_d1sync
.clk
,
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 },
237 .parent
= &clk_mout_d0sync
.clk
,
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 },
246 .parent
= &clk_hclkd0
,
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 },
255 .parent
= &clk_hclkd1
,
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 },
263 /* Clock initialisation code */
264 static struct clksrc_clk
*init_parents
[] = {
275 void __init_or_cpufreq
s5p6442_setup_clocks(void)
277 struct clk
*pclkd0_clk
;
278 struct clk
*pclkd1_clk
;
282 unsigned long hclkd0
= 0;
283 unsigned long hclkd1
= 0;
284 unsigned long pclkd0
= 0;
285 unsigned long pclkd1
= 0;
292 printk(KERN_DEBUG
"%s: registering clocks\n", __func__
);
294 xtal
= clk_get_rate(&clk_xtal
);
296 printk(KERN_DEBUG
"%s: xtal is %ld\n", __func__
, xtal
);
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
);
302 printk(KERN_INFO
"S5P6442: PLL settings, A=%ld, M=%ld, E=%ld",
305 clk_fout_apll
.rate
= apll
;
306 clk_fout_mpll
.rate
= mpll
;
307 clk_fout_epll
.rate
= epll
;
309 for (ptr
= 0; ptr
< ARRAY_SIZE(init_parents
); ptr
++)
310 s3c_set_clksrc(init_parents
[ptr
], true);
312 for (ptr
= 0; ptr
< ARRAY_SIZE(clksrcs
); ptr
++)
313 s3c_set_clksrc(&clksrcs
[ptr
], true);
315 arm
= clk_get_rate(&clk_dout_apll
);
316 hclkd0
= clk_get_rate(&clk_hclkd0
);
317 hclkd1
= clk_get_rate(&clk_hclkd1
);
319 pclkd0_clk
= clk_get(NULL
, "pclkd0");
320 BUG_ON(IS_ERR(pclkd0_clk
));
322 pclkd0
= clk_get_rate(pclkd0_clk
);
325 pclkd1_clk
= clk_get(NULL
, "pclkd1");
326 BUG_ON(IS_ERR(pclkd1_clk
));
328 pclkd1
= clk_get_rate(pclkd1_clk
);
331 printk(KERN_INFO
"S5P6442: HCLKD0=%ld, HCLKD1=%ld, PCLKD0=%ld, PCLKD1=%ld\n",
332 hclkd0
, hclkd1
, pclkd0
, pclkd1
);
334 /* For backward compatibility */
339 clk_pclkd0
.rate
= pclkd0
;
340 clk_pclkd1
.rate
= pclkd1
;
343 static struct clk init_clocks_off
[] = {
347 .parent
= &clk_pclkd1
,
348 .enable
= s5p6442_clk_ip0_ctrl
,
353 static struct clk init_clocks
[] = {
357 .parent
= &clk_pclkd1
,
358 .enable
= s5p6442_clk_ip3_ctrl
,
363 .parent
= &clk_pclkd1
,
364 .enable
= s5p6442_clk_ip3_ctrl
,
369 .parent
= &clk_pclkd1
,
370 .enable
= s5p6442_clk_ip3_ctrl
,
375 .parent
= &clk_pclkd1
,
376 .enable
= s5p6442_clk_ip3_ctrl
,
381 .parent
= &clk_pclkd1
,
382 .enable
= s5p6442_clk_ip3_ctrl
,
383 .ctrlbit
= (1 << 22),
387 .parent
= &clk_pclkd1
,
388 .enable
= s5p6442_clk_ip3_ctrl
,
393 static struct clk
*clks
[] __initdata
= {
400 &clk_mout_d0sync
.clk
,
402 &clk_mout_d1sync
.clk
,
409 void __init
s5p6442_register_clocks(void)
411 s3c24xx_register_clocks(clks
, ARRAY_SIZE(clks
));
413 s3c_register_clksrc(clksrcs
, ARRAY_SIZE(clksrcs
));
414 s3c_register_clocks(init_clocks
, ARRAY_SIZE(init_clocks
));
416 s3c_register_clocks(init_clocks_off
, ARRAY_SIZE(init_clocks_off
));
417 s3c_disable_clocks(init_clocks_off
, ARRAY_SIZE(init_clocks_off
));