summaryrefslogtreecommitdiff
path: root/sound/soc
diff options
context:
space:
mode:
authorScottPeterson <speterson@nvidia.com>2012-09-18 15:01:54 -0700
committerRohan Somvanshi <rsomvanshi@nvidia.com>2012-12-19 00:05:34 -0800
commitb45bc03ac62787292a7a7ed81b04a248b7a8ccc5 (patch)
tree8d99325a824a4d1aa5a0b93b55e8f08e9e67871b /sound/soc
parent8c53a45e1d82657720211b121d5f1221911d6654 (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/soc')
-rw-r--r--sound/soc/codecs/max98088.c1
-rw-r--r--sound/soc/tegra/tegra30_ahub.c63
-rw-r--r--sound/soc/tegra/tegra30_ahub.h6
-rw-r--r--sound/soc/tegra/tegra30_dam.c10
-rw-r--r--sound/soc/tegra/tegra30_i2s.c65
-rw-r--r--sound/soc/tegra/tegra30_i2s.h3
-rw-r--r--sound/soc/tegra/tegra_aic326x.c10
-rw-r--r--sound/soc/tegra/tegra_cs42l73.c9
-rw-r--r--sound/soc/tegra/tegra_max98088.c9
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 =