diff options
author | ScottPeterson <speterson@nvidia.com> | 2012-09-18 15:01:54 -0700 |
---|---|---|
committer | Rohan Somvanshi <rsomvanshi@nvidia.com> | 2012-12-19 00:05:34 -0800 |
commit | b45bc03ac62787292a7a7ed81b04a248b7a8ccc5 (patch) | |
tree | 8d99325a824a4d1aa5a0b93b55e8f08e9e67871b /sound | |
parent | 8c53a45e1d82657720211b121d5f1221911d6654 (diff) |
asoc:tegra: Support setting bit clock
Support for setting I2S bit clock from information
in the pdata structure.
Correctly supported DSPA and DSPB modes of I2S
during voice call.
Change-Id: I50e20ed66d2d0a01050d1d3902d179133f767f87
Signed-off-by: ScottPeterson <speterson@nvidia.com>
Reviewed-on: http://git-master/r/133669
Reviewed-on: http://git-master/r/146605
(cherry picked from commit 46e174b418c2e1b39260fae7e8113786545219d7)
Reviewed-on: http://git-master/r/172070
Reviewed-by: Rohan Somvanshi <rsomvanshi@nvidia.com>
Tested-by: Rohan Somvanshi <rsomvanshi@nvidia.com>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/codecs/max98088.c | 1 | ||||
-rw-r--r-- | sound/soc/tegra/tegra30_ahub.c | 63 | ||||
-rw-r--r-- | sound/soc/tegra/tegra30_ahub.h | 6 | ||||
-rw-r--r-- | sound/soc/tegra/tegra30_dam.c | 10 | ||||
-rw-r--r-- | sound/soc/tegra/tegra30_i2s.c | 65 | ||||
-rw-r--r-- | sound/soc/tegra/tegra30_i2s.h | 3 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_aic326x.c | 10 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_cs42l73.c | 9 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_max98088.c | 9 |
9 files changed, 137 insertions, 39 deletions
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index f11e1698d57e..c2c45a6ab6c5 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -1703,6 +1703,7 @@ static struct snd_soc_dai_driver max98088_dai[] = { .formats = MAX98088_FORMATS, }, .ops = &max98088_dai1_ops, + .symmetric_rates = 1, }, { .name = "Aux", diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index d4a3181caac0..519ee7eee050 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -298,6 +298,29 @@ int tegra30_ahub_tx_fifo_is_enabled(int i2s_id) return val; } + +int tegra30_ahub_rx_fifo_is_empty(int i2s_id) +{ + int val, mask; + + val = tegra30_apbif_read(TEGRA30_AHUB_I2S_LIVE_STATUS); + mask = (TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_RX_FIFO_EMPTY << (i2s_id*2)); + val &= mask; + return val; +} + +int tegra30_ahub_tx_fifo_is_empty(int i2s_id) +{ + int val, mask; + + val = tegra30_apbif_read(TEGRA30_AHUB_I2S_LIVE_STATUS); + mask = (TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_TX_FIFO_EMPTY << (i2s_id*2)); + val &= mask; + + return val; +} + + int tegra30_ahub_dam_ch0_is_enabled(int dam_id) { int val, mask; @@ -334,6 +357,44 @@ int tegra30_ahub_dam_tx_is_enabled(int dam_id) return val; } + +int tegra30_ahub_dam_ch0_is_empty(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_RX0FIFO_EMPTY; + val &= mask; + + return val; +} + +int tegra30_ahub_dam_ch1_is_empty(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_RX1FIFO_EMPTY; + val &= mask; + + return val; +} + +int tegra30_ahub_dam_tx_is_empty(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_TXFIFO_EMPTY; + val &= mask; + + return val; +} + + int tegra30_ahub_set_rx_fifo_pack_mode(enum tegra30_ahub_rxcif rxcif, unsigned int pack_mode) { @@ -661,7 +722,7 @@ static int __devinit tegra30_ahub_probe(struct platform_device *pdev) } clkm_rate = clk_get_rate(clk_get_parent(ahub->clk_d_audio)); - while (clkm_rate > 12000000) + while (clkm_rate > 13000000) clkm_rate >>= 1; clk_set_rate(ahub->clk_d_audio,clkm_rate); diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h index 17f8a0c526e7..e4666c7a8632 100644 --- a/sound/soc/tegra/tegra30_ahub.h +++ b/sound/soc/tegra/tegra30_ahub.h @@ -503,9 +503,15 @@ 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_rx_fifo_is_empty(int i2s_id); +extern int tegra30_ahub_tx_fifo_is_empty(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); +extern int tegra30_ahub_dam_ch0_is_empty(int dam_id); +extern int tegra30_ahub_dam_ch1_is_empty(int dam_id); +extern int tegra30_ahub_dam_tx_is_empty(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 e2511edf219e..bb42edc2e199 100644 --- a/sound/soc/tegra/tegra30_dam.c +++ b/sound/soc/tegra/tegra30_dam.c @@ -952,14 +952,14 @@ void tegra30_dam_enable(int ifc, int on, int chid) if (!on) { if (chid == dam_ch_in0) { - while (tegra30_ahub_dam_ch0_is_enabled(ifc) + while (!tegra30_ahub_dam_ch0_is_empty(ifc) && dcnt--) udelay(100); dcnt = 10; } else { - while (tegra30_ahub_dam_ch1_is_enabled(ifc) + while (!tegra30_ahub_dam_ch1_is_empty(ifc) && dcnt--) udelay(100); @@ -970,14 +970,12 @@ void tegra30_dam_enable(int ifc, int on, int chid) 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--) + while (!tegra30_ahub_dam_tx_is_empty(ifc) && dcnt--) udelay(100); dcnt = 10; } - } } @@ -1044,7 +1042,7 @@ static int __devinit tegra30_dam_probe(struct platform_device *pdev) goto err_free; } clkm_rate = clk_get_rate(clk_get_parent(dam->dam_clk)); - while (clkm_rate > 12000000) + while (clkm_rate > 13000000) clkm_rate >>= 1; clk_set_rate(dam->dam_clk,clkm_rate); diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index ab8e220f6d25..469e9e116bc4 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -39,6 +39,7 @@ #include <linux/io.h> #include <linux/delay.h> #include <mach/iomap.h> +#include <mach/tegra_asoc_pdata.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -803,7 +804,7 @@ static void tegra30_i2s_stop_playback(struct tegra30_i2s *i2s) 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--) + while (!tegra30_ahub_tx_fifo_is_empty(i2s->id) && dcnt--) udelay(100); } @@ -827,6 +828,8 @@ static void tegra30_i2s_stop_capture(struct tegra30_i2s *i2s) udelay(100); } + while (!tegra30_ahub_rx_fifo_is_empty(i2s->id) && dcnt--) + udelay(100); } static int tegra30_i2s_trigger(struct snd_pcm_substream *substream, int cmd, @@ -980,16 +983,23 @@ struct snd_soc_dai_driver tegra30_i2s_dai[] = { }; static int configure_baseband_i2s(struct tegra30_i2s *i2s, int is_i2smaster, - int is_formatdsp, int channels, int rate, int bitsize) + int i2s_mode, int channels, int rate, int bitsize, int bit_clk) { u32 val; - int i2sclock, bitcnt, ret; + int i2sclock, bitcnt, ret, is_formatdsp; + + is_formatdsp = (i2s_mode == TEGRA_DAIFMT_DSP_A) || + (i2s_mode == TEGRA_DAIFMT_DSP_B); - i2sclock = rate * channels * bitsize * 2; + if (bit_clk) { + i2sclock = bit_clk; + } else { + i2sclock = rate * channels * bitsize * 2; - /* additional 8 for baseband */ - if (is_formatdsp) - i2sclock *= 8; + /* additional 8 for baseband */ + if (is_formatdsp) + i2sclock *= 8; + } if (is_i2smaster) { ret = clk_set_parent(i2s->clk_i2s, i2s->clk_pll_a_out0); @@ -1035,10 +1045,14 @@ static int configure_baseband_i2s(struct tegra30_i2s *i2s, int is_i2smaster, if (is_i2smaster) i2s->reg_ctrl |= TEGRA30_I2S_CTRL_MASTER_ENABLE; - if (is_formatdsp) { + if (i2s_mode == TEGRA_DAIFMT_DSP_A) { 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_NEG_EDGE; + } else if (i2s_mode == TEGRA_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; } else { i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK; i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW; @@ -1174,13 +1188,13 @@ int tegra30_make_voice_call_connections(struct codec_config *codec_info, /*Configure codec i2s*/ configure_baseband_i2s(codec_i2s, codec_info->is_i2smaster, - codec_info->is_format_dsp, codec_info->channels, - codec_info->rate, codec_info->bitsize); + codec_info->i2s_mode, codec_info->channels, + codec_info->rate, codec_info->bitsize, codec_info->bit_clk); /*Configure bb i2s*/ configure_baseband_i2s(bb_i2s, bb_info->is_i2smaster, - bb_info->is_format_dsp, bb_info->channels, - bb_info->rate, bb_info->bitsize); + bb_info->i2s_mode, bb_info->channels, + bb_info->rate, bb_info->bitsize, bb_info->bit_clk); if (uses_voice_codec) { /* The following two lines are a hack */ @@ -1275,7 +1289,7 @@ int tegra30_break_voice_call_connections(struct codec_config *codec_info, tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, codec_i2s->reg_ctrl); - while (tegra30_ahub_rx_fifo_is_enabled(codec_i2s->id) && dcnt--) + while (!tegra30_ahub_rx_fifo_is_empty(codec_i2s->id) && dcnt--) udelay(100); dcnt = 10; @@ -1284,7 +1298,7 @@ int tegra30_break_voice_call_connections(struct codec_config *codec_info, 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--) + while (!tegra30_ahub_tx_fifo_is_empty(bb_i2s->id) && dcnt--) udelay(100); dcnt = 10; @@ -1293,7 +1307,7 @@ int tegra30_break_voice_call_connections(struct codec_config *codec_info, bb_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX; tegra30_i2s_write(bb_i2s, TEGRA30_I2S_CTRL, bb_i2s->reg_ctrl); - while (tegra30_ahub_rx_fifo_is_enabled(bb_i2s->id) && dcnt--) + while (!tegra30_ahub_rx_fifo_is_empty(bb_i2s->id) && dcnt--) udelay(100); dcnt = 10; @@ -1304,7 +1318,7 @@ int tegra30_break_voice_call_connections(struct codec_config *codec_info, tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, codec_i2s->reg_ctrl); - while (tegra30_ahub_tx_fifo_is_enabled(codec_i2s->id) && dcnt--) + while (!tegra30_ahub_tx_fifo_is_empty(codec_i2s->id) && dcnt--) udelay(100); dcnt = 10; @@ -1358,6 +1372,25 @@ int tegra30_break_voice_call_connections(struct codec_config *codec_info, codec_i2s->capture_ref_count--; bb_i2s->capture_ref_count--; + /* Soft reset */ + tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, + codec_i2s->reg_ctrl | TEGRA30_I2S_CTRL_SOFT_RESET); + tegra30_i2s_write(bb_i2s, TEGRA30_I2S_CTRL, + bb_i2s->reg_ctrl | TEGRA30_I2S_CTRL_SOFT_RESET); + + codec_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_TX_FLOWCTL_EN; + bb_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_TX_FLOWCTL_EN; + codec_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_SOFT_RESET; + bb_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_SOFT_RESET; + + while ((tegra30_i2s_read(codec_i2s, TEGRA30_I2S_CTRL) & + TEGRA30_I2S_CTRL_SOFT_RESET) && dcnt--) + udelay(100); + dcnt = 10; + while ((tegra30_i2s_read(bb_i2s, TEGRA30_I2S_CTRL) & + TEGRA30_I2S_CTRL_SOFT_RESET) && dcnt--) + udelay(100); + /* Disable the clocks */ tegra30_i2s_disable_clocks(codec_i2s); tegra30_i2s_disable_clocks(bb_i2s); diff --git a/sound/soc/tegra/tegra30_i2s.h b/sound/soc/tegra/tegra30_i2s.h index a0baaf7434aa..ef0aded64b86 100644 --- a/sound/soc/tegra/tegra30_i2s.h +++ b/sound/soc/tegra/tegra30_i2s.h @@ -288,7 +288,8 @@ struct codec_config { int channels; int bitsize; int is_i2smaster; - int is_format_dsp; + int i2s_mode; + int bit_clk; }; int tegra30_make_voice_call_connections(struct codec_config *codec_info, diff --git a/sound/soc/tegra/tegra_aic326x.c b/sound/soc/tegra/tegra_aic326x.c index 6913b3707cb6..eb1caf400aa4 100644 --- a/sound/soc/tegra/tegra_aic326x.c +++ b/sound/soc/tegra/tegra_aic326x.c @@ -1253,11 +1253,11 @@ static __devinit int tegra_aic326x_driver_probe(struct platform_device *pdev) pdata->i2s_param[i].rate; machine->codec_info[i].channels = pdata->i2s_param[i].channels; - if ((pdata->i2s_param[i].i2s_mode == TEGRA_DAIFMT_DSP_A) || - (pdata->i2s_param[i].i2s_mode == TEGRA_DAIFMT_DSP_B)) - machine->codec_info[i].is_format_dsp = 1; - else - machine->codec_info[i].is_format_dsp = 0; + machine->codec_info[i].i2s_mode = + pdata->i2s_param[i].i2s_mode; + machine->codec_info[i].bit_clk = + pdata->i2s_param[i].bit_clk; + } tegra_aic326x_dai[DAI_LINK_HIFI].cpu_dai_name = diff --git a/sound/soc/tegra/tegra_cs42l73.c b/sound/soc/tegra/tegra_cs42l73.c index e5e36b2fb2c6..4c19cde98532 100644 --- a/sound/soc/tegra/tegra_cs42l73.c +++ b/sound/soc/tegra/tegra_cs42l73.c @@ -1322,11 +1322,10 @@ static __devinit int tegra_cs42l73_driver_probe(struct platform_device *pdev) pdata->i2s_param[i].rate; machine->codec_info[i].channels = pdata->i2s_param[i].channels; - if ((pdata->i2s_param[i].i2s_mode == TEGRA_DAIFMT_DSP_A) || - (pdata->i2s_param[i].i2s_mode == TEGRA_DAIFMT_DSP_B)) - machine->codec_info[i].is_format_dsp = 1; - else - machine->codec_info[i].is_format_dsp = 0; + machine->codec_info[i].i2s_mode = + pdata->i2s_param[i].i2s_mode; + machine->codec_info[i].bit_clk = + pdata->i2s_param[i].bit_clk; } tegra_cs42l73_dai[DAI_LINK_HIFI].cpu_dai_name = diff --git a/sound/soc/tegra/tegra_max98088.c b/sound/soc/tegra/tegra_max98088.c index a704160ddd0a..6c45ed149d45 100644 --- a/sound/soc/tegra/tegra_max98088.c +++ b/sound/soc/tegra/tegra_max98088.c @@ -1228,11 +1228,10 @@ static __devinit int tegra_max98088_driver_probe(struct platform_device *pdev) pdata->i2s_param[i].rate; machine->codec_info[i].channels = pdata->i2s_param[i].channels; - if ((pdata->i2s_param[i].i2s_mode == TEGRA_DAIFMT_DSP_A) || - (pdata->i2s_param[i].i2s_mode == TEGRA_DAIFMT_DSP_B)) - machine->codec_info[i].is_format_dsp = 1; - else - machine->codec_info[i].is_format_dsp = 0; + machine->codec_info[i].i2s_mode = + pdata->i2s_param[i].i2s_mode; + machine->codec_info[i].bit_clk = + pdata->i2s_param[i].bit_clk; } tegra_max98088_dai[DAI_LINK_HIFI].cpu_dai_name = |