From c12abc012e18b362204345c323536f228d65c4db Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 7 Aug 2009 09:59:47 +0300 Subject: ARM: OMAP: McBSP: Fix ASoC on OMAP1510 by fixing API of omap_mcbsp_start/stop Simultaneous audio playback and capture on OMAP1510 can cause that second stream is stalled if there is enough delay between startup of the audio streams. Current implementation of the omap_mcbsp_start is starting both transmitter and receiver at the same time and it is called only for firstly started audio stream from the OMAP McBSP based ASoC DAI driver. Since DMA request lines on OMAP1510 are edge sensitive, the DMA request is missed if there is no DMA transfer set up at that time when the first word after McBSP startup is transmitted. The problem hasn't noted before since later OMAPs are using level sensitive DMA request lines. Fix the problem by changing API of omap_mcbsp_start and omap_mcbsp_stop by allowing to start and stop individually McBSP transmitter and receiver logics. Then call those functions individually for both audio playback and capture streams. This ensures that DMA transfer is setup before transmitter or receiver is started. Thanks to Janusz Krzysztofik for detailed problem analysis and Peter Ujfalusi for info about DMA request line behavior differences between the OMAP generations. Reported-and-tested-by: Janusz Krzysztofik Signed-off-by: Jarkko Nikula Acked-by: Tony Lindgren Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcbsp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sound/soc/omap/omap-mcbsp.c') diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index a5d46a7b196a..6a837ffd5d0b 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -183,21 +183,21 @@ static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); - int err = 0; + int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (!mcbsp_data->active++) - omap_mcbsp_start(mcbsp_data->bus_id); + mcbsp_data->active++; + omap_mcbsp_start(mcbsp_data->bus_id, play, !play); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (!--mcbsp_data->active) - omap_mcbsp_stop(mcbsp_data->bus_id); + omap_mcbsp_stop(mcbsp_data->bus_id, play, !play); + mcbsp_data->active--; break; default: err = -EINVAL; -- cgit v1.2.3 From c721bbdad71d2928e8b5015e9b462fbeb35427c6 Mon Sep 17 00:00:00 2001 From: Eero Nurkkala Date: Thu, 20 Aug 2009 16:18:23 +0300 Subject: ASoC: Add runtime check for RFIG and XFIG This is, no RFIG or XFIG (Not defined in 34xx), correct initiliazation of rccr and xccr. Signed-off-by: Eero Nurkkala Acked-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcbsp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'sound/soc/omap/omap-mcbsp.c') diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 6a837ffd5d0b..a7b09614734d 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -321,8 +321,11 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, /* Generic McBSP register settings */ regs->spcr2 |= XINTM(3) | FREE; regs->spcr1 |= RINTM(3); - regs->rcr2 |= RFIG; - regs->xcr2 |= XFIG; + /* RFIG and XFIG are not defined in 34xx */ + if (!cpu_is_omap34xx()) { + regs->rcr2 |= RFIG; + regs->xcr2 |= XFIG; + } if (cpu_is_omap2430() || cpu_is_omap34xx()) { regs->xccr = DXENDLY(1) | XDMAEN; regs->rccr = RFULL_CYCLE | RDMAEN; -- cgit v1.2.3 From ca6e2ce08679c094878d7f39a0349a7db1d13675 Mon Sep 17 00:00:00 2001 From: Eero Nurkkala Date: Thu, 20 Aug 2009 16:18:24 +0300 Subject: ASoC: Always syncronize audio transfers on frames All these steps are required for ASoC to behave correctly. rccr and xccr are format dependent, for example TDM audio has different values than I2S or DSP_A. Also the omap_mcbsp_xmit_enable and/or omap_mcbsp_recv_enable must be called right after the DMA has started. This provides no longer L and R channels switching at random. Signed-off-by: Eero Nurkkala Acked-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcbsp.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'sound/soc/omap/omap-mcbsp.c') diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index a7b09614734d..6e855080e6ea 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -191,6 +191,11 @@ static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: mcbsp_data->active++; omap_mcbsp_start(mcbsp_data->bus_id, play, !play); + /* Make sure data transfer is frame synchronized */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + omap_mcbsp_xmit_enable(mcbsp_data->bus_id, 1); + else + omap_mcbsp_recv_enable(mcbsp_data->bus_id, 1); break; case SNDRV_PCM_TRIGGER_STOP: @@ -336,11 +341,15 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, /* 1-bit data delay */ regs->rcr2 |= RDATDLY(1); regs->xcr2 |= XDATDLY(1); + regs->rccr |= RFULL_CYCLE | RDMAEN | RDISABLE; + regs->xccr |= (DXENDLY(1) | XDMAEN | XDISABLE); break; case SND_SOC_DAIFMT_DSP_A: /* 1-bit data delay */ regs->rcr2 |= RDATDLY(1); regs->xcr2 |= XDATDLY(1); + regs->rccr |= RFULL_CYCLE | RDMAEN | RDISABLE; + regs->xccr |= (DXENDLY(1) | XDMAEN | XDISABLE); /* Invert FS polarity configuration */ temp_fmt ^= SND_SOC_DAIFMT_NB_IF; break; -- cgit v1.2.3 From caebc0cb3ba1e88f5311fbe7aa58b8dff18dd763 Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Thu, 20 Aug 2009 16:18:25 +0300 Subject: ASoC: OMAP: Use McBSP threshold to playback and capture This patch changes the way DMA is done in omap-pcm.c in order to reduce power consumption. There is no need to have so much SW control in order to have DMA in idle state during audio streaming. Configuring McBSP threshold value and DMA to FRAME_SYNC are sufficient. Signed-off-by: Eduardo Valentin Acked-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcbsp.c | 47 +++++++++++++++++++++++++++++++++++++++------ sound/soc/omap/omap-pcm.c | 7 ++++++- sound/soc/omap/omap-pcm.h | 2 ++ 3 files changed, 49 insertions(+), 7 deletions(-) (limited to 'sound/soc/omap/omap-mcbsp.c') diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 6e855080e6ea..580de5a8dba6 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -139,28 +139,59 @@ static const unsigned long omap34xx_mcbsp_port[][2] = { static const unsigned long omap34xx_mcbsp_port[][2] = {}; #endif +static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); + int samples = snd_pcm_lib_period_bytes(substream) >> 1; + + /* Configure McBSP internal buffer usage */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + omap_mcbsp_set_tx_threshold(mcbsp_data->bus_id, samples - 1); + else + omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, samples - 1); +} + static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); + int bus_id = mcbsp_data->bus_id; int err = 0; - if (cpu_is_omap343x() && mcbsp_data->bus_id == 1) { + if (!cpu_dai->active) + err = omap_mcbsp_request(bus_id); + + if (cpu_is_omap343x()) { + int max_period; + /* * McBSP2 in OMAP3 has 1024 * 32-bit internal audio buffer. * Set constraint for minimum buffer size to the same than FIFO * size in order to avoid underruns in playback startup because * HW is keeping the DMA request active until FIFO is filled. */ + if (bus_id == 1) + snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, + 4096, UINT_MAX); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + max_period = omap_mcbsp_get_max_tx_threshold(bus_id); + else + max_period = omap_mcbsp_get_max_rx_threshold(bus_id); + + max_period++; + max_period <<= 1; + snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 4096, UINT_MAX); + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, + 32, max_period); } - if (!cpu_dai->active) - err = omap_mcbsp_request(mcbsp_data->bus_id); - return err; } @@ -220,7 +251,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id; - int wlen, channels, wpf; + int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT; unsigned long port; unsigned int format; @@ -236,6 +267,9 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, } else if (cpu_is_omap343x()) { dma = omap24xx_dma_reqs[bus_id][substream->stream]; port = omap34xx_mcbsp_port[bus_id][substream->stream]; + omap_mcbsp_dai_dma_params[id][substream->stream].set_threshold = + omap_mcbsp_set_threshold; + sync_mode = OMAP_DMA_SYNC_FRAME; } else { return -ENODEV; } @@ -243,6 +277,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, substream->stream ? "Audio Capture" : "Audio Playback"; omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma; omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port; + omap_mcbsp_dai_dma_params[id][substream->stream].sync_mode = sync_mode; cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream]; if (mcbsp_data->configured) { diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index b9633d5a9557..5735945788bf 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -162,7 +162,7 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream) */ dma_params.data_type = OMAP_DMA_DATA_TYPE_S16; dma_params.trigger = dma_data->dma_req; - dma_params.sync_mode = OMAP_DMA_SYNC_ELEMENT; + dma_params.sync_mode = dma_data->sync_mode; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { dma_params.src_amode = OMAP_DMA_AMODE_POST_INC; dma_params.dst_amode = OMAP_DMA_AMODE_CONSTANT; @@ -205,6 +205,7 @@ static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_pcm_runtime *runtime = substream->runtime; struct omap_runtime_data *prtd = runtime->private_data; + struct omap_pcm_dma_data *dma_data = prtd->dma_data; unsigned long flags; int ret = 0; @@ -214,6 +215,10 @@ static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: prtd->period_index = 0; + /* Configure McBSP internal buffer usage */ + if (dma_data->set_threshold) + dma_data->set_threshold(substream); + omap_start_dma(prtd->dma_ch); break; diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h index 8d9d26916b05..38a821dd4118 100644 --- a/sound/soc/omap/omap-pcm.h +++ b/sound/soc/omap/omap-pcm.h @@ -29,6 +29,8 @@ struct omap_pcm_dma_data { char *name; /* stream identifier */ int dma_req; /* DMA request line */ unsigned long port_addr; /* transmit/receive register */ + int sync_mode; /* DMA sync mode */ + void (*set_threshold)(struct snd_pcm_substream *substream); }; extern struct snd_soc_platform omap_soc_platform; -- cgit v1.2.3 From a0a499c5792b8656cd51e11d5e0db9fb21640f58 Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Thu, 20 Aug 2009 16:18:26 +0300 Subject: ASoC: OMAP: Use DMA operating mode of McBSP Configures DMA sync mode depending on McBSP operating mode value. The value is configurable by McBSP instance. So, depending on McBSP operating mode, the DMA sync mode is passed from omap-mcbsp to omap-pcm. Besides that, it also configures McBSP threshold value depending on which McBSP mode is activated. Signed-off-by: Eduardo Valentin Acked-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcbsp.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'sound/soc/omap/omap-mcbsp.c') diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 580de5a8dba6..f5387d962f5d 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -144,7 +144,14 @@ static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); - int samples = snd_pcm_lib_period_bytes(substream) >> 1; + int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id); + int samples; + + /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ + if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) + samples = snd_pcm_lib_period_bytes(substream) >> 1; + else + samples = 1; /* Configure McBSP internal buffer usage */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -166,6 +173,7 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, err = omap_mcbsp_request(bus_id); if (cpu_is_omap343x()) { + int dma_op_mode = omap_mcbsp_get_dma_op_mode(bus_id); int max_period; /* @@ -187,7 +195,8 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, max_period++; max_period <<= 1; - snd_pcm_hw_constraint_minmax(substream->runtime, + if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) + snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32, max_period); } @@ -269,7 +278,10 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, port = omap34xx_mcbsp_port[bus_id][substream->stream]; omap_mcbsp_dai_dma_params[id][substream->stream].set_threshold = omap_mcbsp_set_threshold; - sync_mode = OMAP_DMA_SYNC_FRAME; + /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ + if (omap_mcbsp_get_dma_op_mode(bus_id) == + MCBSP_DMA_MODE_THRESHOLD) + sync_mode = OMAP_DMA_SYNC_FRAME; } else { return -ENODEV; } -- cgit v1.2.3 From 32080af7a612e8c56131d6bdcd268cd9e8b0add1 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Sun, 23 Aug 2009 12:24:26 +0300 Subject: ASoC: OMAP: Fix setup of XCCR and RCCR registers in McBSP DAI Commit ca6e2ce08679c094878d7f39a0349a7db1d13675 is setting up few XCCR and RCCR bits for I2S and DPS_A formats. Part of the bits are already set for all formats and I believe that XDISABLE and RDISABLE bits are format independent. As XCCR and RCCR are found only from OMAP2430 and OMAP34xx, I move setup of XDISABLE and RDISABLE to where those cpu's are tested and remove format dependent part for simplicity. Signed-off-by: Jarkko Nikula Acked-by: Eero Nurkkala Cc: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcbsp.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'sound/soc/omap/omap-mcbsp.c') diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index f5387d962f5d..89e8bce114af 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -379,8 +379,8 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, regs->xcr2 |= XFIG; } if (cpu_is_omap2430() || cpu_is_omap34xx()) { - regs->xccr = DXENDLY(1) | XDMAEN; - regs->rccr = RFULL_CYCLE | RDMAEN; + regs->xccr = DXENDLY(1) | XDMAEN | XDISABLE; + regs->rccr = RFULL_CYCLE | RDMAEN | RDISABLE; } switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { @@ -388,15 +388,11 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, /* 1-bit data delay */ regs->rcr2 |= RDATDLY(1); regs->xcr2 |= XDATDLY(1); - regs->rccr |= RFULL_CYCLE | RDMAEN | RDISABLE; - regs->xccr |= (DXENDLY(1) | XDMAEN | XDISABLE); break; case SND_SOC_DAIFMT_DSP_A: /* 1-bit data delay */ regs->rcr2 |= RDATDLY(1); regs->xcr2 |= XDATDLY(1); - regs->rccr |= RFULL_CYCLE | RDMAEN | RDISABLE; - regs->xccr |= (DXENDLY(1) | XDMAEN | XDISABLE); /* Invert FS polarity configuration */ temp_fmt ^= SND_SOC_DAIFMT_NB_IF; break; -- cgit v1.2.3 From d09a2afc9359407114b7062519101f1ee2d05388 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Sun, 23 Aug 2009 12:24:27 +0300 Subject: ARM: OMAP: McBSP: Merge two functions into omap_mcbsp_start/_stop Functionality of functions omap_mcbsp_xmit_enable and omap_mcbsp_recv_enable can be merged into omap_mcbsp_start and omap_mcbsp_stop since API of those omap_mcbsp_start and omap_mcbsp_stop was changed recently allowing to start and stop individually the transmitter and receiver. This cleans up the code in arch/arm/plat-omap/mcbsp.c and in sound/soc/omap/omap-mcbsp.c which was the only user for those removed functions. Signed-off-by: Jarkko Nikula Acked-by: Eero Nurkkala Cc: Peter Ujfalusi Signed-off-by: Mark Brown --- arch/arm/plat-omap/include/mach/mcbsp.h | 2 - arch/arm/plat-omap/mcbsp.c | 84 +++++++++++---------------------- sound/soc/omap/omap-mcbsp.c | 5 -- 3 files changed, 28 insertions(+), 63 deletions(-) (limited to 'sound/soc/omap/omap-mcbsp.c') diff --git a/arch/arm/plat-omap/include/mach/mcbsp.h b/arch/arm/plat-omap/include/mach/mcbsp.h index 70e950e295e1..63a3f254af7b 100644 --- a/arch/arm/plat-omap/include/mach/mcbsp.h +++ b/arch/arm/plat-omap/include/mach/mcbsp.h @@ -436,8 +436,6 @@ int omap_mcbsp_request(unsigned int id); void omap_mcbsp_free(unsigned int id); void omap_mcbsp_start(unsigned int id, int tx, int rx); void omap_mcbsp_stop(unsigned int id, int tx, int rx); -void omap_mcbsp_xmit_enable(unsigned int id, u8 enable); -void omap_mcbsp_recv_enable(unsigned int id, u8 enable); void omap_mcbsp_xmit_word(unsigned int id, u32 word); u32 omap_mcbsp_recv_word(unsigned int id); diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index ee60ab68251d..8dc7927906f1 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -529,11 +529,13 @@ void omap_mcbsp_start(unsigned int id, int tx, int rx) } /* Enable transmitter and receiver */ + tx &= 1; w = OMAP_MCBSP_READ(io_base, SPCR2); - OMAP_MCBSP_WRITE(io_base, SPCR2, w | (tx & 1)); + OMAP_MCBSP_WRITE(io_base, SPCR2, w | tx); + rx &= 1; w = OMAP_MCBSP_READ(io_base, SPCR1); - OMAP_MCBSP_WRITE(io_base, SPCR1, w | (rx & 1)); + OMAP_MCBSP_WRITE(io_base, SPCR1, w | rx); /* * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec @@ -549,6 +551,16 @@ void omap_mcbsp_start(unsigned int id, int tx, int rx) OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7)); } + if (cpu_is_omap2430() || cpu_is_omap34xx()) { + /* Release the transmitter and receiver */ + w = OMAP_MCBSP_READ(io_base, XCCR); + w &= ~(tx ? XDISABLE : 0); + OMAP_MCBSP_WRITE(io_base, XCCR, w); + w = OMAP_MCBSP_READ(io_base, RCCR); + w &= ~(rx ? RDISABLE : 0); + OMAP_MCBSP_WRITE(io_base, RCCR, w); + } + /* Dump McBSP Regs */ omap_mcbsp_dump_reg(id); } @@ -570,12 +582,24 @@ void omap_mcbsp_stop(unsigned int id, int tx, int rx) io_base = mcbsp->io_base; /* Reset transmitter */ + tx &= 1; + if (cpu_is_omap2430() || cpu_is_omap34xx()) { + w = OMAP_MCBSP_READ(io_base, XCCR); + w |= (tx ? XDISABLE : 0); + OMAP_MCBSP_WRITE(io_base, XCCR, w); + } w = OMAP_MCBSP_READ(io_base, SPCR2); - OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(tx & 1)); + OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~tx); /* Reset receiver */ + rx &= 1; + if (cpu_is_omap2430() || cpu_is_omap34xx()) { + w = OMAP_MCBSP_READ(io_base, RCCR); + w |= (tx ? RDISABLE : 0); + OMAP_MCBSP_WRITE(io_base, RCCR, w); + } w = OMAP_MCBSP_READ(io_base, SPCR1); - OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~(rx & 1)); + OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~rx); idle = !((OMAP_MCBSP_READ(io_base, SPCR2) | OMAP_MCBSP_READ(io_base, SPCR1)) & 1); @@ -588,58 +612,6 @@ void omap_mcbsp_stop(unsigned int id, int tx, int rx) } EXPORT_SYMBOL(omap_mcbsp_stop); -void omap_mcbsp_xmit_enable(unsigned int id, u8 enable) -{ - struct omap_mcbsp *mcbsp; - void __iomem *io_base; - u16 w; - - if (!(cpu_is_omap2430() || cpu_is_omap34xx())) - return; - - if (!omap_mcbsp_check_valid_id(id)) { - printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); - return; - } - - mcbsp = id_to_mcbsp_ptr(id); - io_base = mcbsp->io_base; - - w = OMAP_MCBSP_READ(io_base, XCCR); - - if (enable) - OMAP_MCBSP_WRITE(io_base, XCCR, w & ~(XDISABLE)); - else - OMAP_MCBSP_WRITE(io_base, XCCR, w | XDISABLE); -} -EXPORT_SYMBOL(omap_mcbsp_xmit_enable); - -void omap_mcbsp_recv_enable(unsigned int id, u8 enable) -{ - struct omap_mcbsp *mcbsp; - void __iomem *io_base; - u16 w; - - if (!(cpu_is_omap2430() || cpu_is_omap34xx())) - return; - - if (!omap_mcbsp_check_valid_id(id)) { - printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); - return; - } - - mcbsp = id_to_mcbsp_ptr(id); - io_base = mcbsp->io_base; - - w = OMAP_MCBSP_READ(io_base, RCCR); - - if (enable) - OMAP_MCBSP_WRITE(io_base, RCCR, w & ~(RDISABLE)); - else - OMAP_MCBSP_WRITE(io_base, RCCR, w | RDISABLE); -} -EXPORT_SYMBOL(omap_mcbsp_recv_enable); - /* polled mcbsp i/o operations */ int omap_mcbsp_pollwrite(unsigned int id, u16 buf) { diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 89e8bce114af..0e173e7e0c3a 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -231,11 +231,6 @@ static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: mcbsp_data->active++; omap_mcbsp_start(mcbsp_data->bus_id, play, !play); - /* Make sure data transfer is frame synchronized */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - omap_mcbsp_xmit_enable(mcbsp_data->bus_id, 1); - else - omap_mcbsp_recv_enable(mcbsp_data->bus_id, 1); break; case SNDRV_PCM_TRIGGER_STOP: -- cgit v1.2.3 From d2c0bdaa9362c4b2ab7416420d034a0a2d1ec979 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 28 Aug 2009 15:35:35 +0300 Subject: ASoC: OMAP: Add functionality to set CLKR and FSR sources in McBSP DAI The McBSP1 port in OMAP3 processors (I believe OMAP2 too but I don't have specifications to check it) have additional CLKR and FSR pins for McBSP1 receiver. Reset default is that receiver is using bit clock and frame sync signal from those pins but it is possible to configure to use also CLKX and FSX pins as well. In fact, other McBSP ports are doing that internally that transmitter and receiver share the CLKX and FSX. Add functionaly that machine drivers can set the CLKR and FSR sources by using the snd_soc_dai_set_sysclk. Thanks to "Aggarwal, Anuj" for reporting the issue. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcbsp.c | 41 +++++++++++++++++++++++++++++++++++++++++ sound/soc/omap/omap-mcbsp.h | 4 ++++ 2 files changed, 45 insertions(+) (limited to 'sound/soc/omap/omap-mcbsp.c') diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 0e173e7e0c3a..3341f49402ca 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -512,6 +512,40 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data, return 0; } +static int omap_mcbsp_dai_set_rcvr_src(struct omap_mcbsp_data *mcbsp_data, + int clk_id) +{ + int sel_bit, set = 0; + u16 reg = OMAP2_CONTROL_DEVCONF0; + + if (cpu_class_is_omap1()) + return -EINVAL; /* TODO: Can this be implemented for OMAP1? */ + if (mcbsp_data->bus_id != 0) + return -EINVAL; + + switch (clk_id) { + case OMAP_MCBSP_CLKR_SRC_CLKX: + set = 1; + case OMAP_MCBSP_CLKR_SRC_CLKR: + sel_bit = 3; + break; + case OMAP_MCBSP_FSR_SRC_FSX: + set = 1; + case OMAP_MCBSP_FSR_SRC_FSR: + sel_bit = 4; + break; + default: + return -EINVAL; + } + + if (set) + omap_ctrl_writel(omap_ctrl_readl(reg) | (1 << sel_bit), reg); + else + omap_ctrl_writel(omap_ctrl_readl(reg) & ~(1 << sel_bit), reg); + + return 0; +} + static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int dir) @@ -534,6 +568,13 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, case OMAP_MCBSP_SYSCLK_CLKR_EXT: regs->pcr0 |= SCLKME; break; + + case OMAP_MCBSP_CLKR_SRC_CLKR: + case OMAP_MCBSP_CLKR_SRC_CLKX: + case OMAP_MCBSP_FSR_SRC_FSR: + case OMAP_MCBSP_FSR_SRC_FSX: + err = omap_mcbsp_dai_set_rcvr_src(mcbsp_data, clk_id); + break; default: err = -ENODEV; } diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h index c8147aace813..647d2f981ab0 100644 --- a/sound/soc/omap/omap-mcbsp.h +++ b/sound/soc/omap/omap-mcbsp.h @@ -32,6 +32,10 @@ enum omap_mcbsp_clksrg_clk { OMAP_MCBSP_SYSCLK_CLK, /* Internal ICLK */ OMAP_MCBSP_SYSCLK_CLKX_EXT, /* External CLKX pin */ OMAP_MCBSP_SYSCLK_CLKR_EXT, /* External CLKR pin */ + OMAP_MCBSP_CLKR_SRC_CLKR, /* CLKR from CLKR pin */ + OMAP_MCBSP_CLKR_SRC_CLKX, /* CLKR from CLKX pin */ + OMAP_MCBSP_FSR_SRC_FSR, /* FSR from FSR pin */ + OMAP_MCBSP_FSR_SRC_FSX, /* FSR from FSX pin */ }; /* McBSP dividers */ -- cgit v1.2.3