Merge tag 'sound-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / sound / soc / omap / omap-mcbsp.c
index 1b18627763cede8ba823b90d93fc127f105758dd..a6ee157478593f1e5eb338e51597df176308a953 100644 (file)
@@ -26,6 +26,8 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -33,7 +35,6 @@
 #include <sound/soc.h>
 
 #include <plat/cpu.h>
-#include <plat/dma.h>
 #include <linux/platform_data/asoc-ti-mcbsp.h>
 #include "mcbsp.h"
 #include "omap-mcbsp.h"
@@ -80,9 +81,6 @@ static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
         */
        if (dma_data->packet_size)
                words = dma_data->packet_size;
-       else if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
-               words = snd_pcm_lib_period_bytes(substream) /
-                                               (mcbsp->wlen / 8);
        else
                words = 1;
 
@@ -154,6 +152,9 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
                                           SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2);
        }
 
+       snd_soc_dai_set_dma_data(cpu_dai, substream,
+                                &mcbsp->dma_data[substream->stream]);
+
        return err;
 }
 
@@ -227,20 +228,18 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
        struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
        struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
        struct omap_pcm_dma_data *dma_data;
-       int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT;
+       int wlen, channels, wpf;
        int pkt_size = 0;
        unsigned int format, div, framesize, master;
 
-       dma_data = &mcbsp->dma_data[substream->stream];
+       dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
        channels = params_channels(params);
 
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
-               dma_data->data_type = OMAP_DMA_DATA_TYPE_S16;
                wlen = 16;
                break;
        case SNDRV_PCM_FORMAT_S32_LE:
-               dma_data->data_type = OMAP_DMA_DATA_TYPE_S32;
                wlen = 32;
                break;
        default:
@@ -250,6 +249,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
                dma_data->set_threshold = omap_mcbsp_set_threshold;
                if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) {
                        int period_words, max_thrsh;
+                       int divider = 0;
 
                        period_words = params_period_bytes(params) / (wlen / 8);
                        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -257,46 +257,30 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
                        else
                                max_thrsh = mcbsp->max_rx_thres;
                        /*
-                        * If the period contains less or equal number of words,
-                        * we are using the original threshold mode setup:
-                        * McBSP threshold = sDMA frame size = period_size
-                        * Otherwise we switch to sDMA packet mode:
-                        * McBSP threshold = sDMA packet size
-                        * sDMA frame size = period size
+                        * Use sDMA packet mode if McBSP is in threshold mode:
+                        * If period words less than the FIFO size the packet
+                        * size is set to the number of period words, otherwise
+                        * Look for the biggest threshold value which divides
+                        * the period size evenly.
                         */
-                       if (period_words > max_thrsh) {
-                               int divider = 0;
-
-                               /*
-                                * Look for the biggest threshold value, which
-                                * divides the period size evenly.
-                                */
-                               divider = period_words / max_thrsh;
-                               if (period_words % max_thrsh)
-                                       divider++;
-                               while (period_words % divider &&
-                                       divider < period_words)
-                                       divider++;
-                               if (divider == period_words)
-                                       return -EINVAL;
-
-                               pkt_size = period_words / divider;
-                               sync_mode = OMAP_DMA_SYNC_PACKET;
-                       } else {
-                               sync_mode = OMAP_DMA_SYNC_FRAME;
-                       }
+                       divider = period_words / max_thrsh;
+                       if (period_words % max_thrsh)
+                               divider++;
+                       while (period_words % divider &&
+                               divider < period_words)
+                               divider++;
+                       if (divider == period_words)
+                               return -EINVAL;
+
+                       pkt_size = period_words / divider;
                } else if (channels > 1) {
                        /* Use packet mode for non mono streams */
                        pkt_size = channels;
-                       sync_mode = OMAP_DMA_SYNC_PACKET;
                }
        }
 
-       dma_data->sync_mode = sync_mode;
        dma_data->packet_size = pkt_size;
 
