Skip to content

Commit

Permalink
soundwire: intel: exit clock stop mode on system suspend
Browse files Browse the repository at this point in the history
Intel validation reported an issue where the HW_RST self-clearing bit
is not cleared in hardware, which as a ripple effect creates issues
with the clock stop mode.

This happens is a specific sequence where the Intel manager is
pm_runtime suspended with the clock-stop mode enabled. During the
system suspend, we currently do nothing, which can lead to potential
issues on system resume and the following pm_runtime suspend,
depending on the hardware state.

This patch suggests a full resume (parent+child devices) if the
clock-stop mode is used. This may require extra time but will make the
suspend/resume flows completely symmetric. This also removes a race
condition where we could not access SHIM registers if the parent was
suspended as well. Resuming the link also resumes the parent by
construction.

BugLink: thesofproject#2606
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
  • Loading branch information
plbossart committed Jul 13, 2021
1 parent e12a743 commit 47480f5
Showing 1 changed file with 45 additions and 0 deletions.
45 changes: 45 additions & 0 deletions drivers/soundwire/intel.c
Original file line number Diff line number Diff line change
Expand Up @@ -1517,6 +1517,50 @@ int intel_link_process_wakeen_event(struct auxiliary_device *auxdev)
* PM calls
*/

static int intel_resume_child_device(struct device *dev, void *data)
{
int ret;
struct sdw_slave *slave = dev_to_sdw_dev(dev);

if (!slave->probed) {
dev_dbg(dev, "%s: skipping device, no probed driver\n", __func__);
return 0;
}
if (!slave->dev_num_sticky) {
dev_dbg(dev, "%s: skipping device, never detected on bus\n", __func__);
return 0;
}

ret = pm_request_resume(dev);
if (ret < 0)
dev_err(dev, "%s: pm_request_resume failed: %d\n", __func__, ret);

return ret;
}

static int __maybe_unused intel_pm_prepare(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;
int ret = 0;

if (bus->prop.hw_disabled) {
dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n",
bus->link_id);
return 0;
}

clock_stop_quirks = sdw->link_res->clock_stop_quirks;

if ((clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET) ||
!clock_stop_quirks)
ret = device_for_each_child(bus->dev, NULL, intel_resume_child_device);

return ret;
}

static int __maybe_unused intel_suspend(struct device *dev)
{
struct sdw_cdns *cdns = dev_get_drvdata(dev);
Expand Down Expand Up @@ -1913,6 +1957,7 @@ static int __maybe_unused intel_resume_runtime(struct device *dev)
}

static const struct dev_pm_ops intel_pm = {
.prepare = intel_pm_prepare,
SET_SYSTEM_SLEEP_PM_OPS(intel_suspend, intel_resume)
SET_RUNTIME_PM_OPS(intel_suspend_runtime, intel_resume_runtime, NULL)
};
Expand Down

0 comments on commit 47480f5

Please sign in to comment.