diff options
author | Ben Dooks <ben-linux@fluff.org> | 2009-05-02 08:48:53 -0400 |
---|---|---|
committer | Ben Dooks <ben-linux@fluff.org> | 2009-05-07 06:46:41 -0400 |
commit | 496a3f0927197ca155a604478bf6e7db3eca3bbd (patch) | |
tree | 8f0f68a8f2627743af393b17c5d0fd613f967578 /arch/arm/plat-s3c64xx | |
parent | 8f1ecf1d965f4e1842b32af5dd40f3d7b6d407ed (diff) |
[ARM] S3C64XX: Add ARM clock
Add ARM clock to provide 'arm' from the APLL to the ARM core.
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Diffstat (limited to 'arch/arm/plat-s3c64xx')
-rw-r--r-- | arch/arm/plat-s3c64xx/include/plat/s3c6400.h | 2 | ||||
-rw-r--r-- | arch/arm/plat-s3c64xx/s3c6400-clock.c | 76 |
2 files changed, 76 insertions, 2 deletions
diff --git a/arch/arm/plat-s3c64xx/include/plat/s3c6400.h b/arch/arm/plat-s3c64xx/include/plat/s3c6400.h index e12296666d46..11f2e1e119b0 100644 --- a/arch/arm/plat-s3c64xx/include/plat/s3c6400.h +++ b/arch/arm/plat-s3c64xx/include/plat/s3c6400.h | |||
@@ -15,7 +15,7 @@ | |||
15 | /* Common init code for S3C6400 related SoCs */ | 15 | /* Common init code for S3C6400 related SoCs */ |
16 | 16 | ||
17 | extern void s3c6400_common_init_uarts(struct s3c2410_uartcfg *cfg, int no); | 17 | extern void s3c6400_common_init_uarts(struct s3c2410_uartcfg *cfg, int no); |
18 | extern void s3c6400_register_clocks(void); | 18 | extern void s3c6400_register_clocks(unsigned armclk_divlimit); |
19 | extern void s3c6400_setup_clocks(void); | 19 | extern void s3c6400_setup_clocks(void); |
20 | 20 | ||
21 | #ifdef CONFIG_CPU_S3C6400 | 21 | #ifdef CONFIG_CPU_S3C6400 |
diff --git a/arch/arm/plat-s3c64xx/s3c6400-clock.c b/arch/arm/plat-s3c64xx/s3c6400-clock.c index 96fa9ea4d5bc..1debc1f9f987 100644 --- a/arch/arm/plat-s3c64xx/s3c6400-clock.c +++ b/arch/arm/plat-s3c64xx/s3c6400-clock.c | |||
@@ -133,6 +133,65 @@ static struct clksrc_clk clk_mout_mpll = { | |||
133 | .sources = &clk_src_mpll, | 133 | .sources = &clk_src_mpll, |
134 | }; | 134 | }; |
135 | 135 | ||
136 | static unsigned int armclk_mask; | ||
137 | |||
138 | static unsigned long s3c64xx_clk_arm_get_rate(struct clk *clk) | ||
139 | { | ||
140 | unsigned long rate = clk_get_rate(clk->parent); | ||
141 | u32 clkdiv; | ||
142 | |||
143 | /* divisor mask starts at bit0, so no need to shift */ | ||
144 | clkdiv = __raw_readl(S3C_CLK_DIV0) & armclk_mask; | ||
145 | |||
146 | return rate / (clkdiv + 1); | ||
147 | } | ||
148 | |||
149 | static unsigned long s3c64xx_clk_arm_round_rate(struct clk *clk, | ||
150 | unsigned long rate) | ||
151 | { | ||
152 | unsigned long parent = clk_get_rate(clk->parent); | ||
153 | u32 div; | ||
154 | |||
155 | if (parent < rate) | ||
156 | return rate; | ||
157 | |||
158 | div = (parent / rate) - 1; | ||
159 | if (div > armclk_mask) | ||
160 | div = armclk_mask; | ||
161 | |||
162 | return parent / (div + 1); | ||
163 | } | ||
164 | |||
165 | static int s3c64xx_clk_arm_set_rate(struct clk *clk, unsigned long rate) | ||
166 | { | ||
167 | unsigned long parent = clk_get_rate(clk->parent); | ||
168 | u32 div; | ||
169 | u32 val; | ||
170 | |||
171 | if (rate < parent / (armclk_mask + 1)) | ||
172 | return -EINVAL; | ||
173 | |||
174 | rate = clk_round_rate(clk, rate); | ||
175 | div = clk_get_rate(clk->parent) / rate; | ||
176 | |||
177 | val = __raw_readl(S3C_CLK_DIV0); | ||
178 | val &= armclk_mask; | ||
179 | val |= (div - 1); | ||
180 | __raw_writel(val, S3C_CLK_DIV0); | ||
181 | |||
182 | return 0; | ||
183 | |||
184 | } | ||
185 | |||
186 | static struct clk clk_arm = { | ||
187 | .name = "armclk", | ||
188 | .id = -1, | ||
189 | .parent = &clk_mout_apll.clk, | ||
190 | .get_rate = s3c64xx_clk_arm_get_rate, | ||
191 | .set_rate = s3c64xx_clk_arm_set_rate, | ||
192 | .round_rate = s3c64xx_clk_arm_round_rate, | ||
193 | }; | ||
194 | |||
136 | static unsigned long s3c64xx_clk_doutmpll_get_rate(struct clk *clk) | 195 | static unsigned long s3c64xx_clk_doutmpll_get_rate(struct clk *clk) |
137 | { | 196 | { |
138 | unsigned long rate = clk_get_rate(clk->parent); | 197 | unsigned long rate = clk_get_rate(clk->parent); |
@@ -665,14 +724,29 @@ static struct clk *clks[] __initdata = { | |||
665 | &clk_audio1.clk, | 724 | &clk_audio1.clk, |
666 | &clk_irda.clk, | 725 | &clk_irda.clk, |
667 | &clk_camif.clk, | 726 | &clk_camif.clk, |
727 | &clk_arm, | ||
668 | }; | 728 | }; |
669 | 729 | ||
670 | void __init s3c6400_register_clocks(void) | 730 | /** |
731 | * s3c6400_register_clocks - register clocks for s3c6400 and above | ||
732 | * @armclk_divlimit: Divisor mask for ARMCLK | ||
733 | * | ||
734 | * Register the clocks for the S3C6400 and above SoC range, such | ||
735 | * as ARMCLK and the clocks which have divider chains attached. | ||
736 | * | ||
737 | * This call does not setup the clocks, which is left to the | ||
738 | * s3c6400_setup_clocks() call which may be needed by the cpufreq | ||
739 | * or resume code to re-set the clocks if the bootloader has changed | ||
740 | * them. | ||
741 | */ | ||
742 | void __init s3c6400_register_clocks(unsigned armclk_divlimit) | ||
671 | { | 743 | { |
672 | struct clk *clkp; | 744 | struct clk *clkp; |
673 | int ret; | 745 | int ret; |
674 | int ptr; | 746 | int ptr; |
675 | 747 | ||
748 | armclk_mask = armclk_divlimit; | ||
749 | |||
676 | for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) { | 750 | for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) { |
677 | clkp = clks[ptr]; | 751 | clkp = clks[ptr]; |
678 | ret = s3c24xx_register_clock(clkp); | 752 | ret = s3c24xx_register_clock(clkp); |