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 <semen.protsenko@linaro.org>
This commit is contained in:
Sam Protsenko 2024-03-07 18:04:32 -06:00 committed by Tom Rini
parent 9bc62c980d
commit e5aef1bbf1

View file

@ -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);