diff --git a/arch/sh/include/asm/clock.h b/arch/sh/include/asm/clock.h index e9fced9bd8f5..5de72eef9724 100644 --- a/arch/sh/include/asm/clock.h +++ b/arch/sh/include/asm/clock.h @@ -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); diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c index c683be5ba8b2..e027fe5898d6 100644 --- a/arch/sh/kernel/cpu/clock.c +++ b/arch/sh/kernel/cpu/clock.c @@ -93,38 +93,16 @@ void propagate_rate(struct clk *tclk) } } -static int __clk_enable(struct clk *clk) -{ - if (clk->usecount++ == 0) { - if (clk->parent) - __clk_enable(clk->parent); - - if (clk->ops && clk->ops->enable) - clk->ops->enable(clk); - } - - return 0; -} - -int clk_enable(struct clk *clk) -{ - unsigned long flags; - int ret; - - if (!clk) - return -EINVAL; - - spin_lock_irqsave(&clock_lock, flags); - ret = __clk_enable(clk); - spin_unlock_irqrestore(&clock_lock, flags); - - return ret; -} -EXPORT_SYMBOL_GPL(clk_enable); - static void __clk_disable(struct clk *clk) { - if (clk->usecount > 0 && !(--clk->usecount)) { + if (clk->usecount == 0) { + printk(KERN_ERR "Trying disable clock %s with 0 usecount\n", + clk->name); + WARN_ON(1); + return; + } + + if (!(--clk->usecount)) { if (likely(clk->ops && clk->ops->disable)) clk->ops->disable(clk); if (likely(clk->parent)) @@ -145,6 +123,49 @@ void clk_disable(struct clk *clk) } EXPORT_SYMBOL_GPL(clk_disable); +static int __clk_enable(struct clk *clk) +{ + 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; +} + +int clk_enable(struct clk *clk) +{ + unsigned long flags; + int ret; + + if (!clk) + return -EINVAL; + + spin_lock_irqsave(&clock_lock, flags); + ret = __clk_enable(clk); + spin_unlock_irqrestore(&clock_lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(clk_enable); + static LIST_HEAD(root_clks); /** diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c index f777d00d4af6..1c41db41de7e 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c @@ -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)