From b676926984f3f0fb53d29b01daf9eeb0f7012128 Mon Sep 17 00:00:00 2001 From: Nikesh Oswal Date: Tue, 8 May 2012 16:47:40 +0530 Subject: asoc: tegra: pcm: If there is no dma information exit from trigger If there is no dma information exit from trigger, this is required for the dummy voice call playback and capture streams Change-Id: I5276e7ebb72c17268a9785204fea9f395b2e5d3a Signed-off-by: Nikesh Oswal Reviewed-on: http://git-master/r/101235 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Scott Peterson --- sound/soc/tegra/tegra_pcm.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound/soc/tegra') diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index 3b475a24c9a8..6ba3c9fa4461 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c @@ -257,9 +257,15 @@ int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_pcm_runtime *runtime = substream->runtime; struct tegra_runtime_data *prtd = runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct tegra_pcm_dma_params * dmap; unsigned long flags; int i; + dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + if (!dmap) + return 0; + switch (cmd) { case SNDRV_PCM_TRIGGER_START: prtd->dma_pos = 0; -- cgit v1.2.3 From b472fc27e733c371b9d35a3946b2142ca1a4a6eb Mon Sep 17 00:00:00 2001 From: Nikesh Oswal Date: Thu, 10 May 2012 12:23:45 +0530 Subject: Revert "asoc: tegra: Add TDM mode support" This reverts commit dfa00e184b5fe0d4d48fa62a15fc956de9b6b65c. This is causing a regresssion. Bug: 977319 Change-Id: I4fe6daf88b2988978f089194f2931691eeb0eb09 Signed-off-by: Nikesh Oswal Reviewed-on: http://git-master/r/101687 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Vijaya Bhaskar Reviewed-by: Scott Peterson --- sound/soc/tegra/tegra30_ahub.c | 172 +---------------------------- sound/soc/tegra/tegra30_ahub.h | 16 --- sound/soc/tegra/tegra30_i2s.c | 238 +---------------------------------------- sound/soc/tegra/tegra30_i2s.h | 14 +-- 4 files changed, 9 insertions(+), 431 deletions(-) (limited to 'sound/soc/tegra') diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index ea772f40464b..710d9465b4b0 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -116,15 +116,6 @@ void tegra30_ahub_disable_clocks(void) clk_disable(ahub->clk_d_audio); } -/* - * for TDM mode, ahub has to run faster than I2S controller. This will avoid - * FIFO overflow/underflow, the causes of slot-hopping symptoms - */ -void tegra30_ahub_clock_set_rate(int rate) -{ - clk_set_rate(ahub->clk_d_audio, rate); -} - #ifdef CONFIG_DEBUG_FS static inline u32 tegra30_ahub_read(u32 space, u32 reg) { @@ -281,116 +272,6 @@ int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, return 0; } -int tegra30_ahub_rx_fifo_is_busy(enum tegra30_ahub_rxcif rxcif) -{ - int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; - int reg, val; - - reg = TEGRA30_AHUB_CHANNEL_STATUS + - (channel * TEGRA30_AHUB_CHANNEL_STATUS_STRIDE); - - val = tegra30_apbif_read(reg); - val &= TEGRA30_AHUB_CHANNEL_STATUS_RX_TRIG; - - return val; -} - -int tegra30_ahub_tx_fifo_is_busy(enum tegra30_ahub_txcif txcif) -{ - int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; - int reg, val; - - reg = TEGRA30_AHUB_CHANNEL_STATUS + - (channel * TEGRA30_AHUB_CHANNEL_STATUS_STRIDE); - - val = tegra30_apbif_read(reg); - val &= TEGRA30_AHUB_CHANNEL_STATUS_TX_TRIG; - - return val; -} - -int tegra30_ahub_rx_fifo_clear(enum tegra30_ahub_rxcif rxcif) -{ - int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; - int reg, val; - - reg = TEGRA30_AHUB_CHANNEL_CLEAR + - (channel * TEGRA30_AHUB_CHANNEL_CLEAR_STRIDE); - - val = tegra30_apbif_read(reg); - val |= TEGRA30_AHUB_CHANNEL_CLEAR_RX_SOFT_RESET; - tegra30_apbif_write(reg, val); - - tegra30_ahub_disable_clocks(); - - return 0; -} - -int tegra30_ahub_tx_fifo_clear(enum tegra30_ahub_txcif txcif) -{ - int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; - int reg, val; - - reg = TEGRA30_AHUB_CHANNEL_CLEAR + - (channel * TEGRA30_AHUB_CHANNEL_CLEAR_STRIDE); - - val = tegra30_apbif_read(reg); - val |= TEGRA30_AHUB_CHANNEL_CLEAR_TX_SOFT_RESET; - tegra30_apbif_write(reg, val); - - tegra30_ahub_disable_clocks(); - - return 0; -} - -int tegra30_ahub_set_rx_fifo_pack_mode(enum tegra30_ahub_rxcif rxcif, - unsigned int pack_mode) -{ - int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; - int reg, val; - - tegra30_ahub_enable_clocks(); - reg = TEGRA30_AHUB_CHANNEL_CTRL + - (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); - val = tegra30_apbif_read(reg); - - val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK; - val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN; - - if ((pack_mode == TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16) || - (pack_mode == TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_8_4)) - val |= (TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN | - pack_mode); - tegra30_apbif_write(reg, val); - tegra30_ahub_disable_clocks(); - - return 0; -} - -int tegra30_ahub_set_tx_fifo_pack_mode(enum tegra30_ahub_txcif txcif, - unsigned int pack_mode) -{ - int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; - int reg, val; - - tegra30_ahub_enable_clocks(); - reg = TEGRA30_AHUB_CHANNEL_CTRL + - (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); - val = tegra30_apbif_read(reg); - - val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK; - val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN; - - if ((pack_mode == TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16) || - (pack_mode == TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_8_4)) - val |= (TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN | - pack_mode); - tegra30_apbif_write(reg, val); - tegra30_ahub_disable_clocks(); - - return 0; -} - int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif) { int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; @@ -418,6 +299,8 @@ int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif) val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_EN; tegra30_apbif_write(reg, val); + tegra30_ahub_disable_clocks(); + return 0; } @@ -503,6 +386,8 @@ int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif) val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_EN; tegra30_apbif_write(reg, val); + tegra30_ahub_disable_clocks(); + return 0; } @@ -595,54 +480,6 @@ int tegra30_ahub_set_tx_cif_channels(enum tegra30_ahub_txcif txcif, return 0; } -int tegra30_ahub_set_rx_cif_bits(enum tegra30_ahub_rxcif rxcif, - unsigned int audio_bits, - unsigned int client_bits) -{ - int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; - unsigned int reg, val; - - tegra30_ahub_enable_clocks(); - - reg = TEGRA30_AHUB_CIF_RX_CTRL + - (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE); - val = tegra30_apbif_read(reg); - val &= ~(TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_MASK | - TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_MASK); - val |= ((audio_bits) << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | - ((client_bits) << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT); - tegra30_apbif_write(reg, val); - - tegra30_ahub_disable_clocks(); - - return 0; -} - -int tegra30_ahub_set_tx_cif_bits(enum tegra30_ahub_txcif txcif, - unsigned int audio_bits, - unsigned int client_bits) -{ - int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; - unsigned int reg, val; - - tegra30_ahub_enable_clocks(); - - reg = TEGRA30_AHUB_CIF_TX_CTRL + - (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE); - val = tegra30_apbif_read(reg); - val &= ~(TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_MASK | - TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_MASK); - val |= ((audio_bits) << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | - ((client_bits) << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT); - - tegra30_apbif_write(reg, val); - - tegra30_ahub_disable_clocks(); - - return 0; -} - - static int __devinit tegra30_ahub_probe(struct platform_device *pdev) { struct resource *res0, *res1, *region; @@ -670,7 +507,6 @@ static int __devinit tegra30_ahub_probe(struct platform_device *pdev) goto err_free; } clkm_rate = clk_get_rate(clk_get_parent(ahub->clk_d_audio)); - while (clkm_rate > 12000000) clkm_rate >>= 1; diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h index 2c0f5aab4db1..7de1b7c86c7f 100644 --- a/sound/soc/tegra/tegra30_ahub.h +++ b/sound/soc/tegra/tegra30_ahub.h @@ -464,7 +464,6 @@ enum tegra30_ahub_rxcif { extern void tegra30_ahub_enable_clocks(void); extern void tegra30_ahub_disable_clocks(void); -extern void tegra30_ahub_clock_set_rate(int rate); extern int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, unsigned long *fiforeg, @@ -472,13 +471,8 @@ extern int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, extern int tegra30_ahub_set_rx_cif_channels(enum tegra30_ahub_rxcif rxcif, unsigned int audio_ch, unsigned int client_ch); -extern int tegra30_ahub_set_rx_cif_bits(enum tegra30_ahub_rxcif rxcif, - unsigned int audio_bits, - unsigned int client_bits); extern int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif); extern int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif); -extern int tegra30_ahub_set_rx_fifo_pack_mode(enum tegra30_ahub_rxcif rxcif, - unsigned int pack_mode); extern int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif); extern int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif, @@ -487,24 +481,14 @@ extern int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif, extern int tegra30_ahub_set_tx_cif_channels(enum tegra30_ahub_txcif txcif, unsigned int audio_ch, unsigned int client_ch); -extern int tegra30_ahub_set_tx_cif_bits(enum tegra30_ahub_txcif txcif, - unsigned int audio_bits, - unsigned int client_bits); extern int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif); extern int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif); -extern int tegra30_ahub_set_tx_fifo_pack_mode(enum tegra30_ahub_txcif txcif, - unsigned int pack_mode); extern int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif); extern int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif, enum tegra30_ahub_txcif txcif); extern int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif); -extern int tegra30_ahub_rx_fifo_is_busy(enum tegra30_ahub_rxcif rxcif); -extern int tegra30_ahub_tx_fifo_is_busy(enum tegra30_ahub_txcif txcif); -extern int tegra30_ahub_rx_fifo_clear(enum tegra30_ahub_rxcif rxcif); -extern int tegra30_ahub_tx_fifo_clear(enum tegra30_ahub_txcif txcif); - #ifdef CONFIG_PM extern int tegra30_ahub_apbif_resume(void); #endif diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index c2750bfbef64..02d1038ea36e 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -281,194 +280,6 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai, return 0; } -static void tegra30_i2s_set_channel_bit_count(struct tegra30_i2s *i2s, - int i2sclock, int srate) -{ - int sym_bitclk, bitcnt; - u32 val; - - bitcnt = (i2sclock / (2 * srate)) - 1; - sym_bitclk = !(i2sclock % (2 * srate)); - - val = bitcnt << TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT; - - if (!sym_bitclk) - val |= TEGRA30_I2S_TIMING_NON_SYM_ENABLE; - - tegra30_i2s_write(i2s, TEGRA30_I2S_TIMING, val); -} - -static void tegra30_i2s_set_data_offset(struct tegra30_i2s *i2s) -{ - u32 val; - int rx_data_offset = i2s->dsp_config.rx_data_offset; - int tx_data_offset = i2s->dsp_config.tx_data_offset; - - val = (rx_data_offset << - TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT) | - (tx_data_offset << - TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT); - - tegra30_i2s_write(i2s, TEGRA30_I2S_OFFSET, val); -} - -static void tegra30_i2s_set_slot_control(struct tegra30_i2s *i2s, int stream) -{ - u32 val; - int tx_mask = i2s->dsp_config.tx_mask; - int rx_mask = i2s->dsp_config.rx_mask; - - val = tegra30_i2s_read(i2s, TEGRA30_I2S_SLOT_CTRL); - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - val &= ~TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_MASK; - val |= (tx_mask << TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_SHIFT); - } else { - val &= ~TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_MASK; - val |= (rx_mask << TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT); - } - - val &= ~TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK; - val |= (i2s->dsp_config.num_slots - 1) - << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT; - - tegra30_i2s_write(i2s, TEGRA30_I2S_SLOT_CTRL, val); -} - -static int tegra30_i2s_tdm_setup_clocks(struct device *dev, - struct tegra30_i2s *i2s, int *i2sclock) -{ - int ret; - - if (i2s->reg_ctrl & TEGRA30_I2S_CTRL_MASTER_ENABLE) { - - ret = clk_set_parent(i2s->clk_i2s, i2s->clk_pll_a_out0); - if (ret) { - dev_err(dev, "Can't set parent of I2S clock\n"); - return ret; - } - ret = clk_set_rate(i2s->clk_i2s, *i2sclock); - if (ret) { - dev_err(dev, "Can't set I2S clock rate: %d\n", ret); - return ret; - } - } else { - - ret = clk_set_rate(i2s->clk_i2s_sync, *i2sclock); - if (ret) { - dev_err(dev, "Can't set I2S sync clock rate\n"); - return ret; - } - - ret = clk_set_rate(i2s->clk_audio_2x, *i2sclock); - if (ret) { - dev_err(dev, "Can't set audio2x clock rate\n"); - return ret; - } - - ret = clk_set_parent(i2s->clk_i2s, i2s->clk_audio_2x); - if (ret) { - dev_err(dev, "Can't set parent of audio2x clock\n"); - return ret; - } - } - return ret; -} - - -static int tegra30_i2s_tdm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct device *dev = substream->pcm->card->dev; - struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); - u32 val; - int i2s_client_ch, i2s_audio_ch, i2s_audio_bits, i2s_client_bits; - int i2sclock, srate; - int ret; - - srate = params_rate(params); - - i2sclock = srate * - i2s->dsp_config.num_slots * - i2s->dsp_config.slot_width; - - ret = tegra30_i2s_tdm_setup_clocks(dev, i2s, &i2sclock); - if (ret) - return -EINVAL; - - /* Run ahub clock greater than i2sclock */ - tegra30_ahub_clock_set_rate(i2sclock*2); - - tegra30_i2s_enable_clocks(i2s); - - tegra30_i2s_set_channel_bit_count(i2s, i2sclock*2, srate); - - i2s_client_ch = i2s->dsp_config.num_slots; - i2s_audio_ch = i2s->dsp_config.num_slots; - - i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_BIT_SIZE_MASK; - switch (i2s->dsp_config.slot_width) { - case 16: - i2s_audio_bits = TEGRA30_AUDIOCIF_BITS_16; - i2s_client_bits = TEGRA30_AUDIOCIF_BITS_16; - i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_16; - break; - case 32: - i2s_audio_bits = TEGRA30_AUDIOCIF_BITS_32; - i2s_client_bits = TEGRA30_AUDIOCIF_BITS_32; - i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_32; - break; - } - - val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | - ((i2s_audio_ch - 1) << - TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | - ((i2s_client_ch - 1) << - TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) | - (i2s_audio_bits << - TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | - (i2s_client_bits << - TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX; - tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_RX_CTRL, val); - - tegra30_ahub_set_tx_cif_channels(i2s->txcif, - i2s_audio_ch, - i2s_client_ch); - tegra30_ahub_set_tx_cif_bits(i2s->txcif, - i2s_audio_bits, - i2s_client_bits); - tegra30_ahub_set_tx_fifo_pack_mode(i2s->txcif, 0); - - } else { - val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX; - tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_TX_CTRL, val); - - tegra30_ahub_set_rx_cif_channels(i2s->rxcif, - i2s_audio_ch, - i2s_client_ch); - tegra30_ahub_set_rx_cif_bits(i2s->rxcif, - i2s_audio_bits, - i2s_client_bits); - tegra30_ahub_set_rx_fifo_pack_mode(i2s->rxcif, 0); - } - - tegra30_i2s_set_slot_control(i2s, substream->stream); - - tegra30_i2s_set_data_offset(i2s); - - i2s->reg_ch_ctrl &= ~TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_MASK; - i2s->reg_ch_ctrl |= (i2s->dsp_config.slot_width - 1) << - TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_SHIFT; - tegra30_i2s_write(i2s, TEGRA30_I2S_CH_CTRL, i2s->reg_ch_ctrl); - - tegra30_i2s_disable_clocks(i2s); - - return 0; -} - static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -489,12 +300,6 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - /* TDM mode */ - if ((i2s->reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC) && - (i2s->dsp_config.slot_width > 2)) - return tegra30_i2s_tdm_hw_params(substream, params, dai); - - srate = params_rate(params); if (i2s->reg_ctrl & TEGRA30_I2S_CTRL_MASTER_ENABLE) { @@ -618,16 +423,12 @@ static void tegra30_i2s_start_playback(struct tegra30_i2s *i2s) static void tegra30_i2s_stop_playback(struct tegra30_i2s *i2s) { - int dcnt = 10; - /* if this is the only user of i2s tx then disable it*/ tegra30_ahub_disable_tx_fifo(i2s->txcif); + /* if this is the only user of i2s tx then disable it*/ if (i2s->playback_ref_count == 1) { i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX; tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl); } - while (tegra30_ahub_tx_fifo_is_busy(i2s->txcif) && dcnt--) - udelay(100); - tegra30_ahub_tx_fifo_clear(i2s->txcif); } static void tegra30_i2s_start_capture(struct tegra30_i2s *i2s) @@ -641,15 +442,11 @@ static void tegra30_i2s_start_capture(struct tegra30_i2s *i2s) static void tegra30_i2s_stop_capture(struct tegra30_i2s *i2s) { - int dcnt = 10; tegra30_ahub_disable_rx_fifo(i2s->rxcif); if (!i2s->is_call_mode_rec) { i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX; tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl); } - while (tegra30_ahub_rx_fifo_is_busy(i2s->rxcif) && dcnt--) - udelay(100); - tegra30_ahub_rx_fifo_clear(i2s->rxcif); } static int tegra30_i2s_trigger(struct snd_pcm_substream *substream, int cmd, @@ -703,33 +500,6 @@ static int tegra30_i2s_probe(struct snd_soc_dai *dai) tegra30_i2s_disable_clocks(i2s); #endif - /* Default values for DSP mode */ - i2s->dsp_config.num_slots = 1; - i2s->dsp_config.slot_width = 2; - i2s->dsp_config.tx_mask = 1; - i2s->dsp_config.rx_mask = 1; - i2s->dsp_config.rx_data_offset = 1; - i2s->dsp_config.tx_data_offset = 1; - - - return 0; -} - -int tegra30_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai, - unsigned int tx_mask, - unsigned int rx_mask, - int slots, - int slot_width) -{ - struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai); - - i2s->dsp_config.num_slots = slots; - i2s->dsp_config.slot_width = slot_width; - i2s->dsp_config.tx_mask = tx_mask; - i2s->dsp_config.rx_mask = rx_mask; - i2s->dsp_config.rx_data_offset = 0; - i2s->dsp_config.tx_data_offset = 0; - return 0; } @@ -764,7 +534,6 @@ static struct snd_soc_dai_ops tegra30_i2s_dai_ops = { .set_fmt = tegra30_i2s_set_fmt, .hw_params = tegra30_i2s_hw_params, .trigger = tegra30_i2s_trigger, - .set_tdm_slot = tegra30_i2s_set_tdm_slot, }; #define TEGRA30_I2S_DAI(id) \ @@ -774,13 +543,13 @@ static struct snd_soc_dai_ops tegra30_i2s_dai_ops = { .resume = tegra30_i2s_resume, \ .playback = { \ .channels_min = 1, \ - .channels_max = 16, \ + .channels_max = 2, \ .rates = SNDRV_PCM_RATE_8000_96000, \ .formats = SNDRV_PCM_FMTBIT_S16_LE, \ }, \ .capture = { \ .channels_min = 1, \ - .channels_max = 16, \ + .channels_max = 2, \ .rates = SNDRV_PCM_RATE_8000_96000, \ .formats = SNDRV_PCM_FMTBIT_S16_LE, \ }, \ @@ -1058,6 +827,7 @@ static __devinit int tegra30_i2s_platform_probe(struct platform_device *pdev) ret = PTR_ERR(i2s->clk_i2s); goto exit; } + i2s->clk_i2s_sync = clk_get(&pdev->dev, "ext_audio_sync"); if (IS_ERR(i2s->clk_i2s_sync)) { dev_err(&pdev->dev, "Can't retrieve i2s_sync clock\n"); diff --git a/sound/soc/tegra/tegra30_i2s.h b/sound/soc/tegra/tegra30_i2s.h index 0992bf0d5b17..b9baddd5db8e 100644 --- a/sound/soc/tegra/tegra30_i2s.h +++ b/sound/soc/tegra/tegra30_i2s.h @@ -176,7 +176,7 @@ /* Number of slots in frame, minus 1 */ #define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT 16 #define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK_US 7 -#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK (TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK_US << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT) +#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK (TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOT_MASK_US << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOT_SHIFT) /* TDM mode slot enable bitmask */ #define TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT 8 @@ -231,16 +231,6 @@ /* Number of i2s controllers*/ #define TEGRA30_NR_I2S_IFC 5 -struct dsp_config_t { - int num_slots; - int rx_mask; - int tx_mask; - int slot_width; - int rx_data_offset; - int tx_data_offset; -}; - - struct tegra30_i2s { int id; struct clk *clk_i2s; @@ -264,8 +254,6 @@ struct tegra30_i2s { #endif int call_record_dam_ifc; int is_call_mode_rec; - - struct dsp_config_t dsp_config; }; struct codec_config { -- cgit v1.2.3 From 9de840ea6eaa98d5bd836b132f5d1cbaaaaeeea3 Mon Sep 17 00:00:00 2001 From: Ankit Gupta Date: Thu, 3 May 2012 15:06:27 +0530 Subject: asoc: tegra: pcm: Add support for setting bias level Allow setting bias level to turn off clock extern1 when codec is idle for Enterprise (Maxim 98088 codec). Bug 984678 Signed-off-by: Ankit Gupta Change-Id: I09538dafe6c6f01547ff989de3c23933c9745db0 Reviewed-on: http://git-master/r/100286 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Scott Peterson Reviewed-by: Manoj Gangwal Tested-by: Ankit Gupta (Engrg-SW) --- sound/soc/tegra/tegra_pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/tegra') diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index 6ba3c9fa4461..1b4b949841aa 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c @@ -425,7 +425,7 @@ void tegra_pcm_free(struct snd_pcm *pcm) static int tegra_pcm_probe(struct snd_soc_platform *platform) { - if(machine_is_kai()) + if(machine_is_kai() || machine_is_tegra_enterprise()) platform->dapm.idle_bias_off = 1; return 0; -- cgit v1.2.3 From 71c2ea698d4c1c7d91247ebf638dd33f1563ac26 Mon Sep 17 00:00:00 2001 From: Nikesh Oswal Date: Fri, 11 May 2012 19:53:27 +0530 Subject: asoc:tegra: Enable I2S tx in voice call Associated with I2S there is a playback ref count, when we open the I2S for plyabck it is incremented and during voice call we check if its not zero then enable the tX. This logic fails if the start-trigger is not called for the prior playback stream. Hence we unconditionally enable the tx, which is harmless Bug: 981806 Change-Id: I66aafda596e2b2b03745e93f3e851dedc3b8ef5d Signed-off-by: Nikesh Oswal Reviewed-on: http://git-master/r/101996 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Scott Peterson --- sound/soc/tegra/tegra30_i2s.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'sound/soc/tegra') diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 02d1038ea36e..aba964281349 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -726,10 +726,7 @@ int tegra30_make_voice_call_connections(struct codec_config *codec_info, tegra30_dam_enable(bb_i2s->dam_ifc, TEGRA30_DAM_ENABLE, TEGRA30_DAM_CHIN0_SRC); - /* if this is the only user of i2s tx then enable it*/ - if (codec_i2s->playback_ref_count == 1) - codec_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_TX; - + codec_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_TX; codec_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_RX; tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, codec_i2s->reg_ctrl); -- cgit v1.2.3 From 0172fb19ebf3e5fb667b37e64bf3473ccdd1bc35 Mon Sep 17 00:00:00 2001 From: Ankit Gupta Date: Mon, 14 May 2012 18:43:23 +0530 Subject: asoc: tegra: MAX98088 machine: Add support for setting bias level Allow setting bias level to turn off clock extern1 when codec is idle for enterprise board. (Maxim 98088 codec) Bug 984678 Change-Id: Ib01be71362ab0c5525f570693b41db73777875e6 Signed-off-by: Ankit Gupta Reviewed-on: http://git-master/r/102240 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Manoj Gangwal Reviewed-by: Scott Peterson --- sound/soc/tegra/tegra_max98088.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'sound/soc/tegra') diff --git a/sound/soc/tegra/tegra_max98088.c b/sound/soc/tegra/tegra_max98088.c index 63a067338dc4..8c0e3935ad02 100644 --- a/sound/soc/tegra/tegra_max98088.c +++ b/sound/soc/tegra/tegra_max98088.c @@ -96,6 +96,7 @@ struct tegra_max98088 { #endif enum snd_soc_bias_level bias_level; struct snd_soc_card *pcard; + volatile int clock_enabled; }; static int tegra_call_mode_info(struct snd_kcontrol *kcontrol, @@ -926,6 +927,7 @@ static int tegra_max98088_init(struct snd_soc_pcm_runtime *rtd) machine->pcard = card; machine->bias_level = SND_SOC_BIAS_STANDBY; + machine->clock_enabled = 1; if (gpio_is_valid(pdata->gpio_spkr_en)) { ret = gpio_request(pdata->gpio_spkr_en, "spkr_en"); @@ -1070,8 +1072,11 @@ static int tegra30_soc_set_bias_level(struct snd_soc_card *card, struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card); if (machine->bias_level == SND_SOC_BIAS_OFF && - level != SND_SOC_BIAS_OFF) + level != SND_SOC_BIAS_OFF && (!machine->clock_enabled)) { + machine->clock_enabled = 1; tegra_asoc_utils_clk_enable(&machine->util_data); + machine->bias_level = level; + } return 0; } @@ -1082,8 +1087,10 @@ static int tegra30_soc_set_bias_level_post(struct snd_soc_card *card, struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card); if (machine->bias_level != SND_SOC_BIAS_OFF && - level == SND_SOC_BIAS_OFF) + level == SND_SOC_BIAS_OFF && (machine->clock_enabled)) { + machine->clock_enabled = 0; tegra_asoc_utils_clk_disable(&machine->util_data); + } machine->bias_level = level; @@ -1156,6 +1163,7 @@ static __devinit int tegra_max98088_driver_probe(struct platform_device *pdev) tegra_max98088_i2s_dai_name[machine->codec_info[BT_SCO].i2s_id]; #endif + card->dapm.idle_bias_off = 1; ret = snd_soc_register_card(card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", -- cgit v1.2.3 From 6b7e887d5742406d988cb6f797846a83f00a31bb Mon Sep 17 00:00:00 2001 From: Nitin Pai Date: Tue, 24 Apr 2012 15:57:51 +0530 Subject: asoc: tegra: Add TDM mode support Added TDM mode support in I2S driver. Added support functions in AHUB to pass audio/client bits. Added support functions in AHUB to pass audio/client channels. Fixed the stopping of I2S/TDM by clearing the fifo. Bug 948478 Signed-off-by: Nitin Pai Change-Id: I560f4ab5b71e4833931934275272a094241241fe Reviewed-on: http://git-master/r/103840 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Ravindra Lokhande Reviewed-by: Scott Peterson --- sound/soc/tegra/tegra30_ahub.c | 127 ++++++++++++++++++++++ sound/soc/tegra/tegra30_ahub.h | 14 +++ sound/soc/tegra/tegra30_i2s.c | 236 ++++++++++++++++++++++++++++++++++++++++- sound/soc/tegra/tegra30_i2s.h | 14 ++- 4 files changed, 386 insertions(+), 5 deletions(-) (limited to 'sound/soc/tegra') diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index 710d9465b4b0..30b7e481acc4 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -116,6 +116,15 @@ void tegra30_ahub_disable_clocks(void) clk_disable(ahub->clk_d_audio); } +/* + * for TDM mode, ahub has to run faster than I2S controller. This will avoid + * FIFO overflow/underflow, the causes of slot-hopping symptoms + */ +void tegra30_ahub_clock_set_rate(int rate) +{ + clk_set_rate(ahub->clk_d_audio, rate); +} + #ifdef CONFIG_DEBUG_FS static inline u32 tegra30_ahub_read(u32 space, u32 reg) { @@ -272,6 +281,75 @@ int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, return 0; } +int tegra30_ahub_rx_fifo_is_enabled(int i2s_id) +{ + int val, mask; + + val = tegra30_apbif_read(TEGRA30_AHUB_I2S_LIVE_STATUS); + mask = (TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_RX_FIFO_ENABLED << (i2s_id*2)); + val &= mask; + return val; +} + +int tegra30_ahub_tx_fifo_is_enabled(int i2s_id) +{ + int val, mask; + + val = tegra30_apbif_read(TEGRA30_AHUB_I2S_LIVE_STATUS); + mask = (TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_TX_FIFO_ENABLED << (i2s_id*2)); + val &= mask; + + return val; +} + +int tegra30_ahub_set_rx_fifo_pack_mode(enum tegra30_ahub_rxcif rxcif, + unsigned int pack_mode) +{ + int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; + int reg, val; + + tegra30_ahub_enable_clocks(); + reg = TEGRA30_AHUB_CHANNEL_CTRL + + (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); + val = tegra30_apbif_read(reg); + + val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK; + val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN; + + if ((pack_mode == TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16) || + (pack_mode == TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_8_4)) + val |= (TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN | + pack_mode); + tegra30_apbif_write(reg, val); + tegra30_ahub_disable_clocks(); + + return 0; +} + +int tegra30_ahub_set_tx_fifo_pack_mode(enum tegra30_ahub_txcif txcif, + unsigned int pack_mode) +{ + int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; + int reg, val; + + tegra30_ahub_enable_clocks(); + reg = TEGRA30_AHUB_CHANNEL_CTRL + + (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); + val = tegra30_apbif_read(reg); + + val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK; + val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN; + + if ((pack_mode == TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16) || + (pack_mode == TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_8_4)) + val |= (TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN | + pack_mode); + tegra30_apbif_write(reg, val); + tegra30_ahub_disable_clocks(); + + return 0; +} + int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif) { int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; @@ -480,6 +558,54 @@ int tegra30_ahub_set_tx_cif_channels(enum tegra30_ahub_txcif txcif, return 0; } +int tegra30_ahub_set_rx_cif_bits(enum tegra30_ahub_rxcif rxcif, + unsigned int audio_bits, + unsigned int client_bits) +{ + int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; + unsigned int reg, val; + + tegra30_ahub_enable_clocks(); + + reg = TEGRA30_AHUB_CIF_RX_CTRL + + (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE); + val = tegra30_apbif_read(reg); + val &= ~(TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_MASK | + TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_MASK); + val |= ((audio_bits) << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | + ((client_bits) << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT); + tegra30_apbif_write(reg, val); + + tegra30_ahub_disable_clocks(); + + return 0; +} + +int tegra30_ahub_set_tx_cif_bits(enum tegra30_ahub_txcif txcif, + unsigned int audio_bits, + unsigned int client_bits) +{ + int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; + unsigned int reg, val; + + tegra30_ahub_enable_clocks(); + + reg = TEGRA30_AHUB_CIF_TX_CTRL + + (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE); + val = tegra30_apbif_read(reg); + val &= ~(TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_MASK | + TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_MASK); + val |= ((audio_bits) << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | + ((client_bits) << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT); + + tegra30_apbif_write(reg, val); + + tegra30_ahub_disable_clocks(); + + return 0; +} + + static int __devinit tegra30_ahub_probe(struct platform_device *pdev) { struct resource *res0, *res1, *region; @@ -507,6 +633,7 @@ static int __devinit tegra30_ahub_probe(struct platform_device *pdev) goto err_free; } clkm_rate = clk_get_rate(clk_get_parent(ahub->clk_d_audio)); + while (clkm_rate > 12000000) clkm_rate >>= 1; diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h index 7de1b7c86c7f..8dc27abc5aed 100644 --- a/sound/soc/tegra/tegra30_ahub.h +++ b/sound/soc/tegra/tegra30_ahub.h @@ -464,6 +464,7 @@ enum tegra30_ahub_rxcif { extern void tegra30_ahub_enable_clocks(void); extern void tegra30_ahub_disable_clocks(void); +extern void tegra30_ahub_clock_set_rate(int rate); extern int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, unsigned long *fiforeg, @@ -471,8 +472,13 @@ extern int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, extern int tegra30_ahub_set_rx_cif_channels(enum tegra30_ahub_rxcif rxcif, unsigned int audio_ch, unsigned int client_ch); +extern int tegra30_ahub_set_rx_cif_bits(enum tegra30_ahub_rxcif rxcif, + unsigned int audio_bits, + unsigned int client_bits); extern int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif); extern int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif); +extern int tegra30_ahub_set_rx_fifo_pack_mode(enum tegra30_ahub_rxcif rxcif, + unsigned int pack_mode); extern int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif); extern int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif, @@ -481,14 +487,22 @@ extern int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif, extern int tegra30_ahub_set_tx_cif_channels(enum tegra30_ahub_txcif txcif, unsigned int audio_ch, unsigned int client_ch); +extern int tegra30_ahub_set_tx_cif_bits(enum tegra30_ahub_txcif txcif, + unsigned int audio_bits, + unsigned int client_bits); extern int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif); extern int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif); +extern int tegra30_ahub_set_tx_fifo_pack_mode(enum tegra30_ahub_txcif txcif, + unsigned int pack_mode); extern int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif); extern int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif, enum tegra30_ahub_txcif txcif); extern int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif); +extern int tegra30_ahub_rx_fifo_is_enabled(int i2s_id); +extern int tegra30_ahub_tx_fifo_is_enabled(int i2s_id); + #ifdef CONFIG_PM extern int tegra30_ahub_apbif_resume(void); #endif diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index aba964281349..449359837efb 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -280,6 +281,194 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai, return 0; } +static void tegra30_i2s_set_channel_bit_count(struct tegra30_i2s *i2s, + int i2sclock, int srate) +{ + int sym_bitclk, bitcnt; + u32 val; + + bitcnt = (i2sclock / (2 * srate)) - 1; + sym_bitclk = !(i2sclock % (2 * srate)); + + val = bitcnt << TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT; + + if (!sym_bitclk) + val |= TEGRA30_I2S_TIMING_NON_SYM_ENABLE; + + tegra30_i2s_write(i2s, TEGRA30_I2S_TIMING, val); +} + +static void tegra30_i2s_set_data_offset(struct tegra30_i2s *i2s) +{ + u32 val; + int rx_data_offset = i2s->dsp_config.rx_data_offset; + int tx_data_offset = i2s->dsp_config.tx_data_offset; + + val = (rx_data_offset << + TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT) | + (tx_data_offset << + TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT); + + tegra30_i2s_write(i2s, TEGRA30_I2S_OFFSET, val); +} + +static void tegra30_i2s_set_slot_control(struct tegra30_i2s *i2s, int stream) +{ + u32 val; + int tx_mask = i2s->dsp_config.tx_mask; + int rx_mask = i2s->dsp_config.rx_mask; + + val = tegra30_i2s_read(i2s, TEGRA30_I2S_SLOT_CTRL); + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + val &= ~TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_MASK; + val |= (tx_mask << TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_SHIFT); + } else { + val &= ~TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_MASK; + val |= (rx_mask << TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT); + } + + val &= ~TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK; + val |= (i2s->dsp_config.num_slots - 1) + << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT; + + tegra30_i2s_write(i2s, TEGRA30_I2S_SLOT_CTRL, val); +} + +static int tegra30_i2s_tdm_setup_clocks(struct device *dev, + struct tegra30_i2s *i2s, int *i2sclock) +{ + int ret; + + if (i2s->reg_ctrl & TEGRA30_I2S_CTRL_MASTER_ENABLE) { + + ret = clk_set_parent(i2s->clk_i2s, i2s->clk_pll_a_out0); + if (ret) { + dev_err(dev, "Can't set parent of I2S clock\n"); + return ret; + } + ret = clk_set_rate(i2s->clk_i2s, *i2sclock); + if (ret) { + dev_err(dev, "Can't set I2S clock rate: %d\n", ret); + return ret; + } + } else { + + ret = clk_set_rate(i2s->clk_i2s_sync, *i2sclock); + if (ret) { + dev_err(dev, "Can't set I2S sync clock rate\n"); + return ret; + } + + ret = clk_set_rate(i2s->clk_audio_2x, *i2sclock); + if (ret) { + dev_err(dev, "Can't set audio2x clock rate\n"); + return ret; + } + + ret = clk_set_parent(i2s->clk_i2s, i2s->clk_audio_2x); + if (ret) { + dev_err(dev, "Can't set parent of audio2x clock\n"); + return ret; + } + } + return ret; +} + + +static int tegra30_i2s_tdm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct device *dev = substream->pcm->card->dev; + struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); + u32 val; + int i2s_client_ch, i2s_audio_ch, i2s_audio_bits, i2s_client_bits; + int i2sclock, srate; + int ret; + + srate = params_rate(params); + + i2sclock = srate * + i2s->dsp_config.num_slots * + i2s->dsp_config.slot_width; + + ret = tegra30_i2s_tdm_setup_clocks(dev, i2s, &i2sclock); + if (ret) + return -EINVAL; + + /* Run ahub clock greater than i2sclock */ + tegra30_ahub_clock_set_rate(i2sclock*2); + + tegra30_i2s_enable_clocks(i2s); + + tegra30_i2s_set_channel_bit_count(i2s, i2sclock*2, srate); + + i2s_client_ch = i2s->dsp_config.num_slots; + i2s_audio_ch = i2s->dsp_config.num_slots; + + i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_BIT_SIZE_MASK; + switch (i2s->dsp_config.slot_width) { + case 16: + i2s_audio_bits = TEGRA30_AUDIOCIF_BITS_16; + i2s_client_bits = TEGRA30_AUDIOCIF_BITS_16; + i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_16; + break; + case 32: + i2s_audio_bits = TEGRA30_AUDIOCIF_BITS_32; + i2s_client_bits = TEGRA30_AUDIOCIF_BITS_32; + i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_32; + break; + } + + val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | + ((i2s_audio_ch - 1) << + TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | + ((i2s_client_ch - 1) << + TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) | + (i2s_audio_bits << + TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | + (i2s_client_bits << + TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX; + tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_RX_CTRL, val); + + tegra30_ahub_set_tx_cif_channels(i2s->txcif, + i2s_audio_ch, + i2s_client_ch); + tegra30_ahub_set_tx_cif_bits(i2s->txcif, + i2s_audio_bits, + i2s_client_bits); + tegra30_ahub_set_tx_fifo_pack_mode(i2s->txcif, 0); + + } else { + val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX; + tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_TX_CTRL, val); + + tegra30_ahub_set_rx_cif_channels(i2s->rxcif, + i2s_audio_ch, + i2s_client_ch); + tegra30_ahub_set_rx_cif_bits(i2s->rxcif, + i2s_audio_bits, + i2s_client_bits); + tegra30_ahub_set_rx_fifo_pack_mode(i2s->rxcif, 0); + } + + tegra30_i2s_set_slot_control(i2s, substream->stream); + + tegra30_i2s_set_data_offset(i2s); + + i2s->reg_ch_ctrl &= ~TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_MASK; + i2s->reg_ch_ctrl |= (i2s->dsp_config.slot_width - 1) << + TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_SHIFT; + tegra30_i2s_write(i2s, TEGRA30_I2S_CH_CTRL, i2s->reg_ch_ctrl); + + tegra30_i2s_disable_clocks(i2s); + + return 0; +} + static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -300,6 +489,12 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + /* TDM mode */ + if ((i2s->reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC) && + (i2s->dsp_config.slot_width > 2)) + return tegra30_i2s_tdm_hw_params(substream, params, dai); + + srate = params_rate(params); if (i2s->reg_ctrl & TEGRA30_I2S_CTRL_MASTER_ENABLE) { @@ -423,12 +618,15 @@ static void tegra30_i2s_start_playback(struct tegra30_i2s *i2s) static void tegra30_i2s_stop_playback(struct tegra30_i2s *i2s) { - tegra30_ahub_disable_tx_fifo(i2s->txcif); + int dcnt = 10; /* if this is the only user of i2s tx then disable it*/ + tegra30_ahub_disable_tx_fifo(i2s->txcif); if (i2s->playback_ref_count == 1) { i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX; tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl); } + while (tegra30_ahub_tx_fifo_is_enabled(i2s->id) && dcnt--) + udelay(100); } static void tegra30_i2s_start_capture(struct tegra30_i2s *i2s) @@ -442,11 +640,14 @@ static void tegra30_i2s_start_capture(struct tegra30_i2s *i2s) static void tegra30_i2s_stop_capture(struct tegra30_i2s *i2s) { + int dcnt = 10; tegra30_ahub_disable_rx_fifo(i2s->rxcif); if (!i2s->is_call_mode_rec) { i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX; tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl); } + while (tegra30_ahub_rx_fifo_is_enabled(i2s->id) && dcnt--) + udelay(100); } static int tegra30_i2s_trigger(struct snd_pcm_substream *substream, int cmd, @@ -500,6 +701,33 @@ static int tegra30_i2s_probe(struct snd_soc_dai *dai) tegra30_i2s_disable_clocks(i2s); #endif + /* Default values for DSP mode */ + i2s->dsp_config.num_slots = 1; + i2s->dsp_config.slot_width = 2; + i2s->dsp_config.tx_mask = 1; + i2s->dsp_config.rx_mask = 1; + i2s->dsp_config.rx_data_offset = 1; + i2s->dsp_config.tx_data_offset = 1; + + + return 0; +} + +int tegra30_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai, + unsigned int tx_mask, + unsigned int rx_mask, + int slots, + int slot_width) +{ + struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai); + + i2s->dsp_config.num_slots = slots; + i2s->dsp_config.slot_width = slot_width; + i2s->dsp_config.tx_mask = tx_mask; + i2s->dsp_config.rx_mask = rx_mask; + i2s->dsp_config.rx_data_offset = 0; + i2s->dsp_config.tx_data_offset = 0; + return 0; } @@ -534,6 +762,7 @@ static struct snd_soc_dai_ops tegra30_i2s_dai_ops = { .set_fmt = tegra30_i2s_set_fmt, .hw_params = tegra30_i2s_hw_params, .trigger = tegra30_i2s_trigger, + .set_tdm_slot = tegra30_i2s_set_tdm_slot, }; #define TEGRA30_I2S_DAI(id) \ @@ -543,13 +772,13 @@ static struct snd_soc_dai_ops tegra30_i2s_dai_ops = { .resume = tegra30_i2s_resume, \ .playback = { \ .channels_min = 1, \ - .channels_max = 2, \ + .channels_max = 16, \ .rates = SNDRV_PCM_RATE_8000_96000, \ .formats = SNDRV_PCM_FMTBIT_S16_LE, \ }, \ .capture = { \ .channels_min = 1, \ - .channels_max = 2, \ + .channels_max = 16, \ .rates = SNDRV_PCM_RATE_8000_96000, \ .formats = SNDRV_PCM_FMTBIT_S16_LE, \ }, \ @@ -824,7 +1053,6 @@ static __devinit int tegra30_i2s_platform_probe(struct platform_device *pdev) ret = PTR_ERR(i2s->clk_i2s); goto exit; } - i2s->clk_i2s_sync = clk_get(&pdev->dev, "ext_audio_sync"); if (IS_ERR(i2s->clk_i2s_sync)) { dev_err(&pdev->dev, "Can't retrieve i2s_sync clock\n"); diff --git a/sound/soc/tegra/tegra30_i2s.h b/sound/soc/tegra/tegra30_i2s.h index b9baddd5db8e..0992bf0d5b17 100644 --- a/sound/soc/tegra/tegra30_i2s.h +++ b/sound/soc/tegra/tegra30_i2s.h @@ -176,7 +176,7 @@ /* Number of slots in frame, minus 1 */ #define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT 16 #define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK_US 7 -#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK (TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOT_MASK_US << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOT_SHIFT) +#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK (TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK_US << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT) /* TDM mode slot enable bitmask */ #define TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT 8 @@ -231,6 +231,16 @@ /* Number of i2s controllers*/ #define TEGRA30_NR_I2S_IFC 5 +struct dsp_config_t { + int num_slots; + int rx_mask; + int tx_mask; + int slot_width; + int rx_data_offset; + int tx_data_offset; +}; + + struct tegra30_i2s { int id; struct clk *clk_i2s; @@ -254,6 +264,8 @@ struct tegra30_i2s { #endif int call_record_dam_ifc; int is_call_mode_rec; + + struct dsp_config_t dsp_config; }; struct codec_config { -- cgit v1.2.3 From 4e88128f3c4c40bf3b6cd1146dffe6a5156fef04 Mon Sep 17 00:00:00 2001 From: Nitin Pai Date: Tue, 22 May 2012 12:04:15 +0530 Subject: asoc: tegra: P1852 machine: Add TDM mode settings Pass TDM mode variables for CPU dai. Codec Id is not passed properly, hence use dual instances of the dai_link operations. Bug 948478 Change-Id: I13188d5001b8f9c2f2f67ee7a9d3bec89311037d Signed-off-by: Bob Johnston Reviewed-on: http://git-master/r/103793 Reviewed-by: Nitin Pai Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Scott Peterson --- sound/soc/tegra/tegra_p1852.c | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) (limited to 'sound/soc/tegra') diff --git a/sound/soc/tegra/tegra_p1852.c b/sound/soc/tegra/tegra_p1852.c index 9506a1c842df..85b4cee30c5f 100644 --- a/sound/soc/tegra/tegra_p1852.c +++ b/sound/soc/tegra/tegra_p1852.c @@ -49,7 +49,8 @@ struct tegra_p1852 { }; static int tegra_p1852_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + int codec_id) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; @@ -61,7 +62,6 @@ static int tegra_p1852_hw_params(struct snd_pcm_substream *substream, int i2s_daifmt = 0; int err; struct tegra_p1852_platform_data *pdata; - int codec_id = codec_dai->id; pdata = machine->pdata; @@ -120,15 +120,39 @@ static int tegra_p1852_hw_params(struct snd_pcm_substream *substream, dev_err(card->dev, "cpu_dai fmt not set\n"); return err; } - err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, SND_SOC_CLOCK_IN); if (err < 0) dev_info(card->dev, "codec_dai clock not set\n"); + if (pdata->codec_info[codec_id].i2s_format == + format_tdm) { + err = snd_soc_dai_set_tdm_slot(cpu_dai, + pdata->codec_info[codec_id].rx_mask, + pdata->codec_info[codec_id].tx_mask, + pdata->codec_info[codec_id].num_slots, + pdata->codec_info[codec_id].slot_width); + if (err < 0) + dev_err(card->dev, "cpu_dai tdm mode setting not done\n"); + } + return 0; } +static int tegra_p1852_hw_params_controller1( + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + return tegra_p1852_hw_params(substream, params, 0); +} + +static int tegra_p1852_hw_params_controller2( + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + return tegra_p1852_hw_params(substream, params, 1); +} + static int tegra_hw_free(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -139,8 +163,12 @@ static int tegra_hw_free(struct snd_pcm_substream *substream) return 0; } -static struct snd_soc_ops tegra_p1852_ops = { - .hw_params = tegra_p1852_hw_params, +static struct snd_soc_ops tegra_p1852_ops_controller1 = { + .hw_params = tegra_p1852_hw_params_controller1, + .hw_free = tegra_hw_free, +}; +static struct snd_soc_ops tegra_p1852_ops_controller2 = { + .hw_params = tegra_p1852_hw_params_controller2, .hw_free = tegra_hw_free, }; @@ -149,13 +177,13 @@ static struct snd_soc_dai_link tegra_p1852_dai_link[] = { .name = "I2S-TDM-1", .stream_name = "TEGRA PCM", .platform_name = "tegra-pcm-audio", - .ops = &tegra_p1852_ops, + .ops = &tegra_p1852_ops_controller1, }, { .name = "I2S-TDM-2", .stream_name = "TEGRA PCM", .platform_name = "tegra-pcm-audio", - .ops = &tegra_p1852_ops, + .ops = &tegra_p1852_ops_controller2, } }; -- cgit v1.2.3 From 8e9dc6ce7d8cafba0e65123b2f76320309e8388c Mon Sep 17 00:00:00 2001 From: Ankit Gupta Date: Wed, 23 May 2012 11:55:13 +0530 Subject: asoc: tegra: utils: fix for multiple instances of extern1 clock. The extern1 codec clock was not getting switched off whenever codec goes below BIAS_OFF level. Moreover, there were two instances of extern1 clock whenever codec was on. Reason behind this was that, those codecs for which probe function was called and were not present on board, turned on their extern1 clock, but clean up routine (for switch device register failure) was not able to turn off the clock. With this change, a conditional check is put to turn off the clock. (Bug 984678) Signed-off-by: Ankit Gupta Change-Id: I585ecf73c0cabca856592dcd84e67588dfe13beb Reviewed-on: http://git-master/r/104073 Reviewed-by: Automatic_Commit_Validation_User Tested-by: Ankit Gupta (Engrg-SW) Reviewed-by: Prashant Gaikwad Reviewed-by: Bharat Nihalani --- sound/soc/tegra/tegra_asoc_utils.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound/soc/tegra') diff --git a/sound/soc/tegra/tegra_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c index b134f0808afa..dfbafa061993 100644 --- a/sound/soc/tegra/tegra_asoc_utils.c +++ b/sound/soc/tegra/tegra_asoc_utils.c @@ -276,6 +276,10 @@ void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data) clk_put(data->clk_out1); clk_put(data->clk_cdev1); + /* Just to make sure that clk_cdev1 should turn off in case if it is + * switched on by some codec whose hw switch is not registered.*/ + if (tegra_is_clk_enabled(data->clk_cdev1)) + clk_disable(data->clk_cdev1); if (!IS_ERR(data->clk_pll_a_out0)) clk_put(data->clk_pll_a_out0); -- cgit v1.2.3 From 98c26489fd954b63655c805ff87b8dd6368b31d5 Mon Sep 17 00:00:00 2001 From: Sanjay Singh Rawat Date: Tue, 22 May 2012 10:27:38 +0530 Subject: ASoC: resolve compilation time warnings Bug 949219 Change-Id: If7b4dd928cc5a808fd1a674bcc5f31c9a396a043 Signed-off-by: Sanjay Singh Rawat Reviewed-on: http://git-master/r/103772 Reviewed-by: Simone Willett Tested-by: Simone Willett --- sound/soc/tegra/tegra20_das.c | 6 +++--- sound/soc/tegra/tegra20_das.h | 4 ++-- sound/soc/tegra/tegra_asoc_utils.c | 2 +- sound/soc/tegra/tegra_wm8753.c | 1 - 4 files changed, 6 insertions(+), 7 deletions(-) (limited to 'sound/soc/tegra') diff --git a/sound/soc/tegra/tegra20_das.c b/sound/soc/tegra/tegra20_das.c index 0774d360399a..29c4582cfa79 100644 --- a/sound/soc/tegra/tegra20_das.c +++ b/sound/soc/tegra/tegra20_das.c @@ -50,7 +50,7 @@ static inline u32 tegra20_das_read(u32 reg) } #ifdef CONFIG_PM -int tegra20_das_resume() +int tegra20_das_resume(void) { int i, reg; @@ -67,7 +67,7 @@ int tegra20_das_resume() } #endif -int tegra20_das_set_tristate(int dap_id, int is_tristate) +void tegra20_das_set_tristate(int dap_id, int is_tristate) { enum tegra_pingroup pin; enum tegra_tristate tristate; @@ -86,7 +86,7 @@ int tegra20_das_set_tristate(int dap_id, int is_tristate) pin = TEGRA_PINGROUP_DAP4; break; default: - return -EINVAL; + return; } if (is_tristate) diff --git a/sound/soc/tegra/tegra20_das.h b/sound/soc/tegra/tegra20_das.h index 0d58c7d1bc3f..5cd2d07d43b8 100644 --- a/sound/soc/tegra/tegra20_das.h +++ b/sound/soc/tegra/tegra20_das.h @@ -98,7 +98,7 @@ struct tegra20_das { #ifdef CONFIG_PM /* Restores the das registers from cache */ -extern int tegra20_das_resume(); +extern int tegra20_das_resume(void); #endif /* * Terminology: @@ -143,6 +143,6 @@ extern int tegra20_das_connect_dap_to_dap(int dap_id, int other_dap_sel, */ extern int tegra20_das_connect_dac_to_dap(int dac_id, int dap_sel); -extern int tegra20_das_set_tristate(int dap_id, int is_tristate); +extern void tegra20_das_set_tristate(int dap_id, int is_tristate); #endif diff --git a/sound/soc/tegra/tegra_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c index dfbafa061993..a189fb5c61c1 100644 --- a/sound/soc/tegra/tegra_asoc_utils.c +++ b/sound/soc/tegra/tegra_asoc_utils.c @@ -31,7 +31,7 @@ int g_is_call_mode; -bool tegra_is_voice_call_active() +bool tegra_is_voice_call_active(void) { if (g_is_call_mode) return true; diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c index 795356875ba4..99d0b19c7106 100644 --- a/sound/soc/tegra/tegra_wm8753.c +++ b/sound/soc/tegra/tegra_wm8753.c @@ -379,7 +379,6 @@ static int tegra_bt_call_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_codec *codec = rtd->codec; struct snd_soc_card *card = codec->card; struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card); -- cgit v1.2.3 From 97b5fcb955784c5245debc020473318dd45e5683 Mon Sep 17 00:00:00 2001 From: Sanjay Singh Rawat Date: Thu, 24 May 2012 16:39:37 +0530 Subject: ASoC: tegra: treat compilation warning as error Bug 949219 Change-Id: Ic8976b008772220299369369427a80dd370df596 Signed-off-by: Sanjay Singh Rawat Reviewed-on: http://git-master/r/104419 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Bharat Nihalani --- sound/soc/tegra/Makefile | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/soc/tegra') diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index 9c4346aa265c..7af02a69b8ae 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile @@ -1,5 +1,7 @@ GCOV_PROFILE := y +subdir-ccflags-y := -Werror + # Tegra platform Support snd-soc-tegra-pcm-objs := tegra_pcm.o snd-soc-tegra-tdm-pcm-objs := tegra_tdm_pcm.o -- cgit v1.2.3 From bd09096c7b6431f31d312e45689f59215a0e1356 Mon Sep 17 00:00:00 2001 From: Sumit Bhattacharya Date: Fri, 20 Apr 2012 17:41:16 +0530 Subject: ASoC: Tegra: Add support for AVP rendering Add alsa controls to specify which alsa device is used by AVP to render audio. Also add support for disabling DMA interrupt when AVP renders audio. Also add couple of alsa controls to query DMA channel ID and DMA buffer physical address. Bug 968814 Signed-off-by: Sumit Bhattacharya Change-Id: If593329db72bf00d97f7433f5c54e13500281253 Reviewed-on: http://git-master/r/97916 Reviewed-by: Rohan Somvanshi Tested-by: Rohan Somvanshi --- sound/soc/tegra/tegra_aic326x.c | 4 ++ sound/soc/tegra/tegra_asoc_utils.c | 132 +++++++++++++++++++++++++++++++++++++ sound/soc/tegra/tegra_asoc_utils.h | 4 ++ sound/soc/tegra/tegra_max98088.c | 4 ++ sound/soc/tegra/tegra_max98095.c | 4 ++ sound/soc/tegra/tegra_pcm.c | 18 +++-- sound/soc/tegra/tegra_pcm.h | 1 + sound/soc/tegra/tegra_rt5640.c | 5 ++ sound/soc/tegra/tegra_wm8753.c | 4 ++ sound/soc/tegra/tegra_wm8903.c | 4 ++ 10 files changed, 176 insertions(+), 4 deletions(-) (limited to 'sound/soc/tegra') diff --git a/sound/soc/tegra/tegra_aic326x.c b/sound/soc/tegra/tegra_aic326x.c index a5c6fc0aecb7..4cacb6758eb8 100644 --- a/sound/soc/tegra/tegra_aic326x.c +++ b/sound/soc/tegra/tegra_aic326x.c @@ -1062,6 +1062,10 @@ static int tegra_aic326x_init(struct snd_soc_pcm_runtime *rtd) if (ret < 0) return ret; + ret = tegra_asoc_utils_register_ctls(&machine->util_data); + if (ret < 0) + return ret; + snd_soc_dapm_force_enable_pin(dapm, "MICBIAS_EXT ON"); snd_soc_dapm_force_enable_pin(dapm,"MICBIAS_INT ON"); snd_soc_dapm_sync(dapm); diff --git a/sound/soc/tegra/tegra_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c index a189fb5c61c1..6ab5b2d46a1f 100644 --- a/sound/soc/tegra/tegra_asoc_utils.c +++ b/sound/soc/tegra/tegra_asoc_utils.c @@ -27,6 +27,9 @@ #include +#include + +#include "tegra_pcm.h" #include "tegra_asoc_utils.h" int g_is_call_mode; @@ -40,6 +43,115 @@ bool tegra_is_voice_call_active(void) } EXPORT_SYMBOL_GPL(tegra_is_voice_call_active); +static int tegra_get_avp_device(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tegra_asoc_utils_data *data = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = data->avp_device_id; + return 0; +} + +static int tegra_set_avp_device(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tegra_asoc_utils_data *data = snd_kcontrol_chip(kcontrol); + struct snd_soc_card *card = data->card; + struct snd_soc_pcm_runtime *rtd; + struct snd_pcm_substream *substream; + struct tegra_runtime_data *prtd; + int id, old_id = data->avp_device_id; + + id = ucontrol->value.integer.value[0]; + if ((id >= card->num_rtd) || (id < 0)) + id = -1; + + if (old_id >= 0) { + rtd = &card->rtd[old_id]; + substream = + rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + if (substream && substream->runtime) { + prtd = substream->runtime->private_data; + if (prtd->running) + return -EBUSY; + if (prtd) + prtd->disable_intr = false; + } + } + + if (id >= 0) { + rtd = &card->rtd[id]; + substream = + rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + if (substream && substream->runtime) { + prtd = substream->runtime->private_data; + if (prtd->running) + return -EBUSY; + if (prtd) + prtd->disable_intr = true; + } + } + data->avp_device_id = id; + return 1; +} + +static int tegra_get_dma_ch_id(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tegra_asoc_utils_data *data = snd_kcontrol_chip(kcontrol); + struct snd_soc_card *card = data->card; + struct snd_soc_pcm_runtime *rtd; + struct snd_pcm_substream *substream; + struct tegra_runtime_data *prtd; + + ucontrol->value.integer.value[0] = -1; + if (data->avp_device_id < 0) + return 0; + + rtd = &card->rtd[data->avp_device_id]; + substream = rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + if (!substream || !substream->runtime) + return 0; + + prtd = substream->runtime->private_data; + if (!prtd || !prtd->dma_chan) + return 0; + + ucontrol->value.integer.value[0] = + tegra_dma_get_channel_id(prtd->dma_chan); + return 0; +} + +static int tegra_get_dma_addr(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tegra_asoc_utils_data *data = snd_kcontrol_chip(kcontrol); + struct snd_soc_card *card = data->card; + struct snd_soc_pcm_runtime *rtd; + struct snd_pcm_substream *substream; + + ucontrol->value.integer.value[0] = 0; + if (data->avp_device_id < 0) + return 0; + + rtd = &card->rtd[data->avp_device_id]; + substream = rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + if (!substream || !substream->runtime) + return 0; + + ucontrol->value.integer.value[0] = substream->runtime->dma_addr; + return 0; +} + +struct snd_kcontrol_new tegra_avp_controls[] = { + SOC_SINGLE_EXT("AVP alsa device select", 0, 0, TEGRA_ALSA_MAX_DEVICES, \ + 0, tegra_get_avp_device, tegra_set_avp_device), + SOC_SINGLE_EXT("AVP DMA channel id", 0, 0, TEGRA_DMA_MAX_CHANNELS, \ + 0, tegra_get_dma_ch_id, NULL), + SOC_SINGLE_EXT("AVP DMA address", 0, 0, 0xFFFFFFFF, \ + 0, tegra_get_dma_addr, NULL), +}; + int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, int mclk) { @@ -152,6 +264,26 @@ int tegra_asoc_utils_clk_disable(struct tegra_asoc_utils_data *data) } EXPORT_SYMBOL_GPL(tegra_asoc_utils_clk_disable); +int tegra_asoc_utils_register_ctls(struct tegra_asoc_utils_data *data) +{ + int i; + int ret = 0; + + /* Add AVP related alsa controls */ + data->avp_device_id = -1; + for (i = 0; i < ARRAY_SIZE(tegra_avp_controls); i++) { + ret = snd_ctl_add(data->card->snd_card, + snd_ctl_new1(&tegra_avp_controls[i], data)); + if (ret < 0) { + dev_err(data->dev, "Can't add avp alsa controls"); + return ret; + } + } + + return ret; +} +EXPORT_SYMBOL_GPL(tegra_asoc_utils_register_ctls); + int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data, struct device *dev, struct snd_soc_card *card) { diff --git a/sound/soc/tegra/tegra_asoc_utils.h b/sound/soc/tegra/tegra_asoc_utils.h index 512df0d54eb1..0423f02b76cc 100644 --- a/sound/soc/tegra/tegra_asoc_utils.h +++ b/sound/soc/tegra/tegra_asoc_utils.h @@ -25,6 +25,8 @@ #define TEGRA30_I2S_MASTER_PLAYBACK 1 +#define TEGRA_ALSA_MAX_DEVICES 6 +#define TEGRA_DMA_MAX_CHANNELS 32 struct clk; struct device; @@ -41,6 +43,7 @@ struct tegra_asoc_utils_data { int set_baseclock; int set_mclk; int lock_count; + int avp_device_id; }; int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, @@ -52,6 +55,7 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data, void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data); int tegra_asoc_utils_clk_enable(struct tegra_asoc_utils_data *data); int tegra_asoc_utils_clk_disable(struct tegra_asoc_utils_data *data); +int tegra_asoc_utils_register_ctls(struct tegra_asoc_utils_data *data); #endif diff --git a/sound/soc/tegra/tegra_max98088.c b/sound/soc/tegra/tegra_max98088.c index 8c0e3935ad02..82c2b930a39e 100644 --- a/sound/soc/tegra/tegra_max98088.c +++ b/sound/soc/tegra/tegra_max98088.c @@ -1009,6 +1009,10 @@ static int tegra_max98088_init(struct snd_soc_pcm_runtime *rtd) if (ret < 0) return ret; + ret = tegra_asoc_utils_register_ctls(&machine->util_data); + if (ret < 0) + return ret; + snd_soc_dapm_nc_pin(dapm, "INA1"); snd_soc_dapm_nc_pin(dapm, "INA2"); snd_soc_dapm_nc_pin(dapm, "INB1"); diff --git a/sound/soc/tegra/tegra_max98095.c b/sound/soc/tegra/tegra_max98095.c index 95295ef4151e..b3bed37ac715 100644 --- a/sound/soc/tegra/tegra_max98095.c +++ b/sound/soc/tegra/tegra_max98095.c @@ -542,6 +542,10 @@ static int tegra_max98095_init(struct snd_soc_pcm_runtime *rtd) tegra_max98095_hp_jack_pins); #endif + ret = tegra_asoc_utils_register_ctls(&machine->util_data); + if (ret < 0) + return ret; + /* max98095_headset_detect(codec, &tegra_max98095_hp_jack, SND_JACK_HEADSET); */ diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index 1b4b949841aa..f471fafff2ac 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c @@ -52,8 +52,8 @@ static const struct snd_pcm_hardware tegra_pcm_hardware = { .channels_min = 1, .channels_max = 2, .period_bytes_min = 128, - .period_bytes_max = PAGE_SIZE, - .periods_min = 2, + .period_bytes_max = PAGE_SIZE * 2, + .periods_min = 1, .periods_max = 8, .buffer_bytes_max = PAGE_SIZE * 8, .fifo_size = 4, @@ -272,6 +272,15 @@ int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd) prtd->dma_pos_end = frames_to_bytes(runtime, runtime->periods * runtime->period_size); prtd->period_index = 0; prtd->dma_req_idx = 0; + if (prtd->disable_intr) { + prtd->dma_req_count = 1; + prtd->dma_req[0].complete = NULL; + } else if (!prtd->dma_req[0].complete) { + prtd->dma_req[0].complete = dma_complete_callback; + prtd->dma_req_count = + (MAX_DMA_REQ_COUNT <= runtime->periods) ? + MAX_DMA_REQ_COUNT : runtime->periods; + } /* Fall-through */ case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: @@ -289,8 +298,9 @@ int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd) spin_unlock_irqrestore(&prtd->lock, flags); tegra_dma_cancel(prtd->dma_chan); for (i = 0; i < prtd->dma_req_count; i++) { - if (prtd->dma_req[i].status == - -TEGRA_DMA_REQ_ERROR_ABORTED) + if (prtd->dma_req[i].complete && + (prtd->dma_req[i].status == + -TEGRA_DMA_REQ_ERROR_ABORTED)) prtd->dma_req[i].complete(&prtd->dma_req[i]); } break; diff --git a/sound/soc/tegra/tegra_pcm.h b/sound/soc/tegra/tegra_pcm.h index 7fe22788004b..b63de32023e8 100644 --- a/sound/soc/tegra/tegra_pcm.h +++ b/sound/soc/tegra/tegra_pcm.h @@ -53,6 +53,7 @@ struct tegra_runtime_data { struct tegra_dma_req dma_req[MAX_DMA_REQ_COUNT]; struct tegra_dma_channel *dma_chan; int dma_req_count; + int disable_intr; }; int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd); diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c index 231b0ee61308..765eb59fabae 100644 --- a/sound/soc/tegra/tegra_rt5640.c +++ b/sound/soc/tegra/tegra_rt5640.c @@ -547,6 +547,11 @@ static int tegra_rt5640_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_add_routes(dapm, cardhu_audio_map, ARRAY_SIZE(cardhu_audio_map)); + + ret = tegra_asoc_utils_register_ctls(&machine->util_data); + if (ret < 0) + return ret; + /* FIXME: Calculate automatically based on DAPM routes? */ snd_soc_dapm_nc_pin(dapm, "LOUTL"); snd_soc_dapm_nc_pin(dapm, "LOUTR"); diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c index 99d0b19c7106..f7c7a4c6b5a1 100644 --- a/sound/soc/tegra/tegra_wm8753.c +++ b/sound/soc/tegra/tegra_wm8753.c @@ -782,6 +782,10 @@ static int tegra_wm8753_init(struct snd_soc_pcm_runtime *rtd) if (ret < 0) return ret; + ret = tegra_asoc_utils_register_ctls(&machine->util_data); + if (ret < 0) + return ret; + snd_soc_dapm_nc_pin(dapm, "ACIN"); snd_soc_dapm_nc_pin(dapm, "ACOP"); snd_soc_dapm_nc_pin(dapm, "OUT3"); diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index ce608b007bef..147546575233 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -660,6 +660,10 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) wm8903_mic_detect(codec, &tegra_wm8903_mic_jack, SND_JACK_MICROPHONE, machine_is_cardhu() ? SND_JACK_MICROPHONE : 0); + ret = tegra_asoc_utils_register_ctls(&machine->util_data); + if (ret < 0) + return ret; + snd_soc_dapm_force_enable_pin(dapm, "Mic Bias"); /* FIXME: Calculate automatically based on DAPM routes? */ -- cgit v1.2.3 From ee944d7e32042a63c7e8068c04e00c2fe0330301 Mon Sep 17 00:00:00 2001 From: Juha Tukkinen Date: Wed, 30 May 2012 17:04:48 +0300 Subject: ASoC: tegra: remove compilation warning Ensure i2s_client_bits and i2s_audio_bits do not get used uninitialized. Bug 949219 Change-Id: Ibdd7f2598278639388d2c2afb5843f2471375ea2 Signed-off-by: Juha Tukkinen Reviewed-on: http://git-master/r/105426 Reviewed-by: Sachin Nikam Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Sanjay Singh Rawat --- sound/soc/tegra/tegra30_i2s.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound/soc/tegra') diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 449359837efb..8be00b840fb5 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -418,6 +418,10 @@ static int tegra30_i2s_tdm_hw_params(struct snd_pcm_substream *substream, i2s_client_bits = TEGRA30_AUDIOCIF_BITS_32; i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_32; break; + default: + dev_err(dev, "unknown slot_width %d\n", + i2s->dsp_config.slot_width); + return -EINVAL; } val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | -- cgit v1.2.3 From a828242259b8fb216d76d28619f1ae2927932645 Mon Sep 17 00:00:00 2001 From: Nitin Pai Date: Wed, 30 May 2012 18:31:46 +0530 Subject: asoc: tegra: p1852: Use pcm-driver from platform Use the pcm-driver specified from platform/board specified file. Bug 991926 Change-Id: I9e4c9a3f76bacb22de817273a2281ac9b8959c43 Signed-off-by: Nitin Pai Reviewed-on: http://git-master/r/105415 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Bob Johnston GVS: Gerrit_Virtual_Submit Reviewed-by: Scott Peterson --- sound/soc/tegra/tegra_p1852.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound/soc/tegra') diff --git a/sound/soc/tegra/tegra_p1852.c b/sound/soc/tegra/tegra_p1852.c index 85b4cee30c5f..199bb8046636 100644 --- a/sound/soc/tegra/tegra_p1852.c +++ b/sound/soc/tegra/tegra_p1852.c @@ -227,6 +227,9 @@ static __devinit int tegra_p1852_driver_probe(struct platform_device *pdev) pdata->codec_info[i].codec_dai_name; tegra_p1852_dai_link[i].name = pdata->codec_info[i].name; + if (pdata->codec_info[i].pcm_driver) + tegra_p1852_dai_link[i].platform_name = + pdata->codec_info[i].pcm_driver; } ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card); -- cgit v1.2.3 From f9417ad159c43ae90f25c0ef978e2c37294d27a1 Mon Sep 17 00:00:00 2001 From: Nitin Pai Date: Thu, 24 May 2012 17:16:03 +0530 Subject: asoc: tegra: Fix setting rate for clk_audio_2x - For slave mode, clk_audio_2x needs to be programmed to bitclock value. Setting this frequency is not possible if the parent clock has different frequency. Hence change the parent of this clock to i2s_sync clock first before setting the rate. - Fixed setting uninitialized variables. Bug 948478 Change-Id: Ieb4656e6e114d3a9b815f44003a476c4b9892059 Signed-off-by: Nitin Pai Reviewed-on: http://git-master/r/104445 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Bob Johnston GVS: Gerrit_Virtual_Submit Reviewed-by: Scott Peterson --- sound/soc/tegra/tegra30_i2s.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'sound/soc/tegra') diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 8be00b840fb5..a50b853135ae 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -346,6 +346,7 @@ static int tegra30_i2s_tdm_setup_clocks(struct device *dev, dev_err(dev, "Can't set parent of I2S clock\n"); return ret; } + ret = clk_set_rate(i2s->clk_i2s, *i2sclock); if (ret) { dev_err(dev, "Can't set I2S clock rate: %d\n", ret); @@ -359,6 +360,13 @@ static int tegra30_i2s_tdm_setup_clocks(struct device *dev, return ret; } + ret = clk_set_parent(clk_get_parent(i2s->clk_audio_2x), + i2s->clk_i2s_sync); + if (ret) { + dev_err(dev, "Can't set parent of audio2x clock\n"); + return ret; + } + ret = clk_set_rate(i2s->clk_audio_2x, *i2sclock); if (ret) { dev_err(dev, "Can't set audio2x clock rate\n"); @@ -367,7 +375,7 @@ static int tegra30_i2s_tdm_setup_clocks(struct device *dev, ret = clk_set_parent(i2s->clk_i2s, i2s->clk_audio_2x); if (ret) { - dev_err(dev, "Can't set parent of audio2x clock\n"); + dev_err(dev, "Can't set parent of i2s clock\n"); return ret; } } @@ -382,7 +390,8 @@ static int tegra30_i2s_tdm_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 i2s_client_ch, i2s_audio_ch, i2s_audio_bits, i2s_client_bits; + int i2s_client_ch, i2s_audio_ch; + int i2s_audio_bits = 0, i2s_client_bits = 0; int i2sclock, srate; int ret; -- cgit v1.2.3 From 8e83ca8bde2e1c42df08f37840226c9d07d4af69 Mon Sep 17 00:00:00 2001 From: Rhyland Klein Date: Wed, 6 Jun 2012 15:28:40 -0400 Subject: asoc: max98095: probe with no device there fix There is path through which registering a card will fail to probe, but that error code is not propogated back to the tegra machine driver. To catch this case in the machine driver's probe routine, we need to ensure that after registering the card, the card is instantiated and fail probe if not. Change-Id: I64ba952685ef193a3b248502943771c518396808 Signed-off-by: Rhyland Klein Reviewed-on: http://git-master/r/106837 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Scott Peterson --- sound/soc/tegra/tegra_max98095.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'sound/soc/tegra') diff --git a/sound/soc/tegra/tegra_max98095.c b/sound/soc/tegra/tegra_max98095.c index b3bed37ac715..701571d23251 100644 --- a/sound/soc/tegra/tegra_max98095.c +++ b/sound/soc/tegra/tegra_max98095.c @@ -658,8 +658,17 @@ static __devinit int tegra_max98095_driver_probe(struct platform_device *pdev) goto err_switch_unregister; } + if (!card->instantiated) { + ret = -ENODEV; + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", + ret); + goto err_unregister_card; + } + return 0; +err_unregister_card: + snd_soc_unregister_card(card); err_switch_unregister: #ifdef CONFIG_SWITCH switch_dev_unregister(&wired_switch_dev); -- cgit v1.2.3 From daf2ee7b9eefb84d2140152786ba8a19674b4fe6 Mon Sep 17 00:00:00 2001 From: Rhyland Klein Date: Wed, 30 May 2012 14:34:47 -0400 Subject: sound: soc: tegra: fix compilation errors Several compilation errors popped up when building the 3.1 kernel for chrome. Warnings included callback structure changing and not being updated in the max98095 codec driver and unused labels. With these change I am able to compile in the max98095 codec support and wm8903 without build errors. Bug 986933 Change-Id: Ia8b2511f54b031eadcad8c74efa88be9288f25fb Signed-off-by: Rhyland Klein Reviewed-on: http://git-master/r/105464 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Scott Peterson --- sound/soc/tegra/tegra_max98095.c | 4 +++- sound/soc/tegra/tegra_wm8903.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'sound/soc/tegra') diff --git a/sound/soc/tegra/tegra_max98095.c b/sound/soc/tegra/tegra_max98095.c index 701571d23251..d065b78164ac 100644 --- a/sound/soc/tegra/tegra_max98095.c +++ b/sound/soc/tegra/tegra_max98095.c @@ -581,6 +581,7 @@ static struct snd_soc_dai_link tegra_max98095_dai[] = { }; static int tegra30_soc_set_bias_level(struct snd_soc_card *card, + struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { struct tegra_max98095 *machine = snd_soc_card_get_drvdata(card); @@ -595,6 +596,7 @@ static int tegra30_soc_set_bias_level(struct snd_soc_card *card, } static int tegra30_soc_set_bias_level_post(struct snd_soc_card *card, + struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { struct tegra_max98095 *machine = snd_soc_card_get_drvdata(card); @@ -672,8 +674,8 @@ err_unregister_card: err_switch_unregister: #ifdef CONFIG_SWITCH switch_dev_unregister(&wired_switch_dev); -#endif err_fini_utils: +#endif tegra_asoc_utils_fini(&machine->util_data); err_free_machine: kfree(machine); diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index 147546575233..063aefe50507 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -902,8 +902,8 @@ err_unregister_card: err_unregister_switch: #ifdef CONFIG_SWITCH switch_dev_unregister(&tegra_wm8903_headset_switch); -#endif err_fini_utils: +#endif tegra_asoc_utils_fini(&machine->util_data); err_free_machine: kfree(machine); -- cgit v1.2.3 From 8f751e925da2510ded1003976186a379853b134e Mon Sep 17 00:00:00 2001 From: Nikesh Oswal Date: Fri, 22 Jun 2012 12:54:52 +0530 Subject: asoc: tegra: Change HW disabling dequence and I2S clock parent Change HW disabling dequence and I2S clock parent in slave mode for voice call use-case Bug: 1005176 Signed-off-by: Nikesh Oswal Reviewed-on: http://git-master/r/110529 (cherry picked from commit 4b138cdeb3374575bde9f49d0c644faa91ced68f) Change-Id: Ia037ed5ef45d38972c3e1e1a78b4b7b7f39d8f72 Reviewed-on: http://git-master/r/114444 Reviewed-by: Automatic_Commit_Validation_User Tested-by: Nikesh Oswal Reviewed-by: Scott Peterson --- sound/soc/tegra/tegra30_ahub.c | 37 +++++++++++ sound/soc/tegra/tegra30_ahub.h | 4 ++ sound/soc/tegra/tegra30_dam.c | 47 ++++++++++--- sound/soc/tegra/tegra30_i2s.c | 147 +++++++++++++++++++++++++++++------------ 4 files changed, 183 insertions(+), 52 deletions(-) (limited to 'sound/soc/tegra') diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index 30b7e481acc4..6fac8fc0177b 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -3,6 +3,7 @@ * * Author: Stephen Warren * Copyright (C) 2011 - NVIDIA, Inc. + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -302,6 +303,42 @@ int tegra30_ahub_tx_fifo_is_enabled(int i2s_id) return val; } +int tegra30_ahub_dam_ch0_is_enabled(int dam_id) +{ + int val, mask; + + val = tegra30_apbif_read((TEGRA30_AHUB_DAM_LIVE_STATUS) + + (dam_id * TEGRA30_AHUB_DAM_LIVE_STATUS_STRIDE)); + mask = TEGRA30_AHUB_DAM_LIVE_STATUS_RX0_ENABLED; + val &= mask; + + return val; +} + +int tegra30_ahub_dam_ch1_is_enabled(int dam_id) +{ + int val, mask; + + val = tegra30_apbif_read((TEGRA30_AHUB_DAM_LIVE_STATUS) + + (dam_id * TEGRA30_AHUB_DAM_LIVE_STATUS_STRIDE)); + mask = TEGRA30_AHUB_DAM_LIVE_STATUS_RX1_ENABLED; + val &= mask; + + return val; +} + +int tegra30_ahub_dam_tx_is_enabled(int dam_id) +{ + int val, mask; + + val = tegra30_apbif_read((TEGRA30_AHUB_DAM_LIVE_STATUS) + + (dam_id * TEGRA30_AHUB_DAM_LIVE_STATUS_STRIDE)); + mask = TEGRA30_AHUB_DAM_LIVE_STATUS_TX_ENABLED; + val &= mask; + + return val; +} + int tegra30_ahub_set_rx_fifo_pack_mode(enum tegra30_ahub_rxcif rxcif, unsigned int pack_mode) { diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h index 8dc27abc5aed..b5fd2363f080 100644 --- a/sound/soc/tegra/tegra30_ahub.h +++ b/sound/soc/tegra/tegra30_ahub.h @@ -3,6 +3,7 @@ * * Author: Stephen Warren * Copyright (C) 2011 - NVIDIA, Inc. + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -502,6 +503,9 @@ extern int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif); extern int tegra30_ahub_rx_fifo_is_enabled(int i2s_id); extern int tegra30_ahub_tx_fifo_is_enabled(int i2s_id); +extern int tegra30_ahub_dam_ch0_is_enabled(int dam_id); +extern int tegra30_ahub_dam_ch1_is_enabled(int dam_id); +extern int tegra30_ahub_dam_tx_is_enabled(int dam_id); #ifdef CONFIG_PM extern int tegra30_ahub_apbif_resume(void); diff --git a/sound/soc/tegra/tegra30_dam.c b/sound/soc/tegra/tegra30_dam.c index d308179110c9..8460266d0d66 100644 --- a/sound/soc/tegra/tegra30_dam.c +++ b/sound/soc/tegra/tegra30_dam.c @@ -3,6 +3,7 @@ * * Author: Nikesh Oswal * Copyright (C) 2011 - NVIDIA, Inc. + * Copyright (C) 2012, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -27,6 +28,7 @@ #include #include #include +#include #include #include #include "tegra30_dam.h" @@ -455,6 +457,8 @@ int tegra30_dam_set_acif(int ifc, int chid, unsigned int audio_channels, void tegra30_dam_enable(int ifc, int on, int chid) { u32 old_val, val, enreg; + u32 old_val_dam, val_dam; + int dcnt = 10; struct tegra30_dam_context *dam = dams_cont_info[ifc]; if (ifc >= TEGRA30_NR_DAM_IFC) @@ -476,19 +480,46 @@ void tegra30_dam_enable(int ifc, int on, int chid) val &= ~TEGRA30_DAM_CH0_CTRL_EN; } - if (val != old_val) - tegra30_dam_writel(dam, val, enreg); - - old_val = val = tegra30_dam_readl(dam, TEGRA30_DAM_CTRL); + old_val_dam = val_dam = tegra30_dam_readl(dam, TEGRA30_DAM_CTRL); if (dam->ch_enable_refcnt[dam_ch_in0] || dam->ch_enable_refcnt[dam_ch_in1]) - val |= TEGRA30_DAM_CTRL_DAM_EN; + val_dam |= TEGRA30_DAM_CTRL_DAM_EN; else - val &= ~TEGRA30_DAM_CTRL_DAM_EN; + val_dam &= ~TEGRA30_DAM_CTRL_DAM_EN; + + if (val != old_val) { + tegra30_dam_writel(dam, val, enreg); + + if (!on) { + if (chid == dam_ch_in0) { + while (tegra30_ahub_dam_ch0_is_enabled(ifc) + && dcnt--) + udelay(100); + + dcnt = 10; + } + else { + while (tegra30_ahub_dam_ch1_is_enabled(ifc) + && dcnt--) + udelay(100); + + dcnt = 10; + } + } + } + + if (old_val_dam != val_dam) { + tegra30_dam_writel(dam, val_dam, TEGRA30_DAM_CTRL); + + if (!on) { + while (tegra30_ahub_dam_tx_is_enabled(ifc) && dcnt--) + udelay(100); - if (old_val != val) - tegra30_dam_writel(dam, val, TEGRA30_DAM_CTRL); + dcnt = 10; + } + + } } void tegra30_dam_ch0_set_datasync(struct tegra30_dam_context *dam, int datasync) diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index a50b853135ae..72e64470008a 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -7,6 +7,7 @@ * Based on code copyright/by: * * Copyright (c) 2009-2010, NVIDIA Corporation. + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. * Scott Peterson * * Copyright (C) 2010 Google, Inc. @@ -811,7 +812,47 @@ static int configure_baseband_i2s(struct tegra30_i2s *i2s, int is_i2smaster, int is_formatdsp, int channels, int rate, int bitsize) { u32 val; - int i2sclock, bitcnt; + int i2sclock, bitcnt, ret; + + i2sclock = rate * channels * bitsize * 2; + + /* additional 8 for baseband */ + if (is_formatdsp) + i2sclock *= 8; + + if (is_i2smaster) { + ret = clk_set_parent(i2s->clk_i2s, i2s->clk_pll_a_out0); + if (ret) { + pr_err("Can't set parent of I2S clock\n"); + return ret; + } + + ret = clk_set_rate(i2s->clk_i2s, i2sclock); + if (ret) { + pr_err("Can't set I2S clock rate: %d\n", ret); + return ret; + } + } else { + ret = clk_set_rate(i2s->clk_i2s_sync, i2sclock); + if (ret) { + pr_err("Can't set I2S sync clock rate\n"); + return ret; + } + + ret = clk_set_rate(i2s->clk_audio_2x, i2sclock); + if (ret) { + pr_err("Can't set I2S sync clock rate\n"); + return ret; + } + + ret = clk_set_parent(i2s->clk_i2s, i2s->clk_audio_2x); + if (ret) { + pr_err("Can't set parent of audio2x clock\n"); + return ret; + } + } + + tegra30_i2s_enable_clocks(i2s); i2s->reg_ctrl &= ~(TEGRA30_I2S_CTRL_FRAME_FORMAT_MASK | TEGRA30_I2S_CTRL_LRCK_MASK | @@ -846,14 +887,6 @@ static int configure_baseband_i2s(struct tegra30_i2s *i2s, int is_i2smaster, (1 << TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT); tegra30_i2s_write(i2s, TEGRA30_I2S_OFFSET, val); - i2sclock = rate * channels * bitsize * 2; - - /* additional 8 for baseband */ - if (is_formatdsp) - i2sclock *= 8; - - clk_set_rate(i2s->clk_i2s, i2sclock); - if (is_formatdsp) { bitcnt = (i2sclock/rate) - 1; val = bitcnt << TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT; @@ -916,8 +949,6 @@ int tegra30_make_voice_call_connections(struct codec_config *codec_info, codec_i2s = &i2scont[codec_info->i2s_id]; bb_i2s = &i2scont[bb_info->i2s_id]; - tegra30_i2s_enable_clocks(codec_i2s); - tegra30_i2s_enable_clocks(bb_i2s); /* increment the codec i2s playback ref count */ codec_i2s->playback_ref_count++; @@ -985,61 +1016,89 @@ int tegra30_break_voice_call_connections(struct codec_config *codec_info, { struct tegra30_i2s *codec_i2s; struct tegra30_i2s *bb_i2s; + int dcnt = 10; codec_i2s = &i2scont[codec_info->i2s_id]; bb_i2s = &i2scont[bb_info->i2s_id]; - /* disconnect the ahub connections */ - - /* if this is the only user of i2s tx then break ahub - i2s rx connection */ - if (codec_i2s->playback_ref_count == 1) - tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_I2S0_RX0 - + codec_info->i2s_id); + /*Disable Codec I2S RX (TX to ahub)*/ + codec_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX; + tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, codec_i2s->reg_ctrl); - tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_I2S0_RX0 - + bb_info->i2s_id); - tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX0 - + (codec_i2s->dam_ifc*2)); - tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX0 - + (bb_i2s->dam_ifc*2)); + while (tegra30_ahub_rx_fifo_is_enabled(codec_i2s->id) && dcnt--) + udelay(100); - /* disable the i2s */ + dcnt = 10; - /* if this is the only user of i2s tx then disable it*/ - if (codec_i2s->playback_ref_count == 1) - codec_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX; + /*Disable baseband DAM*/ + tegra30_dam_enable(bb_i2s->dam_ifc, TEGRA30_DAM_DISABLE, + TEGRA30_DAM_CHIN0_SRC); + tegra30_dam_free_channel(bb_i2s->dam_ifc, TEGRA30_DAM_CHIN0_SRC); + bb_i2s->dam_ch_refcount--; + if (!bb_i2s->dam_ch_refcount) + tegra30_dam_free_controller(bb_i2s->dam_ifc); - codec_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX; - tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, codec_i2s->reg_ctrl); + /*Disable baseband I2S TX (RX from ahub)*/ bb_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX; + tegra30_i2s_write(bb_i2s, TEGRA30_I2S_CTRL, bb_i2s->reg_ctrl); + + while (tegra30_ahub_tx_fifo_is_enabled(bb_i2s->id) && dcnt--) + udelay(100); + + dcnt = 10; + + /*Disable baseband I2S RX (TX to ahub)*/ bb_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX; tegra30_i2s_write(bb_i2s, TEGRA30_I2S_CTRL, bb_i2s->reg_ctrl); - tegra30_i2s_disable_clocks(codec_i2s); - tegra30_i2s_disable_clocks(bb_i2s); - /* decrement the codec i2s playback ref count */ - codec_i2s->playback_ref_count--; - bb_i2s->playback_ref_count--; + while (tegra30_ahub_rx_fifo_is_enabled(bb_i2s->id) && dcnt--) + udelay(100); - /* disable the codec dam */ + dcnt = 10; + + /*Disable Codec DAM*/ tegra30_dam_enable(codec_i2s->dam_ifc, TEGRA30_DAM_DISABLE, TEGRA30_DAM_CHIN0_SRC); - tegra30_dam_disable_clock(codec_i2s->dam_ifc); tegra30_dam_free_channel(codec_i2s->dam_ifc, TEGRA30_DAM_CHIN0_SRC); codec_i2s->dam_ch_refcount--; if (!codec_i2s->dam_ch_refcount) tegra30_dam_free_controller(codec_i2s->dam_ifc); - /* disable the bb dam */ - tegra30_dam_enable(bb_i2s->dam_ifc, TEGRA30_DAM_DISABLE, - TEGRA30_DAM_CHIN0_SRC); + /*Disable Codec I2S TX (RX from ahub)*/ + if (codec_i2s->playback_ref_count == 1) + codec_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX; + + tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, codec_i2s->reg_ctrl); + + while (tegra30_ahub_tx_fifo_is_enabled(codec_i2s->id) && dcnt--) + udelay(100); + + dcnt = 10; + + /* Disconnect the ahub connections */ + /* If this is the only user of i2s tx then break ahub + i2s rx connection */ + if (codec_i2s->playback_ref_count == 1) + tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_I2S0_RX0 + + codec_info->i2s_id); + + tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_I2S0_RX0 + + bb_info->i2s_id); + tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX0 + + (codec_i2s->dam_ifc*2)); + tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX0 + + (bb_i2s->dam_ifc*2)); + + /* Decrement the codec and bb i2s playback ref count */ + codec_i2s->playback_ref_count--; + bb_i2s->playback_ref_count--; + + /* Disable the clocks */ + tegra30_i2s_disable_clocks(codec_i2s); + tegra30_i2s_disable_clocks(bb_i2s); + tegra30_dam_disable_clock(codec_i2s->dam_ifc); tegra30_dam_disable_clock(bb_i2s->dam_ifc); - tegra30_dam_free_channel(bb_i2s->dam_ifc, TEGRA30_DAM_CHIN0_SRC); - bb_i2s->dam_ch_refcount--; - if (!bb_i2s->dam_ch_refcount) - tegra30_dam_free_controller(bb_i2s->dam_ifc); return 0; } -- cgit v1.2.3