ARM: OMAP3+: DPLL: stop reparenting to same parent if already done
[cascardo/linux.git] / arch / arm / mach-omap2 / dpll3xxx.c
index 3a0296c..d9bcbf7 100644 (file)
@@ -50,10 +50,10 @@ static void _omap3_dpll_write_clken(struct clk_hw_omap *clk, u8 clken_bits)
 
        dd = clk->dpll_data;
 
-       v = __raw_readl(dd->control_reg);
+       v = omap2_clk_readl(clk, dd->control_reg);
        v &= ~dd->enable_mask;
        v |= clken_bits << __ffs(dd->enable_mask);
-       __raw_writel(v, dd->control_reg);
+       omap2_clk_writel(v, clk, dd->control_reg);
 }
 
 /* _omap3_wait_dpll_status: wait for a DPLL to enter a specific state */
@@ -69,8 +69,8 @@ static int _omap3_wait_dpll_status(struct clk_hw_omap *clk, u8 state)
 
        state <<= __ffs(dd->idlest_mask);
 
-       while (((__raw_readl(dd->idlest_reg) & dd->idlest_mask) != state) &&
-              i < MAX_DPLL_WAIT_TRIES) {
+       while (((omap2_clk_readl(clk, dd->idlest_reg) & dd->idlest_mask)
+               != state) && i < MAX_DPLL_WAIT_TRIES) {
                i++;
                udelay(1);
        }
@@ -147,7 +147,7 @@ static int _omap3_noncore_dpll_lock(struct clk_hw_omap *clk)
        state <<= __ffs(dd->idlest_mask);
 
        /* Check if already locked */
-       if ((__raw_readl(dd->idlest_reg) & dd->idlest_mask) == state)
+       if ((omap2_clk_readl(clk, dd->idlest_reg) & dd->idlest_mask) == state)
                goto done;
 
        ai = omap3_dpll_autoidle_read(clk);
@@ -311,14 +311,14 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel)
         * only since freqsel field is no longer present on other devices.
         */
        if (cpu_is_omap343x()) {
-               v = __raw_readl(dd->control_reg);
+               v = omap2_clk_readl(clk, dd->control_reg);
                v &= ~dd->freqsel_mask;
                v |= freqsel << __ffs(dd->freqsel_mask);
-               __raw_writel(v, dd->control_reg);
+               omap2_clk_writel(v, clk, dd->control_reg);
        }
 
        /* Set DPLL multiplier, divider */
-       v = __raw_readl(dd->mult_div1_reg);
+       v = omap2_clk_readl(clk, dd->mult_div1_reg);
        v &= ~(dd->mult_mask | dd->div1_mask);
        v |= dd->last_rounded_m << __ffs(dd->mult_mask);
        v |= (dd->last_rounded_n - 1) << __ffs(dd->div1_mask);
@@ -336,11 +336,11 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel)
                v |= sd_div << __ffs(dd->sddiv_mask);
        }
 
-       __raw_writel(v, dd->mult_div1_reg);
+       omap2_clk_writel(v, clk, dd->mult_div1_reg);
 
        /* Set 4X multiplier and low-power mode */
        if (dd->m4xen_mask || dd->lpmode_mask) {
-               v = __raw_readl(dd->control_reg);
+               v = omap2_clk_readl(clk, dd->control_reg);
 
                if (dd->m4xen_mask) {
                        if (dd->last_rounded_m4xen)
@@ -356,7 +356,7 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel)
                                v &= ~dd->lpmode_mask;
                }
 
-               __raw_writel(v, dd->control_reg);
+               omap2_clk_writel(v, clk, dd->control_reg);
        }
 
        /* We let the clock framework set the other output dividers later */
@@ -525,7 +525,7 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
        * stuff is inherited for free
        */
 
-       if (!ret)
+       if (!ret && clk_get_parent(hw->clk) != new_parent)
                __clk_reparent(hw->clk, new_parent);
 
        return 0;
@@ -554,7 +554,7 @@ u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk)
        if (!dd->autoidle_reg)
                return -EINVAL;
 
-       v = __raw_readl(dd->autoidle_reg);
+       v = omap2_clk_readl(clk, dd->autoidle_reg);
        v &= dd->autoidle_mask;
        v >>= __ffs(dd->autoidle_mask);
 
@@ -588,10 +588,10 @@ void omap3_dpll_allow_idle(struct clk_hw_omap *clk)
         * by writing 0x5 instead of 0x1.  Add some mechanism to
         * optionally enter this mode.
         */
-       v = __raw_readl(dd->autoidle_reg);
+       v = omap2_clk_readl(clk, dd->autoidle_reg);
        v &= ~dd->autoidle_mask;
        v |= DPLL_AUTOIDLE_LOW_POWER_STOP << __ffs(dd->autoidle_mask);
-       __raw_writel(v, dd->autoidle_reg);
+       omap2_clk_writel(v, clk, dd->autoidle_reg);
 
 }
 
@@ -614,10 +614,10 @@ void omap3_dpll_deny_idle(struct clk_hw_omap *clk)
        if (!dd->autoidle_reg)
                return;
 
-       v = __raw_readl(dd->autoidle_reg);
+       v = omap2_clk_readl(clk, dd->autoidle_reg);
        v &= ~dd->autoidle_mask;
        v |= DPLL_AUTOIDLE_DISABLE << __ffs(dd->autoidle_mask);
-       __raw_writel(v, dd->autoidle_reg);
+       omap2_clk_writel(v, clk, dd->autoidle_reg);
 
 }
 
@@ -639,6 +639,9 @@ unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
        struct clk_hw_omap *pclk = NULL;
        struct clk *parent;
 
+       if (!parent_rate)
+               return 0;
+
        /* Walk up the parents of clk, looking for a DPLL */
        do {
                do {
@@ -660,7 +663,7 @@ unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
 
        WARN_ON(!dd->enable_mask);
 
-       v = __raw_readl(dd->control_reg) & dd->enable_mask;
+       v = omap2_clk_readl(pclk, dd->control_reg) & dd->enable_mask;
        v >>= __ffs(dd->enable_mask);
        if ((v != OMAP3XXX_EN_DPLL_LOCKED) || (dd->flags & DPLL_J_TYPE))
                rate = parent_rate;