Merge tag 'sound-3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
[firefly-linux-kernel-4.4.55.git] / sound / soc / davinci / davinci-mcasp.c
index 9321e5c9d8c125b3d8894dda33df44d94b7068dc..56ecfc72f2e9500ebda81214d972b65f291cd518 100644 (file)
 #define DISMOD         (val)(val<<2)
 #define TXSTATE                BIT(4)
 #define RXSTATE                BIT(5)
+#define SRMOD_MASK     3
+#define SRMOD_INACTIVE 0
 
 /*
  * DAVINCI_MCASP_LBCTL_REG - Loop Back Control Register Bits
@@ -503,7 +505,10 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                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, ACLKX | AFSX);
+               mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG,
+                               ACLKX | ACLKR);
+               mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG,
+                               AFSX | AFSR);
                break;
        case SND_SOC_DAIFMT_CBM_CFS:
                /* codec is clock master and frame slave */
@@ -563,7 +568,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                mcasp_set_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
                mcasp_clr_bits(base + DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
 
-               mcasp_clr_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+               mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
                mcasp_clr_bits(base + DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
                break;
 
@@ -634,35 +639,43 @@ static int davinci_config_channel_size(struct davinci_audio_dev *dev,
         * callback, take it into account here. That allows us to for example
         * send 32 bits per channel to the codec, while only 16 of them carry
         * audio payload.
-        * The clock ratio is given for a full period of data (both left and
-        * right channels), so it has to be divided by 2.
+        * The clock ratio is given for a full period of data (for I2S format
+        * both left and right channels), so it has to be divided by number of
+        * tdm-slots (for I2S - divided by 2).
         */
        if (dev->bclk_lrclk_ratio)
-               word_length = dev->bclk_lrclk_ratio / 2;
+               word_length = dev->bclk_lrclk_ratio / dev->tdm_slots;
 
        /* mapping of the XSSZ bit-field as described in the datasheet */
        fmt = (word_length >> 1) - 1;
 
-       mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG,
-                                       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));
+       if (dev->op_mode != DAVINCI_MCASP_DIT_MODE) {
+               mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG,
+                               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_RXMASK_REG,
+                               mask);
+       }
+
        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)
+static int davinci_hw_common_param(struct davinci_audio_dev *dev, int stream,
+                                   int channels)
 {
        int i;
        u8 tx_ser = 0;
        u8 rx_ser = 0;
-
+       u8 ser;
+       u8 slots = dev->tdm_slots;
+       u8 max_active_serializers = (channels + slots - 1) / slots;
        /* Default configuration */
        mcasp_set_bits(dev->base + DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
 
@@ -682,17 +695,33 @@ 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 &&
+                                       tx_ser < max_active_serializers) {
                        mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG,
                                        AXR(i));
                        tx_ser++;
-               } else if (dev->serial_dir[i] == RX_MODE) {
+               } else if (dev->serial_dir[i] == RX_MODE &&
+                                       rx_ser < max_active_serializers) {
                        mcasp_clr_bits(dev->base + DAVINCI_MCASP_PDIR_REG,
                                        AXR(i));
                        rx_ser++;
+               } else {
+                       mcasp_mod_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i),
+                                       SRMOD_INACTIVE, SRMOD_MASK);
                }
        }
 
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+               ser = tx_ser;
+       else
+               ser = rx_ser;
+
+       if (ser < max_active_serializers) {
+               dev_warn(dev->dev, "stream has more channels (%d) than are "
+                       "enabled in mcasp (%d)\n", channels, ser * slots);
+               return -EINVAL;
+       }
+
        if (dev->txnumevt && stream == SNDRV_PCM_STREAM_PLAYBACK) {
                if (dev->txnumevt * tx_ser > 64)
                        dev->txnumevt = 1;
@@ -729,6 +758,8 @@ static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream)
                                ((dev->rxnumevt * rx_ser) << 8), NUMEVT_MASK);
                }
        }
+
+       return 0;
 }
 
 static void davinci_hw_param(struct davinci_audio_dev *dev, int stream)
