ASoC: davinci-mcasp: Fix bit clock polarity settings
[cascardo/linux.git] / sound / soc / davinci / davinci-mcasp.c
index 670afa2..4f75cac 100644 (file)
 #include "davinci-pcm.h"
 #include "davinci-mcasp.h"
 
+struct davinci_mcasp_context {
+       u32     txfmtctl;
+       u32     rxfmtctl;
+       u32     txfmt;
+       u32     rxfmt;
+       u32     aclkxctl;
+       u32     aclkrctl;
+       u32     pdir;
+};
+
 struct davinci_mcasp {
        struct davinci_pcm_dma_params dma_params[2];
        struct snd_dmaengine_dai_dma_data dma_data[2];
@@ -53,6 +63,9 @@ struct davinci_mcasp {
        u16     bclk_lrclk_ratio;
        int     streams;
 
+       int     sysclk_freq;
+       bool    bclk_master;
+
        /* McASP FIFO related */
        u8      txnumevt;
        u8      rxnumevt;
@@ -60,15 +73,7 @@ struct davinci_mcasp {
        bool    dat_port;
 
 #ifdef CONFIG_PM_SLEEP
-       struct {
-               u32     txfmtctl;
-               u32     rxfmtctl;
-               u32     txfmt;
-               u32     rxfmt;
-               u32     aclkxctl;
-               u32     aclkrctl;
-               u32     pdir;
-       } context;
+       struct davinci_mcasp_context context;
 #endif
 };
 
@@ -294,6 +299,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 
                mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
                mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
+               mcasp->bclk_master = 1;
                break;
        case SND_SOC_DAIFMT_CBM_CFS:
                /* codec is clock master and frame slave */
@@ -305,6 +311,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
                mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
+               mcasp->bclk_master = 0;
                break;
        case SND_SOC_DAIFMT_CBM_CFM:
                /* codec is clock and frame master */
@@ -316,6 +323,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG,
                               ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR);
+               mcasp->bclk_master = 0;
                break;
 
        default:
@@ -328,7 +336,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
 
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
                break;
 
@@ -336,7 +344,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
                mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
 
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
                mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
                break;
 
@@ -344,7 +352,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
                mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
 
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
                mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
                break;
 
@@ -410,6 +418,8 @@ static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX);
        }
 
+       mcasp->sysclk_freq = freq;
+
        return 0;
 }
 
@@ -603,20 +613,23 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
        u8 fifo_level;
        u8 slots = mcasp->tdm_slots;
        u8 active_serializers;
-       int channels;
+       int channels = params_channels(params);
        int ret;
-       struct snd_interval *pcm_channels = hw_param_interval(params,
-                                       SNDRV_PCM_HW_PARAM_CHANNELS);
-       channels = pcm_channels->min;
 
-       active_serializers = (channels + slots - 1) / slots;
+       /* If mcasp is BCLK master we need to set BCLK divider */
+       if (mcasp->bclk_master) {
+               unsigned int bclk_freq = snd_soc_params_to_bclk(params);
+               if (mcasp->sysclk_freq % bclk_freq != 0) {
+                       dev_err(mcasp->dev, "Can't produce requred BCLK\n");
+                       return -EINVAL;
+               }
+               davinci_mcasp_set_clkdiv(
+                       cpu_dai, 1, mcasp->sysclk_freq / bclk_freq);
+       }
 
-       if (mcasp_common_hw_param(mcasp, substream->stream, channels) == -EINVAL)
-               return -EINVAL;
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               fifo_level = mcasp->txnumevt * active_serializers;
-       else
-               fifo_level = mcasp->rxnumevt * active_serializers;
+       ret = mcasp_common_hw_param(mcasp, substream->stream, channels);
+       if (ret)
+               return ret;
 
        if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
                ret = mcasp_dit_hw_param(mcasp);
@@ -658,6 +671,13 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
+       /* Calculate FIFO level */
+       active_serializers = (channels + slots - 1) / slots;
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               fifo_level = mcasp->txnumevt * active_serializers;
+       else
+               fifo_level = mcasp->rxnumevt * active_serializers;
+
        if (mcasp->version == MCASP_VERSION_2 && !fifo_level)
                dma_params->acnt = 4;
        else
@@ -719,6 +739,43 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
        .set_sysclk     = davinci_mcasp_set_sysclk,
 };
 
