ASoC: DaVinci: McASP FIFO related updates
[pandora-kernel.git] / sound / soc / davinci / davinci-mcasp.c
index b27aab6..50ad051 100644 (file)
 /* Receive Buffer for Serializer n */
 #define DAVINCI_MCASP_RXBUF_REG                0x280
 
+/* McASP FIFO Registers */
+#define DAVINCI_MCASP_WFIFOCTL         (0x1010)
+#define DAVINCI_MCASP_WFIFOSTS         (0x1014)
+#define DAVINCI_MCASP_RFIFOCTL         (0x1018)
+#define DAVINCI_MCASP_RFIFOSTS         (0x101C)
 
 /*
  * DAVINCI_MCASP_PWREMUMGT_REG - Power Down and Emulation Management
  */
 #define TXDATADMADIS   BIT(0)
 
+/*
+ * DAVINCI_MCASP_W[R]FIFOCTL - Write/Read FIFO Control Register bits
+ */
+#define FIFO_ENABLE    BIT(16)
+#define NUMEVT_MASK    (0xFF << 8)
+#define NUMDMA_MASK    (0xFF)
+
 #define DAVINCI_MCASP_NUM_SERIALIZER   16
 
 static inline void mcasp_set_bits(void __iomem *reg, u32 val)
@@ -320,14 +332,6 @@ static inline void mcasp_set_ctl_reg(void __iomem *regs, u32 val)
                printk(KERN_ERR "GBLCTL write error\n");
 }
 
-static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
-                                               struct snd_soc_dai *cpu_dai)
-{
-       struct davinci_audio_dev *dev = cpu_dai->private_data;
-       cpu_dai->dma_data = dev->dma_params[substream->stream];
-       return 0;
-}
-
 static void mcasp_start_rx(struct davinci_audio_dev *dev)
 {
        mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST);
@@ -345,6 +349,9 @@ static void mcasp_start_rx(struct davinci_audio_dev *dev)
 
 static void mcasp_start_tx(struct davinci_audio_dev *dev)
 {
+       u8 offset = 0, i;
+       u32 cnt;
+
        mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
        mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
        mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR);
@@ -353,15 +360,35 @@ static void mcasp_start_tx(struct davinci_audio_dev *dev)
        mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXSMRST);
        mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
        mcasp_set_reg(dev->base + DAVINCI_MCASP_TXBUF_REG, 0);
+       for (i = 0; i < dev->num_serializer; i++) {
+               if (dev->serial_dir[i] == TX_MODE) {
+                       offset = i;
+                       break;
+               }
+       }
+
+       /* wait for TX ready */
+       cnt = 0;
+       while (!(mcasp_get_reg(dev->base + DAVINCI_MCASP_XRSRCTL_REG(offset)) &
+                TXSTATE) && (cnt < 100000))
+               cnt++;
+
        mcasp_set_reg(dev->base + DAVINCI_MCASP_TXBUF_REG, 0);
 }
 
 static void davinci_mcasp_start(struct davinci_audio_dev *dev, int stream)
 {
-       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               if (dev->txnumevt)      /* enable FIFO */
+                       mcasp_set_bits(dev->base + DAVINCI_MCASP_WFIFOCTL,
+                                                               FIFO_ENABLE);
                mcasp_start_tx(dev);
-       else
+       } else {
+               if (dev->rxnumevt)      /* enable FIFO */
+                       mcasp_set_bits(dev->base + DAVINCI_MCASP_RFIFOCTL,
+                                                               FIFO_ENABLE);
                mcasp_start_rx(dev);
+       }
 }
 
 static void mcasp_stop_rx(struct davinci_audio_dev *dev)
