Merge branch 'for-2.6.39' into for-2.6.40
[firefly-linux-kernel-4.4.55.git] / sound / soc / blackfin / bf5xx-tdm.c
index 5515ac9e05c70bca470a3f2fe913747cb95fe16f..a822d1ee1380057db79148c265785e933616d1b2 100644 (file)
 #include "bf5xx-sport.h"
 #include "bf5xx-tdm.h"
 
-static struct bf5xx_tdm_port bf5xx_tdm;
-static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
-
-static struct sport_param sport_params[2] = {
-       {
-               .dma_rx_chan    = CH_SPORT0_RX,
-               .dma_tx_chan    = CH_SPORT0_TX,
-               .err_irq        = IRQ_SPORT0_ERROR,
-               .regs           = (struct sport_register *)SPORT0_TCR1,
-       },
-       {
-               .dma_rx_chan    = CH_SPORT1_RX,
-               .dma_tx_chan    = CH_SPORT1_TX,
-               .err_irq        = IRQ_SPORT1_ERROR,
-               .regs           = (struct sport_register *)SPORT1_TCR1,
-       }
-};
-
-/*
- * Setting the TFS pin selector for SPORT 0 based on whether the selected
- * port id F or G. If the port is F then no conflict should exist for the
- * TFS. When Port G is selected and EMAC then there is a conflict between
- * the PHY interrupt line and TFS.  Current settings prevent the conflict
- * by ignoring the TFS pin when Port G is selected. This allows both
- * codecs and EMAC using Port G concurrently.
- */
-#ifdef CONFIG_BF527_SPORT0_PORTG
-#define LOCAL_SPORT0_TFS (0)
-#else
-#define LOCAL_SPORT0_TFS (P_SPORT0_TFS)
-#endif
-
-static u16 sport_req[][7] = { {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
-       P_SPORT0_DRPRI, P_SPORT0_RSCLK, LOCAL_SPORT0_TFS, 0},
-          {P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, P_SPORT1_DRPRI,
-                  P_SPORT1_RSCLK, P_SPORT1_TFS, 0} };
-
 static int bf5xx_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai,
        unsigned int fmt)
 {
@@ -119,14 +82,16 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params,
        struct snd_soc_dai *dai)
 {
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+       struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
        int ret = 0;
 
-       bf5xx_tdm.tcr2 &= ~0x1f;
-       bf5xx_tdm.rcr2 &= ~0x1f;
+       bf5xx_tdm->tcr2 &= ~0x1f;
+       bf5xx_tdm->rcr2 &= ~0x1f;
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S32_LE:
-               bf5xx_tdm.tcr2 |= 31;
-               bf5xx_tdm.rcr2 |= 31;
+               bf5xx_tdm->tcr2 |= 31;
+               bf5xx_tdm->rcr2 |= 31;
                sport_handle->wdsize = 4;
                break;
                /* at present, we only support 32bit transfer */
@@ -136,7 +101,7 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
                break;
        }
 
-       if (!bf5xx_tdm.configured) {
+       if (!bf5xx_tdm->configured) {
                /*
                 * TX and RX are not independent,they are enabled at the
                 * same time, even if only one side is running. So, we
@@ -145,21 +110,21 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
                 *
                 * CPU DAI:slave mode.
                 */
-               ret = sport_config_rx(sport_handle, bf5xx_tdm.rcr1,
-                       bf5xx_tdm.rcr2, 0, 0);
+               ret = sport_config_rx(sport_handle, bf5xx_tdm->rcr1,
+                       bf5xx_tdm->rcr2, 0, 0);
                if (ret) {
                        pr_err("SPORT is busy!\n");
                        return -EBUSY;
                }
 
-               ret = sport_config_tx(sport_handle, bf5xx_tdm.tcr1,
-                       bf5xx_tdm.tcr2, 0, 0);
+               ret = sport_config_tx(sport_handle, bf5xx_tdm->tcr1,
+                       bf5xx_tdm->tcr2, 0, 0);
                if (ret) {
                        pr_err("SPORT is busy!\n");
                        return -EBUSY;
                }
 
-               bf5xx_tdm.configured = 1;
+               bf5xx_tdm->configured = 1;
        }
 
        return 0;
@@ -168,15 +133,20 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
 static void bf5xx_tdm_shutdown(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+       struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
+
        /* No active stream, SPORT is allowed to be configured again. */
        if (!dai->active)
-               bf5xx_tdm.configured = 0;
+               bf5xx_tdm->configured = 0;
 }
 
 static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
                unsigned int tx_num, unsigned int *tx_slot,
                unsigned int rx_num, unsigned int *rx_slot)
 {
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+       struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
        int i;
        unsigned int slot;
        unsigned int tx_mapped = 0, rx_mapped = 0;
@@ -189,7 +159,7 @@ static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
                slot = tx_slot[i];
                if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
                                (!(tx_mapped & (1 << slot)))) {
-                       bf5xx_tdm.tx_map[i] = slot;
+                       bf5xx_tdm->tx_map[i] = slot;
                        tx_mapped |= 1 << slot;
                } else
                        return -EINVAL;
