diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-05 21:21:21 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-05 21:21:21 -0400 |
commit | c861cd3e92d92ae946e19099f198018fcb4fd887 (patch) | |
tree | fab678a30a85cf80038c560221d6ab01812a3891 /arch/arm/plat-s3c24xx | |
parent | 7abec10c623d9e0416dab6919a0ea22e6283516b (diff) | |
parent | b8bc83971cc20cae3c3b65c26a804f350d74960c (diff) |
Merge branch 'next/devel2' of git://git.linaro.org/people/arnd/arm-soc
* 'next/devel2' of git://git.linaro.org/people/arnd/arm-soc: (30 commits)
ARM: mmp: register internal sram bank
ARM: mmp: register audio sram bank
ARM: mmp: add sram allocator
gpio/samsung: Complain loudly if we don't know the SoC
ARM: S3C64XX: Fix SoC identification for S3C64xx devices
ARM: S3C2443: Remove redundant s3c_register_clocks call for init_clocks
ARM: S3C24XX: Add devname for hsmmc1 pclk
ARM: S3C24XX: use clk_get_rate to init fclk in common_setup_clocks
ARM: S3C2443: Accommodate cpufreq frequency scheme in armdiv
ARM: S3C2443: handle unset armdiv values gracefully
ARM: S3C2443: Add get_rate operation for clk_armdiv
ARM: S3C2416: Add comment describing the armdiv/armclk
ARM: S3C2443: Move clk_arm and clk_armdiv to common code
ARM: S3C24XX: Add infrastructure to transmit armdiv to common code
ARM: S3C2416: Add armdiv_mask constant
ARM: EXYNOS4: Add support for M-5MOLS camera on Nuri board
ARM: EXYNOS4: Enable MFC on ORIGEN
ARM: SAMSUNG: Add support s3c2416-adc for S3C2416/S3C2450
ARM: SAMSUNG: Add support s3c2443-adc for S3C2443
ARM: SAMSUNG: Allow overriding of adc device name for S3C24XX
...
Diffstat (limited to 'arch/arm/plat-s3c24xx')
-rw-r--r-- | arch/arm/plat-s3c24xx/s3c2443-clock.c | 135 |
1 files changed, 130 insertions, 5 deletions
diff --git a/arch/arm/plat-s3c24xx/s3c2443-clock.c b/arch/arm/plat-s3c24xx/s3c2443-clock.c index 07a4c81587ac..5a21b15b2a97 100644 --- a/arch/arm/plat-s3c24xx/s3c2443-clock.c +++ b/arch/arm/plat-s3c24xx/s3c2443-clock.c | |||
@@ -160,6 +160,124 @@ static struct clk clk_prediv = { | |||
160 | }, | 160 | }, |
161 | }; | 161 | }; |
162 | 162 | ||
163 | /* armdiv | ||
164 | * | ||
165 | * this clock is sourced from msysclk and can have a number of | ||
166 | * divider values applied to it to then be fed into armclk. | ||
167 | */ | ||
168 | |||
169 | static unsigned int *armdiv; | ||
170 | static int nr_armdiv; | ||
171 | static int armdivmask; | ||
172 | |||
173 | static unsigned long s3c2443_armclk_roundrate(struct clk *clk, | ||
174 | unsigned long rate) | ||
175 | { | ||
176 | unsigned long parent = clk_get_rate(clk->parent); | ||
177 | unsigned long calc; | ||
178 | unsigned best = 256; /* bigger than any value */ | ||
179 | unsigned div; | ||
180 | int ptr; | ||
181 | |||
182 | if (!nr_armdiv) | ||
183 | return -EINVAL; | ||
184 | |||
185 | for (ptr = 0; ptr < nr_armdiv; ptr++) { | ||
186 | div = armdiv[ptr]; | ||
187 | if (div) { | ||
188 | /* cpufreq provides 266mhz as 266666000 not 266666666 */ | ||
189 | calc = (parent / div / 1000) * 1000; | ||
190 | if (calc <= rate && div < best) | ||
191 | best = div; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | return parent / best; | ||
196 | } | ||
197 | |||
198 | static unsigned long s3c2443_armclk_getrate(struct clk *clk) | ||
199 | { | ||
200 | unsigned long rate = clk_get_rate(clk->parent); | ||
201 | unsigned long clkcon0; | ||
202 | int val; | ||
203 | |||
204 | if (!nr_armdiv || !armdivmask) | ||
205 | return -EINVAL; | ||
206 | |||
207 | clkcon0 = __raw_readl(S3C2443_CLKDIV0); | ||
208 | clkcon0 &= armdivmask; | ||
209 | val = clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT; | ||
210 | |||
211 | return rate / armdiv[val]; | ||
212 | } | ||
213 | |||
214 | static int s3c2443_armclk_setrate(struct clk *clk, unsigned long rate) | ||
215 | { | ||
216 | unsigned long parent = clk_get_rate(clk->parent); | ||
217 | unsigned long calc; | ||
218 | unsigned div; | ||
219 | unsigned best = 256; /* bigger than any value */ | ||
220 | int ptr; | ||
221 | int val = -1; | ||
222 | |||
223 | if (!nr_armdiv || !armdivmask) | ||
224 | return -EINVAL; | ||
225 | |||
226 | for (ptr = 0; ptr < nr_armdiv; ptr++) { | ||
227 | div = armdiv[ptr]; | ||
228 | if (div) { | ||
229 | /* cpufreq provides 266mhz as 266666000 not 266666666 */ | ||
230 | calc = (parent / div / 1000) * 1000; | ||
231 | if (calc <= rate && div < best) { | ||
232 | best = div; | ||
233 | val = ptr; | ||
234 | } | ||
235 | } | ||
236 | } | ||
237 | |||
238 | if (val >= 0) { | ||
239 | unsigned long clkcon0; | ||
240 | |||
241 | clkcon0 = __raw_readl(S3C2443_CLKDIV0); | ||
242 | clkcon0 &= ~armdivmask; | ||
243 | clkcon0 |= val << S3C2443_CLKDIV0_ARMDIV_SHIFT; | ||
244 | __raw_writel(clkcon0, S3C2443_CLKDIV0); | ||
245 | } | ||
246 | |||
247 | return (val == -1) ? -EINVAL : 0; | ||
248 | } | ||
249 | |||
250 | static struct clk clk_armdiv = { | ||
251 | .name = "armdiv", | ||
252 | .parent = &clk_msysclk.clk, | ||
253 | .ops = &(struct clk_ops) { | ||
254 | .round_rate = s3c2443_armclk_roundrate, | ||
255 | .get_rate = s3c2443_armclk_getrate, | ||
256 | .set_rate = s3c2443_armclk_setrate, | ||
257 | }, | ||
258 | }; | ||
259 | |||
260 | /* armclk | ||
261 | * | ||
262 | * this is the clock fed into the ARM core itself, from armdiv or from hclk. | ||
263 | */ | ||
264 | |||
265 | static struct clk *clk_arm_sources[] = { | ||
266 | [0] = &clk_armdiv, | ||
267 | [1] = &clk_h, | ||
268 | }; | ||
269 | |||
270 | static struct clksrc_clk clk_arm = { | ||
271 | .clk = { | ||
272 | .name = "armclk", | ||
273 | }, | ||
274 | .sources = &(struct clksrc_sources) { | ||
275 | .sources = clk_arm_sources, | ||
276 | .nr_sources = ARRAY_SIZE(clk_arm_sources), | ||
277 | }, | ||
278 | .reg_src = { .reg = S3C2443_CLKDIV0, .size = 1, .shift = 13 }, | ||
279 | }; | ||
280 | |||
163 | /* usbhost | 281 | /* usbhost |
164 | * | 282 | * |
165 | * usb host bus-clock, usually 48MHz to provide USB bus clock timing | 283 | * usb host bus-clock, usually 48MHz to provide USB bus clock timing |
@@ -308,6 +426,7 @@ static struct clk init_clocks[] = { | |||
308 | .ctrlbit = S3C2443_HCLKCON_DMA5, | 426 | .ctrlbit = S3C2443_HCLKCON_DMA5, |
309 | }, { | 427 | }, { |
310 | .name = "hsmmc", | 428 | .name = "hsmmc", |
429 | .devname = "s3c-sdhci.1", | ||
311 | .parent = &clk_h, | 430 | .parent = &clk_h, |
312 | .enable = s3c2443_clkcon_enable_h, | 431 | .enable = s3c2443_clkcon_enable_h, |
313 | .ctrlbit = S3C2443_HCLKCON_HSMMC, | 432 | .ctrlbit = S3C2443_HCLKCON_HSMMC, |
@@ -402,8 +521,7 @@ static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0) | |||
402 | 521 | ||
403 | /* EPLLCON compatible enough to get on/off information */ | 522 | /* EPLLCON compatible enough to get on/off information */ |
404 | 523 | ||
405 | void __init_or_cpufreq s3c2443_common_setup_clocks(pll_fn get_mpll, | 524 | void __init_or_cpufreq s3c2443_common_setup_clocks(pll_fn get_mpll) |
406 | fdiv_fn get_fdiv) | ||
407 | { | 525 | { |
408 | unsigned long epllcon = __raw_readl(S3C2443_EPLLCON); | 526 | unsigned long epllcon = __raw_readl(S3C2443_EPLLCON); |
409 | unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON); | 527 | unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON); |
@@ -423,7 +541,7 @@ void __init_or_cpufreq s3c2443_common_setup_clocks(pll_fn get_mpll, | |||
423 | pll = get_mpll(mpllcon, xtal); | 541 | pll = get_mpll(mpllcon, xtal); |
424 | clk_msysclk.clk.rate = pll; | 542 | clk_msysclk.clk.rate = pll; |
425 | 543 | ||
426 | fclk = pll / get_fdiv(clkdiv0); | 544 | fclk = clk_get_rate(&clk_armdiv); |
427 | hclk = s3c2443_prediv_getrate(&clk_prediv); | 545 | hclk = s3c2443_prediv_getrate(&clk_prediv); |
428 | hclk /= s3c2443_get_hdiv(clkdiv0); | 546 | hclk /= s3c2443_get_hdiv(clkdiv0); |
429 | pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1); | 547 | pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1); |
@@ -458,6 +576,7 @@ static struct clk *clks[] __initdata = { | |||
458 | &clk_ext, | 576 | &clk_ext, |
459 | &clk_epll, | 577 | &clk_epll, |
460 | &clk_usb_bus, | 578 | &clk_usb_bus, |
579 | &clk_armdiv, | ||
461 | }; | 580 | }; |
462 | 581 | ||
463 | static struct clksrc_clk *clksrcs[] __initdata = { | 582 | static struct clksrc_clk *clksrcs[] __initdata = { |
@@ -467,13 +586,19 @@ static struct clksrc_clk *clksrcs[] __initdata = { | |||
467 | &clk_epllref, | 586 | &clk_epllref, |
468 | &clk_esysclk, | 587 | &clk_esysclk, |
469 | &clk_msysclk, | 588 | &clk_msysclk, |
589 | &clk_arm, | ||
470 | }; | 590 | }; |
471 | 591 | ||
472 | void __init s3c2443_common_init_clocks(int xtal, pll_fn get_mpll, | 592 | void __init s3c2443_common_init_clocks(int xtal, pll_fn get_mpll, |
473 | fdiv_fn get_fdiv) | 593 | unsigned int *divs, int nr_divs, |
594 | int divmask) | ||
474 | { | 595 | { |
475 | int ptr; | 596 | int ptr; |
476 | 597 | ||
598 | armdiv = divs; | ||
599 | nr_armdiv = nr_divs; | ||
600 | armdivmask = divmask; | ||
601 | |||
477 | /* s3c2443 parents h and p clocks from prediv */ | 602 | /* s3c2443 parents h and p clocks from prediv */ |
478 | clk_h.parent = &clk_prediv; | 603 | clk_h.parent = &clk_prediv; |
479 | clk_p.parent = &clk_prediv; | 604 | clk_p.parent = &clk_prediv; |
@@ -494,5 +619,5 @@ void __init s3c2443_common_init_clocks(int xtal, pll_fn get_mpll, | |||
494 | s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); | 619 | s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); |
495 | s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); | 620 | s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); |
496 | 621 | ||
497 | s3c2443_common_setup_clocks(get_mpll, get_fdiv); | 622 | s3c2443_common_setup_clocks(get_mpll); |
498 | } | 623 | } |