All of lore.kernel.org
 help / color / mirror / Atom feed
From: Quentin Schulz <quentin.schulz@free-electrons.com>
To: Stephen Boyd <sboyd@codeaurora.org>
Cc: mturquette@baylibre.com, robh+dt@kernel.org,
	mark.rutland@arm.com, lgirdwood@gmail.com, broonie@kernel.org,
	nicolas.ferre@microchip.com,
	alexandre.belloni@free-electrons.com, linux@armlinux.org.uk,
	boris.brezillon@free-electrons.com, perex@perex.cz,
	tiwai@suse.com, cyrille.pitchen@wedev4u.fr,
	thomas.petazzoni@free-electrons.com, linux-clk@vger.kernel.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	alsa-devel@alsa-project.org,
	linux-arm-kernel@lists.infradead.org,
	Nicolas Ferre <nicolas.ferre@atmel.com>
Subject: Re: [PATCH v3 3/9] clk: at91: add audio pll clock drivers
Date: Mon, 24 Jul 2017 10:37:33 +0200	[thread overview]
Message-ID: <859d2f48-a987-afda-1e9d-02930e4fad7d@free-electrons.com> (raw)
In-Reply-To: <20170721222029.GO19878@codeaurora.org>

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.ferre@atmel.com>
>> + *  Copyright (C) 2017 Free Electrons,
>> + *		       Quentin Schulz <quentin.schulz@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

WARNING: multiple messages have this Message-ID (diff)
From: Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
To: Stephen Boyd <sboyd-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
Cc: mturquette-rdvid1DuHRBWk0Htik3J/w@public.gmane.org,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
	mark.rutland-5wv7dgnIgG8@public.gmane.org,
	lgirdwood-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org,
	broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
	nicolas.ferre-UWL1GkI3JZL3oGB3hsPCZA@public.gmane.org,
	alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org,
	linux-I+IVW8TIWO2tmTQ+vhA3Yw@public.gmane.org,
	boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org,
	perex-/Fr2/VpizcU@public.gmane.org,
	tiwai-IBi9RG/b67k@public.gmane.org,
	cyrille.pitchen-yU5RGvR974pGWvitb5QawA@public.gmane.org,
	thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org,
	linux-clk-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw@public.gmane.org,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	Nicolas Ferre
	<nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
Subject: Re: [PATCH v3 3/9] clk: at91: add audio pll clock drivers
Date: Mon, 24 Jul 2017 10:37:33 +0200	[thread overview]
Message-ID: <859d2f48-a987-afda-1e9d-02930e4fad7d@free-electrons.com> (raw)
In-Reply-To: <20170721222029.GO19878-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>

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.ferre-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
>> + *  Copyright (C) 2017 Free Electrons,
>> + *		       Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
>> + *
>> + * 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
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

WARNING: multiple messages have this Message-ID (diff)
From: quentin.schulz@free-electrons.com (Quentin Schulz)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v3 3/9] clk: at91: add audio pll clock drivers
Date: Mon, 24 Jul 2017 10:37:33 +0200	[thread overview]
Message-ID: <859d2f48-a987-afda-1e9d-02930e4fad7d@free-electrons.com> (raw)
In-Reply-To: <20170721222029.GO19878@codeaurora.org>

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.ferre@atmel.com>
>> + *  Copyright (C) 2017 Free Electrons,
>> + *		       Quentin Schulz <quentin.schulz@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	other threads:[~2017-07-24  8:37 UTC|newest]

