Skip to content

Commit

Permalink
ASoC: omap-mcpdm: Fix for full duplex audio use case
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Peter Ujfalusi authored and Mark Brown committed Mar 20, 2013
1 parent 6237663 commit 81054b2
Showing 1 changed file with 26 additions and 1 deletion.
27 changes: 26 additions & 1 deletion sound/soc/omap/omap-mcpdm.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ struct omap_mcpdm {

/* McPDM dn offsets for rx1, and 2 channels */
u32 dn_rx_offset;

/* McPDM needs to be restarted due to runtime reconfiguration */
bool restart;
};

/*
Expand Down Expand Up @@ -149,7 +152,7 @@ static void omap_mcpdm_start(struct omap_mcpdm *mcpdm)
static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm)
{
u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
u32 link_mask = mcpdm->config[0].link_mask | mcpdm->config[1].link_mask;
u32 link_mask = MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK;

ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
Expand Down Expand Up @@ -287,6 +290,8 @@ static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
if (omap_mcpdm_active(mcpdm)) {
omap_mcpdm_stop(mcpdm);
omap_mcpdm_close_streams(mcpdm);
mcpdm->config[0].link_mask = 0;
mcpdm->config[1].link_mask = 0;
}
}

Expand Down Expand Up @@ -334,11 +339,26 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
/* Configure McPDM channels, and DMA packet size */
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
link_mask <<= 3;

/* If capture is not running assume a stereo stream to come */
if (!mcpdm->config[!stream].link_mask)
mcpdm->config[!stream].link_mask = 0x3;

dma_data->packet_size =
(MCPDM_DN_THRES_MAX - threshold) * channels;
} else {
/* If playback is not running assume a stereo stream to come */
if (!mcpdm->config[!stream].link_mask)
mcpdm->config[!stream].link_mask = (0x3 << 3);

dma_data->packet_size = threshold * channels;
}

/* Check if we need to restart McPDM with this stream */
if (mcpdm->config[stream].link_mask &&
mcpdm->config[stream].link_mask != link_mask)
mcpdm->restart = true;

mcpdm->config[stream].link_mask = link_mask;

return 0;
Expand All @@ -352,6 +372,11 @@ static int omap_mcpdm_prepare(struct snd_pcm_substream *substream,
if (!omap_mcpdm_active(mcpdm)) {
omap_mcpdm_start(mcpdm);
omap_mcpdm_reg_dump(mcpdm);
} else if (mcpdm->restart) {
omap_mcpdm_stop(mcpdm);
omap_mcpdm_start(mcpdm);
mcpdm->restart = false;
omap_mcpdm_reg_dump(mcpdm);
}

return 0;
Expand Down

0 comments on commit 81054b2

Please sign in to comment.