diff options
Diffstat (limited to 'sound/soc/davinci/davinci-mcasp.c')
-rw-r--r-- | sound/soc/davinci/davinci-mcasp.c | 110 |
1 files changed, 77 insertions, 33 deletions
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 9321e5c9d8c1..8b85049daab0 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -235,6 +235,8 @@ #define DISMOD (val)(val<<2) #define TXSTATE BIT(4) #define RXSTATE BIT(5) +#define SRMOD_MASK 3 +#define SRMOD_INACTIVE 0 /* * DAVINCI_MCASP_LBCTL_REG - Loop Back Control Register Bits @@ -634,35 +636,43 @@ static int davinci_config_channel_size(struct davinci_audio_dev *dev, * callback, take it into account here. That allows us to for example * send 32 bits per channel to the codec, while only 16 of them carry * audio payload. - * The clock ratio is given for a full period of data (both left and - * right channels), so it has to be divided by 2. + * The clock ratio is given for a full period of data (for I2S format + * both left and right channels), so it has to be divided by number of + * tdm-slots (for I2S - divided by 2). */ if (dev->bclk_lrclk_ratio) - word_length = dev->bclk_lrclk_ratio / 2; + word_length = dev->bclk_lrclk_ratio / dev->tdm_slots; /* mapping of the XSSZ bit-field as described in the datasheet */ fmt = (word_length >> 1) - 1; - mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, - RXSSZ(fmt), RXSSZ(0x0F)); - mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, - TXSSZ(fmt), TXSSZ(0x0F)); - mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, TXROT(rotate), - TXROT(7)); - mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, RXROT(rotate), - RXROT(7)); + if (dev->op_mode != DAVINCI_MCASP_DIT_MODE) { + mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, + RXSSZ(fmt), RXSSZ(0x0F)); + mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, + TXSSZ(fmt), TXSSZ(0x0F)); + mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, + TXROT(rotate), TXROT(7)); + mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, + RXROT(rotate), RXROT(7)); + mcasp_set_reg(dev->base + DAVINCI_MCASP_RXMASK_REG, + mask); + } + mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, mask); - mcasp_set_reg(dev->base + DAVINCI_MCASP_RXMASK_REG, mask); return 0; } -static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream) +static int davinci_hw_common_param(struct davinci_audio_dev *dev, int stream, + int channels) { int i; u8 tx_ser = 0; u8 rx_ser = 0; - + u8 ser; + u8 slots = dev->tdm_slots; + u8 max_active_serializers = (channels + slots - 1) / slots; /* Default configuration */ mcasp_set_bits(dev->base + DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT); @@ -682,17 +692,33 @@ static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream) for (i = 0; i < dev->num_serializer; i++) { mcasp_set_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i), dev->serial_dir[i]); - if (dev->serial_dir[i] == TX_MODE) { + if (dev->serial_dir[i] == TX_MODE && + tx_ser < max_active_serializers) { mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AXR(i)); tx_ser++; - } else if (dev->serial_dir[i] == RX_MODE) { + } else if (dev->serial_dir[i] == RX_MODE && + rx_ser < max_active_serializers) { mcasp_clr_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AXR(i)); rx_ser++; + } else { + mcasp_mod_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i), + SRMOD_INACTIVE, SRMOD_MASK); } } + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + ser = tx_ser; + else + ser = rx_ser; + + if (ser < max_active_serializers) { + dev_warn(dev->dev, "stream has more channels (%d) than are " + "enabled in mcasp (%d)\n", channels, ser * slots); + return -EINVAL; + } + if (dev->txnumevt && stream == SNDRV_PCM_STREAM_PLAYBACK) { if (dev->txnumevt * tx_ser > 64) dev->txnumevt = 1; @@ -729,6 +755,8 @@ static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream) ((dev->rxnumevt * rx_ser) << 8), NUMEVT_MASK); } } + + return 0; } static void davinci_hw_param(struct davinci_audio_dev *dev, int stream) @@ -772,12 +800,6 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream) /* S/PDIF */ static void davinci_hw_dit_param(struct davinci_audio_dev *dev) { - /* Set the PDIR for Serialiser as output */ - mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AFSX); - - /* TXMASK for 24 bits */ - mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, 0x00FFFFFF); - /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0 and LSB first */ mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, @@ -812,12 +834,21 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, &dev->dma_params[substream->stream]; int word_length; u8 fifo_level; + u8 slots = dev->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; + + active_serializers = (channels + slots - 1) / slots; - davinci_hw_common_param(dev, substream->stream); + if (davinci_hw_common_param(dev, substream->stream, channels) == -EINVAL) + return -EINVAL; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - fifo_level = dev->txnumevt; + fifo_level = dev->txnumevt * active_serializers; else - fifo_level = dev->rxnumevt; + fifo_level = dev->rxnumevt * active_serializers; if (dev->op_mode == DAVINCI_MCASP_DIT_MODE) davinci_hw_dit_param(dev); @@ -936,13 +967,13 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = { .name = "davinci-mcasp.0", .playback = { .channels_min = 2, - .channels_max = 2, + .channels_max = 32 * 16, .rates = DAVINCI_MCASP_RATES, .formats = DAVINCI_MCASP_PCM_FMTS, }, .capture = { .channels_min = 2, - .channels_max = 2, + .channels_max = 32 * 16, .rates = DAVINCI_MCASP_RATES, .formats = DAVINCI_MCASP_PCM_FMTS, }, @@ -962,6 +993,10 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = { }; +static const struct snd_soc_component_driver davinci_mcasp_component = { + .name = "davinci-mcasp", +}; + static const struct of_device_id mcasp_dt_ids[] = { { .compatible = "ti,dm646x-mcasp-audio", @@ -1015,8 +1050,16 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of( pdata->op_mode = val; ret = of_property_read_u32(np, "tdm-slots", &val); - if (ret >= 0) + if (ret >= 0) { + if (val < 2 || val > 32) { + dev_err(&pdev->dev, + "tdm-slots must be in rage [2-32]\n"); + ret = -EINVAL; + goto nodata; + } + pdata->tdm_slots = val; + } ret = of_property_read_u32(np, "num-serializer", &val); if (ret >= 0) @@ -1170,7 +1213,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dma_data->channel = res->start; dev_set_drvdata(&pdev->dev, dev); - ret = snd_soc_register_dai(&pdev->dev, &davinci_mcasp_dai[pdata->op_mode]); + ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component, + &davinci_mcasp_dai[pdata->op_mode], 1); if (ret != 0) goto err_release_clk; @@ -1178,13 +1222,13 @@ static int davinci_mcasp_probe(struct platform_device *pdev) ret = davinci_soc_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "register PCM failed: %d\n", ret); - goto err_unregister_dai; + goto err_unregister_component; } return 0; -err_unregister_dai: - snd_soc_unregister_dai(&pdev->dev); +err_unregister_component: + snd_soc_unregister_component(&pdev->dev); err_release_clk: pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); @@ -1194,7 +1238,7 @@ err_release_clk: static int davinci_mcasp_remove(struct platform_device *pdev) { - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); davinci_soc_platform_unregister(&pdev->dev); pm_runtime_put_sync(&pdev->dev); |