drivers: clk: Fix using assigned-clocks in the node of the clock it sets up

This fixes the case where assigned-clocks is used to define a clock
defaults inside this same clock's node. This is used sometimes to setup a
default parents and/or rate for a clock.

example:
muxed_clock: muxed_clock {
	clocks = <&clk_provider 0>, <&clk_provider 1>;
	#clock-cells = <0>;
	assigned-clocks = <&muxed_clock>;
	assigned-clock-parents = <&clk_provider 1>;
};

It doesn't work in u-boot because the assigned-clocks are setup *before*
the clock is probed. (clk_set_parent() will likely crash or fail if called
before the device probe function)
Making it work by handling "assigned-clocks" in 2 steps: first before the
clk device is probed, and then after the clk device is probed.

Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
This commit is contained in:
Jean-Jacques Hiblot 2019-10-22 14:00:06 +02:00 committed by Lukasz Majewski
parent dd2e0ce2a4
commit fd1ba29652
3 changed files with 48 additions and 9 deletions

View File

@ -178,7 +178,7 @@ bulk_get_err:
return ret; return ret;
} }
static int clk_set_default_parents(struct udevice *dev) static int clk_set_default_parents(struct udevice *dev, int stage)
{ {
struct clk clk, parent_clk; struct clk clk, parent_clk;
int index; int index;
@ -214,8 +214,18 @@ static int clk_set_default_parents(struct udevice *dev)
return ret; return ret;
} }
ret = clk_set_parent(&clk, &parent_clk); /* This is clk provider device trying to reparent itself
* It cannot be done right now but need to wait after the
* device is probed
*/
if (stage == 0 && clk.dev == dev)
continue;
if (stage > 0 && clk.dev != dev)
/* do not setup twice the parent clocks */
continue;
ret = clk_set_parent(&clk, &parent_clk);
/* /*
* Not all drivers may support clock-reparenting (as of now). * Not all drivers may support clock-reparenting (as of now).
* Ignore errors due to this. * Ignore errors due to this.
@ -233,7 +243,7 @@ static int clk_set_default_parents(struct udevice *dev)
return 0; return 0;
} }
static int clk_set_default_rates(struct udevice *dev) static int clk_set_default_rates(struct udevice *dev, int stage)
{ {
struct clk clk; struct clk clk;
int index; int index;
@ -268,7 +278,19 @@ static int clk_set_default_rates(struct udevice *dev)
continue; continue;
} }
/* This is clk provider device trying to program itself
* It cannot be done right now but need to wait after the
* device is probed
*/
if (stage == 0 && clk.dev == dev)
continue;
if (stage > 0 && clk.dev != dev)
/* do not setup twice the parent clocks */
continue;
ret = clk_set_rate(&clk, rates[index]); ret = clk_set_rate(&clk, rates[index]);
if (ret < 0) { if (ret < 0) {
debug("%s: failed to set rate on clock index %d (%ld) for %s\n", debug("%s: failed to set rate on clock index %d (%ld) for %s\n",
__func__, index, clk.id, dev_read_name(dev)); __func__, index, clk.id, dev_read_name(dev));
@ -281,7 +303,7 @@ fail:
return ret; return ret;
} }
int clk_set_defaults(struct udevice *dev) int clk_set_defaults(struct udevice *dev, int stage)
{ {
int ret; int ret;
@ -294,11 +316,11 @@ int clk_set_defaults(struct udevice *dev)
debug("%s(%s)\n", __func__, dev_read_name(dev)); debug("%s(%s)\n", __func__, dev_read_name(dev));
ret = clk_set_default_parents(dev); ret = clk_set_default_parents(dev, stage);
if (ret) if (ret)
return ret; return ret;
ret = clk_set_default_rates(dev); ret = clk_set_default_rates(dev, stage);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -673,7 +695,21 @@ void devm_clk_put(struct udevice *dev, struct clk *clk)
WARN_ON(rc); WARN_ON(rc);
} }
int clk_uclass_post_probe(struct udevice *dev)
{
/*
* when a clock provider is probed. Call clk_set_defaults()
* also after the device is probed. This takes care of cases
* where the DT is used to setup default parents and rates
* using assigned-clocks
*/
clk_set_defaults(dev, 1);
return 0;
}
UCLASS_DRIVER(clk) = { UCLASS_DRIVER(clk) = {
.id = UCLASS_CLK, .id = UCLASS_CLK,
.name = "clk", .name = "clk",
.post_probe = clk_uclass_post_probe,
}; };

View File

@ -423,7 +423,7 @@ int device_probe(struct udevice *dev)
* Process 'assigned-{clocks/clock-parents/clock-rates}' * Process 'assigned-{clocks/clock-parents/clock-rates}'
* properties * properties
*/ */
ret = clk_set_defaults(dev); ret = clk_set_defaults(dev, 0);
if (ret) if (ret)
goto fail; goto fail;
} }

View File

@ -244,10 +244,13 @@ static inline int clk_release_all(struct clk *clk, int count)
* *
* @dev: A device to process (the ofnode associated with this device * @dev: A device to process (the ofnode associated with this device
* will be processed). * will be processed).
* @stage: A integer. 0 indicates that this is called before the device
* is probed. 1 indicates that this is called just after the
* device has been probed
*/ */
int clk_set_defaults(struct udevice *dev); int clk_set_defaults(struct udevice *dev, int stage);
#else #else
static inline int clk_set_defaults(struct udevice *dev) static inline int clk_set_defaults(struct udevice *dev, int stage)
{ {
return 0; return 0;
} }