@@ -378,10 +405,17 @@ static void mcasp_stop_tx(struct davinci_audio_dev *dev)
 
 static void davinci_mcasp_stop(struct davinci_audio_dev *dev, int stream)
 {
-       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               if (dev->txnumevt)      /* disable FIFO */
+                       mcasp_clr_bits(dev->base + DAVINCI_MCASP_WFIFOCTL,
+                                                               FIFO_ENABLE);
                mcasp_stop_tx(dev);
-       else
+       } else {
+               if (dev->rxnumevt)      /* disable FIFO */
+                       mcasp_clr_bits(dev->base + DAVINCI_MCASP_RFIFOCTL,
+                                                               FIFO_ENABLE);
                mcasp_stop_rx(dev);
+       }
 }
 
 static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
@@ -401,7 +435,16 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 
                mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, (0x7 << 26));
                break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               /* codec is clock master and frame slave */
+               mcasp_set_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
+               mcasp_set_bits(base + DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
+
+               mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
+               mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
 
+               mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, (0x2d << 26));
+               break;
        case SND_SOC_DAIFMT_CBM_CFM:
                /* codec is clock and frame master */
                mcasp_clr_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
@@ -461,34 +504,49 @@ static int davinci_config_channel_size(struct davinci_audio_dev *dev,
                                       int channel_size)
 {
        u32 fmt = 0;
+       u32 mask, rotate;
 
        switch (channel_size) {
        case DAVINCI_AUDIO_WORD_8:
                fmt = 0x03;
+               rotate = 6;
+               mask = 0x000000ff;
                break;
 
        case DAVINCI_AUDIO_WORD_12:
                fmt = 0x05;
+               rotate = 5;
+               mask = 0x00000fff;
                break;
 
        case DAVINCI_AUDIO_WORD_16:
                fmt = 0x07;
+               rotate = 4;
+               mask = 0x0000ffff;
                break;
 
        case DAVINCI_AUDIO_WORD_20:
                fmt = 0x09;
+               rotate = 3;
+               mask = 0x000fffff;
                break;
 
        case DAVINCI_AUDIO_WORD_24:
                fmt = 0x0B;
+               rotate = 2;
+               mask = 0x00ffffff;
                break;
 
        case DAVINCI_AUDIO_WORD_28:
                fmt = 0x0D;
+               rotate = 1;
+               mask = 0x0fffffff;
                break;
 
        case DAVINCI_AUDIO_WORD_32:
                fmt = 0x0F;
+               rotate = 0;
+               mask = 0xffffffff;
                break;
 
        default:
@@ -499,12 +557,21 @@ static int davinci_config_channel_size(struct davinci_audio_dev *dev,
                                        RXSSZ(fmt), RXSSZ(0x0F));
        mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
                                        TXSSZ(fmt), TXSSZ(0x0F));
+       mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, TXROT(rotate),
+                                                       TXROT(7));
+       mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, RXROT(rotate),
+                                                       RXROT(7));
+       mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, mask);
+       mcasp_set_reg(dev->base + DAVINCI_MCASP_RXMASK_REG, mask);
+
        return 0;
 }
 
 static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream)
 {
        int i;
+       u8 tx_ser = 0;
+       u8 rx_ser = 0;
 
        /* Default configuration */
        mcasp_set_bits(dev->base + DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
@@ -525,12 +592,37 @@ static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream)
        for (i = 0; i < dev->num_serializer; i++) {
                mcasp_set_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i),
                                        dev->serial_dir[i]);
-               if (dev->serial_dir[i] == TX_MODE)
+               if (dev->serial_dir[i] == TX_MODE) {
                        mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG,
                                        AXR(i));