-       snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
-
        if (mcbsp->configured) {
                /* McBSP already configured by another stream */
                return 0;
@@ -399,12 +383,14 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
        /* Generic McBSP register settings */
        regs->spcr2     |= XINTM(3) | FREE;
        regs->spcr1     |= RINTM(3);
-       /* RFIG and XFIG are not defined in 34xx */
-       if (!cpu_is_omap34xx() && !cpu_is_omap44xx()) {
+       /* RFIG and XFIG are not defined in 2430 and on OMAP3+ */
+       if (!mcbsp->pdata->has_ccr) {
                regs->rcr2      |= RFIG;
                regs->xcr2      |= XFIG;
        }
-       if (cpu_is_omap2430() || cpu_is_omap34xx() || cpu_is_omap44xx()) {
+
+       /* Configure XCCR/RCCR only for revisions which have ccr registers */
+       if (mcbsp->pdata->has_ccr) {
                regs->xccr = DXENDLY(1) | XDMAEN | XDISABLE;
                regs->rccr = RFULL_CYCLE | RDMAEN | RDISABLE;
        }
@@ -517,21 +503,9 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
                        return -EBUSY;
        }
 
-       if (clk_id == OMAP_MCBSP_SYSCLK_CLK ||
-           clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK ||
-           clk_id == OMAP_MCBSP_SYSCLK_CLKS_EXT ||
-           clk_id == OMAP_MCBSP_SYSCLK_CLKX_EXT ||
-           clk_id == OMAP_MCBSP_SYSCLK_CLKR_EXT) {
-               mcbsp->in_freq = freq;
-               regs->srgr2     &= ~CLKSM;
-               regs->pcr0      &= ~SCLKME;
-       } else if (cpu_class_is_omap1()) {
-               /*
-                * McBSP CLKR/FSR signal muxing functions are only available on
-                * OMAP2 or newer versions
-                */
-               return -EINVAL;
-       }
+       mcbsp->in_freq = freq;
+       regs->srgr2 &= ~CLKSM;
+       regs->pcr0 &= ~SCLKME;
 
        switch (clk_id) {
        case OMAP_MCBSP_SYSCLK_CLK:
@@ -559,20 +533,6 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
        case OMAP_MCBSP_SYSCLK_CLKR_EXT:
                regs->pcr0      |= SCLKME;
                break;
-
-
-       case OMAP_MCBSP_CLKR_SRC_CLKR:
-               err = omap_mcbsp_6pin_src_mux(mcbsp, CLKR_SRC_CLKR);
-               break;
-       case OMAP_MCBSP_CLKR_SRC_CLKX:
-               err = omap_mcbsp_6pin_src_mux(mcbsp, CLKR_SRC_CLKX);
-               break;
-       case OMAP_MCBSP_FSR_SRC_FSR:
-               err = omap_mcbsp_6pin_src_mux(mcbsp, FSR_SRC_FSR);
-               break;
-       case OMAP_MCBSP_FSR_SRC_FSX:
-               err = omap_mcbsp_6pin_src_mux(mcbsp, FSR_SRC_FSX);
-               break;
        default:
                err = -ENODEV;
        }
@@ -642,9 +602,9 @@ static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-#define OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(channel)                      \
+#define OMAP_MCBSP_ST_CHANNEL_VOLUME(channel)                          \
 static int                                                             \
-omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc,        \
+omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc,                \
                                        struct snd_ctl_elem_value *uc)  \
 {                                                                      \
        struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc);            \
@@ -660,11 +620,10 @@ omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc,   \
                                                                        \
        /* OMAP McBSP implementation uses index values 0..4 */          \
        return omap_st_set_chgain(mcbsp, channel, val);                 \
-}
-
-#define OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(channel)                      \
+}                                                                      \
+                                                                       \
 static int                                                             \
-omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc,        \
+omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc,                \
                                        struct snd_ctl_elem_value *uc)  \
 {                                                                      \
        struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc);            \
@@ -678,10 +637,8 @@ omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc,    \
        return 0;                                                       \
 }
 
-OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(0)
-OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(1)
-OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(0)
-OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(1)
+OMAP_MCBSP_ST_CHANNEL_VOLUME(0)
+OMAP_MCBSP_ST_CHANNEL_VOLUME(1)
 
 static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
@@ -711,41 +668,34 @@ static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-static const struct snd_kcontrol_new omap_mcbsp2_st_controls[] = {
-       SOC_SINGLE_EXT("McBSP2 Sidetone Switch", 1, 0, 1, 0,
-                       omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode),
-       OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 0 Volume",
-                                     -32768, 32767,
-                                     omap_mcbsp_get_st_ch0_volume,
-                                     omap_mcbsp_set_st_ch0_volume),
-       OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 1 Volume",
-                                     -32768, 32767,
-                                     omap_mcbsp_get_st_ch1_volume,
-                                     omap_mcbsp_set_st_ch1_volume),
-};
+#define OMAP_MCBSP_ST_CONTROLS(port)                                     \
+static const struct snd_kcontrol_new omap_mcbsp##port##_st_controls[] = { \
+SOC_SINGLE_EXT("McBSP" #port " Sidetone Switch", 1, 0, 1, 0,             \
+              omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode),           \
+OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 0 Volume", \
+                             -32768, 32767,                              \
+                             omap_mcbsp_get_st_ch0_volume,               \
+                             omap_mcbsp_set_st_ch0_volume),              \
+OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 1 Volume", \
+                             -32768, 32767,                              \
+                             omap_mcbsp_get_st_ch1_volume,               \
+                             omap_mcbsp_set_st_ch1_volume),              \
+}
 
