Commit 81054b226b76145628670a962674ab312690ab86
Committed by
Mark Brown
1 parent
623766318a
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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>
Showing 1 changed file with 26 additions and 1 deletions Side-by-side Diff
sound/soc/omap/omap-mcpdm.c
... | ... | @@ -63,6 +63,9 @@ |
63 | 63 | |
64 | 64 | /* McPDM dn offsets for rx1, and 2 channels */ |
65 | 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 @@ |
149 | 152 | static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm) |
150 | 153 | { |
151 | 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 | 157 | ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); |
155 | 158 | omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); |
... | ... | @@ -287,6 +290,8 @@ |
287 | 290 | if (omap_mcpdm_active(mcpdm)) { |
288 | 291 | omap_mcpdm_stop(mcpdm); |
289 | 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 | |
293 | 298 | |
294 | 299 | |
... | ... | @@ -334,11 +339,26 @@ |
334 | 339 | /* Configure McPDM channels, and DMA packet size */ |
335 | 340 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { |
336 | 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 | 347 | dma_data->packet_size = |
338 | 348 | (MCPDM_DN_THRES_MAX - threshold) * channels; |
339 | 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 | 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 | 362 | mcpdm->config[stream].link_mask = link_mask; |
343 | 363 | |
344 | 364 | return 0; |
... | ... | @@ -351,6 +371,11 @@ |
351 | 371 | |
352 | 372 | if (!omap_mcpdm_active(mcpdm)) { |
353 | 373 | omap_mcpdm_start(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; | |
354 | 379 | omap_mcpdm_reg_dump(mcpdm); |
355 | 380 | } |
356 | 381 |