static int _enable()

in mach-omap2/omap_hwmod.c [1866:1953]


static int _enable(struct omap_hwmod *oh)
{
	int r;

	pr_debug("omap_hwmod: %s: enabling\n", oh->name);

	/*
	 * hwmods with HWMOD_INIT_NO_IDLE flag set are left in enabled
	 * state at init.
	 */
	if (oh->_int_flags & _HWMOD_SKIP_ENABLE) {
		oh->_int_flags &= ~_HWMOD_SKIP_ENABLE;
		return 0;
	}

	if (oh->_state != _HWMOD_STATE_INITIALIZED &&
	    oh->_state != _HWMOD_STATE_IDLE &&
	    oh->_state != _HWMOD_STATE_DISABLED) {
		WARN(1, "omap_hwmod: %s: enabled state can only be entered from initialized, idle, or disabled state\n",
			oh->name);
		return -EINVAL;
	}

	/*
	 * If an IP block contains HW reset lines and all of them are
	 * asserted, we let integration code associated with that
	 * block handle the enable.  We've received very little
	 * information on what those driver authors need, and until
	 * detailed information is provided and the driver code is
	 * posted to the public lists, this is probably the best we
	 * can do.
	 */
	if (_are_all_hardreset_lines_asserted(oh))
		return 0;

	_add_initiator_dep(oh, mpu_oh);

	if (oh->clkdm) {
		/*
		 * A clockdomain must be in SW_SUP before enabling
		 * completely the module. The clockdomain can be set
		 * in HW_AUTO only when the module become ready.
		 */
		clkdm_deny_idle(oh->clkdm);
		r = clkdm_hwmod_enable(oh->clkdm, oh);
		if (r) {
			WARN(1, "omap_hwmod: %s: could not enable clockdomain %s: %d\n",
			     oh->name, oh->clkdm->name, r);
			return r;
		}
	}

	_enable_clocks(oh);
	if (soc_ops.enable_module)
		soc_ops.enable_module(oh);
	if (oh->flags & HWMOD_BLOCK_WFI)
		cpu_idle_poll_ctrl(true);

	if (soc_ops.update_context_lost)
		soc_ops.update_context_lost(oh);

	r = (soc_ops.wait_target_ready) ? soc_ops.wait_target_ready(oh) :
		-EINVAL;
	if (oh->clkdm && !(oh->flags & HWMOD_CLKDM_NOAUTO))
		clkdm_allow_idle(oh->clkdm);

	if (!r) {
		oh->_state = _HWMOD_STATE_ENABLED;

		/* Access the sysconfig only if the target is ready */
		if (oh->class->sysc) {
			if (!(oh->_int_flags & _HWMOD_SYSCONFIG_LOADED))
				_update_sysc_cache(oh);
			_enable_sysc(oh);
		}
	} else {
		if (soc_ops.disable_module)
			soc_ops.disable_module(oh);
		_disable_clocks(oh);
		pr_err("omap_hwmod: %s: _wait_target_ready failed: %d\n",
		       oh->name, r);

		if (oh->clkdm)
			clkdm_hwmod_disable(oh->clkdm, oh);
	}

	return r;
}