Skip to content

Commit 22e8209

Browse files
committed
ASoC: SOF: Intel: hda-dai: move code to deal with hda dai/dailink suspend
The location of the code was not optimal and prevents us from using helpers, let's move it to hda-dai.c, add comments and re-align with the TRIGGER_SUSPEND case with an additional call to hda_dai_hw_free_ipc() to free-up resources. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
1 parent 5e9c753 commit 22e8209

File tree

3 files changed

+83
-36
lines changed

3 files changed

+83
-36
lines changed

sound/soc/sof/intel/hda-dai.c

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,63 @@ static const struct snd_soc_dai_ops hda_dai_ops = {
457457
.prepare = hda_dai_prepare,
458458
};
459459

460+
static int hda_dai_suspend(struct hdac_bus *bus)
461+
{
462+
struct snd_soc_pcm_runtime *rtd;
463+
struct hdac_ext_stream *he_stream;
464+
struct hdac_ext_link *link;
465+
struct hdac_stream *s;
466+
const char *name;
467+
int stream_tag;
468+
int ret;
469+
470+
/* set internal flag for BE */
471+
list_for_each_entry(s, &bus->stream_list, list) {
472+
he_stream = stream_to_hdac_ext_stream(s);
473+
474+
if (!he_stream)
475+
return -EINVAL;
476+
477+
/*
478+
* clear stream. This should already be taken care for running
479+
* streams when the SUSPEND trigger is called. But paused
480+
* streams do not get suspended, so this needs to be done
481+
* explicitly during suspend.
482+
*/
483+
if (he_stream->link_substream) {
484+
struct snd_soc_dai *cpu_dai;
485+
struct snd_soc_dai *codec_dai;
486+
487+
rtd = asoc_substream_to_rtd(he_stream->link_substream);
488+
cpu_dai = asoc_rtd_to_cpu(rtd, 0);
489+
codec_dai = asoc_rtd_to_codec(rtd, 0);
490+
name = codec_dai->component->name;
491+
link = snd_hdac_ext_bus_get_link(bus, name);
492+
if (!link)
493+
return -EINVAL;
494+
495+
if (hdac_stream(he_stream)->direction == SNDRV_PCM_STREAM_PLAYBACK) {
496+
stream_tag = hdac_stream(he_stream)->stream_tag;
497+
snd_hdac_ext_link_clear_stream_id(link, stream_tag);
498+
}
499+
500+
he_stream->link_prepared = 0;
501+
502+
/*
503+
* we don't need to call snd_hdac_ext_link_stream_clear(he_stream)
504+
* since we can only reach this case in the pause_push state, and
505+
* the TRIGGER_PAUSE_PUSH already stops the DMA
506+
*/
507+
508+
/* for consistency with TRIGGER_SUSPEND we free DAI resources */
509+
ret = hda_dai_hw_free_ipc(hdac_stream(he_stream)->direction, cpu_dai);
510+
if (ret < 0)
511+
return ret;
512+
}
513+
}
514+
515+
return 0;
516+
}
460517
#endif
461518

462519
/* only one flag used so far to harden hw_params/hw_free/trigger/prepare */
@@ -759,3 +816,22 @@ struct snd_soc_dai_driver skl_dai[] = {
759816
#endif
760817
#endif
761818
};
819+
820+
int hda_dsp_dais_suspend(struct snd_sof_dev *sdev)
821+
{
822+
/*
823+
* In the corner case where a SUSPEND happens during a PAUSE, the ALSA core
824+
* does not throw the TRIGGER_SUSPEND. This leaves the DAIs in an unbalanced state.
825+
* Since the component suspend is called last, we can trap this corner case
826+
* and force the DAIs to release their resources.
827+
*/
828+
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
829+
int ret;
830+
831+
ret = hda_dai_suspend(sof_to_bus(sdev));
832+
if (ret < 0)
833+
return ret;
834+
#endif
835+
836+
return 0;
837+
}

sound/soc/sof/intel/hda-dsp.c

Lines changed: 6 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -902,44 +902,14 @@ int hda_dsp_shutdown(struct snd_sof_dev *sdev)
902902

903903
int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
904904
{
905-
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
906-
struct hdac_bus *bus = sof_to_bus(sdev);
907-
struct snd_soc_pcm_runtime *rtd;
908-
struct hdac_ext_stream *he_stream;
909-
struct hdac_ext_link *link;
910-
struct hdac_stream *s;
911-
const char *name;
912-
int stream_tag;
913-
914-
/* set internal flag for BE */
915-
list_for_each_entry(s, &bus->stream_list, list) {
916-
he_stream = stream_to_hdac_ext_stream(s);
917-
918-
/*
919-
* clear stream. This should already be taken care for running
920-
* streams when the SUSPEND trigger is called. But paused
921-
* streams do not get suspended, so this needs to be done
922-
* explicitly during suspend.
923-
*/
924-
if (he_stream->link_substream) {
925-
rtd = asoc_substream_to_rtd(he_stream->link_substream);
926-
name = asoc_rtd_to_codec(rtd, 0)->component->name;
927-
link = snd_hdac_ext_bus_get_link(bus, name);
928-
if (!link)
929-
return -EINVAL;
930-
931-
he_stream->link_prepared = 0;
905+
int ret;
932906

933-
if (hdac_stream(he_stream)->direction ==
934-
SNDRV_PCM_STREAM_CAPTURE)
935-
continue;
907+
/* make sure all DAI resources are freed */
908+
ret = hda_dsp_dais_suspend(sdev);
909+
if (ret < 0)
910+
dev_warn(sdev->dev, "%s: failure in hda_dsp_dais_suspend\n", __func__);
936911

937-
stream_tag = hdac_stream(he_stream)->stream_tag;
938-
snd_hdac_ext_link_clear_stream_id(link, stream_tag);
939-
}
940-
}
941-
#endif
942-
return 0;
912+
return ret;
943913
}
944914

945915
void hda_dsp_d0i3_work(struct work_struct *work)

sound/soc/sof/intel/hda.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,7 @@ static inline bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev)
708708

709709
/* common dai driver */
710710
extern struct snd_soc_dai_driver skl_dai[];
711+
int hda_dsp_dais_suspend(struct snd_sof_dev *sdev);
711712

712713
/*
713714
* Platform Specific HW abstraction Ops.

0 commit comments

Comments
 (0)