summaryrefslogtreecommitdiff
path: root/sound/soc/tegra/tegra30_i2s.c
diff options
context:
space:
mode:
authorSumit Bhattacharya <sumitb@nvidia.com>2011-11-03 11:18:51 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:49:43 -0800
commitda2332f57ed58830d81cb4a5a3406a16e2e97d32 (patch)
treedc69c1a3c7e7a488e9ddcc0738f27c298eddc846 /sound/soc/tegra/tegra30_i2s.c
parentb65bc666f1521f2e55d2f03c7162ded303b715d6 (diff)
ASoC: Tegra: Support Tegra30 I2s DSP mode
Correct DSP-A/B mode logic and bitcnt calculation logic for DSP mode. Also enable single slot for both I2s and DSP modes. Bug 872652 Signed-off-by: Sumit Bhattacharya <sumitb@nvidia.com> Change-Id: I9df935bfddde71b3c3a0df68cef73f530079176c Reviewed-on: http://git-master/r/62024 Reviewed-by: Scott Peterson <speterson@nvidia.com> Tested-by: Sumit Bhattacharya <sumitb@nvidia.com> Rebase-Id: R8ef4810768bbc7d3d091cc08054e952763d9087f
Diffstat (limited to 'sound/soc/tegra/tegra30_i2s.c')
-rw-r--r--sound/soc/tegra/tegra30_i2s.c42
1 files changed, 34 insertions, 8 deletions
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index ea1e310722ba..ec0deb89d8cb 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -229,26 +229,32 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai,
i2s->reg_ctrl &= ~(TEGRA30_I2S_CTRL_FRAME_FORMAT_MASK |
TEGRA30_I2S_CTRL_LRCK_MASK);
+ i2s->reg_ch_ctrl &= ~TEGRA30_I2S_CH_CTRL_EGDE_CTRL_MASK;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_A:
i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC;
- i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
+ i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_R_LOW;
+ i2s->reg_ch_ctrl |= TEGRA30_I2S_CH_CTRL_EGDE_CTRL_NEG_EDGE;
break;
case SND_SOC_DAIFMT_DSP_B:
i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC;
i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_R_LOW;
+ i2s->reg_ch_ctrl |= TEGRA30_I2S_CH_CTRL_EGDE_CTRL_POS_EDGE;
break;
case SND_SOC_DAIFMT_I2S:
i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK;
i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
+ i2s->reg_ch_ctrl |= TEGRA30_I2S_CH_CTRL_EGDE_CTRL_POS_EDGE;
break;
case SND_SOC_DAIFMT_RIGHT_J:
i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK;
- i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
+ i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_R_LOW;
+ i2s->reg_ch_ctrl |= TEGRA30_I2S_CH_CTRL_EGDE_CTRL_POS_EDGE;
break;
case SND_SOC_DAIFMT_LEFT_J:
i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK;
- i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
+ i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_R_LOW;
+ i2s->reg_ch_ctrl |= TEGRA30_I2S_CH_CTRL_EGDE_CTRL_POS_EDGE;
break;
default:
return -EINVAL;
@@ -264,7 +270,7 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream,
struct device *dev = substream->pcm->card->dev;
struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
u32 val;
- int ret, sample_size, srate, i2sclock, bitcnt;
+ int ret, sample_size, srate, i2sclock, bitcnt, sym_bitclk;
if (params_channels(params) != 2)
return -EINVAL;
@@ -284,9 +290,9 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream,
/* Final "* 2" required by Tegra hardware */
i2sclock = srate * params_channels(params) * sample_size * 2;
- bitcnt = (i2sclock / (2 * srate)) - 1;
- if (bitcnt < 0 || bitcnt > TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US)
- return -EINVAL;
+ /* Additional "* 2" is needed for FSYNC mode */
+ if (i2s->reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC)
+ i2sclock *= 2;
ret = clk_set_rate(i2s->clk_i2s, i2sclock);
if (ret) {
@@ -294,11 +300,19 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream,
return ret;
}
+ if (i2s->reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC) {
+ bitcnt = (i2sclock / srate) - 1;
+ sym_bitclk = !(i2sclock % srate);
+ } else {
+ bitcnt = (i2sclock / (2 * srate)) - 1;
+ sym_bitclk = !(i2sclock % (2 * srate));
+ }
+
tegra30_i2s_enable_clocks(i2s);
val = bitcnt << TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT;
- if (i2sclock % (2 * srate))
+ if (!sym_bitclk)
val |= TEGRA30_I2S_TIMING_NON_SYM_ENABLE;
tegra30_i2s_write(i2s, TEGRA30_I2S_TIMING, val);
@@ -321,6 +335,18 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream,
(1 << TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT);
tegra30_i2s_write(i2s, TEGRA30_I2S_OFFSET, val);
+ tegra30_i2s_write(i2s, TEGRA30_I2S_CH_CTRL, i2s->reg_ch_ctrl);
+
+ val = tegra30_i2s_read(i2s, TEGRA30_I2S_SLOT_CTRL);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ val &= ~TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_MASK;
+ val |= (1 << TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_SHIFT);
+ } else {
+ val &= ~TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_MASK;
+ val |= (1 << TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT);
+ }
+ tegra30_i2s_write(i2s, TEGRA30_I2S_SLOT_CTRL, val);
+
tegra30_i2s_disable_clocks(i2s);
return 0;