ASoC: Tegra: Add support for effects capture
Deepa Madiregama [Fri, 23 May 2014 09:53:51 +0000 (14:53 +0530)]
Add capture node to get the effects data from AVP

Bug 1399923

Change-Id: I854de0966a40fe7867001a25058626da63b87b92
Signed-off-by: Deepa Madiregama <dmadiregama@nvidia.com>
Reviewed-on: http://git-master/r/414091
Reviewed-by: Emad Mir <emir@nvidia.com>
Tested-by: Emad Mir <emir@nvidia.com>

sound/soc/tegra/tegra30_avp.c
sound/soc/tegra/tegra_offload.c
sound/soc/tegra/tegra_offload.h
sound/soc/tegra/tegra_rt5639.c

index d28e25a..aeefdd5 100644 (file)
@@ -713,11 +713,114 @@ static void tegra30_avp_free_shared_mem(struct tegra_offload_mem *mem)
        tegra30_avp_mem_free(mem);
 }
 
+/* Loopback APIs */
+static int tegra30_avp_loopback_set_params(int id,
+               struct tegra_offload_pcm_params *params)
+{
+       struct tegra30_avp_audio *audio_avp = avp_audio_ctx;
+       struct tegra30_avp_stream *avp_stream = &audio_avp->avp_stream[id];
+       struct stream_data *stream = avp_stream->stream;
+       int ret = 0;
+
+       dev_vdbg(audio_avp->dev, "%s:entry\n", __func__);
+
+       /* TODO : check validity of parameters */
+       if (!stream) {
+               dev_err(audio_avp->dev, "AVP platform not initialized.");
+               return -ENODEV;
+       }
+
+
+       stream->stream_notification_interval = params->period_size;
+       stream->stream_notification_enable = 1;
+       stream->stream_params.rate = params->rate;
+       stream->stream_params.channels = params->channels;
+       stream->stream_params.bits_per_sample = params->bits_per_sample;
+
+
+       avp_stream->period_size = params->period_size;
+       avp_stream->notify_cb = params->period_elapsed_cb;
+       avp_stream->notify_args = params->period_elapsed_args;
+
+       stream->source_buffer_system =
+               (uintptr_t)(params->source_buf.virt_addr);
+       stream->source_buffer_avp = params->source_buf.phys_addr;
+       stream->source_buffer_size = params->buffer_size;
+       return ret;
+}
+
+static int tegra30_avp_loopback_set_state(int id, int state)
+{
+       struct tegra30_avp_audio *audio_avp = avp_audio_ctx;
+       struct tegra30_avp_stream *avp_stream = &audio_avp->avp_stream[id];
+       struct stream_data *stream = avp_stream->stream;
+
+       dev_vdbg(audio_avp->dev, "%s : id %d state %d", __func__, id, state);
+
+       if (!stream) {
+               dev_err(audio_avp->dev, "AVP platform not initialized.");
+               return -ENODEV;
+       }
+
+       switch (state) {
+       case SNDRV_PCM_TRIGGER_START:
+               stream->stream_state_target = KSSTATE_RUN;
+               return 0;
+       case SNDRV_PCM_TRIGGER_STOP:
+               stream->stream_state_target = KSSTATE_STOP;
+               stream->source_buffer_write_position = 0;
+               stream->source_buffer_write_count = 0;
+               avp_stream->last_notification_offset = 0;
+               avp_stream->notification_received = 0;
+               avp_stream->source_buffer_offset = 0;
+               return 0;
+       default:
+               dev_err(audio_avp->dev, "Unsupported state.");
+               return -EINVAL;
+       }
+}
+
+static size_t tegra30_avp_loopback_get_position(int id)
+{
+       struct tegra30_avp_audio *audio_avp = avp_audio_ctx;
+       struct tegra30_avp_stream *avp_stream = &audio_avp->avp_stream[id];
+       struct stream_data *stream = avp_stream->stream;
+       size_t pos = 0;
+
+       pos = (size_t)stream->source_buffer_read_position;
+
+       dev_vdbg(audio_avp->dev, "%s id %d pos %d", __func__, id, (u32)pos);
+
+       return pos;
+}
+
+static void tegra30_avp_loopback_data_ready(int id, int bytes)
+{
+       struct tegra30_avp_audio *audio_avp = avp_audio_ctx;
+       struct tegra30_avp_stream *avp_stream = &audio_avp->avp_stream[id];
+       struct stream_data *stream = avp_stream->stream;
+
+       dev_vdbg(audio_avp->dev, "%s :id %d size %d", __func__, id, bytes);
+
+       stream->source_buffer_write_position += bytes;
+       stream->source_buffer_write_position %= stream->source_buffer_size;
+
+       avp_stream->source_buffer_offset += bytes;
+       while (avp_stream->source_buffer_offset >=
+               stream->stream_notification_interval) {
+               stream->source_buffer_write_count++;
+               avp_stream->source_buffer_offset -=
+               stream->stream_notification_interval;
+       }
+       return;
+}
+
 /* PCM APIs */
