diff options
Diffstat (limited to 'arch/arm/mach-omap2/dpll3xxx.c')
-rw-r--r-- | arch/arm/mach-omap2/dpll3xxx.c | 82 |
1 files changed, 70 insertions, 12 deletions
diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c index 2b559fc64855..b32ccd954a1b 100644 --- a/arch/arm/mach-omap2/dpll3xxx.c +++ b/arch/arm/mach-omap2/dpll3xxx.c | |||
@@ -1,11 +1,14 @@ | |||
1 | /* | 1 | /* |
2 | * OMAP3/4 - specific DPLL control functions | 2 | * OMAP3/4 - specific DPLL control functions |
3 | * | 3 | * |
4 | * Copyright (C) 2009 Texas Instruments, Inc. | 4 | * Copyright (C) 2009-2010 Texas Instruments, Inc. |
5 | * Copyright (C) 2009 Nokia Corporation | 5 | * Copyright (C) 2009-2010 Nokia Corporation |
6 | * | 6 | * |
7 | * Written by Paul Walmsley | 7 | * Written by Paul Walmsley |
8 | * Testing and integration fixes by Jouni Högander | 8 | * Testing and integration fixes by Jouni Högander |
9 | * | ||
10 | * 36xx support added by Vishwanath BS, Richard Woodruff, and Nishanth | ||
11 | * Menon | ||
9 | * | 12 | * |
10 | * Parts of this code are based on code written by | 13 | * Parts of this code are based on code written by |
11 | * Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu | 14 | * Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu |
@@ -15,7 +18,6 @@ | |||
15 | * published by the Free Software Foundation. | 18 | * published by the Free Software Foundation. |
16 | */ | 19 | */ |
17 | 20 | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
20 | #include <linux/device.h> | 22 | #include <linux/device.h> |
21 | #include <linux/list.h> | 23 | #include <linux/list.h> |
@@ -23,13 +25,10 @@ | |||
23 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
24 | #include <linux/clk.h> | 26 | #include <linux/clk.h> |
25 | #include <linux/io.h> | 27 | #include <linux/io.h> |
26 | #include <linux/limits.h> | ||
27 | #include <linux/bitops.h> | 28 | #include <linux/bitops.h> |
28 | 29 | ||
29 | #include <plat/cpu.h> | 30 | #include <plat/cpu.h> |
30 | #include <plat/clock.h> | 31 | #include <plat/clock.h> |
31 | #include <plat/sram.h> | ||
32 | #include <asm/div64.h> | ||
33 | #include <asm/clkdev.h> | 32 | #include <asm/clkdev.h> |
34 | 33 | ||
35 | #include "clock.h" | 34 | #include "clock.h" |
@@ -225,6 +224,47 @@ static int _omap3_noncore_dpll_stop(struct clk *clk) | |||
225 | return 0; | 224 | return 0; |
226 | } | 225 | } |
227 | 226 | ||
227 | /** | ||
228 | * lookup_dco_sddiv - Set j-type DPLL4 compensation variables | ||
229 | * @clk: pointer to a DPLL struct clk | ||
230 | * @dco: digital control oscillator selector | ||
231 | * @sd_div: target sigma-delta divider | ||
232 | * @m: DPLL multiplier to set | ||
233 | * @n: DPLL divider to set | ||
234 | * | ||
235 | * See 36xx TRM section 3.5.3.3.3.2 "Type B DPLL (Low-Jitter)" | ||
236 | * | ||
237 | * XXX This code is not needed for 3430/AM35xx; can it be optimized | ||
238 | * out in non-multi-OMAP builds for those chips? | ||
239 | */ | ||
240 | static void lookup_dco_sddiv(struct clk *clk, u8 *dco, u8 *sd_div, u16 m, | ||
241 | u8 n) | ||
242 | { | ||
243 | unsigned long fint, clkinp, sd; /* watch out for overflow */ | ||
244 | int mod1, mod2; | ||
245 | |||
246 | clkinp = clk->parent->rate; | ||
247 | fint = (clkinp / n) * m; | ||
248 | |||
249 | if (fint < 1000000000) | ||
250 | *dco = 2; | ||
251 | else | ||
252 | *dco = 4; | ||
253 | /* | ||
254 | * target sigma-delta to near 250MHz | ||
255 | * sd = ceil[(m/(n+1)) * (clkinp_MHz / 250)] | ||
256 | */ | ||
257 | clkinp /= 100000; /* shift from MHz to 10*Hz for 38.4 and 19.2 */ | ||
258 | mod1 = (clkinp * m) % (250 * n); | ||
259 | sd = (clkinp * m) / (250 * n); | ||
260 | mod2 = sd % 10; | ||
261 | sd /= 10; | ||
262 | |||
263 | if (mod1 || mod2) | ||
264 | sd++; | ||
265 | *sd_div = sd; | ||
266 | } | ||
267 | |||
228 | /* | 268 | /* |
229 | * _omap3_noncore_dpll_program - set non-core DPLL M,N values directly | 269 | * _omap3_noncore_dpll_program - set non-core DPLL M,N values directly |
230 | * @clk: struct clk * of DPLL to set | 270 | * @clk: struct clk * of DPLL to set |
@@ -243,8 +283,11 @@ static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel) | |||
243 | /* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */ | 283 | /* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */ |
244 | _omap3_noncore_dpll_bypass(clk); | 284 | _omap3_noncore_dpll_bypass(clk); |
245 | 285 | ||
246 | /* Set jitter correction */ | 286 | /* |
247 | if (!cpu_is_omap44xx()) { | 287 | * Set jitter correction. No jitter correction for OMAP4 and 3630 |
288 | * since freqsel field is no longer present | ||
289 | */ | ||
290 | if (!cpu_is_omap44xx() && !cpu_is_omap3630()) { | ||
248 | v = __raw_readl(dd->control_reg); | 291 | v = __raw_readl(dd->control_reg); |
249 | v &= ~dd->freqsel_mask; | 292 | v &= ~dd->freqsel_mask; |
250 | v |= freqsel << __ffs(dd->freqsel_mask); | 293 | v |= freqsel << __ffs(dd->freqsel_mask); |
@@ -256,6 +299,21 @@ static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel) | |||
256 | v &= ~(dd->mult_mask | dd->div1_mask); | 299 | v &= ~(dd->mult_mask | dd->div1_mask); |
257 | v |= m << __ffs(dd->mult_mask); | 300 | v |= m << __ffs(dd->mult_mask); |
258 | v |= (n - 1) << __ffs(dd->div1_mask); | 301 | v |= (n - 1) << __ffs(dd->div1_mask); |
302 | |||
303 | /* | ||
304 | * XXX This code is not needed for 3430/AM35XX; can it be optimized | ||
305 | * out in non-multi-OMAP builds for those chips? | ||
306 | */ | ||
307 | if ((dd->flags & DPLL_J_TYPE) && !(dd->flags & DPLL_NO_DCO_SEL)) { | ||
308 | u8 dco, sd_div; | ||
309 | lookup_dco_sddiv(clk, &dco, &sd_div, m, n); | ||
310 | /* XXX This probably will need revision for OMAP4 */ | ||
311 | v &= ~(OMAP3630_PERIPH_DPLL_DCO_SEL_MASK | ||
312 | | OMAP3630_PERIPH_DPLL_SD_DIV_MASK); | ||
313 | v |= dco << __ffs(OMAP3630_PERIPH_DPLL_DCO_SEL_MASK); | ||
314 | v |= sd_div << __ffs(OMAP3630_PERIPH_DPLL_SD_DIV_MASK); | ||
315 | } | ||
316 | |||
259 | __raw_writel(v, dd->mult_div1_reg); | 317 | __raw_writel(v, dd->mult_div1_reg); |
260 | 318 | ||
261 | /* We let the clock framework set the other output dividers later */ | 319 | /* We let the clock framework set the other output dividers later */ |
@@ -387,8 +445,8 @@ int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate) | |||
387 | if (dd->last_rounded_rate == 0) | 445 | if (dd->last_rounded_rate == 0) |
388 | return -EINVAL; | 446 | return -EINVAL; |
389 | 447 | ||
390 | /* No freqsel on OMAP4 */ | 448 | /* No freqsel on OMAP4 and OMAP3630 */ |
391 | if (!cpu_is_omap44xx()) { | 449 | if (!cpu_is_omap44xx() && !cpu_is_omap3630()) { |
392 | freqsel = _omap3_dpll_compute_freqsel(clk, | 450 | freqsel = _omap3_dpll_compute_freqsel(clk, |
393 | dd->last_rounded_n); | 451 | dd->last_rounded_n); |
394 | if (!freqsel) | 452 | if (!freqsel) |
@@ -533,7 +591,7 @@ unsigned long omap3_clkoutx2_recalc(struct clk *clk) | |||
533 | 591 | ||
534 | v = __raw_readl(dd->control_reg) & dd->enable_mask; | 592 | v = __raw_readl(dd->control_reg) & dd->enable_mask; |
535 | v >>= __ffs(dd->enable_mask); | 593 | v >>= __ffs(dd->enable_mask); |
536 | if (v != OMAP3XXX_EN_DPLL_LOCKED) | 594 | if ((v != OMAP3XXX_EN_DPLL_LOCKED) || (dd->flags & DPLL_J_TYPE)) |
537 | rate = clk->parent->rate; | 595 | rate = clk->parent->rate; |
538 | else | 596 | else |
539 | rate = clk->parent->rate * 2; | 597 | rate = clk->parent->rate * 2; |