summaryrefslogtreecommitdiffstats
path: root/drivers/clk/renesas/rcar-gen3-cpg.c
diff options
context:
space:
mode:
authorGeert Uytterhoeven <geert+renesas@glider.be>2021-03-26 13:01:00 +0100
committerGeert Uytterhoeven <geert+renesas@glider.be>2021-05-11 09:57:06 +0200
commit3a0e84845891eebccce767b4f8cd5ed1b9bffc14 (patch)
tree7d4a2b2c9b1fb524e8ef634b98df8a935a34cb73 /drivers/clk/renesas/rcar-gen3-cpg.c
parentclk: renesas: rcar-gen3: Add custom clock for PLLs (diff)
downloadlinux-3a0e84845891eebccce767b4f8cd5ed1b9bffc14.tar.xz
linux-3a0e84845891eebccce767b4f8cd5ed1b9bffc14.zip
clk: renesas: rcar-gen3: Add boost support to Z clocks
Add support for switching the Z and Z2 clocks between normal and boost modes, by requesting clock rate changes to parent PLLs. Inspired by a patch in the BSP by Takeshi Kihara <takeshi.kihara.df@renesas.com>. Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> Acked-by: Stephen Boyd <sboyd@kernel.org> Reviewed-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> Tested-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> Link: https://lore.kernel.org/r/20210326120100.1577596-8-geert+renesas@glider.be
Diffstat (limited to 'drivers/clk/renesas/rcar-gen3-cpg.c')
-rw-r--r--drivers/clk/renesas/rcar-gen3-cpg.c24
1 files changed, 20 insertions, 4 deletions
diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c
index cc9a116d7d09..558191c99b48 100644
--- a/drivers/clk/renesas/rcar-gen3-cpg.c
+++ b/drivers/clk/renesas/rcar-gen3-cpg.c
@@ -165,6 +165,7 @@ struct cpg_z_clk {
struct clk_hw hw;
void __iomem *reg;
void __iomem *kick_reg;
+ unsigned long max_rate; /* Maximum rate for normal mode */
unsigned int fixed_div;
u32 mask;
};
@@ -190,7 +191,18 @@ static int cpg_z_clk_determine_rate(struct clk_hw *hw,
{
struct cpg_z_clk *zclk = to_z_clk(hw);
unsigned int min_mult, max_mult, mult;
- unsigned long prate;
+ unsigned long rate, prate;
+
+ rate = min(req->rate, req->max_rate);
+ if (rate <= zclk->max_rate) {
+ /* Set parent rate to initial value for normal modes */
+ prate = zclk->max_rate;
+ } else {
+ /* Set increased parent rate for boost modes */
+ prate = rate;
+ }
+ req->best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
+ prate * zclk->fixed_div);
prate = req->best_parent_rate / zclk->fixed_div;
min_mult = max(div64_ul(req->min_rate * 32ULL, prate), 1ULL);
@@ -198,7 +210,7 @@ static int cpg_z_clk_determine_rate(struct clk_hw *hw,
if (max_mult < min_mult)
return -EINVAL;
- mult = DIV_ROUND_CLOSEST_ULL(req->rate * 32ULL, prate);
+ mult = DIV_ROUND_CLOSEST_ULL(rate * 32ULL, prate);
mult = clamp(mult, min_mult, max_mult);
req->rate = DIV_ROUND_CLOSEST_ULL((u64)prate * mult, 32);
@@ -268,7 +280,7 @@ static struct clk * __init cpg_z_clk_register(const char *name,
init.name = name;
init.ops = &cpg_z_clk_ops;
- init.flags = 0;
+ init.flags = CLK_SET_RATE_PARENT;
init.parent_names = &parent_name;
init.num_parents = 1;
@@ -279,9 +291,13 @@ static struct clk * __init cpg_z_clk_register(const char *name,
zclk->fixed_div = div; /* PLLVCO x 1/div x SYS-CPU divider */
clk = clk_register(NULL, &zclk->hw);
- if (IS_ERR(clk))
+ if (IS_ERR(clk)) {
kfree(zclk);
+ return clk;
+ }
+ zclk->max_rate = clk_hw_get_rate(clk_hw_get_parent(&zclk->hw)) /
+ zclk->fixed_div;
return clk;
}