diff options
Diffstat (limited to 'arch/arm/mach-omap2/clock34xx.c')
-rw-r--r-- | arch/arm/mach-omap2/clock34xx.c | 90 |
1 files changed, 71 insertions, 19 deletions
diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c index fb0f53b96811..0a14dca31e30 100644 --- a/arch/arm/mach-omap2/clock34xx.c +++ b/arch/arm/mach-omap2/clock34xx.c | |||
@@ -93,7 +93,6 @@ static struct omap_clk omap34xx_clks[] = { | |||
93 | CLK(NULL, "omap_96m_alwon_fck", &omap_96m_alwon_fck, CK_343X), | 93 | CLK(NULL, "omap_96m_alwon_fck", &omap_96m_alwon_fck, CK_343X), |
94 | CLK(NULL, "omap_96m_fck", &omap_96m_fck, CK_343X), | 94 | CLK(NULL, "omap_96m_fck", &omap_96m_fck, CK_343X), |
95 | CLK(NULL, "cm_96m_fck", &cm_96m_fck, CK_343X), | 95 | CLK(NULL, "cm_96m_fck", &cm_96m_fck, CK_343X), |
96 | CLK(NULL, "virt_omap_54m_fck", &virt_omap_54m_fck, CK_343X), | ||
97 | CLK(NULL, "omap_54m_fck", &omap_54m_fck, CK_343X), | 96 | CLK(NULL, "omap_54m_fck", &omap_54m_fck, CK_343X), |
98 | CLK(NULL, "omap_48m_fck", &omap_48m_fck, CK_343X), | 97 | CLK(NULL, "omap_48m_fck", &omap_48m_fck, CK_343X), |
99 | CLK(NULL, "omap_12m_fck", &omap_12m_fck, CK_343X), | 98 | CLK(NULL, "omap_12m_fck", &omap_12m_fck, CK_343X), |
@@ -110,7 +109,6 @@ static struct omap_clk omap34xx_clks[] = { | |||
110 | CLK(NULL, "emu_per_alwon_ck", &emu_per_alwon_ck, CK_343X), | 109 | CLK(NULL, "emu_per_alwon_ck", &emu_per_alwon_ck, CK_343X), |
111 | CLK(NULL, "dpll5_ck", &dpll5_ck, CK_3430ES2), | 110 | CLK(NULL, "dpll5_ck", &dpll5_ck, CK_3430ES2), |
112 | CLK(NULL, "dpll5_m2_ck", &dpll5_m2_ck, CK_3430ES2), | 111 | CLK(NULL, "dpll5_m2_ck", &dpll5_m2_ck, CK_3430ES2), |
113 | CLK(NULL, "omap_120m_fck", &omap_120m_fck, CK_3430ES2), | ||
114 | CLK(NULL, "clkout2_src_ck", &clkout2_src_ck, CK_343X), | 112 | CLK(NULL, "clkout2_src_ck", &clkout2_src_ck, CK_343X), |
115 | CLK(NULL, "sys_clkout2", &sys_clkout2, CK_343X), | 113 | CLK(NULL, "sys_clkout2", &sys_clkout2, CK_343X), |
116 | CLK(NULL, "corex2_fck", &corex2_fck, CK_343X), | 114 | CLK(NULL, "corex2_fck", &corex2_fck, CK_343X), |
@@ -344,7 +342,7 @@ static u16 _omap3_dpll_compute_freqsel(struct clk *clk, u8 n) | |||
344 | unsigned long fint; | 342 | unsigned long fint; |
345 | u16 f = 0; | 343 | u16 f = 0; |
346 | 344 | ||
347 | fint = clk->parent->rate / (n + 1); | 345 | fint = clk->dpll_data->clk_ref->rate / (n + 1); |
348 | 346 | ||
349 | pr_debug("clock: fint is %lu\n", fint); | 347 | pr_debug("clock: fint is %lu\n", fint); |
350 | 348 | ||
@@ -411,7 +409,7 @@ static int _omap3_noncore_dpll_lock(struct clk *clk) | |||
411 | } | 409 | } |
412 | 410 | ||
413 | /* | 411 | /* |
414 | * omap3_noncore_dpll_bypass - instruct a DPLL to bypass and wait for readiness | 412 | * _omap3_noncore_dpll_bypass - instruct a DPLL to bypass and wait for readiness |
415 | * @clk: pointer to a DPLL struct clk | 413 | * @clk: pointer to a DPLL struct clk |
416 | * | 414 | * |
417 | * Instructs a non-CORE DPLL to enter low-power bypass mode. In | 415 | * Instructs a non-CORE DPLL to enter low-power bypass mode. In |
@@ -501,14 +499,25 @@ static int _omap3_noncore_dpll_stop(struct clk *clk) | |||
501 | static int omap3_noncore_dpll_enable(struct clk *clk) | 499 | static int omap3_noncore_dpll_enable(struct clk *clk) |
502 | { | 500 | { |
503 | int r; | 501 | int r; |
502 | struct dpll_data *dd; | ||
504 | 503 | ||
505 | if (clk == &dpll3_ck) | 504 | if (clk == &dpll3_ck) |
506 | return -EINVAL; | 505 | return -EINVAL; |
507 | 506 | ||
508 | if (clk->parent->rate == omap2_get_dpll_rate(clk)) | 507 | dd = clk->dpll_data; |
508 | if (!dd) | ||
509 | return -EINVAL; | ||
510 | |||
511 | if (clk->rate == dd->clk_bypass->rate) { | ||
512 | WARN_ON(clk->parent != dd->clk_bypass); | ||
509 | r = _omap3_noncore_dpll_bypass(clk); | 513 | r = _omap3_noncore_dpll_bypass(clk); |
510 | else | 514 | } else { |
515 | WARN_ON(clk->parent != dd->clk_ref); | ||
511 | r = _omap3_noncore_dpll_lock(clk); | 516 | r = _omap3_noncore_dpll_lock(clk); |
517 | } | ||
518 | /* FIXME: this is dubious - if clk->rate has changed, what about propagating? */ | ||
519 | if (!r) | ||
520 | clk->rate = omap2_get_dpll_rate(clk); | ||
512 | 521 | ||
513 | return r; | 522 | return r; |
514 | } | 523 | } |
@@ -583,13 +592,18 @@ static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel) | |||
583 | * @clk: struct clk * of DPLL to set | 592 | * @clk: struct clk * of DPLL to set |
584 | * @rate: rounded target rate | 593 | * @rate: rounded target rate |
585 | * | 594 | * |
586 | * Program the DPLL with the rounded target rate. Returns -EINVAL upon | 595 | * Set the DPLL CLKOUT to the target rate. If the DPLL can enter |
587 | * error, or 0 upon success. | 596 | * low-power bypass, and the target rate is the bypass source clock |
597 | * rate, then configure the DPLL for bypass. Otherwise, round the | ||
598 | * target rate if it hasn't been done already, then program and lock | ||
599 | * the DPLL. Returns -EINVAL upon error, or 0 upon success. | ||
588 | */ | 600 | */ |
589 | static int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate) | 601 | static int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate) |
590 | { | 602 | { |
603 | struct clk *new_parent = NULL; | ||
591 | u16 freqsel; | 604 | u16 freqsel; |
592 | struct dpll_data *dd; | 605 | struct dpll_data *dd; |
606 | int ret; | ||
593 | 607 | ||
594 | if (!clk || !rate) | 608 | if (!clk || !rate) |
595 | return -EINVAL; | 609 | return -EINVAL; |
@@ -601,18 +615,56 @@ static int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate) | |||
601 | if (rate == omap2_get_dpll_rate(clk)) | 615 | if (rate == omap2_get_dpll_rate(clk)) |
602 | return 0; | 616 | return 0; |
603 | 617 | ||
604 | if (dd->last_rounded_rate != rate) | 618 | /* |
605 | omap2_dpll_round_rate(clk, rate); | 619 | * Ensure both the bypass and ref clocks are enabled prior to |
620 | * doing anything; we need the bypass clock running to reprogram | ||
621 | * the DPLL. | ||
622 | */ | ||
623 | omap2_clk_enable(dd->clk_bypass); | ||
624 | omap2_clk_enable(dd->clk_ref); | ||
625 | |||
626 | if (dd->clk_bypass->rate == rate && | ||
627 | (clk->dpll_data->modes & (1 << DPLL_LOW_POWER_BYPASS))) { | ||
628 | pr_debug("clock: %s: set rate: entering bypass.\n", clk->name); | ||
606 | 629 | ||
607 | if (dd->last_rounded_rate == 0) | 630 | ret = _omap3_noncore_dpll_bypass(clk); |
608 | return -EINVAL; | 631 | if (!ret) |
632 | new_parent = dd->clk_bypass; | ||
633 | } else { | ||
634 | if (dd->last_rounded_rate != rate) | ||
635 | omap2_dpll_round_rate(clk, rate); | ||
636 | |||
637 | if (dd->last_rounded_rate == 0) | ||
638 | return -EINVAL; | ||
639 | |||
640 | freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n); | ||
641 | if (!freqsel) | ||
642 | WARN_ON(1); | ||
609 | 643 | ||
610 | freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n); | 644 | pr_debug("clock: %s: set rate: locking rate to %lu.\n", |
611 | if (!freqsel) | 645 | clk->name, rate); |
612 | WARN_ON(1); | ||
613 | 646 | ||
614 | omap3_noncore_dpll_program(clk, dd->last_rounded_m, dd->last_rounded_n, | 647 | ret = omap3_noncore_dpll_program(clk, dd->last_rounded_m, |
615 | freqsel); | 648 | dd->last_rounded_n, freqsel); |
649 | if (!ret) | ||
650 | new_parent = dd->clk_ref; | ||
651 | } | ||
652 | if (!ret) { | ||
653 | /* | ||
654 | * Switch the parent clock in the heirarchy, and make sure | ||
655 | * that the new parent's usecount is correct. Note: we | ||
656 | * enable the new parent before disabling the old to avoid | ||
657 | * any unnecessary hardware disable->enable transitions. | ||
658 | */ | ||
659 | if (clk->usecount) { | ||
660 | omap2_clk_enable(new_parent); | ||
661 | omap2_clk_disable(clk->parent); | ||
662 | } | ||
663 | clk_reparent(clk, new_parent); | ||
664 | clk->rate = rate; | ||
665 | } | ||
666 | omap2_clk_disable(dd->clk_ref); | ||
667 | omap2_clk_disable(dd->clk_bypass); | ||
616 | 668 | ||
617 | return 0; | 669 | return 0; |
618 | } | 670 | } |
@@ -804,11 +856,11 @@ static unsigned long omap3_clkoutx2_recalc(struct clk *clk) | |||
804 | 856 | ||
805 | dd = pclk->dpll_data; | 857 | dd = pclk->dpll_data; |
806 | 858 | ||
807 | WARN_ON(!dd->control_reg || !dd->enable_mask); | 859 | WARN_ON(!dd->enable_mask); |
808 | 860 | ||
809 | v = __raw_readl(dd->control_reg) & dd->enable_mask; | 861 | v = __raw_readl(dd->control_reg) & dd->enable_mask; |
810 | v >>= __ffs(dd->enable_mask); | 862 | v >>= __ffs(dd->enable_mask); |
811 | if (v != DPLL_LOCKED) | 863 | if (v != OMAP3XXX_EN_DPLL_LOCKED) |
812 | rate = clk->parent->rate; | 864 | rate = clk->parent->rate; |
813 | else | 865 | else |
814 | rate = clk->parent->rate * 2; | 866 | rate = clk->parent->rate * 2; |