]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
clk: renesas: rzv2h: Add fixed-factor module clocks with status reporting
authorLad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Fri, 27 Jun 2025 20:42:35 +0000 (21:42 +0100)
committerGeert Uytterhoeven <geert+renesas@glider.be>
Wed, 2 Jul 2025 18:53:35 +0000 (20:53 +0200)
Add support for fixed-factor module clocks that can report their enable
status through the module status monitor. Introduce a new clock type,
CLK_TYPE_FF_MOD_STATUS, and define the associated structure,
rzv2h_ff_mod_status_clk, to manage these clocks.

Implement the .is_enabled callback by reading the module status register
using monitor index and bit definitions. Provide a helper macro,
DEF_FIXED_MOD_STATUS, to simplify the definition of such clocks.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Link: https://lore.kernel.org/20250627204237.214635-5-prabhakar.mahadev-lad.rj@bp.renesas.com
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
drivers/clk/renesas/rzv2h-cpg.c
drivers/clk/renesas/rzv2h-cpg.h

index 80a44847456457d136853244e68b8fc4084094ab..f468afbb54e2d192c094e0048a698664ae99bd00 100644 (file)
@@ -77,6 +77,7 @@
  * @resets: Array of resets
  * @num_resets: Number of Module Resets in info->resets[]
  * @last_dt_core_clk: ID of the last Core Clock exported to DT
+ * @ff_mod_status_ops: Fixed Factor Module Status Clock operations
  * @mstop_count: Array of mstop values
  * @rcdev: Reset controller entity
  */