@@ -772,12 +803,6 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream)
 /* S/PDIF */
 static void davinci_hw_dit_param(struct davinci_audio_dev *dev)
 {
-       /* Set the PDIR for Serialiser as output */
-       mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AFSX);
-
-       /* TXMASK for 24 bits */
-       mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, 0x00FFFFFF);
-
        /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0
           and LSB first */
        mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
@@ -812,12 +837,21 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
                                        &dev->dma_params[substream->stream];
        int word_length;
        u8 fifo_level;
+       u8 slots = dev->tdm_slots;
+       u8 active_serializers;
+       int channels;
+       struct snd_interval *pcm_channels = hw_param_interval(params,
+                                       SNDRV_PCM_HW_PARAM_CHANNELS);
+       channels = pcm_channels->min;
+
+       active_serializers = (channels + slots - 1) / slots;
 
-       davinci_hw_common_param(dev, substream->stream);
+       if (davinci_hw_common_param(dev, substream->stream, channels) == -EINVAL)
+               return -EINVAL;
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               fifo_level = dev->txnumevt;
+               fifo_level = dev->txnumevt * active_serializers;
        else
-               fifo_level = dev->rxnumevt;
+               fifo_level = dev->rxnumevt * active_serializers;
 
        if (dev->op_mode == DAVINCI_MCASP_DIT_MODE)
                davinci_hw_dit_param(dev);
@@ -936,13 +970,13 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
                .name           = "davinci-mcasp.0",
                .playback       = {
                        .channels_min   = 2,
-                       .channels_max   = 2,
+                       .channels_max   = 32 * 16,
                        .rates          = DAVINCI_MCASP_RATES,
                        .formats        = DAVINCI_MCASP_PCM_FMTS,
                },
                .capture        = {
                        .channels_min   = 2,
-                       .channels_max   = 2,
+                       .channels_max   = 32 * 16,
                        .rates          = DAVINCI_MCASP_RATES,
                        .formats        = DAVINCI_MCASP_PCM_FMTS,
                },
@@ -962,6 +996,10 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
 
 };
 
+static const struct snd_soc_component_driver davinci_mcasp_component = {
+       .name           = "davinci-mcasp",
+};
+
 static const struct of_device_id mcasp_dt_ids[] = {
        {
                .compatible = "ti,dm646x-mcasp-audio",
@@ -1015,8 +1053,16 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
                pdata->op_mode = val;
 
        ret = of_property_read_u32(np, "tdm-slots", &val);
-       if (ret >= 0)
+       if (ret >= 0) {
+               if (val < 2 || val > 32) {
+                       dev_err(&pdev->dev,
+                               "tdm-slots must be in rage [2-32]\n");
+                       ret = -EINVAL;
+                       goto nodata;
+               }
+
                pdata->tdm_slots = val;
+       }
 
        ret = of_property_read_u32(np, "num-serializer", &val);
        if (ret >= 0)
@@ -1170,7 +1216,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 
        dma_data->channel = res->start;
        dev_set_drvdata(&pdev->dev, dev);
-       ret = snd_soc_register_dai(&pdev->dev, &davinci_mcasp_dai[pdata->op_mode]);
+       ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component,
+                                        &davinci_mcasp_dai[pdata->op_mode], 1);
 
        if (ret != 0)
                goto err_release_clk;
@@ -1178,13 +1225,13 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        ret = davinci_soc_platform_register(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
-               goto err_unregister_dai;
+               goto err_unregister_component;
        }
 
        return 0;
 
-err_unregister_dai:
-       snd_soc_unregister_dai(&pdev->dev);
+err_unregister_component:
+       snd_soc_unregister_component(&pdev->dev);
 err_release_clk:
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
@@ -1194,7 +1241,7 @@ err_release_clk:
 static int davinci_mcasp_remove(struct platform_device *pdev)
 {
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        davinci_soc_platform_unregister(&pdev->dev);
 
        pm_runtime_put_sync(&pdev->dev);