ASoC: DaVinci: Add a DAI format to McASP driver
[pandora-kernel.git] / sound / soc / davinci / davinci-mcasp.c
index f0c0347..eca22d7 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)
@@ -345,6 +357,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,6 +368,19 @@ 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);
 }
 
@@ -362,6 +390,13 @@ static void davinci_mcasp_start(struct davinci_audio_dev *dev, int stream)
                mcasp_start_tx(dev);
        else
                mcasp_start_rx(dev);
+
+       /* enable FIFO */
+       if (dev->txnumevt)
+               mcasp_set_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, FIFO_ENABLE);
+
+       if (dev->rxnumevt)
+               mcasp_set_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, FIFO_ENABLE);
 }
 
 static void mcasp_stop_rx(struct davinci_audio_dev *dev)
@@ -382,6 +417,13 @@ static void davinci_mcasp_stop(struct davinci_audio_dev *dev, int stream)
                mcasp_stop_tx(dev);
        else
                mcasp_stop_rx(dev);
+
+       /* disable FIFO */
+       if (dev->txnumevt)
+               mcasp_clr_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, FIFO_ENABLE);
+
+       if (dev->rxnumevt)
+               mcasp_clr_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, FIFO_ENABLE);
 }
 
 static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
@@ -401,7 +443,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);
@@ -505,6 +556,8 @@ static int davinci_config_channel_size(struct davinci_audio_dev *dev,
 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 +578,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 +621,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 */
@@ -622,8 +702,16 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
        struct davinci_pcm_dma_params *dma_params =
                                        dev->dma_params[substream->stream];
        int word_length;
+       u8 numevt;
 
        davinci_hw_common_param(dev, substream->stream);
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               numevt = dev->txnumevt;
+       else
+               numevt = dev->rxnumevt;
+
+       if (!numevt)
+               numevt = 1;
 
        if (dev->op_mode == DAVINCI_MCASP_DIT_MODE)
                davinci_hw_dit_param(dev);
@@ -650,6 +738,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) {
+               dma_params->data_type *= numevt;
+               dma_params->acnt = 4 * numevt;
+       } else
+               dma_params->acnt = dma_params->data_type;
+
        davinci_config_channel_size(dev, word_length);
 
        return 0;
@@ -778,6 +873,9 @@ 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;
@@ -807,9 +905,9 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        }
 
        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]);
+       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;
@@ -827,12 +925,13 @@ err_release_dev:
 
 static int davinci_mcasp_remove(struct platform_device *pdev)
 {
+       struct snd_platform_data *pdata = pdev->dev.platform_data;
        struct davinci_pcm_dma_params *dma_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;