@@ -92,6 +93,8 @@ struct rzv2h_cpg_priv {
        unsigned int num_resets;
        unsigned int last_dt_core_clk;
 
+       struct clk_ops *ff_mod_status_ops;
+
        atomic_t *mstop_count;
 
        struct reset_controller_dev rcdev;
@@ -149,6 +152,22 @@ struct ddiv_clk {
 
 #define to_ddiv_clock(_div) container_of(_div, struct ddiv_clk, div)
 
+/**
+ * struct rzv2h_ff_mod_status_clk - Fixed Factor Module Status Clock
+ *
+ * @priv: CPG private data
+ * @conf: fixed mod configuration
+ * @fix: fixed factor clock
+ */
+struct rzv2h_ff_mod_status_clk {
+       struct rzv2h_cpg_priv *priv;
+       struct fixed_mod_conf conf;
+       struct clk_fixed_factor fix;
+};
+
+#define to_rzv2h_ff_mod_status_clk(_hw) \
+       container_of(_hw, struct rzv2h_ff_mod_status_clk, fix.hw)
+
 static int rzv2h_cpg_pll_clk_is_enabled(struct clk_hw *hw)
 {
        struct pll_clk *pll_clk = to_pll(hw);
@@ -418,6 +437,65 @@ rzv2h_cpg_mux_clk_register(const struct cpg_core_clk *core,
        return clk_hw->clk;
 }
 
+static int
+rzv2h_clk_ff_mod_status_is_enabled(struct clk_hw *hw)
+{
+       struct rzv2h_ff_mod_status_clk *fix = to_rzv2h_ff_mod_status_clk(hw);
+       struct rzv2h_cpg_priv *priv = fix->priv;
+       u32 offset = GET_CLK_MON_OFFSET(fix->conf.mon_index);
+       u32 bitmask = BIT(fix->conf.mon_bit);
+       u32 val;
+
+       val = readl(priv->base + offset);
+       return !!(val & bitmask);
+}
+
+static struct clk * __init
+rzv2h_cpg_fixed_mod_status_clk_register(const struct cpg_core_clk *core,
+                                       struct rzv2h_cpg_priv *priv)
+{
+       struct rzv2h_ff_mod_status_clk *clk_hw_data;
+       struct clk_init_data init = { };
+       struct clk_fixed_factor *fix;
+       const struct clk *parent;
+       const char *parent_name;
+       int ret;
+
+       WARN_DEBUG(core->parent >= priv->num_core_clks);
+       parent = priv->clks[core->parent];
+       if (IS_ERR(parent))
+               return ERR_CAST(parent);
+
+       parent_name = __clk_get_name(parent);
+       parent = priv->clks[core->parent];
+       if (IS_ERR(parent))
+               return ERR_CAST(parent);
+
+       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->cfg.fixed_mod;
+
+       init.name = core->name;
+       init.ops = priv->ff_mod_status_ops;
+       init.flags = CLK_SET_RATE_PARENT;
+       init.parent_names = &parent_name;
+       init.num_parents = 1;
+
+       fix = &clk_hw_data->fix;
+       fix->hw.init = &init;
+       fix->mult = core->mult;
+       fix->div = core->div;
+
+       ret = devm_clk_hw_register(priv->dev, &clk_hw_data->fix.hw);
+       if (ret)
+               return ERR_PTR(ret);
+
+       return clk_hw_data->fix.hw.clk;
+}
+
 static struct clk
 *rzv2h_cpg_clk_src_twocell_get(struct of_phandle_args *clkspec,
                               void *data)
@@ -496,6 +574,20 @@ rzv2h_cpg_register_core_clk(const struct cpg_core_clk *core,
                else
                        clk = clk_hw->clk;
                break;
+       case CLK_TYPE_FF_MOD_STATUS:
+               if (!priv->ff_mod_status_ops) {
+                       priv->ff_mod_status_ops =
+                               devm_kzalloc(dev, sizeof(*priv->ff_mod_status_ops), GFP_KERNEL);
+                       if (!priv->ff_mod_status_ops) {
+                               clk = ERR_PTR(-ENOMEM);
+                               goto fail;
+                       }
+                       memcpy(priv->ff_mod_status_ops, &clk_fixed_factor_ops,
+                              sizeof(const struct clk_ops));
+                       priv->ff_mod_status_ops->is_enabled = rzv2h_clk_ff_mod_status_is_enabled;
+               }
+               clk = rzv2h_cpg_fixed_mod_status_clk_register(core, priv);
+               break;
        case CLK_TYPE_PLL:
                clk = rzv2h_cpg_pll_clk_register(core, priv, &rzv2h_cpg_pll_ops);
                break;
index 25e0a9e5761b6504d518e90bd93aa2d543121542..ba4f0196643f31128d920b8ca3543fce68d105a2 100644 (file)
@@ -94,6 +94,23 @@ struct smuxed {
                .width = (_width), \
        })
 
+/**
+ * struct fixed_mod_conf - Structure for fixed module configuration
+ *
+ * @mon_index: monitor index
+ * @mon_bit: monitor bit
+ */
+struct fixed_mod_conf {
+       u8 mon_index;
+       u8 mon_bit;
+};
+
+#define FIXED_MOD_CONF_PACK(_index, _bit) \
+       ((struct fixed_mod_conf){ \
+               .mon_index = (_index), \
+               .mon_bit = (_bit), \
+       })
+
 #define CPG_SSEL0              (0x300)
 #define CPG_SSEL1              (0x304)
 #define CPG_CDDIV0             (0x400)
@@ -152,6 +169,7 @@ struct cpg_core_clk {
                struct ddiv ddiv;
                struct pll pll;
                struct smuxed smux;
+               struct fixed_mod_conf fixed_mod;
        } cfg;
        const struct clk_div_table *dtable;
        const char * const *parent_names;
@@ -164,6 +182,7 @@ enum clk_types {
        /* Generic */
        CLK_TYPE_IN,            /* External Clock Input */
        CLK_TYPE_FF,            /* Fixed Factor Clock */
+       CLK_TYPE_FF_MOD_STATUS, /* Fixed Factor Clock which can report the status of module clock */
        CLK_TYPE_PLL,
        CLK_TYPE_DDIV,          /* Dynamic Switching Divider */
        CLK_TYPE_SMUX,          /* Static Mux */
@@ -179,6 +198,9 @@ enum clk_types {
        DEF_TYPE(_name, _id, CLK_TYPE_IN)
 #define DEF_FIXED(_name, _id, _parent, _mult, _div) \
        DEF_BASE(_name, _id, CLK_TYPE_FF, _parent, .div = _div, .mult = _mult)
+#define DEF_FIXED_MOD_STATUS(_name, _id, _parent, _mult, _div, _gate) \
+       DEF_BASE(_name, _id, CLK_TYPE_FF_MOD_STATUS, _parent, .div = _div, \
+                .mult = _mult, .cfg.fixed_mod = _gate)
 #define DEF_DDIV(_name, _id, _parent, _ddiv_packed, _dtable) \
        DEF_TYPE(_name, _id, CLK_TYPE_DDIV, \
                .cfg.ddiv = _ddiv_packed, \