]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
clk: renesas: rzg2l: Add support for enabling PLLs
authorBiju Das <biju.das.jz@bp.renesas.com>
Thu, 26 Mar 2026 11:06:36 +0000 (11:06 +0000)
committerGeert Uytterhoeven <geert+renesas@glider.be>
Mon, 27 Apr 2026 09:40:04 +0000 (11:40 +0200)
Add support for enabling PLL clocks in the RZ/G3L CPG driver to turn off
some PLLs, if they are not in use (e.g. PLL6, PLL7).

Introduce .is_enabled() and .enable() callbacks to handle PLL state
transitions.  With the .enable() callback, the PLL will be turned ON
only when the PLL consumer device is enabled; otherwise, it will remain
off.  Define new macros for PLL standby and monitor registers to
facilitate this process.

Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Link: https://patch.msgid.link/20260326110648.29389-3-biju.das.jz@bp.renesas.com
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
drivers/clk/renesas/rzg2l-cpg.c
drivers/clk/renesas/rzg2l-cpg.h

index 910c16a369a5385658d764d13bd84bb2a2344bf9..f98b6eb4f501c676a0b9b56d1936afb07841f4b9 100644 (file)
 #define RZG3S_DIV_NF           GENMASK(12, 1)
 #define RZG3S_SEL_PLL          BIT(0)
 
+#define RZG3L_PLL_STBY_OFFSET(x)       (GET_REG_SAMPLL_CLK1(x) - 0x4)
+#define RZG3L_PLL_STBY_RESETB          BIT(0)
+#define RZG3L_PLL_STBY_RESETB_WEN      BIT(16)
+#define RZG3L_PLL_MON_OFFSET(x)                (GET_REG_SAMPLL_CLK1(x) + 0x8)
+#define RZG3L_PLL_MON_RESETB           BIT(0)
+#define RZG3L_PLL_MON_LOCK             BIT(4)
+
 #define CLK_ON_R(reg)          (reg)
 #define CLK_MON_R(reg)         (0x180 + (reg))
 #define CLK_RST_R(reg)         (reg)
@@ -1175,6 +1182,63 @@ rzg2l_cpg_pll_clk_register(const struct cpg_core_clk *core,
        return pll_clk->hw.clk;
 }
 
+static int rzg3l_cpg_pll_clk_is_enabled(struct clk_hw *hw)
+{
+       struct pll_clk *pll_clk = to_pll(hw);
+       struct rzg2l_cpg_priv *priv = pll_clk->priv;
+       u32 val = readl(priv->base + RZG3L_PLL_MON_OFFSET(pll_clk->conf));
+       u32 mon_val = RZG3L_PLL_MON_RESETB | RZG3L_PLL_MON_LOCK;
+
+       /* Ensure both RESETB and LOCK bits are set */
+       return (mon_val == (val & mon_val));
+}
+
+static int rzg3l_cpg_pll_clk_endisable(struct clk_hw *hw, bool enable)
+{
+       struct pll_clk *pll_clk = to_pll(hw);
+       struct rzg2l_cpg_priv *priv = pll_clk->priv;
+       u32 stby_offset, mon_offset;
+       u32 val, mon_val;
+       int ret;
+
+       stby_offset = RZG3L_PLL_STBY_OFFSET(pll_clk->conf);
+       mon_offset = RZG3L_PLL_MON_OFFSET(pll_clk->conf);
+
+       if (enable) {
+               val = RZG3L_PLL_STBY_RESETB_WEN | RZG3L_PLL_STBY_RESETB;
+               mon_val = RZG3L_PLL_MON_RESETB | RZG3L_PLL_MON_LOCK;
+       } else {
+               val = RZG3L_PLL_STBY_RESETB_WEN;
+               mon_val = 0;
+       }
+
+       writel(val, priv->base + stby_offset);
+
+       /* ensure PLL is in normal/standby mode */
+       ret = readl_poll_timeout_atomic(priv->base + mon_offset, val, mon_val ==
+                                       (val & (RZG3L_PLL_MON_RESETB | RZG3L_PLL_MON_LOCK)),
+                                       10, 100);
+       if (ret)
+               dev_err(priv->dev, "Failed to %s PLL 0x%x/%pC\n", enable ?
+                       "enable" : "disable", stby_offset, hw->clk);
+
+       return ret;
+}
+
+static int rzg3l_cpg_pll_clk_enable(struct clk_hw *hw)
+{
+       if (rzg3l_cpg_pll_clk_is_enabled(hw))
+               return 0;
+
+       return rzg3l_cpg_pll_clk_endisable(hw, true);
+}
+
+static const struct clk_ops rzg3l_cpg_pll_ops = {
+       .is_enabled = rzg3l_cpg_pll_clk_is_enabled,
+       .enable = rzg3l_cpg_pll_clk_enable,
+       .recalc_rate = rzg3s_cpg_pll_clk_recalc_rate,
+};
+
 static struct clk
 *rzg2l_cpg_clk_src_twocell_get(struct of_phandle_args *clkspec,
                               void *data)
@@ -1258,6 +1322,9 @@ rzg2l_cpg_register_core_clk(const struct cpg_core_clk *core,
        case CLK_TYPE_SAM_PLL:
                clk = rzg2l_cpg_pll_clk_register(core, priv, &rzg2l_cpg_pll_ops);
                break;
+       case CLK_TYPE_G3L_PLL:
+               clk = rzg2l_cpg_pll_clk_register(core, priv, &rzg3l_cpg_pll_ops);
+               break;
        case CLK_TYPE_G3S_PLL:
                clk = rzg2l_cpg_pll_clk_register(core, priv, &rzg3s_cpg_pll_ops);
                break;
index 10baf9e71a6e024fe3edab6d3e7b191e2acbe9fb..ebd612d117c0d9fca557302fe390b433cc7825da 100644 (file)
@@ -123,6 +123,7 @@ enum clk_types {
        CLK_TYPE_IN,            /* External Clock Input */
        CLK_TYPE_FF,            /* Fixed Factor Clock */
        CLK_TYPE_SAM_PLL,
+       CLK_TYPE_G3L_PLL,
        CLK_TYPE_G3S_PLL,
 
        /* Clock with divider */
@@ -152,6 +153,9 @@ enum clk_types {
        DEF_TYPE(_name, _id, _type, .parent = _parent)
 #define DEF_SAMPLL(_name, _id, _parent, _conf) \
        DEF_TYPE(_name, _id, CLK_TYPE_SAM_PLL, .parent = _parent, .conf = _conf)
+#define DEF_G3L_PLL(_name, _id, _parent, _conf, _default_rate) \
+       DEF_TYPE(_name, _id, CLK_TYPE_G3L_PLL, .parent = _parent, .conf = _conf, \
+                .default_rate = _default_rate)
 #define DEF_G3S_PLL(_name, _id, _parent, _conf, _default_rate) \
        DEF_TYPE(_name, _id, CLK_TYPE_G3S_PLL, .parent = _parent, .conf = _conf, \
                 .default_rate = _default_rate)