summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorManoj Gangwal <mgangwal@nvidia.com>2014-02-06 15:15:24 +0530
committerBharat Nihalani <bnihalani@nvidia.com>2014-03-03 21:02:49 -0800
commite0b90d9d7d9ff19bf054e86493c97ca521cc1eca (patch)
treec25e1899337e01ea7ba6b221ceb272de5c2c448b /sound
parent287a26629122fe6f073803ddc33209ba24405764 (diff)
Asoc: tegra: Add Dual Mic support for voice call
For dual mic support in voice call , codec also should run at BB sample rate i.e 16k 1) Remove the SRC from UL 2) Add SRC in DL to mix the system sound Bug 1454569 Bug 1467243 Change-Id: I1710cb0fd3872a98ac32a61612d26e6a1b4f738d Signed-off-by: Manoj Gangwal <mgangwal@nvidia.com> Reviewed-on: http://git-master/r/364308 (cherry picked from commit fa6206fc1a152fa2d29166ab4a2c61608c99669b) Reviewed-on: http://git-master/r/374101 Reviewed-by: Sumit Bhattacharya <sumitb@nvidia.com> Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Ravindra Lokhande <rlokhande@nvidia.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/tegra/tegra30_i2s.c279
-rw-r--r--sound/soc/tegra/tegra30_i2s.h10
-rw-r--r--sound/soc/tegra/tegra_rt5639.c17
3 files changed, 283 insertions, 23 deletions
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index ac565be907c7..02d596b7d2e2 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -1629,7 +1629,7 @@ int tegra30_make_voice_call_connections(struct codec_config *codec_info,
struct tegra30_i2s *bb_i2s;
unsigned int val;
unsigned int en_flwcntrl = 0;
- int dcnt = 10;
+ int dcnt = 10, ret = 0;
codec_i2s = i2scont[codec_info->i2s_id];
bb_i2s = i2scont[bb_info->i2s_id];
@@ -1651,7 +1651,8 @@ int tegra30_make_voice_call_connections(struct codec_config *codec_info,
if (val & TEGRA30_I2S_CTRL_XFER_EN_RX) {
regmap_update_bits(codec_i2s->regmap, TEGRA30_I2S_CTRL,
TEGRA30_I2S_CTRL_XFER_EN_RX, 0);
- while (!tegra30_ahub_rx_fifo_is_empty(codec_i2s->id) && dcnt--)
+ while (!tegra30_ahub_rx_fifo_is_empty(codec_i2s->id) &&
+ dcnt--)
udelay(100);
}
@@ -1660,7 +1661,8 @@ int tegra30_make_voice_call_connections(struct codec_config *codec_info,
if (val & TEGRA30_I2S_CTRL_XFER_EN_TX) {
regmap_update_bits(codec_i2s->regmap, TEGRA30_I2S_CTRL,
TEGRA30_I2S_CTRL_XFER_EN_TX, 0);
- while (!tegra30_ahub_tx_fifo_is_empty(codec_i2s->id) && dcnt--)
+ while (!tegra30_ahub_tx_fifo_is_empty(codec_i2s->id) &&
+ dcnt--)
udelay(100);
}
@@ -1680,6 +1682,256 @@ int tegra30_make_voice_call_connections(struct codec_config *codec_info,
bb_info->i2s_mode, bb_info->channels,
bb_info->rate, bb_info->bitsize, bb_info->bit_clk);
+ if (uses_voice_codec) {
+ tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_APBIF_RX0 +
+ codec_info->i2s_id);
+ tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_APBIF_RX0 +
+ bb_info->i2s_id);
+
+ tegra30_ahub_set_rx_cif_source(TEGRA30_AHUB_RXCIF_I2S0_RX0 +
+ bb_info->i2s_id, TEGRA30_AHUB_TXCIF_I2S0_TX0 +
+ codec_info->i2s_id);
+ tegra30_ahub_set_rx_cif_source(TEGRA30_AHUB_RXCIF_I2S0_RX0 +
+ codec_info->i2s_id, TEGRA30_AHUB_TXCIF_I2S0_TX0 +
+ bb_info->i2s_id);
+ if (!(codec_info->is_i2smaster && bb_info->is_i2smaster)) {
+ regmap_write(codec_i2s->regmap, TEGRA30_I2S_FLOWCTL,
+ TEGRA30_I2S_FILTER_QUAD);
+ regmap_write(bb_i2s->regmap, TEGRA30_I2S_FLOWCTL,
+ TEGRA30_I2S_FILTER_QUAD);
+ regmap_write(codec_i2s->regmap, TEGRA30_I2S_TX_STEP, 4);
+ regmap_write(bb_i2s->regmap, TEGRA30_I2S_TX_STEP, 4);
+ en_flwcntrl = 1;
+ }
+ } else {
+ /*configure codec dam*/
+ ret = configure_dam(codec_i2s, codec_info->channels,
+ codec_info->rate, codec_info->bitsize,
+ bb_info->channels, 48000,
+ bb_info->bitsize);
+
+ if (ret)
+ pr_info("%s:Failed to configure dam\n", __func__);
+
+ ret = tegra30_dam_allocate_channel(codec_i2s->dam_ifc,
+ TEGRA30_DAM_CHIN1);
+ if (ret)
+ pr_info("%s:Failed to allocate dam\n", __func__);
+
+ tegra30_dam_set_gain(codec_i2s->dam_ifc,
+ TEGRA30_DAM_CHIN1, 0x1000);
+ tegra30_dam_set_acif(codec_i2s->dam_ifc, TEGRA30_DAM_CHIN1, 1,
+ bb_info->bitsize, 1, 32);
+ tegra30_dam_set_acif(codec_i2s->dam_ifc, TEGRA30_DAM_CHOUT,
+ 2, codec_info->bitsize, 1, 32);
+ tegra30_dam_ch0_set_datasync(codec_i2s->dam_ifc, 2);
+ tegra30_dam_ch1_set_datasync(codec_i2s->dam_ifc, 0);
+
+ /* do routing in ahub */
+ tegra30_ahub_set_rx_cif_source(
+ TEGRA30_AHUB_RXCIF_DAM0_RX1 + (codec_i2s->dam_ifc*2),
+ TEGRA30_AHUB_TXCIF_I2S0_TX0 + bb_info->i2s_id);
+
+ tegra30_ahub_set_rx_cif_source(
+ TEGRA30_AHUB_RXCIF_DAM0_RX0 + (codec_i2s->dam_ifc*2),
+ codec_i2s->playback_fifo_cif);
+
+ tegra30_ahub_set_rx_cif_source(
+ TEGRA30_AHUB_RXCIF_I2S0_RX0 + codec_info->i2s_id,
+ TEGRA30_AHUB_TXCIF_DAM0_TX0 + codec_i2s->dam_ifc);
+
+ tegra30_ahub_set_rx_cif_source(
+ TEGRA30_AHUB_RXCIF_I2S0_RX0 + bb_info->i2s_id,
+ TEGRA30_AHUB_TXCIF_I2S0_TX0 + codec_info->i2s_id);
+
+ /*enable dam and i2s*/
+ tegra30_dam_enable(codec_i2s->dam_ifc, TEGRA30_DAM_ENABLE,
+ TEGRA30_DAM_CHIN0_SRC);
+ tegra30_dam_enable(codec_i2s->dam_ifc, TEGRA30_DAM_ENABLE,
+ TEGRA30_DAM_CHIN1);
+ }
+
+ val = TEGRA30_I2S_CTRL_XFER_EN_TX | TEGRA30_I2S_CTRL_XFER_EN_RX;
+ if (en_flwcntrl)
+ val |= TEGRA30_I2S_CTRL_TX_FLOWCTL_EN;
+
+ msleep(20);
+ regmap_update_bits(codec_i2s->regmap, TEGRA30_I2S_CTRL, val, val);
+ msleep(20);
+ regmap_update_bits(bb_i2s->regmap, TEGRA30_I2S_CTRL, val, val);
+
+ return 0;
+}
+
+int tegra30_break_voice_call_connections(struct codec_config *codec_info,
+ struct codec_config *bb_info, int uses_voice_codec)
+{
+ 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];
+
+ if (codec_i2s == NULL || bb_i2s == NULL)
+ return -ENOENT;
+
+ /*Disable Codec I2S RX (TX to ahub)*/
+ if (codec_i2s->capture_ref_count == 1) {
+ regmap_update_bits(codec_i2s->regmap, TEGRA30_I2S_CTRL,
+ TEGRA30_I2S_CTRL_XFER_EN_RX, 0);
+
+ while (!tegra30_ahub_rx_fifo_is_empty(codec_i2s->id) &&
+ dcnt--)
+ udelay(100);
+
+ dcnt = 10;
+ }
+
+ /*Disable baseband I2S TX (RX from ahub)*/
+ regmap_update_bits(bb_i2s->regmap, TEGRA30_I2S_CTRL,
+ TEGRA30_I2S_CTRL_XFER_EN_TX, 0);
+
+ while (!tegra30_ahub_tx_fifo_is_empty(bb_i2s->id) && dcnt--)
+ udelay(100);
+
+ dcnt = 10;
+
+ /*Disable baseband I2S RX (TX to ahub)*/
+ regmap_update_bits(bb_i2s->regmap, TEGRA30_I2S_CTRL,
+ TEGRA30_I2S_CTRL_XFER_EN_RX, 0);
+
+ while (!tegra30_ahub_rx_fifo_is_empty(bb_i2s->id) && dcnt--)
+ udelay(100);
+
+ dcnt = 10;
+
+ /*Disable Codec I2S TX (RX from ahub)*/
+ if (codec_i2s->playback_ref_count == 1) {
+ regmap_update_bits(codec_i2s->regmap, TEGRA30_I2S_CTRL,
+ TEGRA30_I2S_CTRL_XFER_EN_TX, 0);
+
+ while (!tegra30_ahub_tx_fifo_is_empty(codec_i2s->id) && dcnt--)
+ udelay(100);
+
+ dcnt = 10;
+ }
+
+ if (uses_voice_codec) {
+ tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_I2S0_RX0 +
+ bb_info->i2s_id);
+ tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_I2S0_RX0 +
+ codec_info->i2s_id);
+ } else {
+
+ /*Disable Codec DAM*/
+ tegra30_dam_enable(codec_i2s->dam_ifc,
+ TEGRA30_DAM_DISABLE, TEGRA30_DAM_CHIN0_SRC);
+ tegra30_dam_free_channel(codec_i2s->dam_ifc,
+ TEGRA30_DAM_CHIN0_SRC);
+
+ tegra30_dam_enable(codec_i2s->dam_ifc,
+ TEGRA30_DAM_DISABLE, TEGRA30_DAM_CHIN1);
+ tegra30_dam_free_channel(codec_i2s->dam_ifc,
+ TEGRA30_DAM_CHIN1);
+
+ codec_i2s->dam_ch_refcount--;
+ if (!codec_i2s->dam_ch_refcount)
+ tegra30_dam_free_controller(codec_i2s->dam_ifc);
+
+ 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_RX1
+ + (codec_i2s->dam_ifc*2));
+
+ 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_I2S0_RX0 +
+ codec_info->i2s_id);
+
+ tegra30_dam_ch0_set_datasync(codec_i2s->dam_ifc, 0);
+ tegra30_dam_ch1_set_datasync(codec_i2s->dam_ifc, 0);
+
+ tegra30_dam_disable_clock(codec_i2s->dam_ifc);
+ }
+ /* Decrement the codec and bb i2s playback ref count */
+ codec_i2s->playback_ref_count--;
+ bb_i2s->playback_ref_count--;
+ codec_i2s->capture_ref_count--;
+ bb_i2s->capture_ref_count--;
+
+ /* Soft reset */
+ tegra30_i2s_soft_reset(codec_i2s);
+
+ tegra30_i2s_soft_reset(bb_i2s);
+
+ /* Disable the clocks */
+ pm_runtime_put(codec_i2s->dev);
+ pm_runtime_put(bb_i2s->dev);
+
+ return 0;
+}
+
+int tegra30_make_bt_voice_call_connections(struct codec_config *codec_info,
+ struct codec_config *bb_info, int uses_voice_codec)
+{
+ struct tegra30_i2s *codec_i2s;
+ struct tegra30_i2s *bb_i2s;
+ unsigned int val;
+ unsigned int en_flwcntrl = 0;
+ int dcnt = 10;
+
+ codec_i2s = i2scont[codec_info->i2s_id];
+ bb_i2s = i2scont[bb_info->i2s_id];
+
+ if (codec_i2s == NULL || bb_i2s == NULL)
+ return -ENOENT;
+
+ /* increment the codec i2s playback ref count */
+ codec_i2s->playback_ref_count++;
+ bb_i2s->playback_ref_count++;
+ codec_i2s->capture_ref_count++;
+ bb_i2s->capture_ref_count++;
+
+ pm_runtime_get_sync(codec_i2s->dev);
+ pm_runtime_get_sync(bb_i2s->dev);
+
+ /* Make sure i2s is disabled during the configiration */
+ regmap_read(codec_i2s->regmap, TEGRA30_I2S_CTRL, &val);
+ if (val & TEGRA30_I2S_CTRL_XFER_EN_RX) {
+ regmap_update_bits(codec_i2s->regmap, TEGRA30_I2S_CTRL,
+ TEGRA30_I2S_CTRL_XFER_EN_RX, 0);
+ while (!tegra30_ahub_rx_fifo_is_empty(codec_i2s->id) &&
+ dcnt--)
+ udelay(100);
+ }
+
+ dcnt = 10;
+ regmap_read(codec_i2s->regmap, TEGRA30_I2S_CTRL, &val);
+ if (val & TEGRA30_I2S_CTRL_XFER_EN_TX) {
+ regmap_update_bits(codec_i2s->regmap, TEGRA30_I2S_CTRL,
+ TEGRA30_I2S_CTRL_XFER_EN_TX, 0);
+ while (!tegra30_ahub_tx_fifo_is_empty(codec_i2s->id) &&
+ dcnt--)
+ udelay(100);
+ }
+
+ regmap_read(codec_i2s->regmap, TEGRA30_I2S_CTRL, &val);
+ if (val & TEGRA30_I2S_CTRL_TX_FLOWCTL_EN) {
+ regmap_update_bits(codec_i2s->regmap, TEGRA30_I2S_CTRL,
+ TEGRA30_I2S_CTRL_TX_FLOWCTL_EN, 0);
+ }
+
+ /*Configure codec i2s*/
+ configure_baseband_i2s(codec_i2s, codec_info->is_i2smaster,
+ 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->i2s_mode, bb_info->channels,
+ bb_info->rate, bb_info->bitsize, bb_info->bit_clk);
if (uses_voice_codec) {
tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_APBIF_RX0 +
@@ -1706,15 +1958,10 @@ int tegra30_make_voice_call_connections(struct codec_config *codec_info,
/*configure codec dam*/
configure_dam(codec_i2s, codec_info->channels,
codec_info->rate, codec_info->bitsize,
- bb_info->channels, bb_info->rate,
+ 1, bb_info->rate,
bb_info->bitsize);
- tegra30_dam_allocate_channel(codec_i2s->dam_ifc,
- TEGRA30_DAM_CHIN1);
- tegra30_dam_set_gain(codec_i2s->dam_ifc, TEGRA30_DAM_CHIN1,
- 0x1000);
- tegra30_dam_set_acif(codec_i2s->dam_ifc, TEGRA30_DAM_CHIN1,
- codec_info->channels, codec_info->bitsize, 2, 32);
+ tegra30_dam_ch1_set_datasync(codec_i2s->dam_ifc, 1);
/*configure bb dam*/
configure_dam(bb_i2s, bb_info->channels,
@@ -1752,8 +1999,6 @@ int tegra30_make_voice_call_connections(struct codec_config *codec_info,
/*enable dam and i2s*/
tegra30_dam_enable(codec_i2s->dam_ifc, TEGRA30_DAM_ENABLE,
TEGRA30_DAM_CHIN0_SRC);
- tegra30_dam_enable(codec_i2s->dam_ifc, TEGRA30_DAM_ENABLE,
- TEGRA30_DAM_CHIN1);
tegra30_dam_enable(bb_i2s->dam_ifc, TEGRA30_DAM_ENABLE,
TEGRA30_DAM_CHIN0_SRC);
}
@@ -1770,7 +2015,7 @@ int tegra30_make_voice_call_connections(struct codec_config *codec_info,
return 0;
}
-int tegra30_break_voice_call_connections(struct codec_config *codec_info,
+int tegra30_break_bt_voice_call_connections(struct codec_config *codec_info,
struct codec_config *bb_info, int uses_voice_codec)
{
struct tegra30_i2s *codec_i2s;
@@ -1842,11 +2087,6 @@ int tegra30_break_voice_call_connections(struct codec_config *codec_info,
TEGRA30_DAM_DISABLE, TEGRA30_DAM_CHIN0_SRC);
tegra30_dam_free_channel(codec_i2s->dam_ifc,
TEGRA30_DAM_CHIN0_SRC);
- tegra30_dam_enable(codec_i2s->dam_ifc,
- TEGRA30_DAM_DISABLE, TEGRA30_DAM_CHIN1);
- tegra30_dam_free_channel(codec_i2s->dam_ifc,
- TEGRA30_DAM_CHIN1);
-
codec_i2s->dam_ch_refcount--;
if (!codec_i2s->dam_ch_refcount)
tegra30_dam_free_controller(codec_i2s->dam_ifc);
@@ -1872,6 +2112,8 @@ int tegra30_break_voice_call_connections(struct codec_config *codec_info,
tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_I2S0_RX0 +
codec_info->i2s_id);
+ tegra30_dam_ch1_set_datasync(codec_i2s->dam_ifc, 0);
+
tegra30_dam_disable_clock(codec_i2s->dam_ifc);
tegra30_dam_disable_clock(bb_i2s->dam_ifc);
}
@@ -1893,6 +2135,7 @@ int tegra30_break_voice_call_connections(struct codec_config *codec_info,
return 0;
}
+
static int tegra30_i2s_platform_probe(struct platform_device *pdev)
{
struct tegra30_i2s *i2s;
diff --git a/sound/soc/tegra/tegra30_i2s.h b/sound/soc/tegra/tegra30_i2s.h
index 126ee5dbd655..5b754d2968b7 100644
--- a/sound/soc/tegra/tegra30_i2s.h
+++ b/sound/soc/tegra/tegra30_i2s.h
@@ -1,7 +1,7 @@
/*
* tegra30_i2s.h - Definitions for Tegra30 I2S driver
*
- * Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2010-2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -308,6 +308,14 @@ int tegra30_break_voice_call_connections(struct codec_config *codec_info,
struct codec_config *bb_info,
int uses_voice_codec);
+int tegra30_make_bt_voice_call_connections(struct codec_config *codec_info,
+ struct codec_config *bb_info,
+ int uses_voice_codec);
+
+int tegra30_break_bt_voice_call_connections(struct codec_config *codec_info,
+ struct codec_config *bb_info,
+ int uses_voice_codec);
+
#if defined(CONFIG_ARCH_TEGRA_14x_SOC)
int t14x_make_bt_voice_call_connections(struct codec_config *codec_info,
struct ahub_bbc1_config *bb_info,
diff --git a/sound/soc/tegra/tegra_rt5639.c b/sound/soc/tegra/tegra_rt5639.c
index bac2d0465e1b..408e594576c5 100644
--- a/sound/soc/tegra/tegra_rt5639.c
+++ b/sound/soc/tegra/tegra_rt5639.c
@@ -1,7 +1,7 @@
/*
* tegra_rt5639.c - Tegra machine ASoC driver for boards using ALC5639 codec.
*
- * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2013-2014, 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
* version 2 as published by the Free Software Foundation.
@@ -151,12 +151,21 @@ static int tegra_rt5639_call_mode_put(struct snd_kcontrol *kcontrol,
machine->codec_info[codec_index].i2s_id, false);
tegra_asoc_utils_tristate_dap(
machine->codec_info[BASEBAND].i2s_id, false);
-
- tegra30_make_voice_call_connections(
+ if (machine->is_device_bt)
+ tegra30_make_bt_voice_call_connections(
+ &machine->codec_info[codec_index],
+ &machine->codec_info[BASEBAND], uses_voice_codec);
+ else
+ tegra30_make_voice_call_connections(
&machine->codec_info[codec_index],
&machine->codec_info[BASEBAND], uses_voice_codec);
} else {
- tegra30_break_voice_call_connections(
+ if (machine->is_device_bt)
+ tegra30_break_bt_voice_call_connections(
+ &machine->codec_info[codec_index],
+ &machine->codec_info[BASEBAND], uses_voice_codec);
+ else
+ tegra30_break_voice_call_connections(
&machine->codec_info[codec_index],
&machine->codec_info[BASEBAND], uses_voice_codec);