diff options
Diffstat (limited to 'arch/arm/mach-omap2/clock.c')
-rw-r--r-- | arch/arm/mach-omap2/clock.c | 47 |
1 files changed, 37 insertions, 10 deletions
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 5020cb1f2e7..40cb65ba1fa 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -211,25 +211,52 @@ void omap2_init_clksel_parent(struct clk *clk) return; } -/* Returns the DPLL rate */ +/** + * omap2_get_dpll_rate - returns the current DPLL CLKOUT rate + * @clk: struct clk * of a DPLL + * + * DPLLs can be locked or bypassed - basically, enabled or disabled. + * When locked, the DPLL output depends on the M and N values. When + * bypassed, on OMAP2xxx, the output rate is either the 32KiHz clock + * or sys_clk. Bypass rates on OMAP3 depend on the DPLL: DPLLs 1 and + * 2 are bypassed with dpll1_fclk and dpll2_fclk respectively + * (generated by DPLL3), while DPLL 3, 4, and 5 bypass rates are sys_clk. + * Returns the current DPLL CLKOUT rate (*not* CLKOUTX2) if the DPLL is + * locked, or the appropriate bypass rate if the DPLL is bypassed, or 0 + * if the clock @clk is not a DPLL. + */ u32 omap2_get_dpll_rate(struct clk *clk) { long long dpll_clk; - u32 dpll_mult, dpll_div, dpll; + u32 dpll_mult, dpll_div, v; struct dpll_data *dd; dd = clk->dpll_data; - /* REVISIT: What do we return on error? */ if (!dd) return 0; - dpll = __raw_readl(dd->mult_div1_reg); - dpll_mult = dpll & dd->mult_mask; + /* Return bypass rate if DPLL is bypassed */ + v = __raw_readl(dd->control_reg); + v &= dd->enable_mask; + v >>= __ffs(dd->enable_mask); + + if (cpu_is_omap24xx()) { + if (v == OMAP2XXX_EN_DPLL_LPBYPASS || + v == OMAP2XXX_EN_DPLL_FRBYPASS) + return dd->clk_bypass->rate; + } else if (cpu_is_omap34xx()) { + if (v == OMAP3XXX_EN_DPLL_LPBYPASS || + v == OMAP3XXX_EN_DPLL_FRBYPASS) + return dd->clk_bypass->rate; + } + + v = __raw_readl(dd->mult_div1_reg); + dpll_mult = v & dd->mult_mask; dpll_mult >>= __ffs(dd->mult_mask); - dpll_div = dpll & dd->div1_mask; + dpll_div = v & dd->div1_mask; dpll_div >>= __ffs(dd->div1_mask); - dpll_clk = (long long)clk->parent->rate * dpll_mult; + dpll_clk = (long long)dd->clk_ref->rate * dpll_mult; do_div(dpll_clk, dpll_div + 1); return dpll_clk; @@ -930,7 +957,7 @@ long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate) pr_debug("clock: starting DPLL round_rate for clock %s, target rate " "%ld\n", clk->name, target_rate); - scaled_rt_rp = target_rate / (clk->parent->rate / DPLL_SCALE_FACTOR); + scaled_rt_rp = target_rate / (dd->clk_ref->rate / DPLL_SCALE_FACTOR); scaled_max_m = dd->max_multiplier * DPLL_SCALE_FACTOR; dd->last_rounded_rate = 0; @@ -957,7 +984,7 @@ long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate) break; r = _dpll_test_mult(&m, n, &new_rate, target_rate, - clk->parent->rate); + dd->clk_ref->rate); /* m can't be set low enough for this n - try with a larger n */ if (r == DPLL_MULT_UNDERFLOW) @@ -988,7 +1015,7 @@ long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate) dd->last_rounded_m = min_e_m; dd->last_rounded_n = min_e_n; - dd->last_rounded_rate = _dpll_compute_new_rate(clk->parent->rate, + dd->last_rounded_rate = _dpll_compute_new_rate(dd->clk_ref->rate, min_e_m, min_e_n); pr_debug("clock: final least error: e = %d, m = %d, n = %d\n", |