summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSumit Bhattacharya <sumitb@nvidia.com>2012-04-20 17:41:16 +0530
committerRohan Somvanshi <rsomvanshi@nvidia.com>2012-05-28 13:02:00 -0700
commitbd09096c7b6431f31d312e45689f59215a0e1356 (patch)
tree3f3b0fe474acade2c1c6088471497eb81ea0a0a0
parented1309fe218e55d7f32bee16a40816f74ccd4fe5 (diff)
ASoC: Tegra: Add support for AVP rendering
Add alsa controls to specify which alsa device is used by AVP to render audio. Also add support for disabling DMA interrupt when AVP renders audio. Also add couple of alsa controls to query DMA channel ID and DMA buffer physical address. Bug 968814 Signed-off-by: Sumit Bhattacharya <sumitb@nvidia.com> Change-Id: If593329db72bf00d97f7433f5c54e13500281253 Reviewed-on: http://git-master/r/97916 Reviewed-by: Rohan Somvanshi <rsomvanshi@nvidia.com> Tested-by: Rohan Somvanshi <rsomvanshi@nvidia.com>
-rw-r--r--sound/soc/tegra/tegra_aic326x.c4
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.c132
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.h4
-rw-r--r--sound/soc/tegra/tegra_max98088.c4
-rw-r--r--sound/soc/tegra/tegra_max98095.c4
-rw-r--r--sound/soc/tegra/tegra_pcm.c18
-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.c4
-rw-r--r--sound/soc/tegra/tegra_wm8903.c4
10 files changed, 176 insertions, 4 deletions
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 a189fb5c61c1..6ab5b2d46a1f 100644
--- a/sound/soc/tegra/tegra_asoc_utils.c
+++ b/sound/soc/tegra/tegra_asoc_utils.c
@@ -27,6 +27,9 @@
#include <mach/clk.h>
+#include <sound/soc.h>
+
+#include "tegra_pcm.h"
#include "tegra_asoc_utils.h"
int g_is_call_mode;
@@ -40,6 +43,115 @@ bool tegra_is_voice_call_active(void)
}
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)
{
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 8c0e3935ad02..82c2b930a39e 100644
--- a/sound/soc/tegra/tegra_max98088.c
+++ b/sound/soc/tegra/tegra_max98088.c
@@ -1009,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");
diff --git a/sound/soc/tegra/tegra_max98095.c b/sound/soc/tegra/tegra_max98095.c
index 95295ef4151e..b3bed37ac715 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); */
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index 1b4b949841aa..f471fafff2ac 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -52,8 +52,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,
@@ -272,6 +272,15 @@ int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
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:
@@ -289,8 +298,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;
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 99d0b19c7106..f7c7a4c6b5a1 100644
--- a/sound/soc/tegra/tegra_wm8753.c
+++ b/sound/soc/tegra/tegra_wm8753.c
@@ -782,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..147546575233 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? */