1 /* linux/arch/arm/mach-s5pv210/clock.c
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
6 * S5PV210 - 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/errno.h>
18 #include <linux/err.h>
19 #include <linux/clk.h>
20 #include <linux/sysdev.h>
25 #include <plat/cpu-freq.h>
26 #include <mach/regs-clock.h>
27 #include <plat/clock.h>
30 #include <plat/s5p-clock.h>
31 #include <plat/clock-clksrc.h>
32 #include <plat/s5pv210.h>
34 static int s5pv210_clk_ip0_ctrl(struct clk
*clk
, int enable
)
36 return s5p_gatectrl(S5P_CLKGATE_IP0
, clk
, enable
);
39 static int s5pv210_clk_ip1_ctrl(struct clk
*clk
, int enable
)
41 return s5p_gatectrl(S5P_CLKGATE_IP1
, clk
, enable
);
44 static int s5pv210_clk_ip2_ctrl(struct clk
*clk
, int enable
)
46 return s5p_gatectrl(S5P_CLKGATE_IP2
, clk
, enable
);
49 static int s5pv210_clk_ip3_ctrl(struct clk
*clk
, int enable
)
51 return s5p_gatectrl(S5P_CLKGATE_IP3
, clk
, enable
);
54 static struct clk clk_h200
= {
59 static struct clk clk_h100
= {
64 static struct clk clk_h166
= {
69 static struct clk clk_h133
= {
74 static struct clk clk_p100
= {
79 static struct clk clk_p83
= {
84 static struct clk clk_p66
= {
89 static struct clk
*sys_clks
[] = {
99 static struct clk init_clocks_disable
[] = {
104 .enable
= s5pv210_clk_ip0_ctrl
,
110 .enable
= s5pv210_clk_ip1_ctrl
,
116 .enable
= s5pv210_clk_ip1_ctrl
,
122 .enable
= s5pv210_clk_ip1_ctrl
,
128 .enable
= s5pv210_clk_ip1_ctrl
,
134 .enable
= s5pv210_clk_ip2_ctrl
,
140 .enable
= s5pv210_clk_ip2_ctrl
,
146 .enable
= s5pv210_clk_ip2_ctrl
,
152 .enable
= s5pv210_clk_ip2_ctrl
,
158 .enable
= s5pv210_clk_ip3_ctrl
,
164 .enable
= s5pv210_clk_ip3_ctrl
,
170 .enable
= s5pv210_clk_ip3_ctrl
,
176 .enable
= s5pv210_clk_ip3_ctrl
,
182 .enable
= s5pv210_clk_ip3_ctrl
,
188 .enable
= s5pv210_clk_ip3_ctrl
,
194 .enable
= s5pv210_clk_ip3_ctrl
,
200 .enable
= s5pv210_clk_ip3_ctrl
,
206 .enable
= s5pv210_clk_ip3_ctrl
,
212 .enable
= s5pv210_clk_ip3_ctrl
,
218 .enable
= s5pv210_clk_ip3_ctrl
,
224 .enable
= s5pv210_clk_ip3_ctrl
,
230 .enable
= s5pv210_clk_ip3_ctrl
,
236 .enable
= s5pv210_clk_ip3_ctrl
,
242 .enable
= s5pv210_clk_ip3_ctrl
,
247 static struct clk init_clocks
[] = {
252 .enable
= s5pv210_clk_ip3_ctrl
,
258 .enable
= s5pv210_clk_ip3_ctrl
,
264 .enable
= s5pv210_clk_ip3_ctrl
,
270 .enable
= s5pv210_clk_ip3_ctrl
,
275 static struct clksrc_clk clk_mout_apll
= {
280 .sources
= &clk_src_apll
,
281 .reg_src
= { .reg
= S5P_CLK_SRC0
, .shift
= 0, .size
= 1 },
284 static struct clksrc_clk clk_mout_epll
= {
289 .sources
= &clk_src_epll
,
290 .reg_src
= { .reg
= S5P_CLK_SRC0
, .shift
= 8, .size
= 1 },
293 static struct clksrc_clk clk_mout_mpll
= {
298 .sources
= &clk_src_mpll
,
299 .reg_src
= { .reg
= S5P_CLK_SRC0
, .shift
= 4, .size
= 1 },
302 static struct clk
*clkset_uart_list
[] = {
303 [6] = &clk_mout_mpll
.clk
,
304 [7] = &clk_mout_epll
.clk
,
307 static struct clksrc_sources clkset_uart
= {
308 .sources
= clkset_uart_list
,
309 .nr_sources
= ARRAY_SIZE(clkset_uart_list
),
312 static struct clksrc_clk clksrcs
[] = {
318 .enable
= s5pv210_clk_ip3_ctrl
,
320 .sources
= &clkset_uart
,
321 .reg_src
= { .reg
= S5P_CLK_SRC4
, .shift
= 16, .size
= 4 },
322 .reg_div
= { .reg
= S5P_CLK_DIV4
, .shift
= 16, .size
= 4 },
326 /* Clock initialisation code */
327 static struct clksrc_clk
*init_parents
[] = {
333 #define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
335 void __init_or_cpufreq
s5pv210_setup_clocks(void)
337 struct clk
*xtal_clk
;
339 unsigned long armclk
;
340 unsigned long hclk200
;
341 unsigned long hclk166
;
342 unsigned long hclk133
;
343 unsigned long pclk100
;
344 unsigned long pclk83
;
345 unsigned long pclk66
;
350 u32 clkdiv0
, clkdiv1
;
352 printk(KERN_DEBUG
"%s: registering clocks\n", __func__
);
354 clkdiv0
= __raw_readl(S5P_CLK_DIV0
);
355 clkdiv1
= __raw_readl(S5P_CLK_DIV1
);
357 printk(KERN_DEBUG
"%s: clkdiv0 = %08x, clkdiv1 = %08x\n",
358 __func__
, clkdiv0
, clkdiv1
);
360 xtal_clk
= clk_get(NULL
, "xtal");
361 BUG_ON(IS_ERR(xtal_clk
));
363 xtal
= clk_get_rate(xtal_clk
);
366 printk(KERN_DEBUG
"%s: xtal is %ld\n", __func__
, xtal
);
368 apll
= s5p_get_pll45xx(xtal
, __raw_readl(S5P_APLL_CON
), pll_4508
);
369 mpll
= s5p_get_pll45xx(xtal
, __raw_readl(S5P_MPLL_CON
), pll_4502
);
370 epll
= s5p_get_pll45xx(xtal
, __raw_readl(S5P_EPLL_CON
), pll_4500
);
372 printk(KERN_INFO
"S5PV210: PLL settings, A=%ld, M=%ld, E=%ld",
375 armclk
= apll
/ GET_DIV(clkdiv0
, S5P_CLKDIV0_APLL
);
376 if (__raw_readl(S5P_CLK_SRC0
) & S5P_CLKSRC0_MUX200_MASK
)
377 hclk200
= mpll
/ GET_DIV(clkdiv0
, S5P_CLKDIV0_HCLK200
);
379 hclk200
= armclk
/ GET_DIV(clkdiv0
, S5P_CLKDIV0_HCLK200
);
381 if (__raw_readl(S5P_CLK_SRC0
) & S5P_CLKSRC0_MUX166_MASK
) {
382 hclk166
= apll
/ GET_DIV(clkdiv0
, S5P_CLKDIV0_A2M
);
383 hclk166
= hclk166
/ GET_DIV(clkdiv0
, S5P_CLKDIV0_HCLK166
);
385 hclk166
= mpll
/ GET_DIV(clkdiv0
, S5P_CLKDIV0_HCLK166
);
387 if (__raw_readl(S5P_CLK_SRC0
) & S5P_CLKSRC0_MUX133_MASK
) {
388 hclk133
= apll
/ GET_DIV(clkdiv0
, S5P_CLKDIV0_A2M
);
389 hclk133
= hclk133
/ GET_DIV(clkdiv0
, S5P_CLKDIV0_HCLK133
);
391 hclk133
= mpll
/ GET_DIV(clkdiv0
, S5P_CLKDIV0_HCLK133
);
393 pclk100
= hclk200
/ GET_DIV(clkdiv0
, S5P_CLKDIV0_PCLK100
);
394 pclk83
= hclk166
/ GET_DIV(clkdiv0
, S5P_CLKDIV0_PCLK83
);
395 pclk66
= hclk133
/ GET_DIV(clkdiv0
, S5P_CLKDIV0_PCLK66
);
397 printk(KERN_INFO
"S5PV210: ARMCLK=%ld, HCLKM=%ld, HCLKD=%ld, \
398 HCLKP=%ld, PCLKM=%ld, PCLKD=%ld, PCLKP=%ld\n",
399 armclk
, hclk200
, hclk166
, hclk133
, pclk100
, pclk83
, pclk66
);
401 clk_fout_apll
.rate
= apll
;
402 clk_fout_mpll
.rate
= mpll
;
403 clk_fout_epll
.rate
= epll
;
406 clk_h
.rate
= hclk133
;
408 clk_p66
.rate
= pclk66
;
409 clk_p83
.rate
= pclk83
;
410 clk_h133
.rate
= hclk133
;
411 clk_h166
.rate
= hclk166
;
412 clk_h200
.rate
= hclk200
;
414 for (ptr
= 0; ptr
< ARRAY_SIZE(init_parents
); ptr
++)
415 s3c_set_clksrc(init_parents
[ptr
], true);
417 for (ptr
= 0; ptr
< ARRAY_SIZE(clksrcs
); ptr
++)
418 s3c_set_clksrc(&clksrcs
[ptr
], true);
421 static struct clk
*clks
[] __initdata
= {
426 void __init
s5pv210_register_clocks(void)
432 ret
= s3c24xx_register_clocks(clks
, ARRAY_SIZE(clks
));
434 printk(KERN_ERR
"Failed to register %u clocks\n", ret
);
436 s3c_register_clksrc(clksrcs
, ARRAY_SIZE(clksrcs
));
437 s3c_register_clocks(init_clocks
, ARRAY_SIZE(init_clocks
));
439 ret
= s3c24xx_register_clocks(sys_clks
, ARRAY_SIZE(sys_clks
));
441 printk(KERN_ERR
"Failed to register system clocks\n");
443 clkp
= init_clocks_disable
;
444 for (ptr
= 0; ptr
< ARRAY_SIZE(init_clocks_disable
); ptr
++, clkp
++) {
445 ret
= s3c24xx_register_clock(clkp
);
447 printk(KERN_ERR
"Failed to register clock %s (%d)\n",
450 (clkp
->enable
)(clkp
, 0);