mirror of
https://github.com/u-boot/u-boot.git
synced 2024-11-25 05:04:23 +08:00
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:
parent
dd2e0ce2a4
commit
fd1ba29652
@ -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,
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user