@@ -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+
646719static 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