@@ -198,7 +168,7 @@ static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
                slot = rx_slot[i];
                if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
                                (!(rx_mapped & (1 << slot)))) {
-                       bf5xx_tdm.rx_map[i] = slot;
+                       bf5xx_tdm->rx_map[i] = slot;
                        rx_mapped |= 1 << slot;
                } else
                        return -EINVAL;
@@ -212,12 +182,14 @@ static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
 {
        struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 
-       if (!dai->active)
-               return 0;
-       if (dai->capture_active)
-               sport_rx_stop(sport);
        if (dai->playback_active)
                sport_tx_stop(sport);
+       if (dai->capture_active)
+               sport_rx_stop(sport);
+
+       /* isolate sync/clock pins from codec while sports resume */
+       peripheral_free_list(sport->pin_req);
+
        return 0;
 }
 
@@ -226,9 +198,6 @@ static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
        int ret;
        struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 
-       if (!dai->active)
-               return 0;
-
        ret = sport_set_multichannel(sport, 8, 0xFF, 1);
        if (ret) {
                pr_err("SPORT is busy!\n");
@@ -247,6 +216,8 @@ static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
                ret = -EBUSY;
        }
 
+       peripheral_request_list(sport->pin_req, "soc-audio");
+
        return 0;
 }
 
@@ -280,20 +251,14 @@ static struct snd_soc_dai_driver bf5xx_tdm_dai = {
 
 static int __devinit bfin_tdm_probe(struct platform_device *pdev)
 {
-       int ret = 0;
-
-       if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
-               pr_err("Requesting Peripherals failed\n");
-               return -EFAULT;
-       }
+       struct sport_device *sport_handle;
+       int ret;
 
-       /* request DMA for SPORT */
-       sport_handle = sport_init(&sport_params[sport_num], 4, \
-               8 * sizeof(u32), NULL);
-       if (!sport_handle) {
-               peripheral_free_list(&sport_req[sport_num][0]);
+       /* configure SPORT for TDM */
+       sport_handle = sport_init(pdev, 4, 8 * sizeof(u32),
+               sizeof(struct bf5xx_tdm_port));
+       if (!sport_handle)
                return -ENODEV;
-       }
 
        /* SPORT works in TDM mode */
        ret = sport_set_multichannel(sport_handle, 8, 0xFF, 1);
@@ -323,18 +288,19 @@ static int __devinit bfin_tdm_probe(struct platform_device *pdev)
                goto sport_config_err;
        }
 
-       sport_handle->private_data = &bf5xx_tdm;
        return 0;
 
 sport_config_err:
-       peripheral_free_list(&sport_req[sport_num][0]);
+       sport_done(sport_handle);
        return ret;
 }
 
 static int __devexit bfin_tdm_remove(struct platform_device *pdev)
 {
-       peripheral_free_list(&sport_req[sport_num][0]);
+       struct sport_device *sport_handle = platform_get_drvdata(pdev);
+
        snd_soc_unregister_dai(&pdev->dev);
+       sport_done(sport_handle);
 
        return 0;
 }