]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - sound/soc/omap/omap-mcbsp.c
Merge branch 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm
[linux-2.6-omap-h63xx.git] / sound / soc / omap / omap-mcbsp.c
index d32eb4703cfe533ee6b21a05fc5536084421b665..8485a8a9d0ff0e89687eb73a62755d064c8177e6 100644 (file)
@@ -43,6 +43,7 @@
 struct omap_mcbsp_data {
        unsigned int                    bus_id;
        struct omap_mcbsp_reg_cfg       regs;
+       unsigned int                    fmt;
        /*
         * Flags indicating is the bus already activated and configured by
         * another substream
@@ -59,12 +60,7 @@ static struct omap_mcbsp_data mcbsp_data[NUM_LINKS];
  * Stream DMA parameters. DMA request line and port address are set runtime
  * since they are different between OMAP1 and later OMAPs
  */
-static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2] = {
-{
-       { .name         = "I2S PCM Stereo out", },
-       { .name         = "I2S PCM Stereo in", },
-},
-};
+static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2];
 
 #if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
 static const int omap1_dma_reqs[][2] = {
@@ -84,11 +80,22 @@ static const unsigned long omap1_mcbsp_port[][2] = {
 static const int omap1_dma_reqs[][2] = {};
 static const unsigned long omap1_mcbsp_port[][2] = {};
 #endif
-#if defined(CONFIG_ARCH_OMAP2420)
-static const int omap2420_dma_reqs[][2] = {
+
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+static const int omap24xx_dma_reqs[][2] = {
        { OMAP24XX_DMA_MCBSP1_TX, OMAP24XX_DMA_MCBSP1_RX },
        { OMAP24XX_DMA_MCBSP2_TX, OMAP24XX_DMA_MCBSP2_RX },
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
+       { OMAP24XX_DMA_MCBSP3_TX, OMAP24XX_DMA_MCBSP3_RX },
+       { OMAP24XX_DMA_MCBSP4_TX, OMAP24XX_DMA_MCBSP4_RX },
+       { OMAP24XX_DMA_MCBSP5_TX, OMAP24XX_DMA_MCBSP5_RX },
+#endif
 };
+#else
+static const int omap24xx_dma_reqs[][2] = {};
+#endif
+
+#if defined(CONFIG_ARCH_OMAP2420)
 static const unsigned long omap2420_mcbsp_port[][2] = {
        { OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1,
          OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1 },
@@ -96,10 +103,43 @@ static const unsigned long omap2420_mcbsp_port[][2] = {
          OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1 },
 };
 #else
-static const int omap2420_dma_reqs[][2] = {};
 static const unsigned long omap2420_mcbsp_port[][2] = {};
 #endif
 
+#if defined(CONFIG_ARCH_OMAP2430)
+static const unsigned long omap2430_mcbsp_port[][2] = {
+       { OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DRR },
+};
+#else
+static const unsigned long omap2430_mcbsp_port[][2] = {};
+#endif
+
+#if defined(CONFIG_ARCH_OMAP34XX)
+static const unsigned long omap34xx_mcbsp_port[][2] = {
+       { OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DRR },
+};
+#else
+static const unsigned long omap34xx_mcbsp_port[][2] = {};
+#endif
+
 static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -161,20 +201,26 @@ 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;
        unsigned long port;
 
        if (cpu_class_is_omap1()) {
                dma = omap1_dma_reqs[bus_id][substream->stream];
                port = omap1_mcbsp_port[bus_id][substream->stream];
        } else if (cpu_is_omap2420()) {
-               dma = omap2420_dma_reqs[bus_id][substream->stream];
+               dma = omap24xx_dma_reqs[bus_id][substream->stream];
                port = omap2420_mcbsp_port[bus_id][substream->stream];
+       } else if (cpu_is_omap2430()) {
+               dma = omap24xx_dma_reqs[bus_id][substream->stream];
+               port = omap2430_mcbsp_port[bus_id][substream->stream];
+       } else if (cpu_is_omap343x()) {
+               dma = omap24xx_dma_reqs[bus_id][substream->stream];
+               port = omap34xx_mcbsp_port[bus_id][substream->stream];
        } else {
-               /*
-                * TODO: Add support for 2430 and 3430
-                */
                return -ENODEV;
        }
+       omap_mcbsp_dai_dma_params[id][substream->stream].name =
+               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;
        cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream];
@@ -200,19 +246,29 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
                /* Set word lengths */
+               wlen = 16;
                regs->rcr2      |= RWDLEN2(OMAP_MCBSP_WORD_16);
                regs->rcr1      |= RWDLEN1(OMAP_MCBSP_WORD_16);
                regs->xcr2      |= XWDLEN2(OMAP_MCBSP_WORD_16);
                regs->xcr1      |= XWDLEN1(OMAP_MCBSP_WORD_16);
-               /* Set FS period and length in terms of bit clock periods */
-               regs->srgr2     |= FPER(16 * 2 - 1);
-               regs->srgr1     |= FWID(16 - 1);
                break;
        default:
                /* Unsupported PCM format */
                return -EINVAL;
        }
 
+       /* Set FS period and length in terms of bit clock periods */
+       switch (mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               regs->srgr2     |= FPER(wlen * 2 - 1);
+               regs->srgr1     |= FWID(wlen - 1);
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               regs->srgr2     |= FPER(wlen * 2 - 1);
+               regs->srgr1     |= FWID(wlen * 2 - 2);
+               break;
+       }
+
        omap_mcbsp_config(bus_id, &mcbsp_data->regs);
        mcbsp_data->configured = 1;
 
@@ -232,6 +288,7 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
        if (mcbsp_data->configured)
                return 0;
 
+       mcbsp_data->fmt = fmt;
        memset(regs, 0, sizeof(*regs));
        /* Generic McBSP register settings */
        regs->spcr2     |= XINTM(3) | FREE;
@@ -315,7 +372,7 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
                                       int clk_id)
 {
        int sel_bit;
-       u16 reg;
+       u16 reg, reg_devconf1 = OMAP243X_CONTROL_DEVCONF1;
 
        if (cpu_class_is_omap1()) {
                /* OMAP1's can use only external source clock */
@@ -325,6 +382,12 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
                        return 0;
        }
 
+       if (cpu_is_omap2420() && mcbsp_data->bus_id > 1)
+               return -EINVAL;
+
+       if (cpu_is_omap343x())
+               reg_devconf1 = OMAP343X_CONTROL_DEVCONF1;
+
        switch (mcbsp_data->bus_id) {
        case 0:
                reg = OMAP2_CONTROL_DEVCONF0;
@@ -334,20 +397,26 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
                reg = OMAP2_CONTROL_DEVCONF0;
                sel_bit = 6;
                break;
-       /* TODO: Support for ports 3 - 5 in OMAP2430 and OMAP34xx */
+       case 2:
+               reg = reg_devconf1;
+               sel_bit = 0;
+               break;
+       case 3:
+               reg = reg_devconf1;
+               sel_bit = 2;
+               break;
+       case 4:
+               reg = reg_devconf1;
+               sel_bit = 4;
+               break;
        default:
                return -EINVAL;
        }
 
-       if (cpu_class_is_omap2()) {
-               if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK) {
-                       omap_ctrl_writel(omap_ctrl_readl(reg) &
-                                        ~(1 << sel_bit), reg);
-               } else {
-                       omap_ctrl_writel(omap_ctrl_readl(reg) |
-                                        (1 << sel_bit), reg);
-               }
-       }
+       if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK)
+               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;
 }