diff options
| author | Sam Protsenko <[email protected]> | 2024-03-07 18:04:32 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2024-12-12 14:23:25 -0600 |
| commit | e5aef1bbf11412eebd4c242b46adff5301353c30 (patch) | |
| tree | add17fdeadcdddc9eb7922c7c09486027812df40 | |
| parent | 9bc62c980d418f0a67632ab29cd3501072cdb6f0 (diff) | |
clk: Propagate clk_set_rate() if CLK_SET_PARENT_RATE present
Sometimes clocks provided to a consumer might not have .set_rate
operation (like gate or mux clocks), but have CLK_SET_PARENT_RATE flag
set. In that case it's usually possible to find a parent up the tree
which is capable of setting the rate (div, pll, etc). Implement a simple
lookup procedure for such cases, to traverse the clock tree until
.set_rate capable parent is found, and use that parent to actually
change the rate. The search will stop once the first .set_rate capable
clock is found, which is usually enough to handle most cases.
Signed-off-by: Sam Protsenko <[email protected]>
| -rw-r--r-- | drivers/clk/clk-uclass.c | 16 |
1 files changed, 14 insertions, 2 deletions
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index a9937c22dcb..353ae476068 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -569,8 +569,20 @@ ulong clk_set_rate(struct clk *clk, ulong rate) return 0; ops = clk_dev_ops(clk->dev); - if (!ops->set_rate) - return -ENOSYS; + /* Try to find parents which can set rate */ + while (!ops->set_rate) { + struct clk *parent; + + if (!(clk->flags & CLK_SET_RATE_PARENT)) + return -ENOSYS; + + parent = clk_get_parent(clk); + if (IS_ERR_OR_NULL(parent) || !clk_valid(parent)) + return -ENODEV; + + clk = parent; + ops = clk_dev_ops(clk->dev); + } /* get private clock struct used for cache */ clk_get_priv(clk, &clkp); |
