summaryrefslogtreecommitdiff
path: root/sound/soc/tegra/tegra_max98088.c
diff options
context:
space:
mode:
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,
},
};