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

Reply via email to