|  | @@ -408,3 +408,150 @@ static int _set_softreset(struct omap_hwmod *oh, u32 *v)
 | 
	
		
			
				|  |  |  	if (!oh->class->sysc ||
 | 
	
		
			
				|  |  |  	    !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET))
 | 
	
		
			
				|  |  |  		return -EINVAL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (!oh->class->sysc->sysc_fields) {
 | 
	
		
			
				|  |  | +		WARN(1, "omap_hwmod: %s: offset struct for sysconfig not provided in class\n", oh->name);
 | 
	
		
			
				|  |  | +		return -EINVAL;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	softrst_mask = (0x1 << oh->class->sysc->sysc_fields->srst_shift);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	*v |= softrst_mask;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * _wait_softreset_complete - wait for an OCP softreset to complete
 | 
	
		
			
				|  |  | + * @oh: struct omap_hwmod * to wait on
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * Wait until the IP block represented by @oh reports that its OCP
 | 
	
		
			
				|  |  | + * softreset is complete.  This can be triggered by software (see
 | 
	
		
			
				|  |  | + * _ocp_softreset()) or by hardware upon returning from off-mode (one
 | 
	
		
			
				|  |  | + * example is HSMMC).  Waits for up to MAX_MODULE_SOFTRESET_WAIT
 | 
	
		
			
				|  |  | + * microseconds.  Returns the number of microseconds waited.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +static int _wait_softreset_complete(struct omap_hwmod *oh)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	struct omap_hwmod_class_sysconfig *sysc;
 | 
	
		
			
				|  |  | +	u32 softrst_mask;
 | 
	
		
			
				|  |  | +	int c = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	sysc = oh->class->sysc;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (sysc->sysc_flags & SYSS_HAS_RESET_STATUS)
 | 
	
		
			
				|  |  | +		omap_test_timeout((omap_hwmod_read(oh, sysc->syss_offs)
 | 
	
		
			
				|  |  | +				   & SYSS_RESETDONE_MASK),
 | 
	
		
			
				|  |  | +				  MAX_MODULE_SOFTRESET_WAIT, c);
 | 
	
		
			
				|  |  | +	else if (sysc->sysc_flags & SYSC_HAS_RESET_STATUS) {
 | 
	
		
			
				|  |  | +		softrst_mask = (0x1 << sysc->sysc_fields->srst_shift);
 | 
	
		
			
				|  |  | +		omap_test_timeout(!(omap_hwmod_read(oh, sysc->sysc_offs)
 | 
	
		
			
				|  |  | +				    & softrst_mask),
 | 
	
		
			
				|  |  | +				  MAX_MODULE_SOFTRESET_WAIT, c);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return c;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * _set_dmadisable: set OCP_SYSCONFIG.DMADISABLE bit in @v
 | 
	
		
			
				|  |  | + * @oh: struct omap_hwmod *
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * The DMADISABLE bit is a semi-automatic bit present in sysconfig register
 | 
	
		
			
				|  |  | + * of some modules. When the DMA must perform read/write accesses, the
 | 
	
		
			
				|  |  | + * DMADISABLE bit is cleared by the hardware. But when the DMA must stop
 | 
	
		
			
				|  |  | + * for power management, software must set the DMADISABLE bit back to 1.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * Set the DMADISABLE bit in @v for hwmod @oh.  Returns -EINVAL upon
 | 
	
		
			
				|  |  | + * error or 0 upon success.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +static int _set_dmadisable(struct omap_hwmod *oh)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	u32 v;
 | 
	
		
			
				|  |  | +	u32 dmadisable_mask;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (!oh->class->sysc ||
 | 
	
		
			
				|  |  | +	    !(oh->class->sysc->sysc_flags & SYSC_HAS_DMADISABLE))
 | 
	
		
			
				|  |  | +		return -EINVAL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (!oh->class->sysc->sysc_fields) {
 | 
	
		
			
				|  |  | +		WARN(1, "omap_hwmod: %s: offset struct for sysconfig not provided in class\n", oh->name);
 | 
	
		
			
				|  |  | +		return -EINVAL;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* clocks must be on for this operation */
 | 
	
		
			
				|  |  | +	if (oh->_state != _HWMOD_STATE_ENABLED) {
 | 
	
		
			
				|  |  | +		pr_warn("omap_hwmod: %s: dma can be disabled only from enabled state\n", oh->name);
 | 
	
		
			
				|  |  | +		return -EINVAL;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	pr_debug("omap_hwmod: %s: setting DMADISABLE\n", oh->name);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	v = oh->_sysc_cache;
 | 
	
		
			
				|  |  | +	dmadisable_mask =
 | 
	
		
			
				|  |  | +		(0x1 << oh->class->sysc->sysc_fields->dmadisable_shift);
 | 
	
		
			
				|  |  | +	v |= dmadisable_mask;
 | 
	
		
			
				|  |  | +	_write_sysconfig(v, oh);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * _set_module_autoidle: set the OCP_SYSCONFIG AUTOIDLE field in @v
 | 
	
		
			
				|  |  | + * @oh: struct omap_hwmod *
 | 
	
		
			
				|  |  | + * @autoidle: desired AUTOIDLE bitfield value (0 or 1)
 | 
	
		
			
				|  |  | + * @v: pointer to register contents to modify
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * Update the module autoidle bit in @v to be @autoidle for the @oh
 | 
	
		
			
				|  |  | + * hwmod.  The autoidle bit controls whether the module can gate
 | 
	
		
			
				|  |  | + * internal clocks automatically when it isn't doing anything; the
 | 
	
		
			
				|  |  | + * exact function of this bit varies on a per-module basis.  This
 | 
	
		
			
				|  |  | + * function does not write to the hardware.  Returns -EINVAL upon
 | 
	
		
			
				|  |  | + * error or 0 upon success.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +static int _set_module_autoidle(struct omap_hwmod *oh, u8 autoidle,
 | 
	
		
			
				|  |  | +				u32 *v)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	u32 autoidle_mask;
 | 
	
		
			
				|  |  | +	u8 autoidle_shift;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (!oh->class->sysc ||
 | 
	
		
			
				|  |  | +	    !(oh->class->sysc->sysc_flags & SYSC_HAS_AUTOIDLE))
 | 
	
		
			
				|  |  | +		return -EINVAL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (!oh->class->sysc->sysc_fields) {
 | 
	
		
			
				|  |  | +		WARN(1, "omap_hwmod: %s: offset struct for sysconfig not provided in class\n", oh->name);
 | 
	
		
			
				|  |  | +		return -EINVAL;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	autoidle_shift = oh->class->sysc->sysc_fields->autoidle_shift;
 | 
	
		
			
				|  |  | +	autoidle_mask = (0x1 << autoidle_shift);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	*v &= ~autoidle_mask;
 | 
	
		
			
				|  |  | +	*v |= autoidle << autoidle_shift;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * _set_idle_ioring_wakeup - enable/disable IO pad wakeup on hwmod idle for mux
 | 
	
		
			
				|  |  | + * @oh: struct omap_hwmod *
 | 
	
		
			
				|  |  | + * @set_wake: bool value indicating to set (true) or clear (false) wakeup enable
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * Set or clear the I/O pad wakeup flag in the mux entries for the
 | 
	
		
			
				|  |  | + * hwmod @oh.  This function changes the @oh->mux->pads_dynamic array
 | 
	
		
			
				|  |  | + * in memory.  If the hwmod is currently idled, and the new idle
 | 
	
		
			
				|  |  | + * values don't match the previous ones, this function will also
 | 
	
		
			
				|  |  | + * update the SCM PADCTRL registers.  Otherwise, if the hwmod is not
 | 
	
		
			
				|  |  | + * currently idled, this function won't touch the hardware: the new
 | 
	
		
			
				|  |  | + * mux settings are written to the SCM PADCTRL registers when the
 | 
	
		
			
				|  |  | + * hwmod is idled.  No return value.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +static void _set_idle_ioring_wakeup(struct omap_hwmod *oh, bool set_wake)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	struct omap_device_pad *pad;
 | 
	
		
			
				|  |  | +	bool change = false;
 | 
	
		
			
				|  |  | +	u16 prev_idle;
 | 
	
		
			
				|  |  | +	int j;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (!oh->mux || !oh->mux->enabled)
 |