The AXI and CHI clocks use the same register bit for controlling clock output. Add a new clock type for coupled clocks, which sets the CPG_CLKON_ETH.CLK[01]_ON bit when at least one clock is enabled, and clears the bit only when both clocks are disabled. Signed-off-by: Biju Das <biju.das.jz@xxxxxxxxxxxxxx> Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@xxxxxxxxxxxxxx> --- v2:- * New patch --- drivers/clk/renesas/rzg2l-cpg.c | 31 +++++++++++++++++++++++++++++++ drivers/clk/renesas/rzg2l-cpg.h | 11 ++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 597efc2504eb..4d2af113b54e 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -333,12 +333,16 @@ rzg2l_cpg_register_core_clk(const struct cpg_core_clk *core, * @hw: handle between common and hardware-specific interfaces * @off: register offset * @bit: ON/MON bit + * @is_coupled: flag to indicate coupled clock + * @on_cnt: ON count for coupled clocks * @priv: CPG/MSTP private data */ struct mstp_clock { struct clk_hw hw; u16 off; u8 bit; + bool is_coupled; + u8 on_cnt; struct rzg2l_cpg_priv *priv; }; @@ -392,11 +396,37 @@ static int rzg2l_mod_clock_endisable(struct clk_hw *hw, bool enable) static int rzg2l_mod_clock_enable(struct clk_hw *hw) { + struct mstp_clock *clock = to_mod_clock(hw); + struct rzg2l_cpg_priv *priv = clock->priv; + unsigned long flags; + + spin_lock_irqsave(&priv->rmw_lock, flags); + clock->on_cnt++; + if (clock->is_coupled && clock->on_cnt > 1) { + spin_unlock_irqrestore(&priv->rmw_lock, flags); + return 1; + } + + spin_unlock_irqrestore(&priv->rmw_lock, flags); + return rzg2l_mod_clock_endisable(hw, true); } static void rzg2l_mod_clock_disable(struct clk_hw *hw) { + struct mstp_clock *clock = to_mod_clock(hw); + struct rzg2l_cpg_priv *priv = clock->priv; + unsigned long flags; + + spin_lock_irqsave(&priv->rmw_lock, flags); + clock->on_cnt--; + if (clock->is_coupled && clock->on_cnt) { + spin_unlock_irqrestore(&priv->rmw_lock, flags); + return; + } + + spin_unlock_irqrestore(&priv->rmw_lock, flags); + rzg2l_mod_clock_endisable(hw, false); } @@ -475,6 +505,7 @@ rzg2l_cpg_register_mod_clk(const struct rzg2l_mod_clk *mod, clock->off = mod->off; clock->bit = mod->bit; + clock->is_coupled = mod->is_coupled; clock->priv = priv; clock->hw.init = &init; diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h index 5202c0512483..191c403aa52f 100644 --- a/drivers/clk/renesas/rzg2l-cpg.h +++ b/drivers/clk/renesas/rzg2l-cpg.h @@ -93,6 +93,7 @@ enum clk_types { * @parent: id of parent clock * @off: register offset * @bit: ON/MON bit + * @is_coupled: flag to indicate coupled clock */ struct rzg2l_mod_clk { const char *name; @@ -100,17 +101,25 @@ struct rzg2l_mod_clk { unsigned int parent; u16 off; u8 bit; + bool is_coupled; }; -#define DEF_MOD(_name, _id, _parent, _off, _bit) \ +#define DEF_MOD_BASE(_name, _id, _parent, _off, _bit, _is_coupled) \ { \ .name = _name, \ .id = MOD_CLK_BASE + (_id), \ .parent = (_parent), \ .off = (_off), \ .bit = (_bit), \ + .is_coupled = (_is_coupled), \ } +#define DEF_MOD(_name, _id, _parent, _off, _bit) \ + DEF_MOD_BASE(_name, _id, _parent, _off, _bit, false) + +#define DEF_COUPLED(_name, _id, _parent, _off, _bit) \ + DEF_MOD_BASE(_name, _id, _parent, _off, _bit, true) + /** * struct rzg2l_reset - Reset definitions * -- 2.17.1