|  | @@ -1654,3 +1654,169 @@ static int _deassert_hardreset(struct omap_hwmod *oh, const char *name)
 | 
	
		
			
				|  |  |  	int ret = -EINVAL;
 | 
	
		
			
				|  |  |  	int hwsup = 0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +	if (!oh)
 | 
	
		
			
				|  |  | +		return -EINVAL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (!soc_ops.deassert_hardreset)
 | 
	
		
			
				|  |  | +		return -ENOSYS;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	ret = _lookup_hardreset(oh, name, &ohri);
 | 
	
		
			
				|  |  | +	if (IS_ERR_VALUE(ret))
 | 
	
		
			
				|  |  | +		return ret;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (oh->clkdm) {
 | 
	
		
			
				|  |  | +		/*
 | 
	
		
			
				|  |  | +		 * A clockdomain must be in SW_SUP otherwise reset
 | 
	
		
			
				|  |  | +		 * might not be completed. The clockdomain can be set
 | 
	
		
			
				|  |  | +		 * in HW_AUTO only when the module become ready.
 | 
	
		
			
				|  |  | +		 */
 | 
	
		
			
				|  |  | +		hwsup = clkdm_in_hwsup(oh->clkdm);
 | 
	
		
			
				|  |  | +		ret = clkdm_hwmod_enable(oh->clkdm, oh);
 | 
	
		
			
				|  |  | +		if (ret) {
 | 
	
		
			
				|  |  | +			WARN(1, "omap_hwmod: %s: could not enable clockdomain %s: %d\n",
 | 
	
		
			
				|  |  | +			     oh->name, oh->clkdm->name, ret);
 | 
	
		
			
				|  |  | +			return ret;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	_enable_clocks(oh);
 | 
	
		
			
				|  |  | +	if (soc_ops.enable_module)
 | 
	
		
			
				|  |  | +		soc_ops.enable_module(oh);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	ret = soc_ops.deassert_hardreset(oh, &ohri);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (soc_ops.disable_module)
 | 
	
		
			
				|  |  | +		soc_ops.disable_module(oh);
 | 
	
		
			
				|  |  | +	_disable_clocks(oh);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (ret == -EBUSY)
 | 
	
		
			
				|  |  | +		pr_warning("omap_hwmod: %s: failed to hardreset\n", oh->name);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (!ret) {
 | 
	
		
			
				|  |  | +		/*
 | 
	
		
			
				|  |  | +		 * Set the clockdomain to HW_AUTO, assuming that the
 | 
	
		
			
				|  |  | +		 * previous state was HW_AUTO.
 | 
	
		
			
				|  |  | +		 */
 | 
	
		
			
				|  |  | +		if (oh->clkdm && hwsup)
 | 
	
		
			
				|  |  | +			clkdm_allow_idle(oh->clkdm);
 | 
	
		
			
				|  |  | +	} else {
 | 
	
		
			
				|  |  | +		if (oh->clkdm)
 | 
	
		
			
				|  |  | +			clkdm_hwmod_disable(oh->clkdm, oh);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return ret;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * _read_hardreset - read the HW reset line state of submodules
 | 
	
		
			
				|  |  | + * contained in the hwmod module
 | 
	
		
			
				|  |  | + * @oh: struct omap_hwmod *
 | 
	
		
			
				|  |  | + * @name: name of the reset line to look up and read
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * Return the state of the reset line.  Returns -EINVAL if @oh is
 | 
	
		
			
				|  |  | + * null, -ENOSYS if we have no way of reading the hardreset line
 | 
	
		
			
				|  |  | + * status on the currently-booted SoC, or passes along the return
 | 
	
		
			
				|  |  | + * value from _lookup_hardreset() or the SoC's is_hardreset_asserted
 | 
	
		
			
				|  |  | + * code.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +static int _read_hardreset(struct omap_hwmod *oh, const char *name)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	struct omap_hwmod_rst_info ohri;
 | 
	
		
			
				|  |  | +	int ret = -EINVAL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (!oh)
 | 
	
		
			
				|  |  | +		return -EINVAL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (!soc_ops.is_hardreset_asserted)
 | 
	
		
			
				|  |  | +		return -ENOSYS;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	ret = _lookup_hardreset(oh, name, &ohri);
 | 
	
		
			
				|  |  | +	if (ret < 0)
 | 
	
		
			
				|  |  | +		return ret;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return soc_ops.is_hardreset_asserted(oh, &ohri);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * _are_all_hardreset_lines_asserted - return true if the @oh is hard-reset
 | 
	
		
			
				|  |  | + * @oh: struct omap_hwmod *
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * If all hardreset lines associated with @oh are asserted, then return true.
 | 
	
		
			
				|  |  | + * Otherwise, if part of @oh is out hardreset or if no hardreset lines
 | 
	
		
			
				|  |  | + * associated with @oh are asserted, then return false.
 | 
	
		
			
				|  |  | + * This function is used to avoid executing some parts of the IP block
 | 
	
		
			
				|  |  | + * enable/disable sequence if its hardreset line is set.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +static bool _are_all_hardreset_lines_asserted(struct omap_hwmod *oh)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	int i, rst_cnt = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (oh->rst_lines_cnt == 0)
 | 
	
		
			
				|  |  | +		return false;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	for (i = 0; i < oh->rst_lines_cnt; i++)
 | 
	
		
			
				|  |  | +		if (_read_hardreset(oh, oh->rst_lines[i].name) > 0)
 | 
	
		
			
				|  |  | +			rst_cnt++;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (oh->rst_lines_cnt == rst_cnt)
 | 
	
		
			
				|  |  | +		return true;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return false;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * _are_any_hardreset_lines_asserted - return true if any part of @oh is
 | 
	
		
			
				|  |  | + * hard-reset
 | 
	
		
			
				|  |  | + * @oh: struct omap_hwmod *
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * If any hardreset lines associated with @oh are asserted, then
 | 
	
		
			
				|  |  | + * return true.  Otherwise, if no hardreset lines associated with @oh
 | 
	
		
			
				|  |  | + * are asserted, or if @oh has no hardreset lines, then return false.
 | 
	
		
			
				|  |  | + * This function is used to avoid executing some parts of the IP block
 | 
	
		
			
				|  |  | + * enable/disable sequence if any hardreset line is set.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +static bool _are_any_hardreset_lines_asserted(struct omap_hwmod *oh)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	int rst_cnt = 0;
 | 
	
		
			
				|  |  | +	int i;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	for (i = 0; i < oh->rst_lines_cnt && rst_cnt == 0; i++)
 | 
	
		
			
				|  |  | +		if (_read_hardreset(oh, oh->rst_lines[i].name) > 0)
 | 
	
		
			
				|  |  | +			rst_cnt++;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return (rst_cnt) ? true : false;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * _omap4_disable_module - enable CLKCTRL modulemode on OMAP4
 | 
	
		
			
				|  |  | + * @oh: struct omap_hwmod *
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * Disable the PRCM module mode related to the hwmod @oh.
 | 
	
		
			
				|  |  | + * Return EINVAL if the modulemode is not supported and 0 in case of success.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +static int _omap4_disable_module(struct omap_hwmod *oh)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	int v;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (!oh->clkdm || !oh->prcm.omap4.modulemode)
 | 
	
		
			
				|  |  | +		return -EINVAL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/*
 | 
	
		
			
				|  |  | +	 * Since integration code might still be doing something, only
 | 
	
		
			
				|  |  | +	 * disable if all lines are under hardreset.
 | 
	
		
			
				|  |  | +	 */
 | 
	
		
			
				|  |  | +	if (_are_any_hardreset_lines_asserted(oh))
 | 
	
		
			
				|  |  | +		return 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	omap4_cminst_module_disable(oh->clkdm->prcm_partition,
 | 
	
		
			
				|  |  | +				    oh->clkdm->cm_inst,
 | 
	
		
			
				|  |  | +				    oh->clkdm->clkdm_offs,
 | 
	
		
			
				|  |  | +				    oh->prcm.omap4.clkctrl_offs);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	v = _omap4_wait_target_disable(oh);
 | 
	
		
			
				|  |  | +	if (v)
 | 
	
		
			
				|  |  | +		pr_warn("omap_hwmod: %s: _wait_target_disable failed\n",
 | 
	
		
			
				|  |  | +			oh->name);
 | 
	
		
			
				|  |  | +
 |