summaryrefslogtreecommitdiff
path: root/sound/soc/tegra/tegra_max98088.c
diff options
context:
space:
mode:
authorNikesh Oswal <noswal@nvidia.com>2011-11-11 17:01:45 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:50:08 -0800
commit5c68d67b98772244fdedb056e85c1a9cdf381325 (patch)
treefdf461e07872556f2e691f74975fe28a839d7a4d /sound/soc/tegra/tegra_max98088.c
parentdd717632cb06bfef0ece42a7e45e8c5712943261 (diff)
ASoC: tegra: max98088 machine: connect playback path via the dam
default playback path is established through the dam so as to support mixing of system sounds during voice call and also playing of connection and disconnection tones Bug: 862023 Change-Id: Ia055e7372f4ca18d038db483c3657ee4bbbfb6ca Signed-off-by: Nikesh Oswal <noswal@nvidia.com> Reviewed-on: http://git-master/r/63816 Reviewed-by: Rohan Somvanshi <rsomvanshi@nvidia.com> Rebase-Id: R38a4b7b469f5c8cffdc9c53a4a1fb07c13b5a531
Diffstat (limited to 'sound/soc/tegra/tegra_max98088.c')
-rw-r--r--[-rwxr-xr-x]sound/soc/tegra/tegra_max98088.c145
1 files changed, 143 insertions, 2 deletions
diff --git a/sound/soc/tegra/tegra_max98088.c b/sound/soc/tegra/tegra_max98088.c
index 9bb958fbda4a..acb278d1608a 100755..100644
--- a/sound/soc/tegra/tegra_max98088.c
+++ b/sound/soc/tegra/tegra_max98088.c
@@ -51,6 +51,11 @@
#include "tegra_pcm.h"
#include "tegra_asoc_utils.h"
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+#include "tegra30_ahub.h"
+#include "tegra30_i2s.h"
+#include "tegra30_dam.h"
+#endif
#define DRV_NAME "tegra-snd-max98088"
@@ -63,8 +68,28 @@ struct tegra_max98088 {
struct tegra_asoc_utils_data util_data;
struct tegra_max98088_platform_data *pdata;
int gpio_requested;
+ bool init_done;
};
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+static int tegra_max98088_set_dam_cif(int dam_ifc, int srate,
+ int channels, int bit_size)
+{
+ tegra30_dam_set_samplerate(dam_ifc, TEGRA30_DAM_CHOUT,
+ srate);
+ tegra30_dam_set_samplerate(dam_ifc, TEGRA30_DAM_CHIN1,
+ srate);
+ tegra30_dam_set_acif(dam_ifc, TEGRA30_DAM_CHIN1,
+ channels, bit_size, channels,
+ bit_size);
+ tegra30_dam_set_acif(dam_ifc, TEGRA30_DAM_CHOUT,
+ channels, bit_size, channels,
+ bit_size);
+
+ return 0;
+}
+#endif
+
static int tegra_max98088_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -74,9 +99,20 @@ static int tegra_max98088_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_card *card = codec->card;
struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card);
- int srate, mclk;
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai);
+#endif
+ int srate, mclk, sample_size;
int err;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ sample_size = 16;
+ break;
+ default:
+ return -EINVAL;
+ }
+
srate = params_rate(params);
switch (srate) {
case 8000:
@@ -136,6 +172,12 @@ static int tegra_max98088_hw_params(struct snd_pcm_substream *substream,
return err;
}
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ tegra_max98088_set_dam_cif(i2s->dam_ifc, srate,
+ params_channels(params), sample_size);
+#endif
+
return 0;
}
@@ -188,9 +230,20 @@ static int tegra_bt_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+#endif
struct snd_soc_card *card = rtd->card;
struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card);
- int err, srate, mclk, min_mclk;
+ int err, srate, mclk, min_mclk, sample_size;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ sample_size = 16;
+ break;
+ default:
+ return -EINVAL;
+ }
srate = params_rate(params);
switch (srate) {
@@ -234,6 +287,12 @@ static int tegra_bt_hw_params(struct snd_pcm_substream *substream,
return err;
}
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ tegra_max98088_set_dam_cif(i2s->dam_ifc, params_rate(params),
+ params_channels(params), sample_size);
+#endif
+
return 0;
}
@@ -247,9 +306,81 @@ static void tegra_hw_free(struct snd_pcm_substream *substream)
return 0;
}
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+static int tegra_max98088_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai);
+
+ if ((substream->stream != SNDRV_PCM_STREAM_PLAYBACK) ||
+ !(i2s->is_dam_used))
+ return 0;
+
+ /*dam configuration*/
+ if (!i2s->dam_ch_refcount)
+ i2s->dam_ifc = tegra30_dam_allocate_controller();
+
+ tegra30_dam_allocate_channel(i2s->dam_ifc, TEGRA30_DAM_CHIN1);
+ i2s->dam_ch_refcount++;
+ tegra30_dam_enable_clock(i2s->dam_ifc);
+ tegra30_dam_set_gain(i2s->dam_ifc, TEGRA30_DAM_CHIN1, 0x1000);
+
+ tegra30_ahub_set_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX1 +
+ (i2s->dam_ifc*2), i2s->txcif);
+
+ /*
+ *make the dam tx to i2s rx connection if this is the only client
+ *using i2s for playback
+ */
+ if (i2s->playback_ref_count == 1)
+ tegra30_ahub_set_rx_cif_source(
+ TEGRA30_AHUB_RXCIF_I2S0_RX0 + i2s->id,
+ TEGRA30_AHUB_TXCIF_DAM0_TX0 + i2s->dam_ifc);
+
+ /* enable the dam*/
+ tegra30_dam_enable(i2s->dam_ifc, TEGRA30_DAM_ENABLE,
+ TEGRA30_DAM_CHIN1);
+
+ return 0;
+}
+
+static int tegra_max98088_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai);
+
+ if ((substream->stream != SNDRV_PCM_STREAM_PLAYBACK) ||
+ !(i2s->is_dam_used))
+ return 0;
+
+ /* disable the dam*/
+ tegra30_dam_enable(i2s->dam_ifc, TEGRA30_DAM_DISABLE,
+ TEGRA30_DAM_CHIN1);
+
+ /* disconnect the ahub connections*/
+ tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX1 +
+ (i2s->dam_ifc*2));
+
+ /* disable the dam and free the controller */
+ tegra30_dam_disable_clock(i2s->dam_ifc);
+ tegra30_dam_free_channel(i2s->dam_ifc, TEGRA30_DAM_CHIN1);
+ i2s->dam_ch_refcount--;
+ if (!i2s->dam_ch_refcount)
+ tegra30_dam_free_controller(i2s->dam_ifc);
+
+ return 0;
+}
+#endif
+
static struct snd_soc_ops tegra_max98088_ops = {
.hw_params = tegra_max98088_hw_params,
.hw_free = tegra_hw_free,
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ .startup = tegra_max98088_startup,
+ .shutdown = tegra_max98088_shutdown,
+#endif
};
static struct snd_soc_ops tegra_spdif_ops = {
@@ -260,6 +391,10 @@ static struct snd_soc_ops tegra_spdif_ops = {
static struct snd_soc_ops tegra_bt_ops = {
.hw_params = tegra_bt_hw_params,
.hw_free = tegra_hw_free,
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ .startup = tegra_max98088_startup,
+ .shutdown = tegra_max98088_shutdown,
+#endif
};
static struct snd_soc_jack tegra_max98088_hp_jack;
@@ -381,6 +516,11 @@ static int tegra_max98088_init(struct snd_soc_pcm_runtime *rtd)
struct tegra_max98088_platform_data *pdata = machine->pdata;
int ret;
+ if (machine->init_done)
+ return 0;
+
+ machine->init_done = true;
+
if (gpio_is_valid(pdata->gpio_spkr_en)) {
ret = gpio_request(pdata->gpio_spkr_en, "spkr_en");
if (ret) {
@@ -491,6 +631,7 @@ static struct snd_soc_dai_link tegra_max98088_dai[] = {
.platform_name = "tegra-pcm-audio",
.cpu_dai_name = "tegra30-i2s.3",
.codec_dai_name = "dit-hifi",
+ .init = tegra_max98088_init,
.ops = &tegra_bt_ops,
},
};