diff options
Diffstat (limited to 'arch/arm/mach-omap2/clock.c')
| -rw-r--r-- | arch/arm/mach-omap2/clock.c | 135 | 
1 files changed, 91 insertions, 44 deletions
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index d1f115d0eda..a6d0b34b799 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -37,9 +37,9 @@  u8 cpu_mask; -/*------------------------------------------------------------------------- - * OMAP2/3/4 specific clock functions - *-------------------------------------------------------------------------*/ +/* + * OMAP2+ specific clock functions + */  /* Private functions */ @@ -71,20 +71,6 @@ static void _omap2_module_wait_ready(struct clk *clk)  			     clk->name);  } -/* Enables clock without considering parent dependencies or use count - * REVISIT: Maybe change this to use clk->enable like on omap1? - */ -static int _omap2_clk_enable(struct clk *clk) -{ -	return clk->ops->enable(clk); -} - -/* Disables clock without considering parent dependencies or use count */ -static void _omap2_clk_disable(struct clk *clk) -{ -	clk->ops->disable(clk); -} -  /* Public functions */  /** @@ -245,46 +231,106 @@ const struct clkops clkops_omap2_dflt = {  	.disable	= omap2_dflt_clk_disable,  }; +/** + * omap2_clk_disable - disable a clock, if the system is not using it + * @clk: struct clk * to disable + * + * Decrements the usecount on struct clk @clk.  If there are no users + * left, call the clkops-specific clock disable function to disable it + * in hardware.  If the clock is part of a clockdomain (which they all + * should be), request that the clockdomain be disabled.  (It too has + * a usecount, and so will not be disabled in the hardware until it no + * longer has any users.)  If the clock has a parent clock (most of + * them do), then call ourselves, recursing on the parent clock.  This + * can cause an entire branch of the clock tree to be powered off by + * simply disabling one clock.  Intended to be called with the clockfw_lock + * spinlock held.  No return value. + */  void omap2_clk_disable(struct clk *clk)  { -	if (clk->usecount > 0 && !(--clk->usecount)) { -		_omap2_clk_disable(clk); -		if (clk->parent) -			omap2_clk_disable(clk->parent); -		if (clk->clkdm) -			omap2_clkdm_clk_disable(clk->clkdm, clk); - +	if (clk->usecount == 0) { +		WARN(1, "clock: %s: omap2_clk_disable() called, but usecount " +		     "already 0?", clk->name); +		return;  	} + +	pr_debug("clock: %s: decrementing usecount\n", clk->name); + +	clk->usecount--; + +	if (clk->usecount > 0) +		return; + +	pr_debug("clock: %s: disabling in hardware\n", clk->name); + +	clk->ops->disable(clk); + +	if (clk->clkdm) +		omap2_clkdm_clk_disable(clk->clkdm, clk); + +	if (clk->parent) +		omap2_clk_disable(clk->parent);  } +/** + * omap2_clk_enable - request that the system enable a clock + * @clk: struct clk * to enable + * + * Increments the usecount on struct clk @clk.  If there were no users + * previously, then recurse up the clock tree, enabling all of the + * clock's parents and all of the parent clockdomains, and finally, + * enabling @clk's clockdomain, and @clk itself.  Intended to be + * called with the clockfw_lock spinlock held.  Returns 0 upon success + * or a negative error code upon failure. + */  int omap2_clk_enable(struct clk *clk)  { -	int ret = 0; +	int ret; -	if (clk->usecount++ == 0) { -		if (clk->clkdm) -			omap2_clkdm_clk_enable(clk->clkdm, clk); +	pr_debug("clock: %s: incrementing usecount\n", clk->name); -		if (clk->parent) { -			ret = omap2_clk_enable(clk->parent); -			if (ret) -				goto err; -		} +	clk->usecount++; + +	if (clk->usecount > 1) +		return 0; -		ret = _omap2_clk_enable(clk); +	pr_debug("clock: %s: enabling in hardware\n", clk->name); + +	if (clk->parent) { +		ret = omap2_clk_enable(clk->parent);  		if (ret) { -			if (clk->parent) -				omap2_clk_disable(clk->parent); +			WARN(1, "clock: %s: could not enable parent %s: %d\n", +			     clk->name, clk->parent->name, ret); +			goto oce_err1; +		} +	} -			goto err; +	if (clk->clkdm) { +		ret = omap2_clkdm_clk_enable(clk->clkdm, clk); +		if (ret) { +			WARN(1, "clock: %s: could not enable clockdomain %s: " +			     "%d\n", clk->name, clk->clkdm->name, ret); +			goto oce_err2;  		}  	} -	return ret; -err: +	ret = clk->ops->enable(clk); +	if (ret) { +		WARN(1, "clock: %s: could not enable: %d\n", clk->name, ret); +		goto oce_err3; +	} + +	return 0; + +oce_err3:  	if (clk->clkdm)  		omap2_clkdm_clk_disable(clk->clkdm, clk); +oce_err2: +	if (clk->parent) +		omap2_clk_disable(clk->parent); +oce_err1:  	clk->usecount--; +  	return ret;  } @@ -325,9 +371,9 @@ const struct clkops clkops_omap3_noncore_dpll_ops = {  #endif -/*------------------------------------------------------------------------- - * Omap2 clock reset and init functions - *-------------------------------------------------------------------------*/ +/* + * OMAP2+ clock reset and init functions + */  #ifdef CONFIG_OMAP_RESET_CLOCKS  void omap2_clk_disable_unused(struct clk *clk) @@ -344,8 +390,9 @@ void omap2_clk_disable_unused(struct clk *clk)  	if (cpu_is_omap34xx()) {  		omap2_clk_enable(clk);  		omap2_clk_disable(clk); -	} else -		_omap2_clk_disable(clk); +	} else { +		clk->ops->disable(clk); +	}  	if (clk->clkdm != NULL)  		pwrdm_clkdm_state_switch(clk->clkdm);  }  |