diff options
author | Sumit Bhattacharya <sumitb@nvidia.com> | 2011-11-03 11:18:51 +0530 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:49:43 -0800 |
commit | da2332f57ed58830d81cb4a5a3406a16e2e97d32 (patch) | |
tree | dc69c1a3c7e7a488e9ddcc0738f27c298eddc846 /sound/soc/tegra/tegra30_i2s.c | |
parent | b65bc666f1521f2e55d2f03c7162ded303b715d6 (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.c | 42 |
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; |