ASoC: OMAP: Fix setup of XCCR and RCCR registers in McBSP DAI
[cascardo/linux.git] / sound / soc / omap / omap-mcbsp.c
index a5d46a7..89e8bce 100644 (file)
@@ -139,27 +139,67 @@ 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 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)
+               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 dma_op_mode = omap_mcbsp_get_dma_op_mode(bus_id);
+               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.
                 */
-               snd_pcm_hw_constraint_minmax(substream->runtime,
-                       SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 4096, UINT_MAX);
-       }
+               if (bus_id == 1)
+                       snd_pcm_hw_constraint_minmax(substream->runtime,
+                                       SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+                                       4096, UINT_MAX);
 
-       if (!cpu_dai->active)
-               err = omap_mcbsp_request(mcbsp_data->bus_id);
+               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;
+
+               if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
+                       snd_pcm_hw_constraint_minmax(substream->runtime,
+                                               SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+                                               32, max_period);
+       }
 
        return err;
 }
@@ -183,21 +223,26 @@ 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);
+               /* 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:
        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;
@@ -215,7 +260,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;
 
@@ -231,6 +276,12 @@ 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;
+               /* 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;
        }
@@ -238,6 +289,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) {
@@ -321,11 +373,14 @@ 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;
+               regs->xccr = DXENDLY(1) | XDMAEN | XDISABLE;
+               regs->rccr = RFULL_CYCLE | RDMAEN | RDISABLE;
        }
 
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {