| From 08fd66da92a12f84aa4aeb1d6456d512af16796a Mon Sep 17 00:00:00 2001 |
| From: Rander Wang <rander.wang@linux.intel.com> |
| Date: Fri, 8 Mar 2019 16:38:57 +0800 |
| Subject: ASoC:soc-pcm:fix a codec fixup issue in TDM case |
| |
| [ Upstream commit 570f18b6a8d1f0e60e8caf30e66161b6438dcc91 ] |
| |
| On HDaudio platforms, if playback is started when capture is working, |
| there is no audible output. |
| |
| This can be root-caused to the use of the rx|tx_mask to store an HDaudio |
| stream tag. |
| |
| If capture is stared before playback, rx_mask would be non-zero on HDaudio |
| platform, then the channel number of playback, which is in the same codec |
| dai with the capture, would be changed by soc_pcm_codec_params_fixup based |
| on the tx_mask at first, then overwritten by this function based on rx_mask |
| at last. |
| |
| According to the author of tx|rx_mask, tx_mask is for playback and rx_mask |
| is for capture. And stream direction is checked at all other references of |
| tx|rx_mask in ASoC, so here should be an error. This patch checks stream |
| direction for tx|rx_mask for fixup function. |
| |
| This issue would affect not only HDaudio+ASoC, but also I2S codecs if the |
| channel number based on rx_mask is not equal to the one for tx_mask. It could |
| be rarely reproduecd because most drivers in kernel set the same channel number |
| to tx|rx_mask or rx_mask is zero. |
| |
| Tested on all platforms using stream_tag & HDaudio and intel I2S platforms. |
| |
| Signed-off-by: Rander Wang <rander.wang@linux.intel.com> |
| Acked-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> |
| Signed-off-by: Mark Brown <broonie@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| sound/soc/soc-pcm.c | 7 +++++-- |
| 1 file changed, 5 insertions(+), 2 deletions(-) |
| |
| diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c |
| index e2fb859fbbaa1..4323002c67db2 100644 |
| --- a/sound/soc/soc-pcm.c |
| +++ b/sound/soc/soc-pcm.c |
| @@ -847,10 +847,13 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, |
| codec_params = *params; |
| |
| /* fixup params based on TDM slot masks */ |
| - if (codec_dai->tx_mask) |
| + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && |
| + codec_dai->tx_mask) |
| soc_pcm_codec_params_fixup(&codec_params, |
| codec_dai->tx_mask); |
| - if (codec_dai->rx_mask) |
| + |
| + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && |
| + codec_dai->rx_mask) |
| soc_pcm_codec_params_fixup(&codec_params, |
| codec_dai->rx_mask); |
| |
| -- |
| 2.20.1 |
| |