diff options
| author | Maxime Ripard <maxime.ripard@free-electrons.com> | 2013-04-08 21:39:22 +0200 | 
|---|---|---|
| committer | Maxime Ripard <maxime.ripard@free-electrons.com> | 2013-04-08 21:39:22 +0200 | 
| commit | 7c91d302ffe2ffac813c47d6ba2e7489a2ccb35f (patch) | |
| tree | 78a2cf601e986694765b28079bf749a8eaa6a2b9 /drivers/clk/ux500/clk-prcmu.c | |
| parent | 0b824f8dad9fdfc7c1bf9c1d3ac744075eb73ec6 (diff) | |
| parent | 918d7f6f68620e0721bb31402ebf87e15f826831 (diff) | |
| download | olio-linux-3.10-7c91d302ffe2ffac813c47d6ba2e7489a2ccb35f.tar.xz olio-linux-3.10-7c91d302ffe2ffac813c47d6ba2e7489a2ccb35f.zip | |
Merge remote-tracking branch 'clk/clk-for-3.10' into sunxi/core-for-3.10
Diffstat (limited to 'drivers/clk/ux500/clk-prcmu.c')
| -rw-r--r-- | drivers/clk/ux500/clk-prcmu.c | 132 | 
1 files changed, 79 insertions, 53 deletions
| diff --git a/drivers/clk/ux500/clk-prcmu.c b/drivers/clk/ux500/clk-prcmu.c index 74faa7e3cf5..293a2885441 100644 --- a/drivers/clk/ux500/clk-prcmu.c +++ b/drivers/clk/ux500/clk-prcmu.c @@ -20,15 +20,23 @@  struct clk_prcmu {  	struct clk_hw hw;  	u8 cg_sel; +	int is_prepared;  	int is_enabled; +	int opp_requested;  };  /* PRCMU clock operations. */  static int clk_prcmu_prepare(struct clk_hw *hw)  { +	int ret;  	struct clk_prcmu *clk = to_clk_prcmu(hw); -	return prcmu_request_clock(clk->cg_sel, true); + +	ret = prcmu_request_clock(clk->cg_sel, true); +	if (!ret) +		clk->is_prepared = 1; + +	return ret;;  }  static void clk_prcmu_unprepare(struct clk_hw *hw) @@ -36,7 +44,15 @@ static void clk_prcmu_unprepare(struct clk_hw *hw)  	struct clk_prcmu *clk = to_clk_prcmu(hw);  	if (prcmu_request_clock(clk->cg_sel, false))  		pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, -			hw->init->name); +			__clk_get_name(hw->clk)); +	else +		clk->is_prepared = 0; +} + +static int clk_prcmu_is_prepared(struct clk_hw *hw) +{ +	struct clk_prcmu *clk = to_clk_prcmu(hw); +	return clk->is_prepared;  }  static int clk_prcmu_enable(struct clk_hw *hw) @@ -79,58 +95,52 @@ static int clk_prcmu_set_rate(struct clk_hw *hw, unsigned long rate,  	return prcmu_set_clock_rate(clk->cg_sel, rate);  } -static int request_ape_opp100(bool enable) -{ -	static int reqs; -	int err = 0; - -	if (enable) { -		if (!reqs) -			err = prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, -							"clock", 100); -		if (!err) -			reqs++; -	} else { -		reqs--; -		if (!reqs) -			prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, -						"clock"); -	} -	return err; -} -  static int clk_prcmu_opp_prepare(struct clk_hw *hw)  {  	int err;  	struct clk_prcmu *clk = to_clk_prcmu(hw); -	err = request_ape_opp100(true); -	if (err) { -		pr_err("clk_prcmu: %s failed to request APE OPP100 for %s.\n", -			__func__, hw->init->name); -		return err; +	if (!clk->opp_requested) { +		err = prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, +						(char *)__clk_get_name(hw->clk), +						100); +		if (err) { +			pr_err("clk_prcmu: %s fail req APE OPP for %s.\n", +				__func__, __clk_get_name(hw->clk)); +			return err; +		} +		clk->opp_requested = 1;  	}  	err = prcmu_request_clock(clk->cg_sel, true); -	if (err) -		request_ape_opp100(false); +	if (err) { +		prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, +					(char *)__clk_get_name(hw->clk)); +		clk->opp_requested = 0; +		return err; +	} -	return err; +	clk->is_prepared = 1; +	return 0;  }  static void clk_prcmu_opp_unprepare(struct clk_hw *hw)  {  	struct clk_prcmu *clk = to_clk_prcmu(hw); -	if (prcmu_request_clock(clk->cg_sel, false)) -		goto out_error; -	if (request_ape_opp100(false)) -		goto out_error; -	return; +	if (prcmu_request_clock(clk->cg_sel, false)) { +		pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, +			__clk_get_name(hw->clk)); +		return; +	} + +	if (clk->opp_requested) { +		prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, +					(char *)__clk_get_name(hw->clk)); +		clk->opp_requested = 0; +	} -out_error: -	pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, -		hw->init->name); +	clk->is_prepared = 0;  }  static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw) @@ -138,38 +148,49 @@ static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw)  	int err;  	struct clk_prcmu *clk = to_clk_prcmu(hw); -	err = prcmu_request_ape_opp_100_voltage(true); -	if (err) { -		pr_err("clk_prcmu: %s failed to request APE OPP VOLT for %s.\n", -			__func__, hw->init->name); -		return err; +	if (!clk->opp_requested) { +		err = prcmu_request_ape_opp_100_voltage(true); +		if (err) { +			pr_err("clk_prcmu: %s fail req APE OPP VOLT for %s.\n", +				__func__, __clk_get_name(hw->clk)); +			return err; +		} +		clk->opp_requested = 1;  	}  	err = prcmu_request_clock(clk->cg_sel, true); -	if (err) +	if (err) {  		prcmu_request_ape_opp_100_voltage(false); +		clk->opp_requested = 0; +		return err; +	} -	return err; +	clk->is_prepared = 1; +	return 0;  }  static void clk_prcmu_opp_volt_unprepare(struct clk_hw *hw)  {  	struct clk_prcmu *clk = to_clk_prcmu(hw); -	if (prcmu_request_clock(clk->cg_sel, false)) -		goto out_error; -	if (prcmu_request_ape_opp_100_voltage(false)) -		goto out_error; -	return; +	if (prcmu_request_clock(clk->cg_sel, false)) { +		pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, +			__clk_get_name(hw->clk)); +		return; +	} + +	if (clk->opp_requested) { +		prcmu_request_ape_opp_100_voltage(false); +		clk->opp_requested = 0; +	} -out_error: -	pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, -		hw->init->name); +	clk->is_prepared = 0;  }  static struct clk_ops clk_prcmu_scalable_ops = {  	.prepare = clk_prcmu_prepare,  	.unprepare = clk_prcmu_unprepare, +	.is_prepared = clk_prcmu_is_prepared,  	.enable = clk_prcmu_enable,  	.disable = clk_prcmu_disable,  	.is_enabled = clk_prcmu_is_enabled, @@ -181,6 +202,7 @@ static struct clk_ops clk_prcmu_scalable_ops = {  static struct clk_ops clk_prcmu_gate_ops = {  	.prepare = clk_prcmu_prepare,  	.unprepare = clk_prcmu_unprepare, +	.is_prepared = clk_prcmu_is_prepared,  	.enable = clk_prcmu_enable,  	.disable = clk_prcmu_disable,  	.is_enabled = clk_prcmu_is_enabled, @@ -202,6 +224,7 @@ static struct clk_ops clk_prcmu_rate_ops = {  static struct clk_ops clk_prcmu_opp_gate_ops = {  	.prepare = clk_prcmu_opp_prepare,  	.unprepare = clk_prcmu_opp_unprepare, +	.is_prepared = clk_prcmu_is_prepared,  	.enable = clk_prcmu_enable,  	.disable = clk_prcmu_disable,  	.is_enabled = clk_prcmu_is_enabled, @@ -211,6 +234,7 @@ static struct clk_ops clk_prcmu_opp_gate_ops = {  static struct clk_ops clk_prcmu_opp_volt_scalable_ops = {  	.prepare = clk_prcmu_opp_volt_prepare,  	.unprepare = clk_prcmu_opp_volt_unprepare, +	.is_prepared = clk_prcmu_is_prepared,  	.enable = clk_prcmu_enable,  	.disable = clk_prcmu_disable,  	.is_enabled = clk_prcmu_is_enabled, @@ -242,7 +266,9 @@ static struct clk *clk_reg_prcmu(const char *name,  	}  	clk->cg_sel = cg_sel; +	clk->is_prepared = 1;  	clk->is_enabled = 1; +	clk->opp_requested = 0;  	/* "rate" can be used for changing the initial frequency */  	if (rate)  		prcmu_set_clock_rate(cg_sel, rate); |