static int sysc_enable_module()

in ti-sysc.c [1060:1177]


static int sysc_enable_module(struct device *dev)
{
	struct sysc *ddata;
	const struct sysc_regbits *regbits;
	u32 reg, idlemodes, best_mode;
	int error;

	ddata = dev_get_drvdata(dev);

	/*
	 * Some modules like DSS reset automatically on idle. Enable optional
	 * reset clocks and wait for OCP softreset to complete.
	 */
	if (ddata->cfg.quirks & SYSC_QUIRK_OPT_CLKS_IN_RESET) {
		error = sysc_enable_opt_clocks(ddata);
		if (error) {
			dev_err(ddata->dev,
				"Optional clocks failed for enable: %i\n",
				error);
			return error;
		}
	}
	/*
	 * Some modules like i2c and hdq1w have unusable reset status unless
	 * the module reset quirk is enabled. Skip status check on enable.
	 */
	if (!(ddata->cfg.quirks & SYSC_MODULE_QUIRK_ENA_RESETDONE)) {
		error = sysc_wait_softreset(ddata);
		if (error)
			dev_warn(ddata->dev, "OCP softreset timed out\n");
	}
	if (ddata->cfg.quirks & SYSC_QUIRK_OPT_CLKS_IN_RESET)
		sysc_disable_opt_clocks(ddata);

	/*
	 * Some subsystem private interconnects, like DSS top level module,
	 * need only the automatic OCP softreset handling with no sysconfig
	 * register bits to configure.
	 */
	if (ddata->offsets[SYSC_SYSCONFIG] == -ENODEV)
		return 0;

	regbits = ddata->cap->regbits;
	reg = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]);

	/*
	 * Set CLOCKACTIVITY, we only use it for ick. And we only configure it
	 * based on the SYSC_QUIRK_USE_CLOCKACT flag, not based on the hardware
	 * capabilities. See the old HWMOD_SET_DEFAULT_CLOCKACT flag.
	 */
	if (regbits->clkact_shift >= 0 &&
	    (ddata->cfg.quirks & SYSC_QUIRK_USE_CLOCKACT))
		reg |= SYSC_CLOCACT_ICK << regbits->clkact_shift;

	/* Set SIDLE mode */
	idlemodes = ddata->cfg.sidlemodes;
	if (!idlemodes || regbits->sidle_shift < 0)
		goto set_midle;

	if (ddata->cfg.quirks & (SYSC_QUIRK_SWSUP_SIDLE |
				 SYSC_QUIRK_SWSUP_SIDLE_ACT)) {
		best_mode = SYSC_IDLE_NO;
	} else {
		best_mode = fls(ddata->cfg.sidlemodes) - 1;
		if (best_mode > SYSC_IDLE_MASK) {
			dev_err(dev, "%s: invalid sidlemode\n", __func__);
			return -EINVAL;
		}

		/* Set WAKEUP */
		if (regbits->enwkup_shift >= 0 &&
		    ddata->cfg.sysc_val & BIT(regbits->enwkup_shift))
			reg |= BIT(regbits->enwkup_shift);
	}

	reg &= ~(SYSC_IDLE_MASK << regbits->sidle_shift);
	reg |= best_mode << regbits->sidle_shift;
	sysc_write_sysconfig(ddata, reg);

set_midle:
	/* Set MIDLE mode */
	idlemodes = ddata->cfg.midlemodes;
	if (!idlemodes || regbits->midle_shift < 0)
		goto set_autoidle;

	best_mode = fls(ddata->cfg.midlemodes) - 1;
	if (best_mode > SYSC_IDLE_MASK) {
		dev_err(dev, "%s: invalid midlemode\n", __func__);
		error = -EINVAL;
		goto save_context;
	}

	if (ddata->cfg.quirks & SYSC_QUIRK_SWSUP_MSTANDBY)
		best_mode = SYSC_IDLE_NO;

	reg &= ~(SYSC_IDLE_MASK << regbits->midle_shift);
	reg |= best_mode << regbits->midle_shift;
	sysc_write_sysconfig(ddata, reg);

set_autoidle:
	/* Autoidle bit must enabled separately if available */
	if (regbits->autoidle_shift >= 0 &&
	    ddata->cfg.sysc_val & BIT(regbits->autoidle_shift)) {
		reg |= 1 << regbits->autoidle_shift;
		sysc_write_sysconfig(ddata, reg);
	}

	error = 0;

save_context:
	/* Save context and flush posted write */
	ddata->sysconfig = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]);

	if (ddata->module_enable_quirk)
		ddata->module_enable_quirk(ddata);

	return error;
}