Thread overview: 49+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-07-13  7:49 [PATCH v3 0/9] add support for Sama5d2 audio PLLs and enable ClassD Quentin Schulz
2017-07-13  7:49 ` Quentin Schulz
2017-07-13  7:49 ` [PATCH v3 1/9] clk: at91: clk-generated: remove useless divisor loop Quentin Schulz
2017-07-13  7:49   ` Quentin Schulz
2017-07-13  7:49   ` Quentin Schulz
2017-07-13  7:49 ` [PATCH v3 2/9] clk: at91: add audio plls to the compatible list in DT binding Quentin Schulz
2017-07-13  7:49   ` Quentin Schulz
2017-07-19  6:31   ` Boris Brezillon
2017-07-19  6:31     ` Boris Brezillon
2017-07-19  6:31     ` Boris Brezillon
2017-07-21 22:21   ` Stephen Boyd
2017-07-21 22:21     ` Stephen Boyd
2017-07-13  7:49 ` [PATCH v3 3/9] clk: at91: add audio pll clock drivers Quentin Schulz
2017-07-13  7:49   ` Quentin Schulz
2017-07-13  7:49   ` Quentin Schulz
2017-07-19  6:31   ` Boris Brezillon
2017-07-19  6:31     ` Boris Brezillon
2017-07-21 22:20   ` Stephen Boyd
2017-07-21 22:20     ` Stephen Boyd
2017-07-21 22:20     ` Stephen Boyd
2017-07-24  8:37     ` Quentin Schulz [this message]
2017-07-24  8:37       ` Quentin Schulz
2017-07-24  8:37       ` Quentin Schulz
2017-07-26  0:20       ` Stephen Boyd
2017-07-26  0:20         ` Stephen Boyd
2017-07-26  0:20         ` Stephen Boyd
2017-07-25 11:30     ` Quentin Schulz
2017-07-25 11:30       ` Quentin Schulz
2017-07-26  0:14       ` Stephen Boyd
2017-07-26  0:14         ` Stephen Boyd
2017-07-13  7:49 ` [PATCH v3 4/9] ARM: dts: at91: sama5d2: add classd nodes Quentin Schulz
2017-07-13  7:49   ` Quentin Schulz
2017-07-13  7:49   ` Quentin Schulz
2017-07-13  7:49 ` [PATCH v3 5/9] clk: at91: clk-generated: create function to find best_diff Quentin Schulz
2017-07-13  7:49   ` Quentin Schulz
2017-07-13  7:49 ` [PATCH v3 6/9] clk: at91: clk-generated: make gclk determine audio_pll rate Quentin Schulz
2017-07-13  7:49   ` Quentin Schulz
2017-07-13  7:49   ` Quentin Schulz
2017-07-13  7:49 ` [PATCH v3 7/9] ASoC: atmel-classd: remove aclk clock from DT binding Quentin Schulz
2017-07-13  7:49   ` Quentin Schulz
2017-07-13  7:49   ` Quentin Schulz
2017-07-13  7:49 ` [PATCH v3 8/9] ASoC: atmel-classd: remove aclk clock Quentin Schulz
2017-07-13  7:49   ` Quentin Schulz
2017-07-13  7:49 ` [PATCH v3 9/9] ARM: dts: at91: sama5d2_xplained: add pin muxing and enable classd Quentin Schulz
2017-07-13  7:49   ` Quentin Schulz
2017-07-19  6:28 ` [PATCH v3 0/9] add support for Sama5d2 audio PLLs and enable ClassD Quentin Schulz
2017-07-19  6:28   ` Quentin Schulz
2017-07-19 10:19   ` Mark Brown
2017-07-19 10:19     ` Mark Brown

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=859d2f48-a987-afda-1e9d-02930e4fad7d@free-electrons.com \
    --to=quentin.schulz@free-electrons.com \
    --cc=alexandre.belloni@free-electrons.com \
    --cc=alsa-devel@alsa-project.org \
    --cc=boris.brezillon@free-electrons.com \
    --cc=broonie@kernel.org \
    --cc=cyrille.pitchen@wedev4u.fr \
    --cc=devicetree@vger.kernel.org \
    --cc=lgirdwood@gmail.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-clk@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@armlinux.org.uk \
    --cc=mark.rutland@arm.com \
    --cc=mturquette@baylibre.com \
    --cc=nicolas.ferre@atmel.com \
    --cc=nicolas.ferre@microchip.com \
    --cc=perex@perex.cz \
    --cc=robh+dt@kernel.org \
    --cc=sboyd@codeaurora.org \
    --cc=thomas.petazzoni@free-electrons.com \
    --cc=tiwai@suse.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.