diff options
Diffstat (limited to 'sound/soc/davinci/davinci-mcasp.c')
-rw-r--r-- | sound/soc/davinci/davinci-mcasp.c | 294 |
1 files changed, 160 insertions, 134 deletions
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index b7858bfa0295..a01ae97c90aa 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -37,6 +37,16 @@ #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 }; @@ -263,7 +268,9 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); + int ret = 0; + pm_runtime_get_sync(mcasp->dev); switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_DSP_B: case SND_SOC_DAIFMT_AC97: @@ -292,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 */ @@ -303,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 */ @@ -314,10 +323,12 @@ 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: - return -EINVAL; + ret = -EINVAL; + goto out; } switch (fmt & SND_SOC_DAIFMT_INV_MASK) { @@ -354,10 +365,12 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, break; default: - return -EINVAL; + ret = -EINVAL; + break; } - - return 0; +out: + pm_runtime_put_sync(mcasp->dev); + return ret; } static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) @@ -405,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; } @@ -448,7 +463,7 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp, return 0; } -static int davinci_hw_common_param(struct davinci_mcasp *mcasp, int stream, +static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, int channels) { int i; @@ -524,12 +539,18 @@ static int davinci_hw_common_param(struct davinci_mcasp *mcasp, int stream, return 0; } -static void davinci_hw_param(struct davinci_mcasp *mcasp, int stream) +static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream) { int i, active_slots; u32 mask = 0; u32 busel = 0; + if ((mcasp->tdm_slots < 2) || (mcasp->tdm_slots > 32)) { + dev_err(mcasp->dev, "tdm slot %d not supported\n", + mcasp->tdm_slots); + return -EINVAL; + } + active_slots = (mcasp->tdm_slots > 31) ? 32 : mcasp->tdm_slots; for (i = 0; i < active_slots; i++) mask |= (1 << i); @@ -539,35 +560,21 @@ static void davinci_hw_param(struct davinci_mcasp *mcasp, int stream) if (!mcasp->dat_port) busel = TXSEL; - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - /* bit stream is MSB first with no delay */ - /* DSP_B mode */ - mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask); - mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD); - - if ((mcasp->tdm_slots >= 2) && (mcasp->tdm_slots <= 32)) - mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, - FSXMOD(mcasp->tdm_slots), FSXMOD(0x1FF)); - else - printk(KERN_ERR "playback tdm slot %d not supported\n", - mcasp->tdm_slots); - } else { - /* bit stream is MSB first with no delay */ - /* DSP_B mode */ - mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD); - mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask); - - if ((mcasp->tdm_slots >= 2) && (mcasp->tdm_slots <= 32)) - mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, - FSRMOD(mcasp->tdm_slots), FSRMOD(0x1FF)); - else - printk(KERN_ERR "capture tdm slot %d not supported\n", - mcasp->tdm_slots); - } + mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask); + mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD); + mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, + FSXMOD(mcasp->tdm_slots), FSXMOD(0x1FF)); + + mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask); + mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD); + mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, + FSRMOD(mcasp->tdm_slots), FSRMOD(0x1FF)); + + return 0; } /* S/PDIF */ -static void davinci_hw_dit_param(struct davinci_mcasp *mcasp) +static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp) { /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0 and LSB first */ @@ -589,6 +596,8 @@ static void davinci_hw_dit_param(struct davinci_mcasp *mcasp) /* Enable the DIT */ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN); + + return 0; } static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, @@ -604,24 +613,31 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, u8 fifo_level; u8 slots = mcasp->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; + int channels = params_channels(params); + int ret; - 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 (davinci_hw_common_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) - davinci_hw_dit_param(mcasp); + ret = mcasp_dit_hw_param(mcasp); else - davinci_hw_param(mcasp, substream->stream); + ret = mcasp_i2s_hw_param(mcasp, substream->stream); + + if (ret) + return ret; switch (params_format(params)) { case SNDRV_PCM_FORMAT_U8: @@ -655,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 @@ -678,19 +701,9 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ret = pm_runtime_get_sync(mcasp->dev); - if (IS_ERR_VALUE(ret)) - dev_err(mcasp->dev, "pm_runtime_get_sync() failed\n"); davinci_mcasp_start(mcasp, substream->stream); break; - case SNDRV_PCM_TRIGGER_SUSPEND: - davinci_mcasp_stop(mcasp, substream->stream); - ret = pm_runtime_put_sync(mcasp->dev); - if (IS_ERR_VALUE(ret)) - dev_err(mcasp->dev, "pm_runtime_put_sync() failed\n"); - break; - case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: davinci_mcasp_stop(mcasp, substream->stream); @@ -726,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 | \ @@ -742,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, @@ -775,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, @@ -864,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; @@ -881,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; @@ -973,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; @@ -1042,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; @@ -1084,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); @@ -1134,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, }, }; |