-static int tegra30_avp_pcm_open(int *id)
+static int tegra30_avp_pcm_open(int *id, char *stream)
 {
        struct tegra30_avp_audio *audio_avp = avp_audio_ctx;
        struct audio_engine_data *audio_engine = audio_avp->audio_engine;
+       struct tegra30_avp_stream *avp_stream;
        int ret = 0;
 
        dev_vdbg(audio_avp->dev, "%s", __func__);
@@ -741,20 +844,36 @@ static int tegra30_avp_pcm_open(int *id)
                audio_engine = audio_avp->audio_engine;
        }
 
-       if (!audio_engine->stream[pcm_stream_id].stream_allocated)
-               *id = pcm_stream_id;
-       else if (!audio_engine->stream[pcm2_stream_id].stream_allocated)
-               *id = pcm2_stream_id;
-       else {
-               dev_err(audio_avp->dev, "All AVP PCM streams are busy");
-               return -EBUSY;
+       if (strcmp(stream, "pcm") == 0) {
+               avp_stream = &audio_avp->avp_stream[1];
+               if (!audio_engine->stream[pcm_stream_id].stream_allocated) {
+                       *id = pcm_stream_id;
+                       audio_engine->stream[*id].stream_allocated = 1;
+                       atomic_inc(&audio_avp->stream_active_count);
+               } else if (
+               !audio_engine->stream[pcm2_stream_id].stream_allocated) {
+                       *id = pcm2_stream_id;
+                       audio_engine->stream[*id].stream_allocated = 1;
+                       atomic_inc(&audio_avp->stream_active_count);
+               } else {
+                       dev_err(audio_avp->dev, "All AVP PCM streams are busy");
+                       return -EBUSY;
+               }
+       } else if (strcmp(stream, "loopback") == 0) {
+               avp_stream = &audio_avp->avp_stream[0];
+               if
+               (!audio_engine->stream[loopback_stream_id].stream_allocated) {
+                       dev_vdbg(audio_avp->dev,
+                       "Assigning loopback id:%d\n", loopback_stream_id);
+                       audio_engine->stream[*id].stream_allocated = 1;
+                       *id = loopback_stream_id;
+               } else {
+                       dev_err(audio_avp->dev, "AVP loopback streams is busy");
+                       return -EBUSY;
+               }
        }
 
-       audio_engine->stream[*id].stream_allocated = 1;
-
-       atomic_inc(&audio_avp->stream_active_count);
        tegra30_avp_audio_set_state(KSSTATE_RUN);
-
        return 0;
 }
 
@@ -1248,6 +1367,9 @@ static void tegra30_avp_stream_close(int id)
        stream->stream_allocated = 0;
        tegra30_avp_stream_set_state(id, KSSTATE_STOP);
 
