asoc:tegra: Support setting bit clock
ScottPeterson [Tue, 18 Sep 2012 22:01:54 +0000 (15:01 -0700)]
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>

sound/soc/codecs/max98088.c
sound/soc/tegra/tegra30_ahub.c
sound/soc/tegra/tegra30_ahub.h
sound/soc/tegra/tegra30_dam.c
sound/soc/tegra/tegra30_i2s.c
sound/soc/tegra/tegra30_i2s.h
sound/soc/tegra/tegra_aic326x.c
sound/soc/tegra/tegra_cs42l73.c
sound/soc/tegra/tegra_max98088.c

index f11e169..c2c45a6 100644 (file)
@@ -1703,6 +1703,7 @@ static struct snd_soc_dai_driver max98088_dai[] = {
                .formats = MAX98088_FORMATS,
        },
         .ops = &max98088_dai1_ops,
+               .symmetric_rates = 1,
 },
 {
        .name = "Aux",
index d4a3181..519ee7e 100644 (file)
@@ -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);
index 17f8a0c..e4666c7 100644 (file)
@@ -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);
index e2511ed..bb42edc 100644 (file)
@@ -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);
index ab8e220..469e9e1 100644 (file)
@@ -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);
index a0baaf7..ef0aded 100644 (file)
@@ -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,
index 6913b37..eb1caf4 100644 (file)
@@ -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 =
index e5e36b2..4c19cde 100644 (file)
@@ -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 =
index a704160..6c45ed1 100644 (file)
@@ -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 =