[PATCH] soundwire: intel: Move suspend tracking from trigger to pm suspend

From: Bard Liao

Date: Fri May 08 2026 - 06:20:46 EST


From: Peter Ujfalusi <peter.ujfalusi@xxxxxxxxxxxxxxx>

Mark all open DAI runtimes as suspended in the component .suspend
callback instead of relying on SNDRV_PCM_TRIGGER_SUSPEND, which is
not delivered during PAUSE or xrun states.

If during system suspend a dai is open it means that it is in either in
SUSPENDED, PAUSED or STOPPED (due to xrun) state and they will need to be
re-initialized during resume (which is done in .prepare callback).

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@xxxxxxxxxxxxxxx>
Signed-off-by: Bard Liao <yung-chuan.liao@xxxxxxxxxxxxxxx>
---
drivers/soundwire/intel.c | 31 ++++++--------------------
drivers/soundwire/intel_ace2x.c | 39 ++++++++++++++++++++++-----------
2 files changed, 33 insertions(+), 37 deletions(-)

diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index dcd7440e78fa..af65214836b4 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -906,19 +906,6 @@ static int intel_trigger(struct snd_pcm_substream *substream, int cmd, struct sn
}

switch (cmd) {
- case SNDRV_PCM_TRIGGER_SUSPEND:
-
- /*
- * The .prepare callback is used to deal with xruns and resume operations.
- * In the case of xruns, the DMAs and SHIM registers cannot be touched,
- * but for resume operations the DMAs and SHIM registers need to be initialized.
- * the .trigger callback is used to track the suspend case only.
- */
-
- dai_runtime->suspended = true;
-
- break;
-
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
dai_runtime->paused = true;
break;
@@ -955,10 +942,12 @@ static int intel_component_dais_suspend(struct snd_soc_component *component)
struct snd_soc_dai *dai;

/*
- * In the corner case where a SUSPEND happens during a PAUSE, the ALSA core
- * does not throw the TRIGGER_SUSPEND. This leaves the DAIs in an unbalanced state.
- * Since the component suspend is called last, we can trap this corner case
- * and force the DAIs to release their resources.
+ * Mark all open streams as suspended.
+ * Open streams at this point can be in SUSPENDED, PAUSED or STOPPED
+ * state and during prepare the DMAs and SHIM registers need to be
+ * initialized for them.
+ * The STOPPED state is a special corner case which can happen if audio
+ * experiences xrun at suspend time.
*/
for_each_component_dais(component, dai) {
struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
@@ -966,13 +955,7 @@ static int intel_component_dais_suspend(struct snd_soc_component *component)

dai_runtime = cdns->dai_runtime_array[dai->id];

- if (!dai_runtime)
- continue;
-
- if (dai_runtime->suspended)
- continue;
-
- if (dai_runtime->paused)
+ if (dai_runtime)
dai_runtime->suspended = true;
}

diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c
index 20422534baf1..0a97253fe0c2 100644
--- a/drivers/soundwire/intel_ace2x.c
+++ b/drivers/soundwire/intel_ace2x.c
@@ -894,19 +894,6 @@ static int intel_trigger(struct snd_pcm_substream *substream, int cmd, struct sn
}

switch (cmd) {
- case SNDRV_PCM_TRIGGER_SUSPEND:
-
- /*
- * The .prepare callback is used to deal with xruns and resume operations.
- * In the case of xruns, the DMAs and SHIM registers cannot be touched,
- * but for resume operations the DMAs and SHIM registers need to be initialized.
- * the .trigger callback is used to track the suspend case only.
- */
-
- dai_runtime->suspended = true;
-
- break;
-
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
dai_runtime->paused = true;
break;
@@ -930,8 +917,34 @@ static const struct snd_soc_dai_ops intel_pcm_dai_ops = {
.get_stream = intel_get_sdw_stream,
};

+static int intel_component_dais_suspend(struct snd_soc_component *component)
+{
+ struct snd_soc_dai *dai;
+
+ /*
+ * Mark all open streams as suspended.
+ * Open streams at this point can be in SUSPENDED, PAUSED or STOPPED
+ * state and during prepare the DMAs and SHIM registers need to be
+ * initialized for them.
+ * The STOPPED state is a special corner case which can happen if audio
+ * experiences xrun at suspend time.
+ */
+ for_each_component_dais(component, dai) {
+ struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
+ struct sdw_cdns_dai_runtime *dai_runtime;
+
+ dai_runtime = cdns->dai_runtime_array[dai->id];
+
+ if (dai_runtime)
+ dai_runtime->suspended = true;
+ }
+
+ return 0;
+}
+
static const struct snd_soc_component_driver dai_component = {
.name = "soundwire",
+ .suspend = intel_component_dais_suspend,
};

/*
--
2.43.0