+       if (id == loopback_stream_id)
+               return;
+
        if (atomic_dec_and_test(&audio_avp->stream_active_count)) {
                tegra30_avp_audio_free_dma();
                tegra30_avp_audio_set_state(KSSTATE_STOP);
@@ -1268,6 +1390,14 @@ static struct tegra_offload_ops avp_audio_platform = {
                .get_stream_position = tegra30_avp_pcm_get_position,
                .data_ready = tegra30_avp_pcm_data_ready,
        },
+       .loopback_ops = {
+               .stream_open = tegra30_avp_pcm_open,
+               .stream_close = tegra30_avp_stream_close,
+               .set_stream_params = tegra30_avp_loopback_set_params,
+               .set_stream_state = tegra30_avp_loopback_set_state,
+               .get_stream_position = tegra30_avp_loopback_get_position,
+               .data_ready = tegra30_avp_loopback_data_ready,
+       },
        .compr_ops = {
                .stream_open = tegra30_avp_compr_open,
                .stream_close = tegra30_avp_stream_close,
index bdfe94e..660bb47 100644 (file)
@@ -38,6 +38,7 @@
 enum {
        PCM_OFFLOAD_DAI,
        COMPR_OFFLOAD_DAI,
+       PCM_CAPTURE_OFFLOAD_DAI,
        MAX_OFFLOAD_DAI
 };
 
@@ -61,7 +62,7 @@ static DEFINE_MUTEX(tegra_offload_lock);
 
 static int codec, spk;
 
-static const struct snd_pcm_hardware tegra_offload_pcm_hardware = {
+static const struct snd_pcm_hardware tegra_offload_pcm_hardware_playback = {
        .info                   = SNDRV_PCM_INFO_MMAP |
                                  SNDRV_PCM_INFO_MMAP_VALID |
                                  SNDRV_PCM_INFO_PAUSE |
@@ -78,6 +79,23 @@ static const struct snd_pcm_hardware tegra_offload_pcm_hardware = {
        .fifo_size              = 4,
 };
 
+static const struct snd_pcm_hardware tegra_offload_pcm_hardware_capture = {
+       .info                   = SNDRV_PCM_INFO_MMAP |
+                                 SNDRV_PCM_INFO_MMAP_VALID |
+                                 SNDRV_PCM_INFO_PAUSE |
+                                 SNDRV_PCM_INFO_RESUME |
+                                 SNDRV_PCM_INFO_INTERLEAVED,
+       .formats                = SNDRV_PCM_FMTBIT_S16_LE,
+       .channels_min           = 2,
+       .channels_max           = 2,
+       .period_bytes_min       = 128,
+       .period_bytes_max       = PAGE_SIZE * 2,
+       .periods_min            = 1,
+       .periods_max            = 8,
+       .buffer_bytes_max       = PAGE_SIZE * 8,
+       .fifo_size              = 4,
+};
+
 int tegra_register_offload_ops(struct tegra_offload_ops *ops)
 {
        mutex_lock(&tegra_offload_lock);
@@ -320,7 +338,7 @@ static int tegra_offload_compr_set_params(struct snd_compr_stream *stream,
 }
 
 static int tegra_offload_compr_get_params(struct snd_compr_stream *stream,
-                       struct snd_codec *codec)
+                                       struct snd_codec *codec)
 {
        struct device *dev = stream->device->dev;
        struct tegra_offload_compr_data *data = stream->runtime->private_data;
@@ -343,7 +361,7 @@ static int tegra_offload_compr_trigger(struct snd_compr_stream *stream, int cmd)
 }
 
 static int tegra_offload_compr_pointer(struct snd_compr_stream *stream,
-                       struct snd_compr_tstamp *tstamp)
+               struct snd_compr_tstamp *tstamp)
 {
        struct device *dev = stream->device->dev;
        struct tegra_offload_compr_data *data = stream->runtime->private_data;
@@ -354,7 +372,7 @@ static int tegra_offload_compr_pointer(struct snd_compr_stream *stream,
 }
 
 static int tegra_offload_compr_copy(struct snd_compr_stream *stream,
-                       char __user *buf, size_t count)
+               char __user *buf, size_t count)
 {
        struct device *dev = stream->device->dev;
        struct tegra_offload_compr_data *data = stream->runtime->private_data;
@@ -365,7 +383,7 @@ static int tegra_offload_compr_copy(struct snd_compr_stream *stream,
 }
 
 static int tegra_offload_compr_get_caps(struct snd_compr_stream *stream,
-                       struct snd_compr_caps *caps)
+               struct snd_compr_caps *caps)
 {
        struct device *dev = stream->device->dev;
        struct tegra_offload_compr_data *data = stream->runtime->private_data;
@@ -383,7 +401,7 @@ static int tegra_offload_compr_get_caps(struct snd_compr_stream *stream,
 }
 
 static int tegra_offload_compr_codec_caps(struct snd_compr_stream *stream,
-                       struct snd_compr_codec_caps *codec_caps)
+               struct snd_compr_codec_caps *codec_caps)
 {
        struct device *dev = stream->device->dev;
        struct tegra_offload_compr_data *data = stream->runtime->private_data;
@@ -403,7 +421,6 @@ static int tegra_offload_compr_codec_caps(struct snd_compr_stream *stream,
 }
 
 static struct snd_compr_ops tegra_compr_ops = {
-
        .open = tegra_offload_compr_open,
        .free = tegra_offload_compr_free,
        .set_params = tegra_offload_compr_set_params,
@@ -440,28 +457,45 @@ static int tegra_offload_pcm_open(struct snd_pcm_substream *substream)
 
        data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
        if (!data) {
-               dev_err(dev, "Failed to allocate tegra_offload_pcm_data.");
+               dev_vdbg(dev,
+                       "Failed to allocate tegra_offload_pcm_data\n");
                return -ENOMEM;
        }
-
-       /* Set HW params now that initialization is complete */
-       snd_soc_set_runtime_hwparams(substream, &tegra_offload_pcm_hardware);
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               /* Set HW params now that initialization is complete */
+               snd_soc_set_runtime_hwparams(substream,
+                               &tegra_offload_pcm_hardware_playback);
+       else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+               snd_soc_set_runtime_hwparams(substream,
+                               &tegra_offload_pcm_hardware_capture);
 
        /* Ensure period size is multiple of 4 */
        ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
-               SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 0x4);
+                               SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 0x4);
        if (ret) {
                dev_err(dev, "failed to set constraint %d\n", ret);
                return ret;
        }
-       data->ops = &offload_ops.pcm_ops;
-
-       ret = data->ops->stream_open(&data->stream_id);
-       if (ret < 0) {
-               dev_err(dev, "Failed to open offload stream. err %d", ret);
-               return ret;
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               data->ops = &offload_ops.pcm_ops;
+
+               ret = data->ops->stream_open(&data->stream_id, "pcm");
+               if (ret < 0) {
+                       dev_err(dev,
+                               "Failed to open offload stream err %d", ret);
+                       return ret;
+               }
+       } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+               data->ops = &offload_ops.loopback_ops;
+
+               ret = data->ops->stream_open(&data->stream_id, "loopback");
+               if (ret < 0) {
+                       dev_err(dev,
+                               "Failed to open offload stream err %d", ret);
+                       return ret;
+               }
        }
-        offload_ops.device_ops.set_hw_rate(48000);
+       offload_ops.device_ops.set_hw_rate(48000);
        substream->runtime->private_data = data;
        return 0;
 }
@@ -480,57 +514,69 @@ static int tegra_offload_pcm_close(struct snd_pcm_substream *substream)
 }
 
 static int tegra_offload_pcm_hw_params(struct snd_pcm_substream *substream,
-                               struct snd_pcm_hw_params *params)
+                       struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct device *dev = rtd->platform->dev;
-       struct tegra_offload_pcm_data *data = substream->runtime->private_data;
-       struct snd_dma_buffer *buf = &substream->dma_buffer;
-       struct tegra_pcm_dma_params *dmap;
+       struct tegra_offload_pcm_data *data =
+               substream->runtime->private_data;
        struct tegra_offload_pcm_params offl_params;
