aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/clock34xx.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/clock34xx.c')
-rw-r--r--arch/arm/mach-omap2/clock34xx.c90
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)
501static int omap3_noncore_dpll_enable(struct clk *clk) 499static 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 */
589static int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate) 601static 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;