aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@ti.com>2013-03-20 05:47:13 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2013-03-20 05:59:52 -0400
commit81054b226b76145628670a962674ab312690ab86 (patch)
treeb12a53c9dc24851e3ac20a22c321004e32f1a5cd /sound/soc
parent623766318aeb5f8dee83b2e8926c39cf83568197 (diff)
ASoC: omap-mcpdm: Fix for full duplex audio use case
Due to HW limitation within OMAP McPDM IP uplink and downlink need to be started at the same time. This causes issues when we have two streams running, for example: arecord | aplay In this case the playback stream would have no channels enabled since at the capture start we are not aware that a playback is going to start. The workaround is to configure the other direction to stereo when the first stream is started. When the second stream is coming we check the new stream's number of channels against the pre-configured channels. If it does not match we stop and restart McPDM to update the configuration. This might result a small pop. If the coming stream is a match we do nothing in the McPDM driver. This workaround can handle most use cases without the need to restart McPDM. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/omap/omap-mcpdm.c27
1 files changed, 26 insertions, 1 deletions
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
index 6e19f440a28c..cd0e2ec90128 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/omap/omap-mcpdm.c
@@ -63,6 +63,9 @@ struct omap_mcpdm {
63 63
64 /* McPDM dn offsets for rx1, and 2 channels */ 64 /* McPDM dn offsets for rx1, and 2 channels */
65 u32 dn_rx_offset; 65 u32 dn_rx_offset;
66
67 /* McPDM needs to be restarted due to runtime reconfiguration */
68 bool restart;
66}; 69};
67 70
68/* 71/*
@@ -149,7 +152,7 @@ static void omap_mcpdm_start(struct omap_mcpdm *mcpdm)
149static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm) 152static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm)
150{ 153{
151 u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); 154 u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
152 u32 link_mask = mcpdm->config[0].link_mask | mcpdm->config[1].link_mask; 155 u32 link_mask = MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK;
153 156
154 ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); 157 ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
155 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); 158 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
@@ -287,6 +290,8 @@ static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
287 if (omap_mcpdm_active(mcpdm)) { 290 if (omap_mcpdm_active(mcpdm)) {
288 omap_mcpdm_stop(mcpdm); 291 omap_mcpdm_stop(mcpdm);
289 omap_mcpdm_close_streams(mcpdm); 292 omap_mcpdm_close_streams(mcpdm);
293 mcpdm->config[0].link_mask = 0;
294 mcpdm->config[1].link_mask = 0;
290 } 295 }
291 } 296 }
292 297
@@ -334,11 +339,26 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
334 /* Configure McPDM channels, and DMA packet size */ 339 /* Configure McPDM channels, and DMA packet size */
335 if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 340 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
336 link_mask <<= 3; 341 link_mask <<= 3;
342
343 /* If capture is not running assume a stereo stream to come */
344 if (!mcpdm->config[!stream].link_mask)
345 mcpdm->config[!stream].link_mask = 0x3;
346
337 dma_data->packet_size = 347 dma_data->packet_size =
338 (MCPDM_DN_THRES_MAX - threshold) * channels; 348 (MCPDM_DN_THRES_MAX - threshold) * channels;
339 } else { 349 } else {
350 /* If playback is not running assume a stereo stream to come */
351 if (!mcpdm->config[!stream].link_mask)
352 mcpdm->config[!stream].link_mask = (0x3 << 3);
353
340 dma_data->packet_size = threshold * channels; 354 dma_data->packet_size = threshold * channels;
341 } 355 }
356
357 /* Check if we need to restart McPDM with this stream */
358 if (mcpdm->config[stream].link_mask &&
359 mcpdm->config[stream].link_mask != link_mask)
360 mcpdm->restart = true;
361
342 mcpdm->config[stream].link_mask = link_mask; 362 mcpdm->config[stream].link_mask = link_mask;
343 363
344 return 0; 364 return 0;
@@ -352,6 +372,11 @@ static int omap_mcpdm_prepare(struct snd_pcm_substream *substream,
352 if (!omap_mcpdm_active(mcpdm)) { 372 if (!omap_mcpdm_active(mcpdm)) {
353 omap_mcpdm_start(mcpdm); 373 omap_mcpdm_start(mcpdm);
354 omap_mcpdm_reg_dump(mcpdm); 374 omap_mcpdm_reg_dump(mcpdm);
375 } else if (mcpdm->restart) {
376 omap_mcpdm_stop(mcpdm);
377 omap_mcpdm_start(mcpdm);
378 mcpdm->restart = false;
379 omap_mcpdm_reg_dump(mcpdm);
355 } 380 }
356 381
357 return 0; 382 return 0;