The spi and spix2 clk share same bit for clock gating. Add support for coupled clock with checking the monitor bit for both the clocks. Signed-off-by: Biju Das <biju.das.jz@xxxxxxxxxxxxxx> --- drivers/clk/renesas/rzv2h-cpg.c | 83 ++++++++++++++++++++++++++++++++- drivers/clk/renesas/rzv2h-cpg.h | 19 ++++++-- 2 files changed, 97 insertions(+), 5 deletions(-) diff --git a/drivers/clk/renesas/rzv2h-cpg.c b/drivers/clk/renesas/rzv2h-cpg.c index 469d29549e8e..19fe225d48ed 100644 --- a/drivers/clk/renesas/rzv2h-cpg.c +++ b/drivers/clk/renesas/rzv2h-cpg.c @@ -111,6 +111,8 @@ struct pll_clk { * @on_bit: ON/MON bit * @mon_index: monitor register offset * @mon_bit: montor bit + * @enabled: soft state of the clock, if it is coupled with another clock + * @sibling: pointer to the other coupled clock */ struct mod_clock { struct rzv2h_cpg_priv *priv; @@ -121,6 +123,8 @@ struct mod_clock { u8 on_bit; s8 mon_index; u8 mon_bit; + bool enabled; + struct mod_clock *sibling; }; #define to_mod_clock(_hw) container_of(_hw, struct mod_clock, hw) @@ -573,11 +577,56 @@ static int rzv2h_mod_clock_endisable(struct clk_hw *hw, bool enable) static int rzv2h_mod_clock_enable(struct clk_hw *hw) { - return rzv2h_mod_clock_endisable(hw, true); + struct mod_clock *clock = to_mod_clock(hw); + int ret; + + if (clock->sibling) { + struct rzv2h_cpg_priv *priv = clock->priv; + unsigned long flags; + bool enabled; + + spin_lock_irqsave(&priv->rmw_lock, flags); + enabled = clock->sibling->enabled; + clock->enabled = true; + spin_unlock_irqrestore(&priv->rmw_lock, flags); + if (enabled) { + ret = rzv2h_mod_clock_is_enabled(&clock->hw); + if (!ret) { + dev_err(priv->dev, "Failed CLK_MON_ON 0x%x/%pC\n", + GET_CLK_MON_OFFSET(clock->mon_index), hw->clk); + ret = -ETIMEDOUT; + } else { + ret = 0; + } + + return ret; + } + } + + ret = rzv2h_mod_clock_endisable(hw, true); + if (ret) + clock->enabled = false; + + return ret; } static void rzv2h_mod_clock_disable(struct clk_hw *hw) { + struct mod_clock *clock = to_mod_clock(hw); + + if (clock->sibling) { + struct rzv2h_cpg_priv *priv = clock->priv; + unsigned long flags; + bool enabled; + + spin_lock_irqsave(&priv->rmw_lock, flags); + enabled = clock->sibling->enabled; + clock->enabled = false; + spin_unlock_irqrestore(&priv->rmw_lock, flags); + if (enabled) + return; + } + rzv2h_mod_clock_endisable(hw, false); } @@ -587,6 +636,28 @@ static const struct clk_ops rzv2h_mod_clock_ops = { .is_enabled = rzv2h_mod_clock_is_enabled, }; +static struct mod_clock +*rzv2h_mod_clock_get_sibling(struct mod_clock *clock, + struct rzv2h_cpg_priv *priv) +{ + struct clk_hw *hw; + unsigned int i; + + for (i = 0; i < priv->num_mod_clks; i++) { + struct mod_clock *clk; + + if (priv->clks[priv->num_core_clks + i] == ERR_PTR(-ENOENT)) + continue; + + hw = __clk_get_hw(priv->clks[priv->num_core_clks + i]); + clk = to_mod_clock(hw); + if (clock->on_index == clk->on_index && clock->on_bit == clk->on_bit) + return clk; + } + + return NULL; +} + static void __init rzv2h_cpg_register_mod_clk(const struct rzv2h_mod_clk *mod, struct rzv2h_cpg_priv *priv) @@ -642,6 +713,16 @@ rzv2h_cpg_register_mod_clk(const struct rzv2h_mod_clk *mod, } priv->clks[id] = clock->hw.clk; + if (mod->is_coupled) { + struct mod_clock *sibling; + + clock->enabled = rzv2h_mod_clock_is_enabled(&clock->hw); + sibling = rzv2h_mod_clock_get_sibling(clock, priv); + if (sibling) { + clock->sibling = sibling; + sibling->sibling = clock; + } + } /* * Ensure the module clocks and MSTOP bits are synchronized when they are diff --git a/drivers/clk/renesas/rzv2h-cpg.h b/drivers/clk/renesas/rzv2h-cpg.h index b0e32e0c9ffd..4a568fef905d 100644 --- a/drivers/clk/renesas/rzv2h-cpg.h +++ b/drivers/clk/renesas/rzv2h-cpg.h @@ -162,6 +162,7 @@ enum clk_types { * @on_bit: ON bit * @mon_index: monitor register index * @mon_bit: monitor bit + * @is_coupled: flag to indicate coupled clock */ struct rzv2h_mod_clk { const char *name; @@ -173,9 +174,11 @@ struct rzv2h_mod_clk { u8 on_bit; s8 mon_index; u8 mon_bit; + bool is_coupled; }; -#define DEF_MOD_BASE(_name, _mstop, _parent, _critical, _no_pm, _onindex, _onbit, _monindex, _monbit) \ +#define DEF_MOD_BASE(_name, _mstop, _parent, _critical, _no_pm, _onindex, \ + _onbit, _monindex, _monbit, _iscoupled) \ { \ .name = (_name), \ .mstop_data = (_mstop), \ @@ -186,16 +189,24 @@ struct rzv2h_mod_clk { .on_bit = (_onbit), \ .mon_index = (_monindex), \ .mon_bit = (_monbit), \ + .is_coupled = (_iscoupled), \ } #define DEF_MOD(_name, _parent, _onindex, _onbit, _monindex, _monbit, _mstop) \ - DEF_MOD_BASE(_name, _mstop, _parent, false, false, _onindex, _onbit, _monindex, _monbit) + DEF_MOD_BASE(_name, _mstop, _parent, false, false, _onindex, _onbit, \ + _monindex, _monbit, false) #define DEF_MOD_CRITICAL(_name, _parent, _onindex, _onbit, _monindex, _monbit, _mstop) \ - DEF_MOD_BASE(_name, _mstop, _parent, true, false, _onindex, _onbit, _monindex, _monbit) + DEF_MOD_BASE(_name, _mstop, _parent, true, false, _onindex, _onbit, \ + _monindex, _monbit, false) #define DEF_MOD_NO_PM(_name, _parent, _onindex, _onbit, _monindex, _monbit, _mstop) \ - DEF_MOD_BASE(_name, _mstop, _parent, false, true, _onindex, _onbit, _monindex, _monbit) + DEF_MOD_BASE(_name, _mstop, _parent, false, true, _onindex, _onbit, \ + _monindex, _monbit, false) + +#define DEF_COUPLED(_name, _parent, _onindex, _onbit, _monindex, _monbit, _mstop) \ + DEF_MOD_BASE(_name, _mstop, _parent, false, false, _onindex, _onbit, \ + _monindex, _monbit, true) /** * struct rzv2h_reset - Reset definitions -- 2.43.0