diff options
Diffstat (limited to 'drivers/clk/tegra/clk-super.c')
| -rw-r--r-- | drivers/clk/tegra/clk-super.c | 41 | 
1 files changed, 41 insertions, 0 deletions
diff --git a/drivers/clk/tegra/clk-super.c b/drivers/clk/tegra/clk-super.c index 39ef31b46df5..6099c6e9acd4 100644 --- a/drivers/clk/tegra/clk-super.c +++ b/drivers/clk/tegra/clk-super.c @@ -28,6 +28,9 @@  #define super_state_to_src_shift(m, s) ((m->width * s))  #define super_state_to_src_mask(m) (((1 << m->width) - 1)) +#define CCLK_SRC_PLLP_OUT0 4 +#define CCLK_SRC_PLLP_OUT4 5 +  static u8 clk_super_get_parent(struct clk_hw *hw)  {  	struct tegra_clk_super_mux *mux = to_clk_super_mux(hw); @@ -97,12 +100,23 @@ static int clk_super_set_parent(struct clk_hw *hw, u8 index)  		if (index == mux->div2_index)  			index = mux->pllx_index;  	} + +	/* enable PLLP branches to CPU before selecting PLLP source */ +	if ((mux->flags & TEGRA210_CPU_CLK) && +	    (index == CCLK_SRC_PLLP_OUT0 || index == CCLK_SRC_PLLP_OUT4)) +		tegra_clk_set_pllp_out_cpu(true); +  	val &= ~((super_state_to_src_mask(mux)) << shift);  	val |= (index & (super_state_to_src_mask(mux))) << shift;  	writel_relaxed(val, mux->reg);  	udelay(2); +	/* disable PLLP branches to CPU if not used */ +	if ((mux->flags & TEGRA210_CPU_CLK) && +	    index != CCLK_SRC_PLLP_OUT0 && index != CCLK_SRC_PLLP_OUT4) +		tegra_clk_set_pllp_out_cpu(false); +  out:  	if (mux->lock)  		spin_unlock_irqrestore(mux->lock, flags); @@ -110,9 +124,21 @@ out:  	return err;  } +static void clk_super_mux_restore_context(struct clk_hw *hw) +{ +	int parent_id; + +	parent_id = clk_hw_get_parent_index(hw); +	if (WARN_ON(parent_id < 0)) +		return; + +	clk_super_set_parent(hw, parent_id); +} +  static const struct clk_ops tegra_clk_super_mux_ops = {  	.get_parent = clk_super_get_parent,  	.set_parent = clk_super_set_parent, +	.restore_context = clk_super_mux_restore_context,  };  static long clk_super_round_rate(struct clk_hw *hw, unsigned long rate, @@ -148,12 +174,27 @@ static int clk_super_set_rate(struct clk_hw *hw, unsigned long rate,  	return super->div_ops->set_rate(div_hw, rate, parent_rate);  } +static void clk_super_restore_context(struct clk_hw *hw) +{ +	struct tegra_clk_super_mux *super = to_clk_super_mux(hw); +	struct clk_hw *div_hw = &super->frac_div.hw; +	int parent_id; + +	parent_id = clk_hw_get_parent_index(hw); +	if (WARN_ON(parent_id < 0)) +		return; + +	super->div_ops->restore_context(div_hw); +	clk_super_set_parent(hw, parent_id); +} +  const struct clk_ops tegra_clk_super_ops = {  	.get_parent = clk_super_get_parent,  	.set_parent = clk_super_set_parent,  	.set_rate = clk_super_set_rate,  	.round_rate = clk_super_round_rate,  	.recalc_rate = clk_super_recalc_rate, +	.restore_context = clk_super_restore_context,  };  struct clk *tegra_clk_register_super_mux(const char *name,  | 

