[U-Boot] [PATCH v1 2/7] clk: at91: Improve the clock implementation

Stephen Warren swarren at wwwdotorg.org
Tue Sep 13 21:34:07 CEST 2016


On 09/12/2016 07:54 PM, Wenyou Yang wrote:
> For the peripheral clock, provide the clock ops for the clock
> provider, such as spi0_clk. The .of_xlate is to get the clk->id,
> the .enable is to enable the spi0 peripheral clock, the .get_rate
> is to get the clock frequency.
>
> The driver for periph32ck node is responsible for recursively
> binding its children as clk devices, not provide the clock ops.
>
> So do the generated clock and system clock.

> diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c

> +/**
> + * generated_clk_bind() - for the generated clock driver
> + * Recursively bind its children as clk devices.
> + *
> + * @return: 0 on success, or negative error code on failure
> + */
> +static int generated_clk_bind(struct udevice *dev)
... (code to enumerate/instantiate all child DT nodes)
> +}
> +
> +static const struct udevice_id generated_clk_match[] = {
> +	{ .compatible = "atmel,sama5d2-clk-generated" },
> +	{}
> +};
> +
> +U_BOOT_DRIVER(generated_clk) = {
> +	.name = "generated-clk",
> +	.id = UCLASS_CLK,
> +	.of_match = generated_clk_match,
> +	.bind = generated_clk_bind,
> +};

This driver shouldn't be UCLASS_CLK, and can't be without any clock ops 
implemented. It appears to be for another DT node that solely exists to 
house various sub-nodes which are the actual clock providers. I believe 
you should make this UCLASS_MISC. I guess you need to keep the custom 
bind function, since all the child nodes that it enumerates explicitly 
don't have a compatible value, so you can't rely on e.g. the default 
UCLASS_SIMPLE_BUS bind function to enumerate them.

BTW, while reading ./arch/arm/dts/sama5d2.dtsi, I noticed:

sdmmc0_gclk: sdmmc0_gclk {
	#clock-cells = <0>;
	reg = <31>;
};

Doesn't dtc complain about that? The node has a reg property, yet there 
is no unit address in the node name to match it. Instead, that node 
should be:

sdmmc0_gclk: sdmmc0_gclk at 31 {
	#clock-cells = <0>;
	reg = <31>;
};

> +static int generic_clk_of_xlate(struct clk *clk,
> +			       struct fdtdec_phandle_args *args)
>  {
> -	struct pmc_platdata *plat = dev_get_platdata(clk->dev);
> +	int periph;

The following should likely be added here:

         if (args->args_count) {
                 debug("Invaild args_count: %d\n", args->args_count);
                 return -EINVAL;
         }

> +	periph = fdtdec_get_uint(gd->fdt_blob, clk->dev->of_offset, "reg", -1);
> +	if (periph < 0)
> +		return -EINVAL;
> +
> +	clk->id = periph;

I guess that's OK. of_xlate is really intended to parse/process the 
clocks property in the client DT node. However, I suppose parsing the 
referenced DT node is probably OK too. Has this Atmel clock binding, and 
a similar clock driver implementation (including custom of_xlate) been 
reviewed for inclusion in the Linux kernel? I'd be curious if the same 
technique was/wasn't allowed there.

> +static int generic_clk_probe(struct udevice *dev)
...
> +	dev = dev_get_parent(dev);
> +	dev = dev_get_parent(dev);

That line is duplicated.

> diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c

The same comments as above all apply to this file too.

> +static ulong periph_get_rate(struct clk *clk)
>  {
> +	struct udevice *dev;
> +	struct clk clk_dev;
> +	int ret;
>
> +	dev = dev_get_parent(clk->dev);
> +	ret = clk_request(dev, &clk_dev);

You haven't filled in clk_dev.id here. That needs to be filled in before 
calling clk_request().

> +	if (ret)
> +		return ret;
> +
> +	ret = clk_get_by_index(dev, 0, &clk_dev);

This over-writes everything in clk_dev, thus making the call to 
clk_request() above pointless.

> +	if (ret)
> +		return ret;
> +
> +	return clk_get_rate(&clk_dev);

You need to call clk_free(&clk_dev) before returning. This comment 
applies to generated_clk_get_rate()/generic_clk_get_rate() too (in the 
previous file), although that problem existed before this patch.

> +static int periph_clk_probe(struct udevice *dev)
> +{
> +	struct periph_clk_platdata *plat = dev_get_platdata(dev);
> +
> +	dev = dev_get_parent(dev);
> +	dev = dev_get_parent(dev);
> +	plat->reg_base = (struct at91_pmc *)dev_get_addr_ptr(dev);

It would be helpful documentation-wise to use separate variables for 
those parents; make the variable name indicate what the parent is 
expected to be:

dev_periph_container = dev_get_parent(dev);
dev_pmc = dev_get_parent(dev_periph_container);

> diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c

Likewise, all the same comments above apply to this file too.

> +/**
> + * at91_system_clk_bind() - for the system clock driver
> + * Recursively bind its children as clk devices.
> + *
> + * @return: 0 on success, or negative error code on failure
> + */
> +static int at91_system_clk_bind(struct udevice *dev)
> +{
...
> +		/*
> +		 * If this node has "compatible" property, this is not
> +		 * a pin configuration node, but a normal device. skip.
> +		 */

This is nothing to do with pin configuration, but clocks.

This function is duplicated at least 3 times in this patch. It might be 
useful to implement it in some common location, and just call it from 
all the different clock drivers. You'd need to pass in a string for the 
driver name to bind to, but that's the only difference I see.

I wouldn't be surprised if other parts of the Atmel clock drivers could 
be shared too; of_xlate is probably common, and perhaps get_rate for 
some clocks that are derived from parent clocks. Still, cleaning that up 
might be a job for a separate series.


More information about the U-Boot mailing list