+#ifdef CONFIG_PM_SLEEP
+static int davinci_mcasp_suspend(struct snd_soc_dai *dai)
+{
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
+       struct davinci_mcasp_context *context = &mcasp->context;
+
+       context->txfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG);
+       context->rxfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG);
+       context->txfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMT_REG);
+       context->rxfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMT_REG);
+       context->aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG);
+       context->aclkrctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG);
+       context->pdir = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG);
+
+       return 0;
+}
+
+static int davinci_mcasp_resume(struct snd_soc_dai *dai)
+{
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
+       struct davinci_mcasp_context *context = &mcasp->context;
+
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, context->txfmtctl);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG, context->rxfmtctl);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMT_REG, context->txfmt);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMT_REG, context->rxfmt);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, context->aclkxctl);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, context->aclkrctl);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_PDIR_REG, context->pdir);
+
+       return 0;
+}
+#else
+#define davinci_mcasp_suspend NULL
+#define davinci_mcasp_resume NULL
+#endif
+
 #define DAVINCI_MCASP_RATES    SNDRV_PCM_RATE_8000_192000
 
 #define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \
@@ -735,6 +792,8 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
 static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
        {
                .name           = "davinci-mcasp.0",
+               .suspend        = davinci_mcasp_suspend,
+               .resume         = davinci_mcasp_resume,
                .playback       = {
                        .channels_min   = 2,
                        .channels_max   = 32 * 16,
@@ -768,28 +827,28 @@ static const struct snd_soc_component_driver davinci_mcasp_component = {
 };
 
 /* Some HW specific values and defaults. The rest is filled in from DT. */
-static struct snd_platform_data dm646x_mcasp_pdata = {
+static struct davinci_mcasp_pdata dm646x_mcasp_pdata = {
        .tx_dma_offset = 0x400,
        .rx_dma_offset = 0x400,
        .asp_chan_q = EVENTQ_0,
        .version = MCASP_VERSION_1,
 };
 
-static struct snd_platform_data da830_mcasp_pdata = {
+static struct davinci_mcasp_pdata da830_mcasp_pdata = {
        .tx_dma_offset = 0x2000,
        .rx_dma_offset = 0x2000,
        .asp_chan_q = EVENTQ_0,
        .version = MCASP_VERSION_2,
 };
 
-static struct snd_platform_data am33xx_mcasp_pdata = {
+static struct davinci_mcasp_pdata am33xx_mcasp_pdata = {
        .tx_dma_offset = 0,
        .rx_dma_offset = 0,
        .asp_chan_q = EVENTQ_0,
        .version = MCASP_VERSION_3,
 };
 
-static struct snd_platform_data dra7_mcasp_pdata = {
+static struct davinci_mcasp_pdata dra7_mcasp_pdata = {
        .tx_dma_offset = 0x200,
        .rx_dma_offset = 0x284,
        .asp_chan_q = EVENTQ_0,
@@ -857,11 +916,11 @@ err1:
        return ret;
 }
 
-static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
+static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
                                                struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
-       struct snd_platform_data *pdata = NULL;
+       struct davinci_mcasp_pdata *pdata = NULL;
        const struct of_device_id *match =
                        of_match_device(mcasp_dt_ids, &pdev->dev);
        struct of_phandle_args dma_spec;
@@ -874,7 +933,7 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
                pdata = pdev->dev.platform_data;
                return pdata;
        } else if (match) {
-               pdata = (struct snd_platform_data *) match->data;
+               pdata = (struct davinci_mcasp_pdata*) match->data;
        } else {
                /* control shouldn't reach here. something is wrong */
                ret = -EINVAL;
@@ -966,9 +1025,10 @@ nodata:
 
 static int davinci_mcasp_probe(struct platform_device *pdev)
 {
-       struct davinci_pcm_dma_params *dma_data;
+       struct davinci_pcm_dma_params *dma_params;
+       struct snd_dmaengine_dai_dma_data *dma_data;
        struct resource *mem, *ioarea, *res, *dat;
-       struct snd_platform_data *pdata;
+       struct davinci_mcasp_pdata *pdata;
        struct davinci_mcasp *mcasp;
        int ret;
 
@@ -1035,41 +1095,49 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        if (dat)
                mcasp->dat_port = true;
 
-       dma_data = &mcasp->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
-       dma_data->asp_chan_q = pdata->asp_chan_q;
-       dma_data->ram_chan_q = pdata->ram_chan_q;
-       dma_data->sram_pool = pdata->sram_pool;
-       dma_data->sram_size = pdata->sram_size_playback;
+       dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
+       dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
+       dma_params->asp_chan_q = pdata->asp_chan_q;
+       dma_params->ram_chan_q = pdata->ram_chan_q;
+       dma_params->sram_pool = pdata->sram_pool;
+       dma_params->sram_size = pdata->sram_size_playback;
        if (dat)
-               dma_data->dma_addr = dat->start;
+               dma_params->dma_addr = dat->start;
        else
-               dma_data->dma_addr = mem->start + pdata->tx_dma_offset;
+               dma_params->dma_addr = mem->start + pdata->tx_dma_offset;
 
        /* Unconditional dmaengine stuff */
-       mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = dma_data->dma_addr;
+       dma_data->addr = dma_params->dma_addr;
 
        res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
        if (res)
-               dma_data->channel = res->start;
+               dma_params->channel = res->start;
        else
-               dma_data->channel = pdata->tx_dma_channel;
+               dma_params->channel = pdata->tx_dma_channel;
 
-       dma_data = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE];
-       dma_data->asp_chan_q = pdata->asp_chan_q;
-       dma_data->ram_chan_q = pdata->ram_chan_q;
-       dma_data->sram_pool = pdata->sram_pool;
-       dma_data->sram_size = pdata->sram_size_capture;
+       /* dmaengine filter data for DT and non-DT boot */
+       if (pdev->dev.of_node)
+               dma_data->filter_data = "tx";
+       else
+               dma_data->filter_data = &dma_params->channel;
+
+       dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE];
+       dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
+       dma_params->asp_chan_q = pdata->asp_chan_q;
+       dma_params->ram_chan_q = pdata->ram_chan_q;
+       dma_params->sram_pool = pdata->sram_pool;
+       dma_params->sram_size = pdata->sram_size_capture;
        if (dat)
-               dma_data->dma_addr = dat->start;
+               dma_params->dma_addr = dat->start;
        else
-               dma_data->dma_addr = mem->start + pdata->rx_dma_offset;
+               dma_params->dma_addr = mem->start + pdata->rx_dma_offset;
 
        /* Unconditional dmaengine stuff */
-       mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = dma_data->dma_addr;
+       dma_data->addr = dma_params->dma_addr;
 
        if (mcasp->version < MCASP_VERSION_3) {
                mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE;
-               /* dma_data->dma_addr is pointing to the data port address */
+               /* dma_params->dma_addr is pointing to the data port address */
                mcasp->dat_port = true;
        } else {
                mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE;
@@ -1077,13 +1145,15 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
        if (res)
-               dma_data->channel = res->start;
+               dma_params->channel = res->start;
        else
-               dma_data->channel = pdata->rx_dma_channel;
+               dma_params->channel = pdata->rx_dma_channel;
 
-       /* Unconditional dmaengine stuff */
-       mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data = "tx";
-       mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data = "rx";
+       /* dmaengine filter data for DT and non-DT boot */
+       if (pdev->dev.of_node)
+               dma_data->filter_data = "rx";
+       else
+               dma_data->filter_data = &dma_params->channel;
 
        dev_set_drvdata(&pdev->dev, mcasp);
 
@@ -1127,49 +1197,12 @@ static int davinci_mcasp_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int davinci_mcasp_suspend(struct device *dev)
-{
-       struct davinci_mcasp *mcasp = dev_get_drvdata(dev);
-
-       mcasp->context.txfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG);
-       mcasp->context.rxfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG);
-       mcasp->context.txfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMT_REG);
-       mcasp->context.rxfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMT_REG);
-       mcasp->context.aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG);
-       mcasp->context.aclkrctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG);
-       mcasp->context.pdir = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG);
-
-       return 0;
-}
-
-static int davinci_mcasp_resume(struct device *dev)
-{
-       struct davinci_mcasp *mcasp = dev_get_drvdata(dev);
-
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, mcasp->context.txfmtctl);
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG, mcasp->context.rxfmtctl);
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMT_REG, mcasp->context.txfmt);
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMT_REG, mcasp->context.rxfmt);
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, mcasp->context.aclkxctl);
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, mcasp->context.aclkrctl);
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_PDIR_REG, mcasp->context.pdir);
-
-       return 0;
-}
-#endif
-
-SIMPLE_DEV_PM_OPS(davinci_mcasp_pm_ops,
-                 davinci_mcasp_suspend,
-                 davinci_mcasp_resume);
-
 static struct platform_driver davinci_mcasp_driver = {
        .probe          = davinci_mcasp_probe,
        .remove         = davinci_mcasp_remove,
        .driver         = {
                .name   = "davinci-mcasp",
                .owner  = THIS_MODULE,
-               .pm     = &davinci_mcasp_pm_ops,
                .of_match_table = mcasp_dt_ids,
        },
 };