summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Protsenko <[email protected]>2024-03-07 18:04:32 -0600
committerTom Rini <[email protected]>2024-12-12 14:23:25 -0600
commite5aef1bbf11412eebd4c242b46adff5301353c30 (patch)
treeadd17fdeadcdddc9eb7922c7c09486027812df40
parent9bc62c980d418f0a67632ab29cd3501072cdb6f0 (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.c16
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);