-static const struct snd_kcontrol_new omap_mcbsp3_st_controls[] = {
-       SOC_SINGLE_EXT("McBSP3 Sidetone Switch", 2, 0, 1, 0,
-                       omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode),
-       OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 0 Volume",
-                                     -32768, 32767,
-                                     omap_mcbsp_get_st_ch0_volume,
-                                     omap_mcbsp_set_st_ch0_volume),
-       OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 1 Volume",
-                                     -32768, 32767,
-                                     omap_mcbsp_get_st_ch1_volume,
-                                     omap_mcbsp_set_st_ch1_volume),
-};
+OMAP_MCBSP_ST_CONTROLS(2);
+OMAP_MCBSP_ST_CONTROLS(3);
 
 int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
 
-       if (!mcbsp->st_data)
-               return -ENODEV;
+       if (!mcbsp->st_data) {
+               dev_warn(mcbsp->dev, "No sidetone data for port\n");
+               return 0;
+       }
 
-       switch (cpu_dai->id) {
+       switch (mcbsp->id) {
        case 2: /* McBSP 2 */
                return snd_soc_add_dai_controls(cpu_dai,
                                        omap_mcbsp2_st_controls,
@@ -762,13 +712,74 @@ int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd)
 }
 EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls);
 
+static struct omap_mcbsp_platform_data omap2420_pdata = {
+       .reg_step = 4,
+       .reg_size = 2,
+};
+
+static struct omap_mcbsp_platform_data omap2430_pdata = {
+       .reg_step = 4,
+       .reg_size = 4,
+       .has_ccr = true,
+};
+
+static struct omap_mcbsp_platform_data omap3_pdata = {
+       .reg_step = 4,
+       .reg_size = 4,
+       .has_ccr = true,
+       .has_wakeup = true,
+};
+
+static struct omap_mcbsp_platform_data omap4_pdata = {
+       .reg_step = 4,
+       .reg_size = 4,
+       .has_ccr = true,
+       .has_wakeup = true,
+};
+
+static const struct of_device_id omap_mcbsp_of_match[] = {
+       {
+               .compatible = "ti,omap2420-mcbsp",
+               .data = &omap2420_pdata,
+       },
+       {
+               .compatible = "ti,omap2430-mcbsp",
+               .data = &omap2430_pdata,
+       },
+       {
+               .compatible = "ti,omap3-mcbsp",
+               .data = &omap3_pdata,
+       },
+       {
+               .compatible = "ti,omap4-mcbsp",
+               .data = &omap4_pdata,
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(of, omap_mcbsp_of_match);
+
 static __devinit int asoc_mcbsp_probe(struct platform_device *pdev)
 {
        struct omap_mcbsp_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct omap_mcbsp *mcbsp;
+       const struct of_device_id *match;
        int ret;
 
-       if (!pdata) {
+       match = of_match_device(omap_mcbsp_of_match, &pdev->dev);
+       if (match) {
+               struct device_node *node = pdev->dev.of_node;
+               int buffer_size;
+
+               pdata = devm_kzalloc(&pdev->dev,
+                                    sizeof(struct omap_mcbsp_platform_data),
+                                    GFP_KERNEL);
+               if (!pdata)
+                       return -ENOMEM;
+
+               memcpy(pdata, match->data, sizeof(*pdata));
+               if (!of_property_read_u32(node, "ti,buffer-size", &buffer_size))
+                       pdata->buffer_size = buffer_size;
+       } else if (!pdata) {
                dev_err(&pdev->dev, "missing platform data.\n");
                return -EINVAL;
        }
@@ -810,6 +821,7 @@ static struct platform_driver asoc_mcbsp_driver = {
        .driver = {
                        .name = "omap-mcbsp",
                        .owner = THIS_MODULE,
+                       .of_match_table = omap_mcbsp_of_match,
        },
 
        .probe = asoc_mcbsp_probe,