| 
					
				 | 
			
			
				@@ -221,3 +221,190 @@ static unsigned short free_ls, max_ls, ls_supp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static bool inited; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /* Private functions */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * _fetch_next_ocp_if - return the next OCP interface in a list 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @p: ptr to a ptr to the list_head inside the ocp_if to return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @i: pointer to the index of the element pointed to by @p in the list 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Return a pointer to the struct omap_hwmod_ocp_if record 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * containing the struct list_head pointed to by @p, and increment 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @p such that a future call to this routine will return the next 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * record. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static struct omap_hwmod_ocp_if *_fetch_next_ocp_if(struct list_head **p, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						    int *i) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	struct omap_hwmod_ocp_if *oi; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	oi = list_entry(*p, struct omap_hwmod_link, node)->ocp_if; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	*p = (*p)->next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	*i = *i + 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return oi; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * _update_sysc_cache - return the module OCP_SYSCONFIG register, keep copy 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @oh: struct omap_hwmod * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Load the current value of the hwmod OCP_SYSCONFIG register into the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * struct omap_hwmod for later use.  Returns -EINVAL if the hwmod has no 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * OCP_SYSCONFIG register or 0 upon success. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static int _update_sysc_cache(struct omap_hwmod *oh) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (!oh->class->sysc) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		WARN(1, "omap_hwmod: %s: cannot read OCP_SYSCONFIG: not defined on hwmod's class\n", oh->name); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return -EINVAL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	/* XXX ensure module interface clock is up */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	oh->_sysc_cache = omap_hwmod_read(oh, oh->class->sysc->sysc_offs); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (!(oh->class->sysc->sysc_flags & SYSC_NO_CACHE)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		oh->_int_flags |= _HWMOD_SYSCONFIG_LOADED; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * _write_sysconfig - write a value to the module's OCP_SYSCONFIG register 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @v: OCP_SYSCONFIG value to write 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @oh: struct omap_hwmod * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Write @v into the module class' OCP_SYSCONFIG register, if it has 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * one.  No return value. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void _write_sysconfig(u32 v, struct omap_hwmod *oh) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (!oh->class->sysc) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		WARN(1, "omap_hwmod: %s: cannot write OCP_SYSCONFIG: not defined on hwmod's class\n", oh->name); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	/* XXX ensure module interface clock is up */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	/* Module might have lost context, always update cache and register */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	oh->_sysc_cache = v; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	omap_hwmod_write(v, oh, oh->class->sysc->sysc_offs); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * _set_master_standbymode: set the OCP_SYSCONFIG MIDLEMODE field in @v 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @oh: struct omap_hwmod * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @standbymode: MIDLEMODE field bits 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @v: pointer to register contents to modify 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Update the master standby mode bits in @v to be @standbymode for 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * the @oh hwmod.  Does not write to the hardware.  Returns -EINVAL 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * upon error or 0 upon success. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static int _set_master_standbymode(struct omap_hwmod *oh, u8 standbymode, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				   u32 *v) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	u32 mstandby_mask; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	u8 mstandby_shift; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (!oh->class->sysc || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	    !(oh->class->sysc->sysc_flags & SYSC_HAS_MIDLEMODE)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		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; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	mstandby_shift = oh->class->sysc->sysc_fields->midle_shift; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	mstandby_mask = (0x3 << mstandby_shift); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	*v &= ~mstandby_mask; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	*v |= __ffs(standbymode) << mstandby_shift; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * _set_slave_idlemode: set the OCP_SYSCONFIG SIDLEMODE field in @v 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @oh: struct omap_hwmod * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @idlemode: SIDLEMODE field bits 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @v: pointer to register contents to modify 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Update the slave idle mode bits in @v to be @idlemode for the @oh 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * hwmod.  Does not write to the hardware.  Returns -EINVAL upon error 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * or 0 upon success. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static int _set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode, u32 *v) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	u32 sidle_mask; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	u8 sidle_shift; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (!oh->class->sysc || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	    !(oh->class->sysc->sysc_flags & SYSC_HAS_SIDLEMODE)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		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; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	sidle_shift = oh->class->sysc->sysc_fields->sidle_shift; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	sidle_mask = (0x3 << sidle_shift); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	*v &= ~sidle_mask; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	*v |= __ffs(idlemode) << sidle_shift; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * _set_clockactivity: set OCP_SYSCONFIG.CLOCKACTIVITY bits in @v 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @oh: struct omap_hwmod * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @clockact: CLOCKACTIVITY field bits 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @v: pointer to register contents to modify 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Update the clockactivity mode bits in @v to be @clockact for the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @oh hwmod.  Used for additional powersaving on some modules.  Does 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * not write to the hardware.  Returns -EINVAL upon error or 0 upon 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * success. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static int _set_clockactivity(struct omap_hwmod *oh, u8 clockact, u32 *v) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	u32 clkact_mask; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	u8  clkact_shift; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (!oh->class->sysc || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	    !(oh->class->sysc->sysc_flags & SYSC_HAS_CLOCKACTIVITY)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		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; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	clkact_shift = oh->class->sysc->sysc_fields->clkact_shift; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	clkact_mask = (0x3 << clkact_shift); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	*v &= ~clkact_mask; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	*v |= clockact << clkact_shift; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * _set_softreset: set OCP_SYSCONFIG.CLOCKACTIVITY bits in @v 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @oh: struct omap_hwmod * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @v: pointer to register contents to modify 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Set the SOFTRESET bit in @v for hwmod @oh.  Returns -EINVAL upon 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * error or 0 upon success. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static int _set_softreset(struct omap_hwmod *oh, u32 *v) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	u32 softrst_mask; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (!oh->class->sysc || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	    !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return -EINVAL; 
			 |