]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/arm/plat-omap/clock.c
OMAP clock: support "dry run" rate and parent changes
[linux-2.6-omap-h63xx.git] / arch / arm / plat-omap / clock.c
index be6aab9c68344ef8ac10424d23a7319aee0ab6fa..caac1fc67a2b51e0c495c40e09d628a8f42e0c5e 100644 (file)
@@ -83,8 +83,17 @@ int clk_enable(struct clk *clk)
                return -EINVAL;
 
        spin_lock_irqsave(&clockfw_lock, flags);
-       if (arch_clock->clk_enable)
+       if (arch_clock->clk_enable) {
                ret = arch_clock->clk_enable(clk);
+               if (ret == 0 && clk->flags & RECALC_ON_ENABLE) {
+                       if (clk->recalc)
+                               (*clk->recalc)(clk, clk->parent->rate,
+                                              CURRENT_RATE);
+                       if (clk->flags & RATE_PROPAGATES)
+                               propagate_rate(clk, CURRENT_RATE);
+               }
+       }
+
        spin_unlock_irqrestore(&clockfw_lock, flags);
 
        return ret;
@@ -106,8 +115,16 @@ void clk_disable(struct clk *clk)
                goto out;
        }
 
-       if (arch_clock->clk_disable)
+       if (arch_clock->clk_disable) {
                arch_clock->clk_disable(clk);
+               if (clk->flags & RECALC_ON_ENABLE) {
+                       if (clk->recalc)
+                               (*clk->recalc)(clk, clk->parent->rate,
+                                              CURRENT_RATE);
+                       if (clk->flags & RATE_PROPAGATES)
+                               propagate_rate(clk, CURRENT_RATE);
+               }
+       }
 
 out:
        spin_unlock_irqrestore(&clockfw_lock, flags);
@@ -183,8 +200,18 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
                return ret;
 
        spin_lock_irqsave(&clockfw_lock, flags);
-       if (arch_clock->clk_set_rate)
+
+       if (arch_clock->clk_set_rate) {
                ret = arch_clock->clk_set_rate(clk, rate);
+               if (ret == 0) {
+                       if (clk->recalc)
+                               (*clk->recalc)(clk, clk->parent->rate,
+                                              CURRENT_RATE);
+                       if (clk->flags & RATE_PROPAGATES)
+                               propagate_rate(clk, CURRENT_RATE);
+               }
+       }
+
        spin_unlock_irqrestore(&clockfw_lock, flags);
 
        return ret;
@@ -200,8 +227,18 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
                return ret;
 
        spin_lock_irqsave(&clockfw_lock, flags);
-       if (arch_clock->clk_set_parent)
-               ret =  arch_clock->clk_set_parent(clk, parent);
+
+       if (arch_clock->clk_set_parent) {
+               ret = arch_clock->clk_set_parent(clk, parent);
+               if (ret == 0) {
+                       if (clk->recalc)
+                               (*clk->recalc)(clk, clk->parent->rate,
+                                              CURRENT_RATE);
+                       if (clk->flags & RATE_PROPAGATES)
+                               propagate_rate(clk, CURRENT_RATE);
+               }
+       }
+
        spin_unlock_irqrestore(&clockfw_lock, flags);
 
        return ret;
@@ -250,20 +287,20 @@ static int __init omap_clk_setup(char *str)
 __setup("mpurate=", omap_clk_setup);
 
 /* Used for clocks that always have same value as the parent clock */
-void followparent_recalc(struct clk *clk)
+void followparent_recalc(struct clk *clk, unsigned long new_parent_rate,
+                        u8 rate_storage)
 {
-       if (clk == NULL || IS_ERR(clk))
-               return;
-
-       clk->rate = clk->parent->rate;
-       if (unlikely(clk->flags & RATE_PROPAGATES))
-               propagate_rate(clk);
+       if (rate_storage == CURRENT_RATE)
+               clk->rate = new_parent_rate;
+       else if (rate_storage == TEMP_RATE)
+               clk->temp_rate = new_parent_rate;
 }
 
 /* Propagate rate to children */
-void propagate_rate(struct clk * tclk)
+void propagate_rate(struct clk *tclk, u8 rate_storage)
 {
        struct clk *clkp;
+       unsigned long parent_rate = 0;
 
        if (tclk == NULL || IS_ERR(tclk))
                return;
@@ -271,8 +308,16 @@ void propagate_rate(struct clk * tclk)
        list_for_each_entry(clkp, &clocks, node) {
                if (likely(clkp->parent != tclk))
                        continue;
-               if (likely((u32)clkp->recalc))
-                       clkp->recalc(clkp);
+
+               if (rate_storage == CURRENT_RATE)
+                       parent_rate = tclk->rate;
+               else if (rate_storage == TEMP_RATE)
+                       parent_rate = tclk->temp_rate;
+
+               if (clkp->recalc)
+                       clkp->recalc(clkp, parent_rate, rate_storage);
+               if (clkp->flags & RATE_PROPAGATES)
+                       propagate_rate(clkp, rate_storage);
        }
 }
 
@@ -288,8 +333,12 @@ void recalculate_root_clocks(void)
        struct clk *clkp;
 
        list_for_each_entry(clkp, &clocks, node) {
-               if (unlikely(!clkp->parent) && likely((u32)clkp->recalc))
-                       clkp->recalc(clkp);
+               if (unlikely(!clkp->parent)) {
+                       if (clkp->recalc)
+                               clkp->recalc(clkp, 0, CURRENT_RATE);
+                       if (clkp->flags & RATE_PROPAGATES)
+                               propagate_rate(clkp, CURRENT_RATE);
+               }
        }
 }
 
@@ -383,8 +432,11 @@ static int __init clk_disable_unused(void)
        unsigned long flags;
 
        list_for_each_entry(ck, &clocks, node) {
-               if (ck->usecount > 0 || (ck->flags & ALWAYS_ENABLED) ||
-                       ck->enable_reg == 0)
+               if (ck->usecount > 0 ||
+                   (ck->flags & (ALWAYS_ENABLED | PARENT_CONTROLS_CLOCK)))
+                       continue;
+
+               if (cpu_class_is_omap1() && ck->enable_reg == 0)
                        continue;
 
                spin_lock_irqsave(&clockfw_lock, flags);