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

(cherry picked from commit f270f46bef98a56f44432e608041adb617c22559)

Signed-off-by: Chandrakanth Gorantla <cgorantla@nvidia.com>
Change-Id: I195aae9043f967273283579f44d5367fe73d542f
Reviewed-on: http://git-master/r/129159
Reviewed-by: Automatic_Commit_Validation_User
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 2c18a71..80d22d2 100644 (file)
@@ -86,8 +86,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;
@@ -121,6 +124,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)
 {
@@ -128,6 +155,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)
@@ -138,7 +166,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;
 }
 
@@ -148,7 +183,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 f471faf..a7c9c0a 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 b63de32..5a9531b 100644 (file)
@@ -54,6 +54,7 @@ struct tegra_runtime_data {
        struct tegra_dma_channel *dma_chan;
        int dma_req_count;
        int disable_intr;
+       unsigned int avp_dma_addr;
 };
 
 int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd);