diff options
-rw-r--r-- | sound/soc/tegra/tegra30_i2s.c | 42 | ||||
-rw-r--r-- | sound/soc/tegra/tegra30_i2s.h | 1 |
2 files changed, 35 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; diff --git a/sound/soc/tegra/tegra30_i2s.h b/sound/soc/tegra/tegra30_i2s.h index da3bedc55946..b7835277a037 100644 --- a/sound/soc/tegra/tegra30_i2s.h +++ b/sound/soc/tegra/tegra30_i2s.h @@ -238,6 +238,7 @@ struct tegra30_i2s { void __iomem *regs; struct dentry *debug; u32 reg_ctrl; + u32 reg_ch_ctrl; }; #endif |