summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/soc/sof/intel/hda-dai.c220
1 files changed, 138 insertions, 82 deletions
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index 245009809894..d5ca5b1fefe6 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -176,40 +176,28 @@ static int hda_dai_widget_update(struct snd_soc_dapm_widget *w,
return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, &data);
}
-static int hda_dai_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+static int hda_link_dma_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
{
struct hdac_stream *hstream = substream->runtime->private_data;
- struct hdac_bus *bus = hstream->bus;
struct hdac_ext_stream *hext_stream;
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
struct hda_pipe_params p_params = {0};
- struct snd_soc_dapm_widget *w;
+ struct hdac_bus *bus = hstream->bus;
struct hdac_ext_link *link;
- int stream_tag;
- int ret;
/* get stored dma data if resuming from system suspend */
- hext_stream = snd_soc_dai_get_dma_data(dai, substream);
+ hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
if (!hext_stream) {
hext_stream = hda_link_stream_assign(bus, substream);
if (!hext_stream)
return -EBUSY;
- snd_soc_dai_set_dma_data(dai, substream, (void *)hext_stream);
+ snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)hext_stream);
}
- stream_tag = hdac_stream(hext_stream)->stream_tag;
-
- w = snd_soc_dai_get_widget(dai, substream->stream);
-
- /* set up the DAI widget and send the DAI_CONFIG with the new tag */
- ret = hda_dai_widget_update(w, stream_tag - 1, true);
- if (ret < 0)
- return ret;
-
link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
if (!link)
return -EINVAL;
@@ -232,23 +220,45 @@ static int hda_dai_hw_params(struct snd_pcm_substream *substream,
return hda_link_dma_params(hext_stream, &p_params);
}
-static int hda_dai_prepare(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+static int hda_dai_hw_params_update(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
{
- struct hdac_ext_stream *hext_stream =
- snd_soc_dai_get_dma_data(dai, substream);
- struct snd_sof_dev *sdev =
- snd_soc_component_get_drvdata(dai->component);
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- int stream = substream->stream;
+ struct hdac_ext_stream *hext_stream;
+ struct snd_soc_dapm_widget *w;
+ int stream_tag;
- if (hext_stream->link_prepared)
- return 0;
+ hext_stream = snd_soc_dai_get_dma_data(dai, substream);
+ if (!hext_stream)
+ return -EINVAL;
+
+ stream_tag = hdac_stream(hext_stream)->stream_tag;
- dev_dbg(sdev->dev, "hda: prepare stream dir %d\n", substream->stream);
+ w = snd_soc_dai_get_widget(dai, substream->stream);
- return hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params,
- dai);
+ /* set up the DAI widget and send the DAI_CONFIG with the new tag */
+ return hda_dai_widget_update(w, stream_tag - 1, true);
+}
+
+static int hda_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ int ret;
+
+ ret = hda_link_dma_hw_params(substream, params);
+ if (ret < 0)
+ return ret;
+
+ return hda_dai_hw_params_update(substream, params, dai);
+}
+
+static int hda_link_dma_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ int stream = substream->stream;
+
+ return hda_link_dma_hw_params(substream, &rtd->dpcm[stream].hw_params);
}
static int hda_dai_config_pause_push_ipc(struct snd_soc_dapm_widget *w)
@@ -269,31 +279,44 @@ static int hda_dai_config_pause_push_ipc(struct snd_soc_dapm_widget *w)
return ret;
}
-static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream,
- int cmd, struct snd_soc_dai *dai)
+static int ipc3_hda_dai_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
{
struct hdac_ext_stream *hext_stream =
snd_soc_dai_get_dma_data(dai, substream);
- struct snd_soc_pcm_runtime *rtd;
- struct snd_soc_dapm_widget *w;
- struct hdac_ext_link *link;
- struct hdac_stream *hstream;
- struct hdac_bus *bus;
- int stream_tag;
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ int stream = substream->stream;
int ret;
- hstream = substream->runtime->private_data;
- bus = hstream->bus;
- rtd = asoc_substream_to_rtd(substream);
+ if (hext_stream->link_prepared)
+ return 0;
- link = snd_hdac_ext_bus_get_link(bus, asoc_rtd_to_codec(rtd, 0)->component->name);
- if (!link)
- return -EINVAL;
+ dev_dbg(sdev->dev, "%s: prepare stream dir %d\n", __func__, substream->stream);
- dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd);
+ ret = hda_link_dma_prepare(substream);
+ if (ret < 0)
+ return ret;
- w = snd_soc_dai_get_widget(dai, substream->stream);
+ return hda_dai_hw_params_update(substream, &rtd->dpcm[stream].hw_params, dai);
+}
+
+static int hda_link_dma_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct hdac_stream *hstream = substream->runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
+ struct hdac_ext_link *link;
+ struct hdac_bus *bus = hstream->bus;
+ int stream_tag;
+
+ link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
+ if (!link)
+ return -EINVAL;
+ dev_dbg(cpu_dai->dev, "%s: cmd=%d\n", __func__, cmd);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
@@ -303,13 +326,6 @@ static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_STOP:
snd_hdac_ext_link_stream_clear(hext_stream);
- /*
- * free DAI widget during stop/suspend to keep widget use_count's balanced.
- */
- ret = hda_dai_widget_update(w, DMA_CHAN_INVALID, false);
- if (ret < 0)
- return ret;
-
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
stream_tag = hdac_stream(hext_stream)->stream_tag;
snd_hdac_ext_link_clear_stream_id(link, stream_tag);
@@ -320,50 +336,69 @@ static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
snd_hdac_ext_link_stream_clear(hext_stream);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct snd_soc_dapm_widget *w;
+ int ret;
+
+ ret = hda_link_dma_trigger(substream, cmd);
+ if (ret < 0)
+ return ret;
+
+ w = snd_soc_dai_get_widget(dai, substream->stream);
+
+ dev_dbg(dai->dev, "%s: cmd=%d\n", __func__, cmd);
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_STOP:
+ /*
+ * free DAI widget during stop/suspend to keep widget use_count's balanced.
+ */
+ ret = hda_dai_widget_update(w, DMA_CHAN_INVALID, false);
+ if (ret < 0)
+ return ret;
+
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
ret = hda_dai_config_pause_push_ipc(w);
if (ret < 0)
return ret;
break;
+
default:
- return -EINVAL;
+ break;
}
return 0;
}
-static int hda_dai_hw_free(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+static int hda_link_dma_hw_free(struct snd_pcm_substream *substream)
{
- unsigned int stream_tag;
+ struct hdac_stream *hstream = substream->runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
struct sof_intel_hda_stream *hda_stream;
- struct hdac_bus *bus;
- struct hdac_ext_link *link;
- struct hdac_stream *hstream;
- struct snd_soc_pcm_runtime *rtd;
+ struct hdac_bus *bus = hstream->bus;
struct hdac_ext_stream *hext_stream;
- struct snd_soc_dapm_widget *w;
- int ret;
-
- hstream = substream->runtime->private_data;
- bus = hstream->bus;
- rtd = asoc_substream_to_rtd(substream);
- hext_stream = snd_soc_dai_get_dma_data(dai, substream);
+ struct hdac_ext_link *link;
+ int stream_tag;
+ hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
if (!hext_stream) {
- dev_dbg(dai->dev,
+ dev_dbg(cpu_dai->dev,
"%s: hext_stream is not assigned\n", __func__);
return -EINVAL;
}
- hda_stream = hstream_to_sof_hda_stream(hext_stream);
-
- w = snd_soc_dai_get_widget(dai, substream->stream);
-
- /* free the link DMA channel in the FW and the DAI widget */
- ret = hda_dai_widget_update(w, DMA_CHAN_INVALID, false);
- if (ret < 0)
- return ret;
-
- link = snd_hdac_ext_bus_get_link(bus, asoc_rtd_to_codec(rtd, 0)->component->name);
+ link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
if (!link)
return -EINVAL;
@@ -372,21 +407,42 @@ static int hda_dai_hw_free(struct snd_pcm_substream *substream,
snd_hdac_ext_link_clear_stream_id(link, stream_tag);
}
- snd_soc_dai_set_dma_data(dai, substream, NULL);
+ snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
hext_stream->link_prepared = 0;
/* free the host DMA channel reserved by hostless streams */
+ hda_stream = hstream_to_sof_hda_stream(hext_stream);
hda_stream->host_reserved = 0;
return 0;
}
+static int hda_dai_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_dapm_widget *w;
+ int ret;
+
+ ret = hda_link_dma_hw_free(substream);
+ if (ret < 0)
+ return ret;
+
+ w = snd_soc_dai_get_widget(dai, substream->stream);
+
+ /* free the link DMA channel in the FW and the DAI widget */
+ ret = hda_dai_widget_update(w, DMA_CHAN_INVALID, false);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
static const struct snd_soc_dai_ops ipc3_hda_dai_ops = {
.hw_params = hda_dai_hw_params,
.hw_free = hda_dai_hw_free,
.trigger = ipc3_hda_dai_trigger,
- .prepare = hda_dai_prepare,
+ .prepare = ipc3_hda_dai_prepare,
};
#endif