-               else if (dev->serial_dir[i] == RX_MODE)
+                       tx_ser++;
+               } else if (dev->serial_dir[i] == RX_MODE) {
                        mcasp_clr_bits(dev->base + DAVINCI_MCASP_PDIR_REG,
                                        AXR(i));
+                       rx_ser++;
+               }
+       }
+
+       if (dev->txnumevt && stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               if (dev->txnumevt * tx_ser > 64)
+                       dev->txnumevt = 1;
+
+               mcasp_mod_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, tx_ser,
+                                                               NUMDMA_MASK);
+               mcasp_mod_bits(dev->base + DAVINCI_MCASP_WFIFOCTL,
+                               ((dev->txnumevt * tx_ser) << 8), NUMEVT_MASK);
+               mcasp_set_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, FIFO_ENABLE);
+       }
+
+       if (dev->rxnumevt && stream == SNDRV_PCM_STREAM_CAPTURE) {
+               if (dev->rxnumevt * rx_ser > 64)
+                       dev->rxnumevt = 1;
+
+               mcasp_mod_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, rx_ser,
+                                                               NUMDMA_MASK);
+               mcasp_mod_bits(dev->base + DAVINCI_MCASP_RFIFOCTL,
+                               ((dev->rxnumevt * rx_ser) << 8), NUMEVT_MASK);
+               mcasp_set_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, FIFO_ENABLE);
        }
 }
 
@@ -543,6 +635,8 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream)
        for (i = 0; i < active_slots; i++)
                mask |= (1 << i);
 
+       mcasp_clr_bits(dev->base + DAVINCI_MCASP_ACLKXCTL_REG, TX_ASYNC);
+
        if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
                /* bit stream is MSB first  with no delay */
                /* DSP_B mode */
@@ -558,7 +652,6 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream)
                        printk(KERN_ERR "playback tdm slot %d not supported\n",
                                dev->tdm_slots);
 
-               mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, 0xFFFFFFFF);
                mcasp_clr_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
        } else {
                /* bit stream is MSB first with no delay */
@@ -575,7 +668,6 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream)
                        printk(KERN_ERR "capture tdm slot %d not supported\n",
                                dev->tdm_slots);
 
-               mcasp_set_reg(dev->base + DAVINCI_MCASP_RXMASK_REG, 0xFFFFFFFF);
                mcasp_clr_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
        }
 }
@@ -620,10 +712,15 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
 {
        struct davinci_audio_dev *dev = cpu_dai->private_data;
        struct davinci_pcm_dma_params *dma_params =
-                                       dev->dma_params[substream->stream];
+                                       &dev->dma_params[substream->stream];
        int word_length;
+       u8 fifo_level;
 
        davinci_hw_common_param(dev, substream->stream);
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               fifo_level = dev->txnumevt;
+       else
+               fifo_level = dev->rxnumevt;
 
        if (dev->op_mode == DAVINCI_MCASP_DIT_MODE)
                davinci_hw_dit_param(dev);
@@ -650,6 +747,13 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
                printk(KERN_WARNING "davinci-mcasp: unsupported PCM format");
                return -EINVAL;
        }
+
+       if (dev->version == MCASP_VERSION_2 && !fifo_level)
+               dma_params->acnt = 4;
+       else
+               dma_params->acnt = dma_params->data_type;
+
+       dma_params->fifo_level = fifo_level;
        davinci_config_channel_size(dev, word_length);
 
        return 0;
@@ -683,7 +787,6 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
 }
 
 static struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
-       .startup        = davinci_mcasp_startup,
        .trigger        = davinci_mcasp_trigger,
        .hw_params      = davinci_mcasp_hw_params,
        .set_fmt        = davinci_mcasp_set_dai_fmt,
@@ -734,20 +837,12 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        struct resource *mem, *ioarea, *res;
        struct snd_platform_data *pdata;
        struct davinci_audio_dev *dev;
-       int count = 0;
        int ret = 0;
 
        dev = kzalloc(sizeof(struct davinci_audio_dev), GFP_KERNEL);
        if (!dev)
                return  -ENOMEM;
 
-       dma_data = kzalloc(sizeof(struct davinci_pcm_dma_params) * 2,
-                                                               GFP_KERNEL);
-       if (!dma_data) {
-               ret = -ENOMEM;
-               goto err_release_dev;
-       }
-
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!mem) {
                dev_err(&pdev->dev, "no mem resource?\n");
@@ -764,7 +859,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        }
 
        pdata = pdev->dev.platform_data;
