Merge branch 'for-2.6.30' into for-2.6.31
[pandora-kernel.git] / sound / soc / omap / omap-mcbsp.c
index d6882be..495192a 100644 (file)
@@ -3,7 +3,8 @@
  *
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Jarkko Nikula <jarkko.nikula@nokia.com>
+ * Contact: Jarkko Nikula <jhnikula@gmail.com>
+ *          Peter Ujfalusi <peter.ujfalusi@nokia.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -146,6 +147,17 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
        struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
        int err = 0;
 
+       if (cpu_is_omap343x() && mcbsp_data->bus_id == 1) {
+               /*
+                * 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 (!cpu_dai->active)
                err = omap_mcbsp_request(mcbsp_data->bus_id);
 
@@ -203,8 +215,9 @@ 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;
+       int wlen, channels, wpf;
        unsigned long port;
+       unsigned int format;
 
        if (cpu_class_is_omap1()) {
                dma = omap1_dma_reqs[bus_id][substream->stream];
@@ -232,18 +245,23 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
                return 0;
        }
 
-       channels = params_channels(params);
+       format = mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+       wpf = channels = params_channels(params);
        switch (channels) {
        case 2:
-               /* Use dual-phase frames */
-               regs->rcr2      |= RPHASE;
-               regs->xcr2      |= XPHASE;
+               if (format == SND_SOC_DAIFMT_I2S) {
+                       /* Use dual-phase frames */
+                       regs->rcr2      |= RPHASE;
+                       regs->xcr2      |= XPHASE;
+                       /* Set 1 word per (McBSP) frame for phase1 and phase2 */
+                       wpf--;
+                       regs->rcr2      |= RFRLEN2(wpf - 1);
+                       regs->xcr2      |= XFRLEN2(wpf - 1);
+               }
        case 1:
-               /* Set 1 word per (McBSP) frame */
-               regs->rcr2      |= RFRLEN2(1 - 1);
-               regs->rcr1      |= RFRLEN1(1 - 1);
-               regs->xcr2      |= XFRLEN2(1 - 1);
-               regs->xcr1      |= XFRLEN1(1 - 1);
+               /* Set word per (McBSP) frame for phase1 */
+               regs->rcr1      |= RFRLEN1(wpf - 1);
+               regs->xcr1      |= XFRLEN1(wpf - 1);
                break;
        default:
                /* Unsupported number of channels */
@@ -265,14 +283,15 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
        }
 
        /* Set FS period and length in terms of bit clock periods */
-       switch (mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       switch (format) {
        case SND_SOC_DAIFMT_I2S:
-               regs->srgr2     |= FPER(wlen * 2 - 1);
+               regs->srgr2     |= FPER(wlen * channels - 1);
                regs->srgr1     |= FWID(wlen - 1);
                break;
+       case SND_SOC_DAIFMT_DSP_A:
        case SND_SOC_DAIFMT_DSP_B:
                regs->srgr2     |= FPER(wlen * channels - 1);
-               regs->srgr1     |= FWID(wlen * channels - 2);
+               regs->srgr1     |= FWID(0);
                break;
        }
 
@@ -291,6 +310,7 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 {
        struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
        struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
+       unsigned int temp_fmt = fmt;
 
        if (mcbsp_data->configured)
                return 0;
@@ -313,10 +333,19 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                regs->rcr2      |= RDATDLY(1);
                regs->xcr2      |= XDATDLY(1);
                break;
+       case SND_SOC_DAIFMT_DSP_A:
+               /* 1-bit data delay */
+               regs->rcr2      |= RDATDLY(1);
+               regs->xcr2      |= XDATDLY(1);
+               /* Invert FS polarity configuration */
+               temp_fmt ^= SND_SOC_DAIFMT_NB_IF;
+               break;
        case SND_SOC_DAIFMT_DSP_B:
                /* 0-bit data delay */
                regs->rcr2      |= RDATDLY(0);
                regs->xcr2      |= XDATDLY(0);
+               /* Invert FS polarity configuration */
+               temp_fmt ^= SND_SOC_DAIFMT_NB_IF;
                break;
        default:
                /* Unsupported data format */
@@ -340,7 +369,7 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
        }
 
        /* Set bit clock (CLKX/CLKR) and FS polarities */
-       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       switch (temp_fmt & SND_SOC_DAIFMT_INV_MASK) {
        case SND_SOC_DAIFMT_NB_NF:
                /*
                 * Normal BCLK + FS.
@@ -518,6 +547,6 @@ static void __exit snd_omap_mcbsp_exit(void)
 }
 module_exit(snd_omap_mcbsp_exit);
 
-MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>");
+MODULE_AUTHOR("Jarkko Nikula <jhnikula@gmail.com>");
 MODULE_DESCRIPTION("OMAP I2S SoC Interface");
 MODULE_LICENSE("GPL");