Russell King - ARM Linux <li...@arm.linux.org.uk> writes: > On Fri, Oct 16, 2009 at 12:09:17PM -0700, Kevin Hilman wrote: >> From: Sekhar Nori <nsek...@ti.com> >> >> The clk_set_parent() API is implemented to enable re-parenting >> clocks in the clock tree. >> >> This is useful in DVFS and helps by shifting clocks to an asynchronous >> domain where supported by hardware >> >> Signed-off-by: Sekhar Nori <nsek...@ti.com> >> Signed-off-by: Kevin Hilman <khil...@deeprootsystems.com> >> --- >> arch/arm/mach-davinci/clock.c | 23 +++++++++++++++++++++++ >> 1 files changed, 23 insertions(+), 0 deletions(-) >> >> diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c >> index 09e0e1c..12ceeea 100644 >> --- a/arch/arm/mach-davinci/clock.c >> +++ b/arch/arm/mach-davinci/clock.c >> @@ -141,6 +141,29 @@ int clk_set_rate(struct clk *clk, unsigned long rate) >> } >> EXPORT_SYMBOL(clk_set_rate); >> >> +int clk_set_parent(struct clk *clk, struct clk *parent) >> +{ >> + unsigned long flags; >> + >> + if (clk == NULL || IS_ERR(clk)) >> + return -EINVAL; >> + >> + mutex_lock(&clocks_mutex); >> + clk->parent = parent; >> + list_del_init(&clk->childnode); >> + list_add(&clk->childnode, &clk->parent->children); >> + mutex_unlock(&clocks_mutex); > > This is bad, and is suffering from precisely the same problem which > OMAP suffered from: > > 1. it takes no notice of whether the clk is in use. > 2. it takes no notice of whether the parent clocks are being used. > > The result is that using clk_set_parent() on a clk_enable()'d clock, > you totally destroy the usecounting of the parent clocks, leading to > the clock tree usecount becoming totally buggered up. > > Either refuse to change the parent of an already clk_enable()'d clock, > or do proper usecount fixups when changing the parent.
On davinci, we only reparent during early init, so refusing to change the parent of an enabled will suffice. I've added a check (and warning) if the clock is already enabled as well as a refusal to re-parent: int clk_set_parent(struct clk *clk, struct clk *parent) { unsigned long flags; if (clk == NULL || IS_ERR(clk)) return -EINVAL; /* Cannot change parent on enabled clock */ if (WARN_ON(clk->usecount)) return -EINVAL; mutex_lock(&clocks_mutex); clk->parent = parent; list_del_init(&clk->childnode); list_add(&clk->childnode, &clk->parent->children); mutex_unlock(&clocks_mutex); spin_lock_irqsave(&clockfw_lock, flags); if (clk->recalc) clk->rate = clk->recalc(clk); propagate_rate(clk); spin_unlock_irqrestore(&clockfw_lock, flags); return 0; } _______________________________________________ Davinci-linux-open-source mailing list Davinci-linux-open-source@linux.davincidsp.com http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source