-       dev->clk = clk_get(&pdev->dev, pdata->clk_name);
+       dev->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(dev->clk)) {
                ret = -ENODEV;
                goto err_release_region;
@@ -778,12 +873,14 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        dev->num_serializer = pdata->num_serializer;
        dev->serial_dir = pdata->serial_dir;
        dev->codec_fmt = pdata->codec_fmt;
+       dev->version = pdata->version;
+       dev->txnumevt = pdata->txnumevt;
+       dev->rxnumevt = pdata->rxnumevt;
 
-       dma_data[count].name = "I2S PCM Stereo out";
-       dma_data[count].eventq_no = pdata->eventq_no;
-       dma_data[count].dma_addr = (dma_addr_t) (pdata->tx_dma_offset +
+       dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
+       dma_data->eventq_no = pdata->eventq_no;
+       dma_data->dma_addr = (dma_addr_t) (pdata->tx_dma_offset +
                                                        io_v2p(dev->base));
-       dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK] = &dma_data[count];
 
        /* first TX, then RX */
        res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
@@ -792,13 +889,12 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
                goto err_release_region;
        }
 
-       dma_data[count].channel = res->start;
-       count++;
-       dma_data[count].name = "I2S PCM Stereo in";
-       dma_data[count].eventq_no = pdata->eventq_no;
-       dma_data[count].dma_addr = (dma_addr_t)(pdata->rx_dma_offset +
+       dma_data->channel = res->start;
+
+       dma_data = &dev->dma_params[SNDRV_PCM_STREAM_CAPTURE];
+       dma_data->eventq_no = pdata->eventq_no;
+       dma_data->dma_addr = (dma_addr_t)(pdata->rx_dma_offset +
                                                        io_v2p(dev->base));
-       dev->dma_params[SNDRV_PCM_STREAM_CAPTURE] = &dma_data[count];
 
        res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
        if (!res) {
@@ -806,10 +902,10 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
                goto err_release_region;
        }
 
-       dma_data[count].channel = res->start;
-       davinci_mcasp_dai[pdev->id].private_data = dev;
-       davinci_mcasp_dai[pdev->id].dev = &pdev->dev;
-       ret = snd_soc_register_dai(&davinci_mcasp_dai[pdev->id]);
+       dma_data->channel = res->start;
+       davinci_mcasp_dai[pdata->op_mode].private_data = dev;
+       davinci_mcasp_dai[pdata->op_mode].dev = &pdev->dev;
+       ret = snd_soc_register_dai(&davinci_mcasp_dai[pdata->op_mode]);
 
        if (ret != 0)
                goto err_release_region;
@@ -818,8 +914,6 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 err_release_region:
        release_mem_region(mem->start, (mem->end - mem->start) + 1);
 err_release_data:
-       kfree(dma_data);
-err_release_dev:
        kfree(dev);
 
        return ret;
@@ -827,12 +921,12 @@ err_release_dev:
 
 static int davinci_mcasp_remove(struct platform_device *pdev)
 {
-       struct davinci_pcm_dma_params *dma_data;
+       struct snd_platform_data *pdata = pdev->dev.platform_data;
        struct davinci_audio_dev *dev;
        struct resource *mem;
 
-       snd_soc_unregister_dai(&davinci_mcasp_dai[pdev->id]);
-       dev = davinci_mcasp_dai[pdev->id].private_data;
+       snd_soc_unregister_dai(&davinci_mcasp_dai[pdata->op_mode]);
+       dev = davinci_mcasp_dai[pdata->op_mode].private_data;
        clk_disable(dev->clk);
        clk_put(dev->clk);
        dev->clk = NULL;
@@ -840,8 +934,6 @@ static int davinci_mcasp_remove(struct platform_device *pdev)
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        release_mem_region(mem->start, (mem->end - mem->start) + 1);
 
-       dma_data = dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
-       kfree(dma_data);
        kfree(dev);
 
        return 0;