]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
sh: clkfwk: Fix up the clk_enable() error path.
authorPaul Mundt <lethal@linux-sh.org>
Mon, 11 May 2009 20:30:10 +0000 (05:30 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Mon, 11 May 2009 20:30:10 +0000 (05:30 +0900)
There are a couple of instances where a clk_enable() can fail, which the
SH-Mobile code presently handles, but doesn't get reported all the way
back up. This fixes up the return type so the errors make it all the way
down to the drivers.

Additionally, we now also error out properly if the parent enable fails.
Prep work for aggressively turning off unused clocks on boot.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
arch/sh/include/asm/clock.h
arch/sh/kernel/cpu/clock.c
arch/sh/kernel/cpu/sh4a/clock-sh7722.c

index e9fced9bd8f5f371dfd1a21a22c6451a74f4d993..5de72eef97244c55b9cb83d29a8a9777c59dce94 100644 (file)
@@ -10,7 +10,7 @@ struct clk;
 
 struct clk_ops {
        void (*init)(struct clk *clk);
-       void (*enable)(struct clk *clk);
+       int (*enable)(struct clk *clk);
        void (*disable)(struct clk *clk);
        unsigned long (*recalc)(struct clk *clk);
        int (*set_rate)(struct clk *clk, unsigned long rate, int algo_id);
index c683be5ba8b2b6e930640405b7bd68d9c0cceedb..e027fe5898d688f8c01a943e09d8ade7cacfb76b 100644 (file)
@@ -93,57 +93,78 @@ void propagate_rate(struct clk *tclk)
        }
 }
 
-static int __clk_enable(struct clk *clk)
+static void __clk_disable(struct clk *clk)
 {
-       if (clk->usecount++ == 0) {
-               if (clk->parent)
-                       __clk_enable(clk->parent);
-
-               if (clk->ops && clk->ops->enable)
-                       clk->ops->enable(clk);
+       if (clk->usecount == 0) {
+               printk(KERN_ERR "Trying disable clock %s with 0 usecount\n",
+                      clk->name);
+               WARN_ON(1);
+               return;
        }
 
-       return 0;
+       if (!(--clk->usecount)) {
+               if (likely(clk->ops && clk->ops->disable))
+                       clk->ops->disable(clk);
+               if (likely(clk->parent))
+                       __clk_disable(clk->parent);
+       }
 }
 
-int clk_enable(struct clk *clk)
+void clk_disable(struct clk *clk)
 {
        unsigned long flags;
-       int ret;
 
        if (!clk)
-               return -EINVAL;
+               return;
 
        spin_lock_irqsave(&clock_lock, flags);
-       ret = __clk_enable(clk);
+       __clk_disable(clk);
        spin_unlock_irqrestore(&clock_lock, flags);
-
-       return ret;
 }
-EXPORT_SYMBOL_GPL(clk_enable);
+EXPORT_SYMBOL_GPL(clk_disable);
 
-static void __clk_disable(struct clk *clk)
+static int __clk_enable(struct clk *clk)
 {
-       if (clk->usecount > 0 && !(--clk->usecount)) {
-               if (likely(clk->ops && clk->ops->disable))
-                       clk->ops->disable(clk);
-               if (likely(clk->parent))
-                       __clk_disable(clk->parent);
+       int ret = 0;
+
+       if (clk->usecount++ == 0) {
+               if (clk->parent) {
+                       ret = __clk_enable(clk->parent);
+                       if (unlikely(ret))
+                               goto err;
+               }
+
+               if (clk->ops && clk->ops->enable) {
+                       ret = clk->ops->enable(clk);
+                       if (ret) {
+                               if (clk->parent)
+                                       __clk_disable(clk->parent);
+                               goto err;
+                       }
+               }
        }
+
+       return ret;
+err:
+       clk->usecount--;
+       return ret;
 }
 
-void clk_disable(struct clk *clk)
+int clk_enable(struct clk *clk)
 {
        unsigned long flags;
+       int ret;
 
        if (!clk)
-               return;
+               return -EINVAL;
 
        spin_lock_irqsave(&clock_lock, flags);
-       __clk_disable(clk);
+       ret = __clk_enable(clk);
        spin_unlock_irqrestore(&clock_lock, flags);
+
+       return ret;
 }
-EXPORT_SYMBOL_GPL(clk_disable);
+EXPORT_SYMBOL_GPL(clk_enable);
 
 static LIST_HEAD(root_clks);
 
index f777d00d4af689f7d493145f0f62054fbe935f9e..1c41db41de7e777505838afd09f9b388635259b2 100644 (file)
@@ -472,9 +472,9 @@ static int sh7722_siu_start_stop(struct clk *clk, int enable)
        return 0;
 }
 
-static void sh7722_siu_enable(struct clk *clk)
+static int sh7722_siu_enable(struct clk *clk)
 {
-       sh7722_siu_start_stop(clk, 1);
+       return sh7722_siu_start_stop(clk, 1);
 }
 
 static void sh7722_siu_disable(struct clk *clk)
@@ -491,12 +491,13 @@ static struct clk_ops sh7722_siu_clk_ops = {
 
 #endif /* CONFIG_CPU_SUBTYPE_SH7343 */
 
-static void sh7722_video_enable(struct clk *clk)
+static int sh7722_video_enable(struct clk *clk)
 {
        unsigned long r;
 
        r = ctrl_inl(VCLKCR);
        ctrl_outl( r & ~(1<<8), VCLKCR);
+       return 0;
 }
 
 static void sh7722_video_disable(struct clk *clk)
@@ -630,9 +631,9 @@ static int sh7722_mstpcr_start_stop(struct clk *clk, int enable)
        return 0;
 }
 
-static void sh7722_mstpcr_enable(struct clk *clk)
+static int sh7722_mstpcr_enable(struct clk *clk)
 {
-       sh7722_mstpcr_start_stop(clk, 1);
+       return sh7722_mstpcr_start_stop(clk, 1);
 }
 
 static void sh7722_mstpcr_disable(struct clk *clk)