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;
}