ASoC: Tegra: Add ALSA ctl to set DMA address
Sumit Bhattacharya [Mon, 27 Aug 2012 08:07:39 +0000 (16:07 +0800)]
Add support for setting of DMA address through alsa control for AVP
rendering. This is required to directly do DMA from IRAM to I2S.

Bug 1024403

Change-Id: I6b79ae6e9a562160a19d238b817e1a8b407ac208
Signed-off-by: Sumit Bhattacharya <sumitb@nvidia.com>
Reviewed-on: http://git-master/r/127436
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Niranjan Wartikar <nwartikar@nvidia.com>
Reviewed-by: Ravindra Lokhande <rlokhande@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Scott Peterson <speterson@nvidia.com>

sound/soc/tegra/tegra_asoc_utils.c
sound/soc/tegra/tegra_asoc_utils.h
sound/soc/tegra/tegra_pcm.c
sound/soc/tegra/tegra_pcm.h

index a0c1cb9..660093f 100644 (file)
@@ -87,8 +87,11 @@ static int tegra_set_avp_device(struct snd_kcontrol *kcontrol,
                        prtd = substream->runtime->private_data;
                        if (prtd->running)
                                return -EBUSY;
-                       if (prtd)
+                       if (prtd) {
                                prtd->disable_intr = true;
+                               if (data->avp_dma_addr || prtd->avp_dma_addr)
+                                       prtd->avp_dma_addr = data->avp_dma_addr;
+                       }
                }
        }
        data->avp_device_id = id;
@@ -122,6 +125,30 @@ static int tegra_get_dma_ch_id(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
+static int tegra_set_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;
+       struct tegra_runtime_data *prtd;
+
+       data->avp_dma_addr = ucontrol->value.integer.value[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)
+               return 0;
+
+       prtd->avp_dma_addr = data->avp_dma_addr;
+       return 1;
+}
+
 static int tegra_get_dma_addr(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
 {
@@ -129,6 +156,7 @@ static int tegra_get_dma_addr(struct snd_kcontrol *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] = 0;
        if (data->avp_device_id < 0)
@@ -139,7 +167,14 @@ static int tegra_get_dma_addr(struct snd_kcontrol *kcontrol,
        if (!substream || !substream->runtime)
                return 0;
 
-       ucontrol->value.integer.value[0] = substream->runtime->dma_addr;
+       prtd = substream->runtime->private_data;
+       if (!prtd || !prtd->dma_chan)
+               return 0;
+
+       ucontrol->value.integer.value[0] = prtd->avp_dma_addr ?
+                                          prtd->avp_dma_addr :
+                                          substream->runtime->dma_addr;
+
        return 0;
 }
 
@@ -149,7 +184,7 @@ struct snd_kcontrol_new tegra_avp_controls[] = {
        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),
+                       0, tegra_get_dma_addr, tegra_set_dma_addr),
 };
 
 int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
index ce379e3..cd13796 100644 (file)
@@ -43,6 +43,7 @@ struct tegra_asoc_utils_data {
        int set_mclk;
        int lock_count;
        int avp_device_id;
+       unsigned int avp_dma_addr;
 };
 
 int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
index f06f05f..387444d 100644 (file)
@@ -70,7 +70,11 @@ static void tegra_pcm_queue_dma(struct tegra_runtime_data *prtd)
        if (++prtd->dma_req_idx >= prtd->dma_req_count)
                prtd->dma_req_idx -= prtd->dma_req_count;
 
-       addr = buf->addr + prtd->dma_pos;
+       if (prtd->avp_dma_addr)
+               addr = prtd->avp_dma_addr + prtd->dma_pos;
+       else
+               addr = buf->addr + prtd->dma_pos;
+
        prtd->dma_pos += dma_req->size;
        if (prtd->dma_pos >= prtd->dma_pos_end)
                prtd->dma_pos = 0;
index b7e7ca3..7a0fbfc 100644 (file)
@@ -59,6 +59,7 @@ struct tegra_runtime_data {
        struct tegra_dma_channel *dma_chan;
        int dma_req_count;
        int disable_intr;
+       unsigned int avp_dma_addr;
 };
 
 #ifdef TEGRA30_USE_SMMU