clk: renesas: div6: Consider all parents for requested rate

Currently the .determine_rate() callback considers only the current
parent clock, limiting the range of achievable clock rates on DIV6
clocks with multiple parents, as found on SH/R-Mobile SoCs.

Extend the callback to consider all available parent clocks.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Link: https://lore.kernel.org/r/60e639692b462f99e0b6ab868c3675b3d97dbdb0.1617281699.git.geert+renesas@glider.be
This commit is contained in:
Geert Uytterhoeven 2021-04-01 15:01:37 +02:00
parent c9d1b58b27
commit 1c924fc679

View file

@ -103,10 +103,39 @@ static unsigned int cpg_div6_clock_calc_div(unsigned long rate,
static int cpg_div6_clock_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
unsigned int div = cpg_div6_clock_calc_div(req->rate,
req->best_parent_rate);
unsigned long prate, calc_rate, diff, best_rate, best_prate;
unsigned int num_parents = clk_hw_get_num_parents(hw);
struct clk_hw *parent, *best_parent = NULL;
unsigned long min_diff = ULONG_MAX;
unsigned int i, div;
req->rate = req->best_parent_rate / div;
for (i = 0; i < num_parents; i++) {
parent = clk_hw_get_parent_by_index(hw, i);
if (!parent)
continue;
prate = clk_hw_get_rate(parent);
if (!prate)
continue;
div = cpg_div6_clock_calc_div(req->rate, prate);
calc_rate = prate / div;
diff = calc_rate > req->rate ? calc_rate - req->rate
: req->rate - calc_rate;
if (diff < min_diff) {
best_rate = calc_rate;
best_parent = parent;
best_prate = prate;
min_diff = diff;
}
}
if (!best_parent)
return -EINVAL;
req->best_parent_rate = best_prate;
req->best_parent_hw = best_parent;
req->rate = best_rate;
return 0;
}