If the playback and capture of the same McASP is connected to different dai link (non duplex PCM links, like with pcm3168a codec) then there is a high probability of race between the two direction leaving McASP in a confused state.
Protect the hw_params() with a mutex to make sure that this is not happening.
The concurrent execution of hw_params for capture and playback can be easily triggered with custom .asoundrc file (for pcm3168a codec):
pcm.dmixed8 { type dmix ipc_key 2048 ipc_perm 0666 slave { pcm "hw:0,0" format S24_LE channels 8 rate 96000 } bindings { 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 } }
pcm.cpb-headset-1 { type plug slave.pcm dmixed8
hint { show on description "Headset 1 jack" } ttable.0.0 1 ttable.1.4 1 }
pcm.dsnooped6 { type dsnoop ipc_key 2049 ipc_perm 0666 slave { pcm "hw:0,1" format S24_LE channels 6 rate 96000 } bindings { 0 0 1 1 2 2 3 3 4 4 5 5 } }
pcm.cpb-mic-1 { type plug slave.pcm "dsnooped6"
hint { show on description "Microphone 1 jack" } ttable.0.0 1 ttable.1.3 1 }
Then running: arecord -D cpb-mic-1 -f S24_LE -c2 -r48000 | aplay -D cpb-headset-1 -f S24_LE -c2 -r48000
Signed-off-by: Peter Ujfalusi peter.ujfalusi@ti.com --- sound/soc/ti/davinci-mcasp.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index 7aa3c32e4a49..fe7a0b3572e2 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -111,6 +111,7 @@ struct davinci_mcasp { u32 channels; int max_format_width; u8 active_serializers[2]; + struct mutex mutex;
#ifdef CONFIG_GPIOLIB struct gpio_chip gpio_chip; @@ -1169,6 +1170,8 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, int period_size = params_period_size(params); int ret;
+ mutex_lock(&mcasp->mutex); + switch (params_format(params)) { case SNDRV_PCM_FORMAT_U8: case SNDRV_PCM_FORMAT_S8: @@ -1197,12 +1200,13 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
default: printk(KERN_WARNING "davinci-mcasp: unsupported PCM format"); - return -EINVAL; + ret = -EINVAL; + goto out; }
ret = davinci_mcasp_set_dai_fmt(cpu_dai, mcasp->dai_fmt); if (ret) - return ret; + goto out;
/* * If mcasp is BCLK master, and a BCLK divider was not provided by @@ -1223,7 +1227,7 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, ret = mcasp_common_hw_param(mcasp, substream->stream, period_size * channels, channels); if (ret) - return ret; + goto out;
if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) ret = mcasp_dit_hw_param(mcasp, params_rate(params)); @@ -1232,7 +1236,7 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, channels);
if (ret) - return ret; + goto out;
davinci_config_channel_size(mcasp, word_length);
@@ -1242,7 +1246,10 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, mcasp->max_format_width = word_length; }
- return 0; +out: + mutex_unlock(&mcasp->mutex); + + return ret; }
static int davinci_mcasp_trigger(struct snd_pcm_substream *substream, @@ -2335,6 +2342,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev) if (ret) return -EINVAL;
+ mutex_init(&mcasp->mutex); + ret = devm_snd_soc_register_component(&pdev->dev, &davinci_mcasp_component, &davinci_mcasp_dai[pdata->op_mode], 1);