sh: clkfwk: Fix up the clk_enable() error path.
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>
This commit is contained in:
parent
154502e160
commit
ae891a4264
|
@ -10,7 +10,7 @@ struct clk;
|
||||||
|
|
||||||
struct clk_ops {
|
struct clk_ops {
|
||||||
void (*init)(struct clk *clk);
|
void (*init)(struct clk *clk);
|
||||||
void (*enable)(struct clk *clk);
|
int (*enable)(struct clk *clk);
|
||||||
void (*disable)(struct clk *clk);
|
void (*disable)(struct clk *clk);
|
||||||
unsigned long (*recalc)(struct clk *clk);
|
unsigned long (*recalc)(struct clk *clk);
|
||||||
int (*set_rate)(struct clk *clk, unsigned long rate, int algo_id);
|
int (*set_rate)(struct clk *clk, unsigned long rate, int algo_id);
|
||||||
|
|
|
@ -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)
|
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))
|
if (likely(clk->ops && clk->ops->disable))
|
||||||
clk->ops->disable(clk);
|
clk->ops->disable(clk);
|
||||||
if (likely(clk->parent))
|
if (likely(clk->parent))
|
||||||
|
@ -145,6 +123,49 @@ void clk_disable(struct clk *clk)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(clk_disable);
|
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);
|
static LIST_HEAD(root_clks);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -472,9 +472,9 @@ static int sh7722_siu_start_stop(struct clk *clk, int enable)
|
||||||
return 0;
|
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)
|
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 */
|
#endif /* CONFIG_CPU_SUBTYPE_SH7343 */
|
||||||
|
|
||||||
static void sh7722_video_enable(struct clk *clk)
|
static int sh7722_video_enable(struct clk *clk)
|
||||||
{
|
{
|
||||||
unsigned long r;
|
unsigned long r;
|
||||||
|
|
||||||
r = ctrl_inl(VCLKCR);
|
r = ctrl_inl(VCLKCR);
|
||||||
ctrl_outl( r & ~(1<<8), VCLKCR);
|
ctrl_outl( r & ~(1<<8), VCLKCR);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sh7722_video_disable(struct clk *clk)
|
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;
|
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)
|
static void sh7722_mstpcr_disable(struct clk *clk)
|
||||||
|
|
Loading…
Reference in New Issue