Skip to content

Commit dfa8f2c

Browse files
committed
soundwire: intel: exit clock stop mode on system suspend
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: #2606 Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
1 parent 01af2d1 commit dfa8f2c

1 file changed

Lines changed: 65 additions & 0 deletions

File tree

drivers/soundwire/intel.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1527,6 +1527,70 @@ int intel_link_process_wakeen_event(struct auxiliary_device *auxdev)
15271527
* PM calls
15281528
*/
15291529

1530+
static int intel_resume_child_device(struct device *dev, void *data)
1531+
{
1532+
int ret;
1533+
struct sdw_slave *slave = dev_to_sdw_dev(dev);
1534+
1535+
if (!slave->probed) {
1536+
dev_dbg(dev, "%s: skipping device, no probed driver\n", __func__);
1537+
return 0;
1538+
}
1539+
if (!slave->dev_num_sticky) {
1540+
dev_dbg(dev, "%s: skipping device, never detected on bus\n", __func__);
1541+
return 0;
1542+
}
1543+
1544+
ret = pm_request_resume(dev);
1545+
if (ret < 0)
1546+
dev_err(dev, "%s: pm_request_resume failed: %d\n", __func__, ret);
1547+
1548+
return ret;
1549+
}
1550+
1551+
static int __maybe_unused intel_pm_prepare(struct device *dev)
1552+
{
1553+
struct sdw_cdns *cdns = dev_get_drvdata(dev);
1554+
struct sdw_intel *sdw = cdns_to_intel(cdns);
1555+
struct sdw_bus *bus = &cdns->bus;
1556+
u32 clock_stop_quirks;
1557+
int ret = 0;
1558+
1559+
if (bus->prop.hw_disabled || !sdw->startup_done) {
1560+
dev_dbg(dev, "SoundWire master %d is disabled or not-started, ignoring\n",
1561+
bus->link_id);
1562+
return 0;
1563+
}
1564+
1565+
clock_stop_quirks = sdw->link_res->clock_stop_quirks;
1566+
1567+
if ((clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET) ||
1568+
!clock_stop_quirks) {
1569+
/*
1570+
* Try to resume the entire bus (parent + child devices) to exit
1571+
* the clock stop mode. If this fails, we keep going since we don't want
1572+
* to prevent system suspend from happening and errors should be recoverable
1573+
* on resume.
1574+
*/
1575+
ret = device_for_each_child(bus->dev, NULL, intel_resume_child_device);
1576+
1577+
if (ret < 0)
1578+
dev_err(dev, "%s: intel_resume_child_device failed: %d\n", __func__, ret);
1579+
1580+
/*
1581+
* in the case where a link was started but does not have anything connected,
1582+
* we still need to resume to keep link power up/down sequences balanced.
1583+
* This is a no-op if a child device was present, since resuming the child
1584+
* device would also resume the parent
1585+
*/
1586+
ret = pm_request_resume(dev);
1587+
if (ret < 0)
1588+
dev_err(dev, "%s: pm_request_resume failed: %d\n", __func__, ret);
1589+
}
1590+
1591+
return 0;
1592+
}
1593+
15301594
static int __maybe_unused intel_suspend(struct device *dev)
15311595
{
15321596
struct sdw_cdns *cdns = dev_get_drvdata(dev);
@@ -1923,6 +1987,7 @@ static int __maybe_unused intel_resume_runtime(struct device *dev)
19231987
}
19241988

19251989
static const struct dev_pm_ops intel_pm = {
1990+
.prepare = intel_pm_prepare,
19261991
SET_SYSTEM_SLEEP_PM_OPS(intel_suspend, intel_resume)
19271992
SET_RUNTIME_PM_OPS(intel_suspend_runtime, intel_resume_runtime, NULL)
19281993
};

0 commit comments

Comments
 (0)