Hi Stephen,

On 22/07/2017 00:20, Stephen Boyd wrote:
> On 07/13, Quentin Schulz wrote:
>> diff --git a/drivers/clk/at91/clk-audio-pll-pad.c 
>> b/drivers/clk/at91/clk-audio-pll-pad.c
>> new file mode 100644
>> index 000000000000..10dd6d625696
>> --- /dev/null
>> +++ b/drivers/clk/at91/clk-audio-pll-pad.c
>> @@ -0,0 +1,206 @@
>> +/*
>> + *  Copyright (C) 2016 Atmel Corporation,
>> + *                     Nicolas Ferre <nicolas.fe...@atmel.com>
>> + *  Copyright (C) 2017 Free Electrons,
>> + *                 Quentin Schulz <quentin.sch...@free-electrons.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + */
>> +#include <linux/clk.h>
>> +#include <linux/clk-provider.h>
>> +#include <linux/clkdev.h>
> 
> Used?
> 

Not really, I need slab.h for kzalloc tough which was included by clkdev.

[...]
>> +static int clk_audio_pll_pad_set_rate(struct clk_hw *hw, unsigned long rate,
>> +                                  unsigned long parent_rate)
>> +{
>> +    struct clk_audio_pad *apad_ck = to_clk_audio_pad(hw);
>> +    u8 tmp_div;
>> +
>> +    pr_debug("A PLL/PAD: %s, rate = %lu (parent_rate = %lu)\n", __func__,
>> +             rate, parent_rate);
>> +
>> +    if (!rate)
>> +            return -EINVAL;
> 
> This happens?
> 

I don't know, but it's better to do this quick check rather than being
exposed to a division by zero IMHO. Nothing in clk_ops states that the
rate given to set_rate is non-zero, so I made sure this can't happen.

>> +
>> +    tmp_div = parent_rate / rate;
>> +    if (tmp_div % 3 == 0) {
>> +            apad_ck->qdaudio = tmp_div / 3;
>> +            apad_ck->div = 3;
>> +    } else {
>> +            apad_ck->qdaudio = tmp_div / 2;
>> +            apad_ck->div = 2;
>> +    }[...]
>> +static void __init of_sama5d2_clk_audio_pll_pad_setup(struct device_node 
>> *np)
>> +{
>> +    struct clk_audio_pad *apad_ck;
>> +    struct clk_init_data init;
> 
> Best to initialize to { } just in case we add something later.
> 

ACK.

>> +    struct regmap *regmap;
>> +    const char *parent_name;
>> +    const char *name = np->name;
>> +    int ret;
>> +
>> +    parent_name = of_clk_get_parent_name(np, 0);
>> +
>> +    of_property_read_string(np, "clock-output-names", &name);
>> +
>> +    regmap = syscon_node_to_regmap(of_get_parent(np));
>> +    if (IS_ERR(regmap))
>> +            return;
>> +
>> +    apad_ck = kzalloc(sizeof(*apad_ck), GFP_KERNEL);
>> +    if (!apad_ck)
>> +            return;
>> +
>> +    init.name = name;
>> +    init.ops = &audio_pll_pad_ops;
>> +    init.parent_names = (parent_name ? &parent_name : NULL);
> 
> Use of_clk_parent_fill()?
> 

[Deleting `parent_name = of_clk_get_parent_name(np, 0);`]
[Deleting `init.parent_names = (parent_name ? &parent_name : NULL);`]

+ const char *parent_names[1];
[...]
+ of_clk_parent_fill(np, parent_names, 1);
+ init.parent_names = parent_names;

Is it what you're asking?

>> +    init.num_parents = 1;
>> +    init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
>> +            CLK_SET_RATE_PARENT;
>> +
>> +    apad_ck->hw.init = &init;
>> +    apad_ck->regmap = regmap;
>> +
>> +    ret = clk_hw_register(NULL, &apad_ck->hw);
>> +    if (ret)
>> +            kfree(apad_ck);
>> +    else
>> +            of_clk_add_hw_provider(np, of_clk_hw_simple_get, &apad_ck->hw);
> 
> Maybe we should make this register sequence a helper function.
> Seems common.
> 

I can put such an helper in an header if this is what you meant.

>> +}
>> +
>> +CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pad_setup,
>> +           "atmel,sama5d2-clk-audio-pll-pad",
>> +           of_sama5d2_clk_audio_pll_pad_setup);
> 
> We can't have a device driver for this?
> 

Could you elaborate please?

