Skip to content

Commit e1a0cba

Browse files
crojewsk-intelbroonie
authored andcommitted
ASoC: Intel: avs: Fix sound clipping in single capture scenario
To avoid sound clipping when there just one, single CAPTURE stream ongoing, disable L1SEN before it is started. Any PLAYBACK stream or additional CAPTURE allows L1SEN to be re-enabled. Reviewed-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com> Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com> Link: https://msgid.link/r/20240220115035.770402-3-cezary.rojewski@intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 1b72943 commit e1a0cba

1 file changed

Lines changed: 75 additions & 2 deletions

File tree

sound/soc/intel/avs/pcm.c

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,79 @@ static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_so
643643
return 0;
644644
}
645645

646+
static void avs_hda_stream_start(struct hdac_bus *bus, struct hdac_ext_stream *host_stream)
647+
{
648+
struct hdac_stream *first_running = NULL;
649+
struct hdac_stream *pos;
650+
struct avs_dev *adev = hdac_to_avs(bus);
651+
652+
list_for_each_entry(pos, &bus->stream_list, list) {
653+
if (pos->running) {
654+
if (first_running)
655+
break; /* more than one running */
656+
first_running = pos;
657+
}
658+
}
659+
660+
/*
661+
* If host_stream is a CAPTURE stream and will be the only one running,
662+
* disable L1SEN to avoid sound clipping.
663+
*/
664+
if (!first_running) {
665+
if (hdac_stream(host_stream)->direction == SNDRV_PCM_STREAM_CAPTURE)
666+
avs_hda_l1sen_enable(adev, false);
667+
snd_hdac_stream_start(hdac_stream(host_stream));
668+
return;
669+
}
670+
671+
snd_hdac_stream_start(hdac_stream(host_stream));
672+
/*
673+
* If host_stream is the first stream to break the rule above,
674+
* re-enable L1SEN.
675+
*/
676+
if (list_entry_is_head(pos, &bus->stream_list, list) &&
677+
first_running->direction == SNDRV_PCM_STREAM_CAPTURE)
678+
avs_hda_l1sen_enable(adev, true);
679+
}
680+
681+
static void avs_hda_stream_stop(struct hdac_bus *bus, struct hdac_ext_stream *host_stream)
682+
{
683+
struct hdac_stream *first_running = NULL;
684+
struct hdac_stream *pos;
685+
struct avs_dev *adev = hdac_to_avs(bus);
686+
687+
list_for_each_entry(pos, &bus->stream_list, list) {
688+
if (pos == hdac_stream(host_stream))
689+
continue; /* ignore stream that is about to be stopped */
690+
if (pos->running) {
691+
if (first_running)
692+
break; /* more than one running */
693+
first_running = pos;
694+
}
695+
}
696+
697+
/*
698+
* If host_stream is a CAPTURE stream and is the only one running,
699+
* re-enable L1SEN.
700+
*/
701+
if (!first_running) {
702+
snd_hdac_stream_stop(hdac_stream(host_stream));
703+
if (hdac_stream(host_stream)->direction == SNDRV_PCM_STREAM_CAPTURE)
704+
avs_hda_l1sen_enable(adev, true);
705+
return;
706+
}
707+
708+
/*
709+
* If by stopping host_stream there is only a single, CAPTURE stream running
710+
* left, disable L1SEN to avoid sound clipping.
711+
*/
712+
if (list_entry_is_head(pos, &bus->stream_list, list) &&
713+
first_running->direction == SNDRV_PCM_STREAM_CAPTURE)
714+
avs_hda_l1sen_enable(adev, false);
715+
716+
snd_hdac_stream_stop(hdac_stream(host_stream));
717+
}
718+
646719
static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
647720
{
648721
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
@@ -664,7 +737,7 @@ static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, stru
664737
case SNDRV_PCM_TRIGGER_START:
665738
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
666739
spin_lock_irqsave(&bus->reg_lock, flags);
667-
snd_hdac_stream_start(hdac_stream(host_stream));
740+
avs_hda_stream_start(bus, host_stream);
668741
spin_unlock_irqrestore(&bus->reg_lock, flags);
669742

670743
/* Timeout on DRSM poll shall not stop the resume so ignore the result. */
@@ -694,7 +767,7 @@ static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, stru
694767
dev_err(dai->dev, "pause FE path failed: %d\n", ret);
695768

696769
spin_lock_irqsave(&bus->reg_lock, flags);
697-
snd_hdac_stream_stop(hdac_stream(host_stream));
770+
avs_hda_stream_stop(bus, host_stream);
698771
spin_unlock_irqrestore(&bus->reg_lock, flags);
699772

700773
ret = avs_path_reset(data->path);

0 commit comments

Comments
 (0)