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_ip3_ctrl(struct clk
*clk
, int enable
)
197 return s5p_gatectrl(S5P_CLKGATE_IP3
, clk
, enable
);
200 static struct clksrc_clk clksrcs
[] = {
205 .parent
= &clk_mout_apll
.clk
,
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 },
214 .parent
= &clk_mout_arm
.clk
,
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 },
223 .parent
= &clk_mout_d1sync
.clk
,
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 },
232 .parent
= &clk_mout_d0sync
.clk
,
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 },
241 .parent
= &clk_hclkd0
,
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 },
250 .parent
= &clk_hclkd1
,
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 },
258 /* Clock initialisation code */
259 static struct clksrc_clk
*init_parents
[] = {
270 void __init_or_cpufreq
s5p6442_setup_clocks(void)
272 struct clk
*pclkd0_clk
;
273 struct clk
*pclkd1_clk
;
277 unsigned long hclkd0
= 0;
278 unsigned long hclkd1
= 0;
279 unsigned long pclkd0
= 0;
280 unsigned long pclkd1
= 0;
287 printk(KERN_DEBUG
"%s: registering clocks\n", __func__
);
289 xtal
= clk_get_rate(&clk_xtal
);
291 printk(KERN_DEBUG
"%s: xtal is %ld\n", __func__
, xtal
);
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
);
297 printk(KERN_INFO
"S5P6440: PLL settings, A=%ld, M=%ld, E=%ld",
300 clk_fout_apll
.rate
= apll
;
301 clk_fout_mpll
.rate
= mpll
;
302 clk_fout_epll
.rate
= epll
;
304 for (ptr
= 0; ptr
< ARRAY_SIZE(init_parents
); ptr
++)
305 s3c_set_clksrc(init_parents
[ptr
], true);
307 for (ptr
= 0; ptr
< ARRAY_SIZE(clksrcs
); ptr
++)
308 s3c_set_clksrc(&clksrcs
[ptr
], true);
310 arm
= clk_get_rate(&clk_dout_apll
);
311 hclkd0
= clk_get_rate(&clk_hclkd0
);
312 hclkd1
= clk_get_rate(&clk_hclkd1
);
314 pclkd0_clk
= clk_get(NULL
, "pclkd0");
315 BUG_ON(IS_ERR(pclkd0_clk
));
317 pclkd0
= clk_get_rate(pclkd0_clk
);
320 pclkd1_clk
= clk_get(NULL
, "pclkd1");
321 BUG_ON(IS_ERR(pclkd1_clk
));
323 pclkd1
= clk_get_rate(pclkd1_clk
);
326 printk(KERN_INFO
"S5P6442: HCLKD0=%ld, HCLKD1=%ld, PCLKD0=%ld, PCLKD1=%ld\n",
327 hclkd0
, hclkd1
, pclkd0
, pclkd1
);
329 /* For backward compatibility */
334 clk_pclkd0
.rate
= pclkd0
;
335 clk_pclkd1
.rate
= pclkd1
;
338 static struct clk init_clocks
[] = {
342 .parent
= &clk_pclkd1
,
343 .enable
= s5p6442_clk_ip3_ctrl
,
348 .parent
= &clk_pclkd1
,
349 .enable
= s5p6442_clk_ip3_ctrl
,
354 .parent
= &clk_pclkd1
,
355 .enable
= s5p6442_clk_ip3_ctrl
,
360 .parent
= &clk_pclkd1
,
361 .enable
= s5p6442_clk_ip3_ctrl
,
366 .parent
= &clk_pclkd1
,
367 .enable
= s5p6442_clk_ip3_ctrl
,
372 static struct clk
*clks
[] __initdata
= {
379 &clk_mout_d0sync
.clk
,
381 &clk_mout_d1sync
.clk
,
388 void __init
s5p6442_register_clocks(void)
390 s3c24xx_register_clocks(clks
, ARRAY_SIZE(clks
));
392 s3c_register_clksrc(clksrcs
, ARRAY_SIZE(clksrcs
));
393 s3c_register_clocks(init_clocks
, ARRAY_SIZE(init_clocks
));