+       struct snd_dma_buffer *buf = &substream->dma_buffer;
        int ret = 0;
 
        dev_vdbg(dev, "%s", __func__);
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               struct tegra_pcm_dma_params *dmap;
+
+               dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+               if (!dmap) {
+                       struct snd_soc_dpcm *dpcm;
+
+                       if
+                       (list_empty(&rtd->dpcm[substream->stream].be_clients)) {
+                               dev_err(dev, "No backend DAIs enabled for %s\n",
+                               rtd->dai_link->name);
+                               return -EINVAL;
+                       }
 
-       dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-       if (!dmap) {
-               struct snd_soc_dpcm *dpcm;
-
-               if (list_empty(&rtd->dpcm[substream->stream].be_clients)) {
-                       dev_err(dev, "No backend DAIs enabled for %s\n",
-                                       rtd->dai_link->name);
-                       return -EINVAL;
-               }
-
-               list_for_each_entry(dpcm,
-                       &rtd->dpcm[substream->stream].be_clients, list_be) {
-                       struct snd_soc_pcm_runtime *be = dpcm->be;
-                       struct snd_pcm_substream *be_substream =
-                               snd_soc_dpcm_get_substream(be,
+                       list_for_each_entry(dpcm,
+                               &rtd->dpcm[substream->stream].be_clients,
+                               list_be) {
+                               struct snd_soc_pcm_runtime *be = dpcm->be;
+                               struct snd_pcm_substream *be_substream =
+                                               snd_soc_dpcm_get_substream(be,
                                                substream->stream);
-                       struct snd_soc_dai_link *dai_link = be->dai_link;
+                               struct snd_soc_dai_link *dai_link =
+                                                       be->dai_link;
 
-                       dmap = snd_soc_dai_get_dma_data(be->cpu_dai,
-                                               be_substream);
-
-                       if (spk && strstr(dai_link->name, "speaker")) {
-                               dmap = snd_soc_dai_get_dma_data(be->cpu_dai,
-                                               be_substream);
-                               break;
-                       }
-                       if (codec && strstr(dai_link->name, "codec")) {
                                dmap = snd_soc_dai_get_dma_data(be->cpu_dai,
-                                               be_substream);
-                               break;
+                                                               be_substream);
+
+                               if (spk && strstr(dai_link->name, "speaker")) {
+                                       dmap = snd_soc_dai_get_dma_data(
+                                                       be->cpu_dai,
+                                                       be_substream);
+                                       break;
+                               }
+                               if (codec && strstr(dai_link->name, "codec")) {
+                                       dmap = snd_soc_dai_get_dma_data(
+                                                       be->cpu_dai,
+                                                       be_substream);
+                                       break;
+                               }
+                               /* TODO : Multiple BE to
+                                * single FE not yet supported */
                        }
-                       /* TODO : Multiple BE to single FE not yet supported */
                }
+               if (!dmap) {
+                       dev_err(dev, "Failed to get DMA params.");
+                       return -ENODEV;
+               }
+               offl_params.dma_params.addr = dmap->addr;
+               offl_params.dma_params.width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+               offl_params.dma_params.req_sel = dmap->req_sel;
+               offl_params.dma_params.max_burst = 4;
        }
-       if (!dmap) {
-               dev_err(dev, "Failed to get DMA params.");
-               return -ENODEV;
-       }
-
        offl_params.bits_per_sample =
                snd_pcm_format_width(params_format(params));
        offl_params.rate = params_rate(params);
@@ -539,19 +585,17 @@ static int tegra_offload_pcm_hw_params(struct snd_pcm_substream *substream,
        offl_params.period_size = params_period_size(params) *
                ((offl_params.bits_per_sample >> 3) * offl_params.channels);
 
-       offl_params.dma_params.addr = dmap->addr;
-       offl_params.dma_params.width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-       offl_params.dma_params.req_sel = dmap->req_sel;
-       offl_params.dma_params.max_burst = 4;
 
        offl_params.source_buf.virt_addr = buf->area;
        offl_params.source_buf.phys_addr = buf->addr;
        offl_params.source_buf.bytes = buf->bytes;
 
-       offl_params.period_elapsed_cb = tegra_offload_pcm_period_elapsed;
+       offl_params.period_elapsed_cb =
+               tegra_offload_pcm_period_elapsed;
        offl_params.period_elapsed_args = (void *)substream;
 
-       ret = data->ops->set_stream_params(data->stream_id, &offl_params);
+       ret = data->ops->set_stream_params(data->stream_id,
+                                       &offl_params);
        if (ret < 0) {
                dev_err(dev, "Failed to set avp params. ret %d", ret);
                return ret;
@@ -582,10 +626,9 @@ static int tegra_offload_pcm_trigger(struct snd_pcm_substream *substream,
 
        data->ops->set_stream_state(data->stream_id, cmd);
        if ((cmd == SNDRV_PCM_TRIGGER_STOP) ||
-           (cmd == SNDRV_PCM_TRIGGER_SUSPEND) ||
-           (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH))
+       (cmd == SNDRV_PCM_TRIGGER_SUSPEND) ||
+       (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH))
                data->appl_ptr = 0;
-
        return 0;
 }
 
@@ -607,6 +650,7 @@ static int tegra_offload_pcm_ack(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct tegra_offload_pcm_data *data = runtime->private_data;
+
        int data_size = runtime->control->appl_ptr - data->appl_ptr;
 
        if (data_size < 0)
@@ -768,17 +812,40 @@ static int tegra_offload_dma_allocate(struct snd_soc_pcm_runtime *rtd,
 static int tegra_offload_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct device *dev = rtd->platform->dev;
+       struct snd_pcm *pcm = rtd->pcm;
+       int ret = 0;
 
-       dev_vdbg(dev, "%s", __func__);
 
-       return tegra_offload_dma_allocate(rtd , SNDRV_PCM_STREAM_PLAYBACK,
-                               tegra_offload_pcm_hardware.buffer_bytes_max);
+       dev_vdbg(dev, "%s", __func__);
+       dev_err(pcm->card->dev, "Allocating for stream playback\n");
+       ret = tegra_offload_dma_allocate(rtd , SNDRV_PCM_STREAM_PLAYBACK,
+                       tegra_offload_pcm_hardware_playback.buffer_bytes_max);
+       if (ret < 0) {
+               dev_err(pcm->card->dev, "failing in pcm_new:1 goto err");
+               goto err;
+       }
+       dev_err(pcm->card->dev, "Allocating for stream capture\n");
+       ret = tegra_offload_dma_allocate(rtd , SNDRV_PCM_STREAM_CAPTURE,
+                       tegra_offload_pcm_hardware_capture.buffer_bytes_max);
+       if (ret < 0) {
+               dev_err(pcm->card->dev, "failing in pcm_new:1 goto err");
+               goto err;
+       }
+err:
+       return ret;
 }
 
 static void tegra_offload_pcm_free(struct snd_pcm *pcm)
 {
-       tegra_offload_dma_free(pcm, SNDRV_PCM_STREAM_PLAYBACK);
        pr_debug("%s", __func__);
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
+               dev_err(pcm->card->dev, "PCM free for stream playback\n");
+               tegra_offload_dma_free(pcm, SNDRV_PCM_STREAM_PLAYBACK);
+       }
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+               dev_err(pcm->card->dev, "PCM free for stream capture\n");
+               tegra_offload_dma_free(pcm, SNDRV_PCM_STREAM_CAPTURE);
+       }
 }
 
 static int tegra_offload_pcm_probe(struct snd_soc_platform *platform)
@@ -827,6 +894,13 @@ static struct snd_soc_dai_driver tegra_offload_dai[] = {
                        .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
                        .formats = SNDRV_PCM_FMTBIT_S16_LE,
                },
+               .capture = {
+                       .stream_name = "offload-pcm-capture",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               },
        },
        [COMPR_OFFLOAD_DAI] = {
                .name = "tegra-offload-compr",
index 6a1d0cf..b67c19a 100644 (file)
@@ -56,7 +56,7 @@ struct tegra_offload_compr_params {
 };
 
 struct tegra_offload_pcm_ops {
-       int     (*stream_open)(int *id);
+       int     (*stream_open)(int *id, char *stream);
        void    (*stream_close)(int id);
        int     (*set_stream_params)(int id,
                        struct tegra_offload_pcm_params *params);
@@ -88,6 +88,7 @@ struct tegra_offload_device_ops {
 struct tegra_offload_ops {
        struct tegra_offload_device_ops device_ops;
        struct tegra_offload_pcm_ops    pcm_ops;
+       struct tegra_offload_pcm_ops    loopback_ops;
        struct tegra_offload_compr_ops  compr_ops;
 };
 
index 467375e..b260965 100644 (file)
@@ -59,8 +59,9 @@
 #define DAI_LINK_BT_VOICE_CALL 4
 #define DAI_LINK_PCM_OFFLOAD_FE        5
 #define DAI_LINK_COMPR_OFFLOAD_FE      6
-#define DAI_LINK_I2S_OFFLOAD_BE        7
-#define NUM_DAI_LINKS          8
+#define DAI_LINK_PCM_OFFLOAD_CAPTURE_FE        7
+#define DAI_LINK_I2S_OFFLOAD_BE        8
+#define NUM_DAI_LINKS          9
 
 extern int g_is_call_mode;
 
@@ -1062,6 +1063,17 @@ static struct snd_soc_dai_link tegra_rt5639_dai[NUM_DAI_LINKS] = {
 
                .dynamic = 1,
        },
+       [DAI_LINK_PCM_OFFLOAD_CAPTURE_FE] = {
+               .name = "offload-pcm-capture",
+               .stream_name = "offload-pcm-capture",
+
+               .platform_name = "tegra-offload",
+               .cpu_dai_name = "tegra-offload-pcm",
+
+               .codec_dai_name =  "snd-soc-dummy-dai",
+               .codec_name = "snd-soc-dummy",
+
+       },
        [DAI_LINK_I2S_OFFLOAD_BE] = {
                .name = "offload-audio-codec",
                .stream_name = "offload-audio-pcm",