summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sound/soc/sof/intel/hda-dai.c1
-rw-r--r--sound/soc/sof/ipc3-pcm.c1
-rw-r--r--sound/soc/sof/ipc4-pcm.c3
-rw-r--r--sound/soc/sof/pcm.c29
-rw-r--r--sound/soc/sof/sof-audio.h6
5 files changed, 31 insertions, 9 deletions
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index 9637f0f44b01..46a17afdd1ea 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -305,7 +305,6 @@ static int hda_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct
switch (cmd) {
case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_STOP:
ret = hda_link_dma_cleanup(substream, hext_stream, dai, codec_dai);
if (ret < 0) {
dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__);
diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c
index b29d93e0d216..b7f1eb21ca26 100644
--- a/sound/soc/sof/ipc3-pcm.c
+++ b/sound/soc/sof/ipc3-pcm.c
@@ -382,4 +382,5 @@ const struct sof_ipc_pcm_ops ipc3_pcm_ops = {
.hw_free = sof_ipc3_pcm_hw_free,
.trigger = sof_ipc3_pcm_trigger,
.dai_link_fixup = sof_ipc3_pcm_dai_link_fixup,
+ .reset_hw_params_during_stop = true,
};
diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c
index db64200ba1e5..a2cd21256e44 100644
--- a/sound/soc/sof/ipc4-pcm.c
+++ b/sound/soc/sof/ipc4-pcm.c
@@ -835,5 +835,6 @@ const struct sof_ipc_pcm_ops ipc4_pcm_ops = {
.dai_link_fixup = sof_ipc4_pcm_dai_link_fixup,
.pcm_setup = sof_ipc4_pcm_setup,
.pcm_free = sof_ipc4_pcm_free,
- .delay = sof_ipc4_pcm_delay
+ .delay = sof_ipc4_pcm_delay,
+ .ipc_first_on_start = true
};
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c
index 445acb5c3a21..d9b4633bba7a 100644
--- a/sound/soc/sof/pcm.c
+++ b/sound/soc/sof/pcm.c
@@ -301,6 +301,8 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
ipc_first = true;
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (pcm_ops && pcm_ops->ipc_first_on_start)
+ ipc_first = true;
break;
case SNDRV_PCM_TRIGGER_START:
if (spcm->stream[substream->stream].suspend_ignored) {
@@ -312,6 +314,9 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
spcm->stream[substream->stream].suspend_ignored = false;
return 0;
}
+
+ if (pcm_ops && pcm_ops->ipc_first_on_start)
+ ipc_first = true;
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
if (sdev->system_suspend_target == SOF_SUSPEND_S0IX &&
@@ -328,26 +333,36 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
fallthrough;
case SNDRV_PCM_TRIGGER_STOP:
ipc_first = true;
- reset_hw_params = true;
+ if (pcm_ops && pcm_ops->reset_hw_params_during_stop)
+ reset_hw_params = true;
break;
default:
dev_err(component->dev, "Unhandled trigger cmd %d\n", cmd);
return -EINVAL;
}
- /*
- * DMA and IPC sequence is different for start and stop. Need to send
- * STOP IPC before stop DMA
- */
if (!ipc_first)
snd_sof_pcm_platform_trigger(sdev, substream, cmd);
if (pcm_ops && pcm_ops->trigger)
ret = pcm_ops->trigger(component, substream, cmd);
- /* need to STOP DMA even if trigger IPC failed */
- if (ipc_first)
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_START:
+ /* invoke platform trigger to start DMA only if pcm_ops is successful */
+ if (ipc_first && !ret)
+ snd_sof_pcm_platform_trigger(sdev, substream, cmd);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_STOP:
+ /* invoke platform trigger to stop DMA even if pcm_ops failed */
snd_sof_pcm_platform_trigger(sdev, substream, cmd);
+ break;
+ default:
+ break;
+ }
/* free PCM if reset_hw_params is set and the STOP IPC is successful */
if (!ret && reset_hw_params)
diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h
index d220af5f08fb..6c64376858b3 100644
--- a/sound/soc/sof/sof-audio.h
+++ b/sound/soc/sof/sof-audio.h
@@ -104,6 +104,10 @@ struct snd_sof_dai_config_data {
* @pcm_free: Function pointer for PCM free that can be used for freeing any
* additional memory in the SOF PCM stream structure
* @delay: Function pointer for pcm delay calculation
+ * @reset_hw_params_during_stop: Flag indicating whether the hw_params should be reset during the
+ * STOP pcm trigger
+ * @ipc_first_on_start: Send IPC before invoking platform trigger during
+ * START/PAUSE_RELEASE triggers
*/
struct sof_ipc_pcm_ops {
int (*hw_params)(struct snd_soc_component *component, struct snd_pcm_substream *substream,
@@ -117,6 +121,8 @@ struct sof_ipc_pcm_ops {
void (*pcm_free)(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm);
snd_pcm_sframes_t (*delay)(struct snd_soc_component *component,
struct snd_pcm_substream *substream);
+ bool reset_hw_params_during_stop;
+ bool ipc_first_on_start;
};
/**