diff options
Diffstat (limited to 'sound/soc/davinci/davinci-mcasp.c')
| -rw-r--r-- | sound/soc/davinci/davinci-mcasp.c | 349 |
1 files changed, 242 insertions, 107 deletions
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 4f75cac462d1..c28508da34cf 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -27,16 +27,21 @@ #include <linux/of_platform.h> #include <linux/of_device.h> +#include <sound/asoundef.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/initval.h> #include <sound/soc.h> #include <sound/dmaengine_pcm.h> +#include <sound/omap-pcm.h> #include "davinci-pcm.h" +#include "edma-pcm.h" #include "davinci-mcasp.h" +#define MCASP_MAX_AFIFO_DEPTH 64 + struct davinci_mcasp_context { u32 txfmtctl; u32 rxfmtctl; @@ -60,6 +65,7 @@ struct davinci_mcasp { u8 num_serializer; u8 *serial_dir; u8 version; + u8 bclk_div; u16 bclk_lrclk_ratio; int streams; @@ -269,25 +275,51 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, { struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); int ret = 0; + u32 data_delay; + bool fs_pol_rising; + bool inv_fs = false; pm_runtime_get_sync(mcasp->dev); switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); + mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); + /* 1st data bit occur one ACLK cycle after the frame sync */ + data_delay = 1; + break; case SND_SOC_DAIFMT_DSP_B: case SND_SOC_DAIFMT_AC97: mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); + /* No delay after FS */ + data_delay = 0; break; - default: + case SND_SOC_DAIFMT_I2S: /* configure a full-word SYNC pulse (LRCLK) */ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); - - /* make 1st data bit occur one ACLK cycle after the frame sync */ - mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, FSXDLY(1)); - mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(1)); + /* 1st data bit occur one ACLK cycle after the frame sync */ + data_delay = 1; + /* FS need to be inverted */ + inv_fs = true; break; + case SND_SOC_DAIFMT_LEFT_J: + /* configure a full-word SYNC pulse (LRCLK) */ + mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); + mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); + /* No delay after FS */ + data_delay = 0; + break; + default: + ret = -EINVAL; + goto out; } + mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, FSXDLY(data_delay), + FSXDLY(3)); + mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(data_delay), + FSRDLY(3)); + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: /* codec is clock and frame slave */ @@ -325,7 +357,6 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR); mcasp->bclk_master = 0; break; - default: ret = -EINVAL; goto out; @@ -334,39 +365,38 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_IB_NF: mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); - mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); - mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); - mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); + fs_pol_rising = true; break; - case SND_SOC_DAIFMT_NB_IF: mcasp_set_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_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); + fs_pol_rising = false; break; - case SND_SOC_DAIFMT_IB_IF: mcasp_clr_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_RXFMCTL_REG, FSRPOL); + fs_pol_rising = false; break; - case SND_SOC_DAIFMT_NB_NF: mcasp_set_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_RXFMCTL_REG, FSRPOL); + fs_pol_rising = true; break; - default: ret = -EINVAL; - break; + goto out; + } + + if (inv_fs) + fs_pol_rising = !fs_pol_rising; + + if (fs_pol_rising) { + mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); + mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); + } else { + mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); + mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); } out: pm_runtime_put_sync(mcasp->dev); @@ -390,6 +420,7 @@ static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div ACLKXDIV(div - 1), ACLKXDIV_MASK); mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRDIV(div - 1), ACLKRDIV_MASK); + mcasp->bclk_div = div; break; case 2: /* BCLK/LRCLK ratio */ @@ -464,17 +495,19 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp, } static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, - int channels) + int period_words, int channels) { + struct davinci_pcm_dma_params *dma_params = &mcasp->dma_params[stream]; + struct snd_dmaengine_dai_dma_data *dma_data = &mcasp->dma_data[stream]; int i; u8 tx_ser = 0; u8 rx_ser = 0; - u8 ser; u8 slots = mcasp->tdm_slots; u8 max_active_serializers = (channels + slots - 1) / slots; + int active_serializers, numevt, n; u32 reg; /* Default configuration */ - if (mcasp->version != MCASP_VERSION_4) + if (mcasp->version < MCASP_VERSION_3) mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT); /* All PINS as McASP */ @@ -505,37 +538,71 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, } } - if (stream == SNDRV_PCM_STREAM_PLAYBACK) - ser = tx_ser; - else - ser = rx_ser; + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + active_serializers = tx_ser; + numevt = mcasp->txnumevt; + reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; + } else { + active_serializers = rx_ser; + numevt = mcasp->rxnumevt; + reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; + } - if (ser < max_active_serializers) { + if (active_serializers < max_active_serializers) { dev_warn(mcasp->dev, "stream has more channels (%d) than are " - "enabled in mcasp (%d)\n", channels, ser * slots); + "enabled in mcasp (%d)\n", channels, + active_serializers * slots); return -EINVAL; } - if (mcasp->txnumevt && stream == SNDRV_PCM_STREAM_PLAYBACK) { - if (mcasp->txnumevt * tx_ser > 64) - mcasp->txnumevt = 1; - - reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; - mcasp_mod_bits(mcasp, reg, tx_ser, NUMDMA_MASK); - mcasp_mod_bits(mcasp, reg, ((mcasp->txnumevt * tx_ser) << 8), - NUMEVT_MASK); + /* AFIFO is not in use */ + if (!numevt) { + /* Configure the burst size for platform drivers */ + if (active_serializers > 1) { + /* + * If more than one serializers are in use we have one + * DMA request to provide data for all serializers. + * For example if three serializers are enabled the DMA + * need to transfer three words per DMA request. + */ + dma_params->fifo_level = active_serializers; + dma_data->maxburst = active_serializers; + } else { + dma_params->fifo_level = 0; + dma_data->maxburst = 0; + } + return 0; } - if (mcasp->rxnumevt && stream == SNDRV_PCM_STREAM_CAPTURE) { - if (mcasp->rxnumevt * rx_ser > 64) - mcasp->rxnumevt = 1; - - reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; - mcasp_mod_bits(mcasp, reg, rx_ser, NUMDMA_MASK); - mcasp_mod_bits(mcasp, reg, ((mcasp->rxnumevt * rx_ser) << 8), - NUMEVT_MASK); + if (period_words % active_serializers) { + dev_err(mcasp->dev, "Invalid combination of period words and " + "active serializers: %d, %d\n", period_words, + active_serializers); + return -EINVAL; } + /* + * Calculate the optimal AFIFO depth for platform side: + * The number of words for numevt need to be in steps of active + * serializers. + */ + n = numevt % active_serializers; + if (n) + numevt += (active_serializers - n); + while (period_words % numevt && numevt > 0) + numevt -= active_serializers; + if (numevt <= 0) + numevt = active_serializers; + + mcasp_mod_bits(mcasp, reg, active_serializers, NUMDMA_MASK); + mcasp_mod_bits(mcasp, reg, NUMEVT(numevt), NUMEVT_MASK); + + /* Configure the burst size for platform drivers */ + if (numevt == 1) + numevt = 0; + dma_params->fifo_level = numevt; + dma_data->maxburst = numevt; + return 0; } @@ -574,8 +641,12 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream) } /* S/PDIF */ -static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp) +static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp, + unsigned int rate) { + u32 cs_value = 0; + u8 *cs_bytes = (u8*) &cs_value; + /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0 and LSB first */ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(6) | TXSSZ(15)); @@ -597,6 +668,46 @@ static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp) /* Enable the DIT */ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN); + /* Set S/PDIF channel status bits */ + cs_bytes[0] = IEC958_AES0_CON_NOT_COPYRIGHT; + cs_bytes[1] = IEC958_AES1_CON_PCM_CODER; + + switch (rate) { + case 22050: + cs_bytes[3] |= IEC958_AES3_CON_FS_22050; + break; + case 24000: + cs_bytes[3] |= IEC958_AES3_CON_FS_24000; + break; + case 32000: + cs_bytes[3] |= IEC958_AES3_CON_FS_32000; + break; + case 44100: + cs_bytes[3] |= IEC958_AES3_CON_FS_44100; + break; + case 48000: + cs_bytes[3] |= IEC958_AES3_CON_FS_48000; + break; + case 88200: + cs_bytes[3] |= IEC958_AES3_CON_FS_88200; + break; + case 96000: + cs_bytes[3] |= IEC958_AES3_CON_FS_96000; + break; + case 176400: + cs_bytes[3] |= IEC958_AES3_CON_FS_176400; + break; + case 192000: + cs_bytes[3] |= IEC958_AES3_CON_FS_192000; + break; + default: + printk(KERN_WARNING "unsupported sampling rate: %d\n", rate); + return -EINVAL; + } + + mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRA_REG, cs_value); + mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRB_REG, cs_value); + return 0; } @@ -607,32 +718,36 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); struct davinci_pcm_dma_params *dma_params = &mcasp->dma_params[substream->stream]; - struct snd_dmaengine_dai_dma_data *dma_data = - &mcasp->dma_data[substream->stream]; int word_length; - u8 fifo_level; - u8 slots = mcasp->tdm_slots; - u8 active_serializers; int channels = params_channels(params); + int period_size = params_period_size(params); int ret; - /* If mcasp is BCLK master we need to set BCLK divider */ - if (mcasp->bclk_master) { + /* + * If mcasp is BCLK master, and a BCLK divider was not provided by + * the machine driver, we need to calculate the ratio. + */ + if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) { unsigned int bclk_freq = snd_soc_params_to_bclk(params); + unsigned int div = mcasp->sysclk_freq / bclk_freq; if (mcasp->sysclk_freq % bclk_freq != 0) { - dev_err(mcasp->dev, "Can't produce requred BCLK\n"); - return -EINVAL; + if (((mcasp->sysclk_freq / div) - bclk_freq) > + (bclk_freq - (mcasp->sysclk_freq / (div+1)))) + div++; + dev_warn(mcasp->dev, + "Inaccurate BCLK: %u Hz / %u != %u Hz\n", + mcasp->sysclk_freq, div, bclk_freq); } - davinci_mcasp_set_clkdiv( - cpu_dai, 1, mcasp->sysclk_freq / bclk_freq); + davinci_mcasp_set_clkdiv(cpu_dai, 1, div); } - ret = mcasp_common_hw_param(mcasp, substream->stream, channels); + ret = mcasp_common_hw_param(mcasp, substream->stream, + period_size * channels, channels); if (ret) return ret; if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) - ret = mcasp_dit_hw_param(mcasp); + ret = mcasp_dit_hw_param(mcasp, params_rate(params)); else ret = mcasp_i2s_hw_param(mcasp, substream->stream); @@ -660,6 +775,10 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, case SNDRV_PCM_FORMAT_U24_LE: case SNDRV_PCM_FORMAT_S24_LE: + dma_params->data_type = 4; + word_length = 24; + break; + case SNDRV_PCM_FORMAT_U32_LE: case SNDRV_PCM_FORMAT_S32_LE: dma_params->data_type = 4; @@ -671,21 +790,11 @@ 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) + if (mcasp->version == MCASP_VERSION_2 && !dma_params->fifo_level) dma_params->acnt = 4; else dma_params->acnt = dma_params->data_type; - dma_params->fifo_level = fifo_level; - dma_data->maxburst = fifo_level; - davinci_config_channel_size(mcasp, word_length); return 0; @@ -716,22 +825,7 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream, return ret; } -static int davinci_mcasp_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); - - if (mcasp->version == MCASP_VERSION_4) - snd_soc_dai_set_dma_data(dai, substream, - &mcasp->dma_data[substream->stream]); - else - snd_soc_dai_set_dma_data(dai, substream, mcasp->dma_params); - - return 0; -} - static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { - .startup = davinci_mcasp_startup, .trigger = davinci_mcasp_trigger, .hw_params = davinci_mcasp_hw_params, .set_fmt = davinci_mcasp_set_dai_fmt, @@ -739,6 +833,25 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { .set_sysclk = davinci_mcasp_set_sysclk, }; +static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai) +{ + struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); + + if (mcasp->version >= MCASP_VERSION_3) { + /* Using dmaengine PCM */ + dai->playback_dma_data = + &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; + dai->capture_dma_data = + &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE]; + } else { + /* Using davinci-pcm */ + dai->playback_dma_data = mcasp->dma_params; + dai->capture_dma_data = mcasp->dma_params; + } + + return 0; +} + #ifdef CONFIG_PM_SLEEP static int davinci_mcasp_suspend(struct snd_soc_dai *dai) { @@ -792,6 +905,7 @@ static int davinci_mcasp_resume(struct snd_soc_dai *dai) static struct snd_soc_dai_driver davinci_mcasp_dai[] = { { .name = "davinci-mcasp.0", + .probe = davinci_mcasp_dai_probe, .suspend = davinci_mcasp_suspend, .resume = davinci_mcasp_resume, .playback = { @@ -811,6 +925,7 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = { }, { .name = "davinci-mcasp.1", + .probe = davinci_mcasp_dai_probe, .playback = { .channels_min = 1, .channels_max = 384, @@ -1078,7 +1193,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) if (!mcasp->base) { dev_err(&pdev->dev, "ioremap failed\n"); ret = -ENOMEM; - goto err_release_clk; + goto err; } mcasp->op_mode = pdata->op_mode; @@ -1159,25 +1274,51 @@ static int davinci_mcasp_probe(struct platform_device *pdev) mcasp_reparent_fck(pdev); - ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component, - &davinci_mcasp_dai[pdata->op_mode], 1); + ret = devm_snd_soc_register_component(&pdev->dev, + &davinci_mcasp_component, + &davinci_mcasp_dai[pdata->op_mode], 1); if (ret != 0) - goto err_release_clk; - - if (mcasp->version != MCASP_VERSION_4) { + goto err; + + switch (mcasp->version) { +#if IS_BUILTIN(CONFIG_SND_DAVINCI_SOC) || \ + (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \ + IS_MODULE(CONFIG_SND_DAVINCI_SOC)) + case MCASP_VERSION_1: + case MCASP_VERSION_2: ret = davinci_soc_platform_register(&pdev->dev); - if (ret) { - dev_err(&pdev->dev, "register PCM failed: %d\n", ret); - goto err_unregister_component; - } + break; +#endif +#if IS_BUILTIN(CONFIG_SND_EDMA_SOC) || \ + (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \ + IS_MODULE(CONFIG_SND_EDMA_SOC)) + case MCASP_VERSION_3: + ret = edma_pcm_platform_register(&pdev->dev); + break; +#endif +#if IS_BUILTIN(CONFIG_SND_OMAP_SOC) || \ + (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \ + IS_MODULE(CONFIG_SND_OMAP_SOC)) + case MCASP_VERSION_4: + ret = omap_pcm_platform_register(&pdev->dev); + break; +#endif + default: + dev_err(&pdev->dev, "Invalid McASP version: %d\n", + mcasp->version); + ret = -EINVAL; + break; + } + + if (ret) { + dev_err(&pdev->dev, "register PCM failed: %d\n", ret); + goto err; } return 0; -err_unregister_component: - snd_soc_unregister_component(&pdev->dev); -err_release_clk: +err: pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); return ret; @@ -1185,12 +1326,6 @@ err_release_clk: static int davinci_mcasp_remove(struct platform_device *pdev) { - struct davinci_mcasp *mcasp = dev_get_drvdata(&pdev->dev); - - snd_soc_unregister_component(&pdev->dev); - if (mcasp->version != MCASP_VERSION_4) - davinci_soc_platform_unregister(&pdev->dev); - pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); |
