|  | @@ -240,3 +240,142 @@ int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst,
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /**
 | 
	
		
			
				|  |  | + * omap2xxx_cm_wait_module_ready - wait for a module to leave idle or standby
 | 
	
		
			
				|  |  | + * @prcm_mod: PRCM module offset
 | 
	
		
			
				|  |  | + * @idlest_id: CM_IDLESTx register ID (i.e., x = 1, 2, 3)
 | 
	
		
			
				|  |  | + * @idlest_shift: shift of the bit in the CM_IDLEST* register to check
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * Wait for the PRCM to indicate that the module identified by
 | 
	
		
			
				|  |  | + * (@prcm_mod, @idlest_id, @idlest_shift) is clocked.  Return 0 upon
 | 
	
		
			
				|  |  | + * success or -EBUSY if the module doesn't enable in time.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +int omap2xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	int ena = 0, i = 0;
 | 
	
		
			
				|  |  | +	u8 cm_idlest_reg;
 | 
	
		
			
				|  |  | +	u32 mask;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (!idlest_id || (idlest_id > ARRAY_SIZE(omap2xxx_cm_idlest_offs)))
 | 
	
		
			
				|  |  | +		return -EINVAL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	cm_idlest_reg = omap2xxx_cm_idlest_offs[idlest_id - 1];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	mask = 1 << idlest_shift;
 | 
	
		
			
				|  |  | +	ena = mask;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	omap_test_timeout(((omap2_cm_read_mod_reg(prcm_mod, cm_idlest_reg) &
 | 
	
		
			
				|  |  | +			    mask) == ena), MAX_MODULE_READY_TIME, i);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* Clockdomain low-level functions */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void omap2xxx_clkdm_allow_idle(struct clockdomain *clkdm)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	if (atomic_read(&clkdm->usecount) > 0)
 | 
	
		
			
				|  |  | +		_clkdm_add_autodeps(clkdm);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
 | 
	
		
			
				|  |  | +				       clkdm->clktrctrl_mask);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void omap2xxx_clkdm_deny_idle(struct clockdomain *clkdm)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
 | 
	
		
			
				|  |  | +					clkdm->clktrctrl_mask);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (atomic_read(&clkdm->usecount) > 0)
 | 
	
		
			
				|  |  | +		_clkdm_del_autodeps(clkdm);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int omap2xxx_clkdm_clk_enable(struct clockdomain *clkdm)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	bool hwsup = false;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (!clkdm->clktrctrl_mask)
 | 
	
		
			
				|  |  | +		return 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
 | 
	
		
			
				|  |  | +					      clkdm->clktrctrl_mask);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (hwsup) {
 | 
	
		
			
				|  |  | +		/* Disable HW transitions when we are changing deps */
 | 
	
		
			
				|  |  | +		omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
 | 
	
		
			
				|  |  | +						clkdm->clktrctrl_mask);
 | 
	
		
			
				|  |  | +		_clkdm_add_autodeps(clkdm);
 | 
	
		
			
				|  |  | +		omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
 | 
	
		
			
				|  |  | +					       clkdm->clktrctrl_mask);
 | 
	
		
			
				|  |  | +	} else {
 | 
	
		
			
				|  |  | +		if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
 | 
	
		
			
				|  |  | +			omap2xxx_clkdm_wakeup(clkdm);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int omap2xxx_clkdm_clk_disable(struct clockdomain *clkdm)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	bool hwsup = false;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (!clkdm->clktrctrl_mask)
 | 
	
		
			
				|  |  | +		return 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
 | 
	
		
			
				|  |  | +					      clkdm->clktrctrl_mask);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (hwsup) {
 | 
	
		
			
				|  |  | +		/* Disable HW transitions when we are changing deps */
 | 
	
		
			
				|  |  | +		omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
 | 
	
		
			
				|  |  | +						clkdm->clktrctrl_mask);
 | 
	
		
			
				|  |  | +		_clkdm_del_autodeps(clkdm);
 | 
	
		
			
				|  |  | +		omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
 | 
	
		
			
				|  |  | +					       clkdm->clktrctrl_mask);
 | 
	
		
			
				|  |  | +	} else {
 | 
	
		
			
				|  |  | +		if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP)
 | 
	
		
			
				|  |  | +			omap2xxx_clkdm_sleep(clkdm);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +struct clkdm_ops omap2_clkdm_operations = {
 | 
	
		
			
				|  |  | +	.clkdm_add_wkdep	= omap2_clkdm_add_wkdep,
 | 
	
		
			
				|  |  | +	.clkdm_del_wkdep	= omap2_clkdm_del_wkdep,
 | 
	
		
			
				|  |  | +	.clkdm_read_wkdep	= omap2_clkdm_read_wkdep,
 | 
	
		
			
				|  |  | +	.clkdm_clear_all_wkdeps	= omap2_clkdm_clear_all_wkdeps,
 | 
	
		
			
				|  |  | +	.clkdm_sleep		= omap2xxx_clkdm_sleep,
 | 
	
		
			
				|  |  | +	.clkdm_wakeup		= omap2xxx_clkdm_wakeup,
 | 
	
		
			
				|  |  | +	.clkdm_allow_idle	= omap2xxx_clkdm_allow_idle,
 | 
	
		
			
				|  |  | +	.clkdm_deny_idle	= omap2xxx_clkdm_deny_idle,
 | 
	
		
			
				|  |  | +	.clkdm_clk_enable	= omap2xxx_clkdm_clk_enable,
 | 
	
		
			
				|  |  | +	.clkdm_clk_disable	= omap2xxx_clkdm_clk_disable,
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static struct cm_ll_data omap2xxx_cm_ll_data = {
 | 
	
		
			
				|  |  | +	.split_idlest_reg	= &omap2xxx_cm_split_idlest_reg,
 | 
	
		
			
				|  |  | +	.wait_module_ready	= &omap2xxx_cm_wait_module_ready,
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +int __init omap2xxx_cm_init(void)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	if (!cpu_is_omap24xx())
 | 
	
		
			
				|  |  | +		return 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return cm_register(&omap2xxx_cm_ll_data);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void __exit omap2xxx_cm_exit(void)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	if (!cpu_is_omap24xx())
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* Should never happen */
 | 
	
		
			
				|  |  | +	WARN(cm_unregister(&omap2xxx_cm_ll_data),
 | 
	
		
			
				|  |  | +	     "%s: cm_ll_data function pointer mismatch\n", __func__);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +__exitcall(omap2xxx_cm_exit);
 |