>> diff --git a/drivers/clk/at91/clk-audio-pll-pmc.c 
>> b/drivers/clk/at91/clk-audio-pll-pmc.c
>> new file mode 100644
>> index 000000000000..7b0847ed7a4b
>> --- /dev/null
>> +++ b/drivers/clk/at91/clk-audio-pll-pmc.c
[...]
>> +static int clk_audio_pll_pmc_set_rate(struct clk_hw *hw, unsigned long rate,
>> +                                  unsigned long parent_rate)
>> +{
>> +    struct clk_audio_pmc *apmc_ck = to_clk_audio_pmc(hw);
>> +
>> +    if (!rate)
>> +            return -EINVAL;
>> +
>> +    pr_debug("A PLL/PMC: %s, rate = %lu (parent_rate = %lu)\n", __func__,
>> +             rate, parent_rate);
>> +
>> +    apmc_ck->qdpmc = parent_rate / rate - 1;
> 
> Hopefully rate isn't 1 or that goes undefined.
> 

Thanks to operator precedence, the only check to do is rate != 0 (done
few lines above). Division has precedence over substraction.

[...]
>> +static void __init of_sama5d2_clk_audio_pll_pmc_setup(struct device_node 
>> *np)
>> +{
>> +    struct clk_audio_pmc *apmc_ck;
>> +    struct clk_init_data init;
>> +    struct regmap *regmap;
>> +    const char *parent_name;
>> +    const char *name = np->name;
>> +    int ret;
>> +
>> +    parent_name = of_clk_get_parent_name(np, 0);
>> +
>> +    of_property_read_string(np, "clock-output-names", &name);
>> +
>> +    regmap = syscon_node_to_regmap(of_get_parent(np));
>> +    if (IS_ERR(regmap))
>> +            return;
>> +
>> +    apmc_ck = kzalloc(sizeof(*apmc_ck), GFP_KERNEL);
>> +    if (!apmc_ck)
>> +            return;
>> +
>> +    init.name = name;
>> +    init.ops = &audio_pll_pmc_ops;
>> +    init.parent_names = (parent_name ? &parent_name : NULL);
> 
> This feels repetitive.
> 
>> +    init.num_parents = 1;
>> +    init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
>> +            CLK_SET_RATE_PARENT;
>> +
>> +    apmc_ck->hw.init = &init;
>> +    apmc_ck->regmap = regmap;
>> +
>> +    ret = clk_hw_register(NULL, &apmc_ck->hw);
>> +    if (ret)
>> +            kfree(apmc_ck);
>> +    else
>> +            of_clk_add_hw_provider(np, of_clk_hw_simple_get, &apmc_ck->hw);
>> +}
>> +
>> +CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pmc_setup,
>> +           "atmel,sama5d2-clk-audio-pll-pmc",
>> +           of_sama5d2_clk_audio_pll_pmc_setup);
> 
> Very
> 

Basically, both share almost the same code but have different formulae
for the rate.

>> diff --git a/drivers/clk/at91/clk-audio-pll.c 
>> b/drivers/clk/at91/clk-audio-pll.c
>> new file mode 100644
>> index 000000000000..efc2cb58da85
>> --- /dev/null
>> +++ b/drivers/clk/at91/clk-audio-pll.c
[...]
>> +static unsigned long clk_audio_pll_fout(unsigned long parent_rate,
>> +                                    unsigned long nd, unsigned long fracr)
>> +{
>> +    unsigned long long fr = (unsigned long long)parent_rate *
>> +                                            (unsigned long long)fracr;
> 
> We only need one cast here?
> 

Indeed, I'll remove the casting of fracr.

[...]
>> +static long clk_audio_pll_round_rate(struct clk_hw *hw, unsigned long rate,
>> +                                 unsigned long *parent_rate)
>> +{
>> +    long best_rate = -EINVAL;
>> +    unsigned long fracr, nd;
>> +    int ret;
>> +
>> +    pr_debug("A PLL: %s, rate = %lu (parent_rate = %lu)\n", __func__, rate,
>> +             *parent_rate);
>> +
>> +    if (rate < AUDIO_PLL_FOUT_MIN)
>> +            rate = AUDIO_PLL_FOUT_MIN;
>> +    else if (rate > AUDIO_PLL_FOUT_MAX)
>> +            rate = AUDIO_PLL_FOUT_MAX;
> 
> Use clamp. Also, did you want to use determine_rate callback and
> clamp the requested rate range?
> 

Didn't know this one, thanks!

I want determine_rate to return a valid rate for the pll so I clamp the
requested rate range in this one. In set_rate, I just tell the user that
any requested rate outside of the valid range is invalid. Does that
answer your question?

[...]
>> +static void __init of_sama5d2_clk_audio_pll_setup(struct device_node *np)
>> +{
>> +    struct clk_audio_frac *fck;
>> +    struct clk_init_data init;
>> +    struct regmap *regmap;
>> +    const char *parent_name;
>> +    const char *name = np->name;
>> +    int ret;
>> +
>> +    parent_name = of_clk_get_parent_name(np, 0);
>> +
>> +    of_property_read_string(np, "clock-output-names", &name);
> 
> Any way to not rely on clock-output-names?
> 

I guess we could use the name of the DT node (as it's done in the
variable initialization block above) and not override it by
clock-output-names?

>> +
>> +    regmap = syscon_node_to_regmap(of_get_parent(np));
>> +    if (IS_ERR(regmap))
>> +            return;
>> +
>> +    fck = kzalloc(sizeof(*fck), GFP_KERNEL);
> 
> This variable name looks like f*ck, perhaps name it something
> else. frac?

Sure.

[...]

Thanks,
Quentin

-- 
Quentin Schulz, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

Reply via email to