summaryrefslogtreecommitdiff
path: root/drivers/clk/renesas
diff options
context:
space:
mode:
authorGeert Uytterhoeven <geert+renesas@glider.be>2021-04-01 16:01:37 +0300
committerGeert Uytterhoeven <geert+renesas@glider.be>2021-05-11 10:58:13 +0300
commit1c924fc679123e6057239693d226c8d8c5780626 (patch)
tree8dc911dc69921aa64f89a9e57eb37fb8dba6d449 /drivers/clk/renesas
parentc9d1b58b272e272fc7121929e2d0e0755ea1656e (diff)
downloadlinux-1c924fc679123e6057239693d226c8d8c5780626.tar.xz
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
Diffstat (limited to 'drivers/clk/renesas')
-rw-r--r--drivers/clk/renesas/clk-div6.c35
1 files changed, 32 insertions, 3 deletions
diff --git a/drivers/clk/renesas/clk-div6.c b/drivers/clk/renesas/clk-div6.c
index 3af65ef5690e..a9ac2a83c1d0 100644
--- a/drivers/clk/renesas/clk-div6.c
+++ b/drivers/clk/renesas/clk-div6.c
@@ -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;
+
+ 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->rate = req->best_parent_rate / div;
+ req->best_parent_rate = best_prate;
+ req->best_parent_hw = best_parent;
+ req->rate = best_rate;
return 0;
}