ASoC: SOF: Intel: hda: Handle prepare without close for non-HDA DAI's
authorRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Wed, 16 Oct 2024 03:29:08 +0000 (11:29 +0800)
committerMark Brown <broonie@kernel.org>
Thu, 17 Oct 2024 11:11:18 +0000 (12:11 +0100)
When a PCM is restarted after a snd_pcm_drain/snd_pcm_drop(), the prepare
callback will be invoked and the hw_params will be set again. For the
HDA DAI's, the hw_params function handles this case already but not for
the non-HDA DAI's. So, add the check for link_prepared to verify if the
hw_params should be done again or not. Additionally, for SDW DAI's reset
the PCMSyCM registers as would be done in the case of a start after a
hw_free.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
All: stable@vger.kernel.org # 6.10.x 6.11.x
Link: https://patch.msgid.link/20241016032910.14601-3-yung-chuan.liao@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sof/intel/hda-dai.c

index 1c823f9eea570082b06827133d7290bb1e8963ab..8cccf38967e728de5ea3e9d96abf3a171c464e33 100644 (file)
@@ -370,6 +370,13 @@ static int non_hda_dai_hw_params_data(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
+       sdev = widget_to_sdev(w);
+       hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
+
+       /* nothing more to do if the link is already prepared */
+       if (hext_stream && hext_stream->link_prepared)
+               return 0;
+
        /* use HDaudio stream handling */
        ret = hda_dai_hw_params_data(substream, params, cpu_dai, data, flags);
        if (ret < 0) {
@@ -377,7 +384,6 @@ static int non_hda_dai_hw_params_data(struct snd_pcm_substream *substream,
                return ret;
        }
 
-       sdev = widget_to_sdev(w);
        if (sdev->dspless_mode_selected)
                return 0;
 
@@ -482,6 +488,31 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
        int ret;
        int i;
 
+       ops = hda_dai_get_ops(substream, cpu_dai);
+       if (!ops) {
+               dev_err(cpu_dai->dev, "DAI widget ops not set\n");
+               return -EINVAL;
+       }
+
+       sdev = widget_to_sdev(w);
+       hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
+
+       /* nothing more to do if the link is already prepared */
+       if (hext_stream && hext_stream->link_prepared)
+               return 0;
+
+       /*
+        * reset the PCMSyCM registers to handle a prepare callback when the PCM is restarted
+        * due to xruns or after a call to snd_pcm_drain/drop()
+        */
+       ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id,
+                                            0, 0, substream->stream);
+       if (ret < 0) {
+               dev_err(cpu_dai->dev, "%s:  hdac_bus_eml_sdw_map_stream_ch failed %d\n",
+                       __func__, ret);
+               return ret;
+       }
+
        data.dai_index = (link_id << 8) | cpu_dai->id;
        data.dai_node_id = intel_alh_id;
        ret = non_hda_dai_hw_params_data(substream, params, cpu_dai, &data, flags);
@@ -490,10 +521,7 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
                return ret;
        }
 
-       ops = hda_dai_get_ops(substream, cpu_dai);
-       sdev = widget_to_sdev(w);
        hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
-
        if (!hext_stream)
                return -ENODEV;