]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
clk: renesas: rzg2l: Add PLL5_4 clk mux support
authorBiju Das <biju.das.jz@bp.renesas.com>
Sat, 30 Apr 2022 11:41:49 +0000 (12:41 +0100)
committerGeert Uytterhoeven <geert+renesas@glider.be>
Thu, 5 May 2022 10:10:21 +0000 (12:10 +0200)
Add PLL5_4 clk mux support to select clock from clock
sources FOUTPOSTDIV and FOUT1PH0.

Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Link: https://lore.kernel.org/r/20220430114156.6260-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 d1ede40b521047c86d8c06e78a0f17284b69f25c..ec2ccfd316f97c108f910ab82f2d00e3ac746a9b 100644 (file)
@@ -304,6 +304,96 @@ rzg2l_cpg_get_foutpostdiv_rate(struct rzg2l_pll5_param *params,
        return foutpostdiv_rate;
 }
 
+struct pll5_mux_hw_data {
+       struct clk_hw hw;
+       u32 conf;
+       unsigned long rate;
+       struct rzg2l_cpg_priv *priv;
+};
+
+#define to_pll5_mux_hw_data(_hw)       container_of(_hw, struct pll5_mux_hw_data, hw)
+
+static int rzg2l_cpg_pll5_4_clk_mux_determine_rate(struct clk_hw *hw,
+                                                  struct clk_rate_request *req)
+{
+       struct clk_hw *parent;
+       struct pll5_mux_hw_data *hwdata = to_pll5_mux_hw_data(hw);
+       struct rzg2l_cpg_priv *priv = hwdata->priv;
+
+       parent = clk_hw_get_parent_by_index(hw, priv->mux_dsi_div_params.clksrc);
+       req->best_parent_hw = parent;
+       req->best_parent_rate = req->rate;
+
+       return 0;
+}
+
+static int rzg2l_cpg_pll5_4_clk_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+       struct pll5_mux_hw_data *hwdata = to_pll5_mux_hw_data(hw);
+       struct rzg2l_cpg_priv *priv = hwdata->priv;
+
+       /*
+        * FOUTPOSTDIV--->|
+        *  |             | -->MUX -->DIV_DSIA_B -->M3 -->VCLK
+        *  |--FOUT1PH0-->|
+        *
+        * Based on the dot clock, the DSI divider clock calculates the parent
+        * rate and clk source for the MUX. It propagates that info to
+        * pll5_4_clk_mux which sets the clock source for DSI divider clock.
+        */
+
+       writel(CPG_OTHERFUNC1_REG_RES0_ON_WEN | index,
+              priv->base + CPG_OTHERFUNC1_REG);
+
+       return 0;
+}
+
+static u8 rzg2l_cpg_pll5_4_clk_mux_get_parent(struct clk_hw *hw)
+{
+       struct pll5_mux_hw_data *hwdata = to_pll5_mux_hw_data(hw);
+       struct rzg2l_cpg_priv *priv = hwdata->priv;
+
+       return readl(priv->base + GET_REG_OFFSET(hwdata->conf));
+}
+
+static const struct clk_ops rzg2l_cpg_pll5_4_clk_mux_ops = {
+       .determine_rate = rzg2l_cpg_pll5_4_clk_mux_determine_rate,
+       .set_parent     = rzg2l_cpg_pll5_4_clk_mux_set_parent,
+       .get_parent     = rzg2l_cpg_pll5_4_clk_mux_get_parent,
+};
+
+static struct clk * __init
+rzg2l_cpg_pll5_4_mux_clk_register(const struct cpg_core_clk *core,
+                                 struct rzg2l_cpg_priv *priv)
+{
+       struct pll5_mux_hw_data *clk_hw_data;
+       struct clk_init_data init;
+       struct clk_hw *clk_hw;
+       int ret;
+
+       clk_hw_data = devm_kzalloc(priv->dev, sizeof(*clk_hw_data), GFP_KERNEL);
+       if (!clk_hw_data)
+               return ERR_PTR(-ENOMEM);
+
+       clk_hw_data->priv = priv;
+       clk_hw_data->conf = core->conf;
+
+       init.name = core->name;
+       init.ops = &rzg2l_cpg_pll5_4_clk_mux_ops;
+       init.flags = CLK_SET_RATE_PARENT;
+       init.num_parents = core->num_parents;
+       init.parent_names = core->parent_names;
+
+       clk_hw = &clk_hw_data->hw;
+       clk_hw->init = &init;
+
+       ret = devm_clk_hw_register(priv->dev, clk_hw);
+       if (ret)
+               return ERR_PTR(ret);
+
+       return clk_hw->clk;
+}
+
 struct sipll5 {
        struct clk_hw hw;
        u32 conf;
@@ -640,6 +730,9 @@ rzg2l_cpg_register_core_clk(const struct cpg_core_clk *core,
        case CLK_TYPE_SD_MUX:
                clk = rzg2l_cpg_sd_mux_clk_register(core, priv->base, priv);
                break;
+       case CLK_TYPE_PLL5_4_MUX:
+               clk = rzg2l_cpg_pll5_4_mux_clk_register(core, priv);
+               break;
        default:
                goto fail;
        }
index c39c0ca8d1550dfbcbc81c49ab839b01b4049988..2503251cb18f87912bddaa044d8abe489bb23173 100644 (file)
@@ -24,6 +24,7 @@
 #define CPG_PL3_SSEL           (0x408)
 #define CPG_PL6_SSEL           (0x414)
 #define CPG_PL6_ETH_SSEL       (0x418)
+#define CPG_OTHERFUNC1_REG     (0xBE8)
 
 #define CPG_SIPLL5_STBY_RESETB         BIT(0)
 #define CPG_SIPLL5_STBY_RESETB_WEN     BIT(16)
@@ -35,6 +36,8 @@
 #define CPG_SIPLL5_CLK4_RESV_LSB       (0xFF)
 #define CPG_SIPLL5_MON_PLL5_LOCK       BIT(4)
 
+#define CPG_OTHERFUNC1_REG_RES0_ON_WEN BIT(16)
+
 #define CPG_CLKSTATUS_SELSDHI0_STS     BIT(28)
 #define CPG_CLKSTATUS_SELSDHI1_STS     BIT(29)
 
@@ -59,6 +62,7 @@
                (((offset) << 20) | ((bitpos) << 12) | ((size) << 8))
 
 #define SEL_PLL3_3     SEL_PLL_PACK(CPG_PL3_SSEL, 8, 1)
+#define SEL_PLL5_4     SEL_PLL_PACK(CPG_OTHERFUNC1_REG, 0, 1)
 #define SEL_PLL6_2     SEL_PLL_PACK(CPG_PL6_ETH_SSEL, 0, 1)
 #define SEL_GPU2       SEL_PLL_PACK(CPG_PL6_SSEL, 12, 1)
 
@@ -107,6 +111,9 @@ enum clk_types {
 
        /* Clock for SIPLL5 */
        CLK_TYPE_SIPLL5,
+
+       /* Clock for PLL5_4 clock source selector */
+       CLK_TYPE_PLL5_4_MUX,
 };
 
 #define DEF_TYPE(_name, _id, _type...) \
@@ -132,6 +139,9 @@ enum clk_types {
                 .parent_names = _parent_names, .num_parents = _num_parents)
 #define DEF_PLL5_FOUTPOSTDIV(_name, _id, _parent) \
        DEF_TYPE(_name, _id, CLK_TYPE_SIPLL5, .parent = _parent)
+#define DEF_PLL5_4_MUX(_name, _id, _conf, _parent_names, _num_parents) \
+       DEF_TYPE(_name, _id, CLK_TYPE_PLL5_4_MUX, .conf = _conf, \
+                .parent_names = _parent_names, .num_parents = _num_parents)
 
 /**
  * struct rzg2l_mod_clk - Module Clocks definitions