Re: [PATCH V3] PM / clk: Add support for obtaining clocks from device-tree
From: Geert Uytterhoeven
Date: Thu Mar 10 2016 - 07:40:51 EST
On Thu, Mar 10, 2016 at 1:27 PM, Jon Hunter <jonathanh@xxxxxxxxxx> wrote:
> On 10/03/16 09:41, Geert Uytterhoeven wrote:
>> On Thu, Mar 10, 2016 at 10:00 AM, Jon Hunter <jonathanh@xxxxxxxxxx> wrote:
>>> The PM clocks framework requires clients to pass either a con-id or a
>>> valid clk pointer in order to add a clock to a device. Add a new
>>> function of_pm_clk_add_clks() to allows device clocks to be retrieved
>>> from device-tree and populated for a given device. Note that
>>> of_clk_get_from_provider() is not defined if CONFIG_OF and
>>> CONFIG_COMMON_CLK are not selected. Therefore, make of_pm_clk_add_clks()
>>> dependent on these options.
>>> An optional function pointer may be passed to of_pm_clk_add_clks() that
>>> can be used to filter the clocks that are added for a device when
>>> calling of_pm_clk_add_clks().
>>> In order to handle errors encountered when adding clocks from
>>> device-tree, add a function pm_clk_remove_clk() to remove any clocks
>>> (using a pointer to the clk structure) that have been added
>>> successfully before the error occurred.
>>> Signed-off-by: Jon Hunter <jonathanh@xxxxxxxxxx>
>> Tested-by: Geert Uytterhoeven <geert+renesas@xxxxxxxxx>
>> But more comments below...
>>> --- a/drivers/base/power/clock_ops.c
>>> +++ b/drivers/base/power/clock_ops.c
>>> @@ -137,6 +137,81 @@ int pm_clk_add_clk(struct device *dev, struct clk *clk)
>>> return __pm_clk_add(dev, NULL, clk);
>>> +#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
>>> + * of_pm_clk_add_clks - Start using device clock(s) for power management.
>>> + * @dev: Device whose clock(s) is going to be used for power management.
>>> + * @of_pm_clk_filter: Optional function for filtering clocks
>>> + *
>>> + * Add a series of clocks described in the 'clocks' device-tree node for
>>> + * a device to the list of clocks used for the power management of @dev.
>>> + * If 'of_pm_clk_filter' is specified, then this filter function will be
>>> + * called for each clock found and the clock will be added to the list
>>> + * of clocks if this function returns true. Return success if clocks are
>>> + * added successfully and return a negative error code if adding a clock
>>> + * fails or there are no clocks that match with the filter function.
>>> + */
>>> +int of_pm_clk_add_clks(struct device *dev, of_pm_clk_filter fn, void *data)
>>> + count = of_count_phandle_with_args(dev->of_node, "clocks",
>>> + "#clock-cells");
>>> + if (count == 0)
>>> + return -ENODEV;
>> + return added ? 0 : -ENODEV;
>> Is it an error condition if no clocks were present in DT, or if no clocks have
>> been accepted by the filter function? If not, the caller has to check for
>> -ENODEV. Now the caller has to call pm_clk_create() first, before it knows if
>> any clocks will be added, it may want to call pm_clk_destroy() later if no
>> clocks have been added.
> It seems odd to me that someone would call this function and either
> there are no clocks in the DT or they are all filtered out. For example,
> most drivers are calling of_clk_get() because there are clocks they need
> to add.
of_pm_clk_add_clks() would typically be called from the .attach_dev()
callback of the PM Domain, for all devices in the PM Domain. However, there may
exist devices without clocks properties, or without gateable clocks.
>> Alternatively, you could return 0 vs. the actual number of clocks added.
> However, a nice comprise here could be to return the number of clocks
> added and let the user decide what to do. I like that idea. Not sure I
> understand what you mean by "0 vs. the actual number of clocks added".
> Do you just mean the return the number added?
Yes, that what I meant:
(current) -ENODEV => (new) 0
(current) 0 => (new) number of clocks added
Sorry for the confusion.
>> I hooked up your code in renesas-cpg-mssr.c, and it worked.
>> However, I noticed it added 27 clocks for one device node (rcar_sound), and
>> only then I realized that I only want to add the first clock accepted by the
>> filter, not all of them, as the others are under driver control.
>> I'm not sure this can be handled in the filter function.
>> So I can't use your code (for now)...
> I see, that is unfortunate. Are you using the void *data variable in
> your filter? If not may be you could use this to indicate a clock has
> been 'found' and don't match any further clocks.
Perhaps. I'll think about it...
> If you cannot use it, then I am tempted to drop the filter function for
> now as this simplifies the code. It can always be added later if someone
> has a need for it.
That's fine for me.
Note that if the need arises for the filter function, you'll have to add a new
function and make the old one a wrapper, to avoid having to update all
existing users that don't use the filter function.
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@xxxxxxxxxxxxxx
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds