in intel.c [1813:1993]
static int __maybe_unused intel_resume_runtime(struct device *dev)
{
struct sdw_cdns *cdns = dev_get_drvdata(dev);
struct sdw_intel *sdw = cdns_to_intel(cdns);
struct sdw_bus *bus = &cdns->bus;
u32 clock_stop_quirks;
bool clock_stop0;
int link_flags;
bool multi_link;
int status;
int ret;
if (bus->prop.hw_disabled || !sdw->startup_done) {
dev_dbg(dev, "SoundWire master %d is disabled or not-started, ignoring\n",
bus->link_id);
return 0;
}
link_flags = md_flags >> (bus->link_id * 8);
multi_link = !(link_flags & SDW_INTEL_MASTER_DISABLE_MULTI_LINK);
clock_stop_quirks = sdw->link_res->clock_stop_quirks;
if (clock_stop_quirks & SDW_INTEL_CLK_STOP_TEARDOWN) {
ret = intel_init(sdw);
if (ret) {
dev_err(dev, "%s failed: %d\n", __func__, ret);
return ret;
}
/*
* make sure all Slaves are tagged as UNATTACHED and provide
* reason for reinitialization
*/
sdw_clear_slave_status(bus, SDW_UNATTACH_REQUEST_MASTER_RESET);
ret = sdw_cdns_enable_interrupt(cdns, true);
if (ret < 0) {
dev_err(dev, "cannot enable interrupts during resume\n");
return ret;
}
/*
* follow recommended programming flows to avoid
* timeouts when gsync is enabled
*/
if (multi_link)
intel_shim_sync_arm(sdw);
ret = sdw_cdns_init(&sdw->cdns);
if (ret < 0) {
dev_err(dev, "unable to initialize Cadence IP during resume\n");
return ret;
}
ret = sdw_cdns_exit_reset(cdns);
if (ret < 0) {
dev_err(dev, "unable to exit bus reset sequence during resume\n");
return ret;
}
if (multi_link) {
ret = intel_shim_sync_go(sdw);
if (ret < 0) {
dev_err(dev, "sync go failed during resume\n");
return ret;
}
}
sdw_cdns_check_self_clearing_bits(cdns, "intel_resume_runtime TEARDOWN",
true, INTEL_MASTER_RESET_ITERATIONS);
} else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET) {
ret = intel_init(sdw);
if (ret) {
dev_err(dev, "%s failed: %d\n", __func__, ret);
return ret;
}
/*
* An exception condition occurs for the CLK_STOP_BUS_RESET
* case if one or more masters remain active. In this condition,
* all the masters are powered on for they are in the same power
* domain. Master can preserve its context for clock stop0, so
* there is no need to clear slave status and reset bus.
*/
clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns);
if (!clock_stop0) {
/*
* make sure all Slaves are tagged as UNATTACHED and
* provide reason for reinitialization
*/
status = SDW_UNATTACH_REQUEST_MASTER_RESET;
sdw_clear_slave_status(bus, status);
ret = sdw_cdns_enable_interrupt(cdns, true);
if (ret < 0) {
dev_err(dev, "cannot enable interrupts during resume\n");
return ret;
}
/*
* follow recommended programming flows to avoid
* timeouts when gsync is enabled
*/
if (multi_link)
intel_shim_sync_arm(sdw);
/*
* Re-initialize the IP since it was powered-off
*/
sdw_cdns_init(&sdw->cdns);
} else {
ret = sdw_cdns_enable_interrupt(cdns, true);
if (ret < 0) {
dev_err(dev, "cannot enable interrupts during resume\n");
return ret;
}
}
ret = sdw_cdns_clock_restart(cdns, !clock_stop0);
if (ret < 0) {
dev_err(dev, "unable to restart clock during resume\n");
return ret;
}
if (!clock_stop0) {
ret = sdw_cdns_exit_reset(cdns);
if (ret < 0) {
dev_err(dev, "unable to exit bus reset sequence during resume\n");
return ret;
}
if (multi_link) {
ret = intel_shim_sync_go(sdw);
if (ret < 0) {
dev_err(sdw->cdns.dev, "sync go failed during resume\n");
return ret;
}
}
}
sdw_cdns_check_self_clearing_bits(cdns, "intel_resume_runtime BUS_RESET",
true, INTEL_MASTER_RESET_ITERATIONS);
} else if (!clock_stop_quirks) {
clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns);
if (!clock_stop0)
dev_err(dev, "%s invalid configuration, clock was not stopped", __func__);
ret = intel_init(sdw);
if (ret) {
dev_err(dev, "%s failed: %d\n", __func__, ret);
return ret;
}
ret = sdw_cdns_enable_interrupt(cdns, true);
if (ret < 0) {
dev_err(dev, "cannot enable interrupts during resume\n");
return ret;
}
ret = sdw_cdns_clock_restart(cdns, false);
if (ret < 0) {
dev_err(dev, "unable to resume master during resume\n");
return ret;
}
sdw_cdns_check_self_clearing_bits(cdns, "intel_resume_runtime no_quirks",
true, INTEL_MASTER_RESET_ITERATIONS);
} else {
dev_err(dev, "%s clock_stop_quirks %x unsupported\n",
__func__, clock_stop_quirks);
ret = -EINVAL;
}
return ret;
}