Paused streams do not get suspended when the system enters S3.
So, clear and release link DMA channel for such streams in the
hda_dsp_set_hw_params_upon_resume() callback. Also, invalidate
the link DMA channel in the DAI config before restoring the
dai config upon resume. Also, modify the signature for the
set_hw_params_upon_resume() op to return an int.
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
return 0;
}
-void hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
+int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
{
struct hdac_bus *bus = sof_to_bus(sdev);
struct sof_intel_hda_stream *hda_stream;
struct hdac_ext_stream *stream;
struct hdac_stream *s;
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+ struct snd_soc_pcm_runtime *rtd;
+ struct hdac_ext_link *link;
+ const char *name;
+ int stream_tag;
+#endif
+
/* set internal flag for BE */
list_for_each_entry(s, &bus->stream_list, list) {
stream = stream_to_hdac_ext_stream(s);
hda_stream = container_of(stream, struct sof_intel_hda_stream,
hda_stream);
hda_stream->hw_params_upon_resume = 1;
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+ /*
+ * clear and release stream. This should already be taken care
+ * for running streams when the SUSPEND trigger is called.
+ * But paused streams do not get suspended, so this needs to be
+ * done explicitly during suspend.
+ */
+ if (stream->link_substream) {
+ rtd = snd_pcm_substream_chip(stream->link_substream);
+ name = rtd->codec_dai->component->name;
+ link = snd_hdac_ext_bus_get_link(bus, name);
+ if (!link)
+ return -EINVAL;
+ stream_tag = hdac_stream(stream)->stream_tag;
+ snd_hdac_ext_link_clear_stream_id(link, stream_tag);
+ snd_hdac_ext_stream_release(stream,
+ HDAC_EXT_STREAM_TYPE_LINK);
+ }
+#endif
}
+ return 0;
}
int hda_dsp_resume(struct snd_sof_dev *sdev);
int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state);
int hda_dsp_runtime_resume(struct snd_sof_dev *sdev);
-void hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev);
+int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev);
void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags);
void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags);
void hda_ipc_dump(struct snd_sof_dev *sdev);
return 0;
}
-static inline void snd_sof_dsp_hw_params_upon_resume(struct snd_sof_dev *sdev)
+static inline int snd_sof_dsp_hw_params_upon_resume(struct snd_sof_dev *sdev)
{
if (sof_ops(sdev)->set_hw_params_upon_resume)
- sof_ops(sdev)->set_hw_params_upon_resume(sdev);
+ return sof_ops(sdev)->set_hw_params_upon_resume(sdev);
+ return 0;
}
static inline int snd_sof_dsp_set_clk(struct snd_sof_dev *sdev, u32 freq)
continue;
}
+ /*
+ * The link DMA channel would be invalidated for running
+ * streams but not for streams that were in the PAUSED
+ * state during suspend. So invalidate it here before setting
+ * the dai config in the DSP.
+ */
+ if (config->type == SOF_DAI_INTEL_HDA)
+ config->hda.link_dma_ch = DMA_CHAN_INVALID;
+
ret = sof_ipc_tx_message(sdev->ipc,
config->hdr.cmd, config,
config->hdr.size,
sizeof(pm_ctx), &reply, sizeof(reply));
}
-static void sof_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
+static int sof_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
{
struct snd_pcm_substream *substream;
struct snd_sof_pcm *spcm;
}
/* set internal flag for BE */
- snd_sof_dsp_hw_params_upon_resume(sdev);
+ return snd_sof_dsp_hw_params_upon_resume(sdev);
}
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
snd_sof_release_trace(sdev);
/* set restore_stream for all streams during system suspend */
- if (!runtime_suspend)
- sof_set_hw_params_upon_resume(sdev);
+ if (!runtime_suspend) {
+ ret = sof_set_hw_params_upon_resume(sdev);
+ if (ret < 0) {
+ dev_err(sdev->dev,
+ "error: setting hw_params flag during suspend %d\n",
+ ret);
+ return ret;
+ }
+ }
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
/* cache debugfs contents during runtime suspend */
int (*runtime_suspend)(struct snd_sof_dev *sof_dev,
int state); /* optional */
int (*runtime_resume)(struct snd_sof_dev *sof_dev); /* optional */
- void (*set_hw_params_upon_resume)(struct snd_sof_dev *sdev); /* optional */
+ int (*set_hw_params_upon_resume)(struct snd_sof_dev *sdev); /* optional */
/* DSP clocking */
int (*set_clk)(struct snd_sof_dev *sof_dev, u32 freq); /* optional */