summaryrefslogtreecommitdiff
path: root/sound/soc/tegra
diff options
context:
space:
mode:
authorMarcel Ziswiler <marcel.ziswiler@toradex.com>2012-09-10 14:53:27 +0200
committerMarcel Ziswiler <marcel.ziswiler@toradex.com>2012-09-10 15:04:19 +0200
commitd5bbf34613a877dbe3da847fa0432da8c6721e73 (patch)
tree902a90fd7eda61aad7abae9c35b0da2e7a786995 /sound/soc/tegra
parentc6c1f7a2c194f1a2291a15c6691c0d6785f8976e (diff)
parent336961dd3cf9c39456dd9657e8f205718740c797 (diff)
Merge branch 'l4t/l4t-r16' into colibri
Merge with latest NVIDIA L4T R16. Only real conflict concerning inverted VBUS gpio support.
Diffstat (limited to 'sound/soc/tegra')
-rw-r--r--sound/soc/tegra/Makefile2
-rw-r--r--sound/soc/tegra/tegra20_das.c6
-rw-r--r--sound/soc/tegra/tegra20_das.h4
-rw-r--r--sound/soc/tegra/tegra30_ahub.c78
-rw-r--r--sound/soc/tegra/tegra30_ahub.h10
-rw-r--r--sound/soc/tegra/tegra30_dam.c47
-rw-r--r--sound/soc/tegra/tegra30_i2s.c175
-rw-r--r--sound/soc/tegra/tegra_aic326x.c4
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.c138
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.h4
-rw-r--r--sound/soc/tegra/tegra_max98088.c16
-rw-r--r--sound/soc/tegra/tegra_max98095.c17
-rw-r--r--sound/soc/tegra/tegra_p1852.c45
-rw-r--r--sound/soc/tegra/tegra_pcm.c26
-rw-r--r--sound/soc/tegra/tegra_pcm.h1
-rw-r--r--sound/soc/tegra/tegra_rt5640.c5
-rw-r--r--sound/soc/tegra/tegra_wm8753.c5
-rw-r--r--sound/soc/tegra/tegra_wm8903.c6
18 files changed, 461 insertions, 128 deletions
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index 274421b483de..079a28ccbe99 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
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/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
index ea772f40464b..6fac8fc0177b 100644
--- a/sound/soc/tegra/tegra30_ahub.c
+++ b/sound/soc/tegra/tegra30_ahub.c
@@ -3,6 +3,7 @@
*
* Author: Stephen Warren <swarren@nvidia.com>
* 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
@@ -281,66 +282,61 @@ 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 tegra30_ahub_rx_fifo_is_enabled(int i2s_id)
{
- 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;
+ 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_busy(enum tegra30_ahub_txcif txcif)
+int tegra30_ahub_tx_fifo_is_enabled(int i2s_id)
{
- int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
- int reg, val;
+ int val, mask;
- reg = TEGRA30_AHUB_CHANNEL_STATUS +
- (channel * TEGRA30_AHUB_CHANNEL_STATUS_STRIDE);
-
- val = tegra30_apbif_read(reg);
- val &= TEGRA30_AHUB_CHANNEL_STATUS_TX_TRIG;
+ 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_rx_fifo_clear(enum tegra30_ahub_rxcif rxcif)
+int tegra30_ahub_dam_ch0_is_enabled(int dam_id)
{
- 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);
+ int val, mask;
- tegra30_ahub_disable_clocks();
+ 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 0;
+ return val;
}
-int tegra30_ahub_tx_fifo_clear(enum tegra30_ahub_txcif txcif)
+int tegra30_ahub_dam_ch1_is_enabled(int dam_id)
{
- int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
- int reg, val;
+ int val, mask;
- reg = TEGRA30_AHUB_CHANNEL_CLEAR +
- (channel * TEGRA30_AHUB_CHANNEL_CLEAR_STRIDE);
+ 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;
- val = tegra30_apbif_read(reg);
- val |= TEGRA30_AHUB_CHANNEL_CLEAR_TX_SOFT_RESET;
- tegra30_apbif_write(reg, val);
+ return val;
+}
- tegra30_ahub_disable_clocks();
+int tegra30_ahub_dam_tx_is_enabled(int dam_id)
+{
+ int val, mask;
- return 0;
+ 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,
@@ -418,6 +414,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 +501,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;
}
diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h
index 2c0f5aab4db1..b5fd2363f080 100644
--- a/sound/soc/tegra/tegra30_ahub.h
+++ b/sound/soc/tegra/tegra30_ahub.h
@@ -3,6 +3,7 @@
*
* Author: Stephen Warren <swarren@nvidia.com>
* 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
@@ -500,10 +501,11 @@ 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);
+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 <noswal@nvidia.com>
* 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 <linux/platform_device.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
+#include <linux/delay.h>
#include <linux/io.h>
#include <sound/soc.h>
#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 c2750bfbef64..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 <speterson@nvidia.com>
*
* Copyright (C) 2010 Google, Inc.
@@ -346,6 +347,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 +361,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 +376,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 +391,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;
@@ -418,6 +428,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) |
@@ -625,9 +639,8 @@ 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_busy(i2s->txcif) && dcnt--)
+ while (tegra30_ahub_tx_fifo_is_enabled(i2s->id) && dcnt--)
udelay(100);
- tegra30_ahub_tx_fifo_clear(i2s->txcif);
}
static void tegra30_i2s_start_capture(struct tegra30_i2s *i2s)
@@ -647,9 +660,8 @@ static void tegra30_i2s_stop_capture(struct tegra30_i2s *i2s)
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--)
+ while (tegra30_ahub_rx_fifo_is_enabled(i2s->id) && dcnt--)
udelay(100);
- tegra30_ahub_rx_fifo_clear(i2s->rxcif);
}
static int tegra30_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
@@ -800,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 |
@@ -835,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;
@@ -905,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++;
@@ -957,10 +999,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);
@@ -977,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);
+
+ dcnt = 10;
- /* disable the codec dam */
+ /*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;
}
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 b134f0808afa..6ab5b2d46a1f 100644
--- a/sound/soc/tegra/tegra_asoc_utils.c
+++ b/sound/soc/tegra/tegra_asoc_utils.c
@@ -27,11 +27,14 @@
#include <mach/clk.h>
+#include <sound/soc.h>
+
+#include "tegra_pcm.h"
#include "tegra_asoc_utils.h"
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;
@@ -40,6 +43,115 @@ bool tegra_is_voice_call_active()
}
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)
{
@@ -276,6 +408,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);
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 63a067338dc4..82c2b930a39e 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");
@@ -1007,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");
@@ -1070,8 +1076,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 +1091,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 +1167,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",
diff --git a/sound/soc/tegra/tegra_max98095.c b/sound/soc/tegra/tegra_max98095.c
index 95295ef4151e..d065b78164ac 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); */
@@ -577,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);
@@ -591,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);
@@ -654,13 +660,22 @@ 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);
-#endif
err_fini_utils:
+#endif
tegra_asoc_utils_fini(&machine->util_data);
err_free_machine:
kfree(machine);
diff --git a/sound/soc/tegra/tegra_p1852.c b/sound/soc/tegra/tegra_p1852.c
index 9506a1c842df..199bb8046636 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,
}
};
@@ -199,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);
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index 5f2553b3dd66..090e8481dc37 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -58,8 +58,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,
@@ -281,15 +281,30 @@ 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;
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:
@@ -307,8 +322,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;
@@ -443,7 +459,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;
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 795356875ba4..f7c7a4c6b5a1 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);
@@ -783,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..063aefe50507 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? */
@@ -898,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);