summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorDeepa Madiregama <dmadiregama@nvidia.com>2014-05-23 15:23:51 +0530
committerEmad Mir <emir@nvidia.com>2014-07-09 15:10:38 -0700
commit4e914c4dc48b6ba8d9cc92a3d788bf80aceea102 (patch)
tree70d592a05ac1f4c65b7cbef090f17af83dcfada8 /sound
parent9b51faf398f7f47cc101f5e1843195c2ff59147b (diff)
ASoC: Tegra: Add support for effects capture
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>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/tegra/tegra30_avp.c154
-rw-r--r--sound/soc/tegra/tegra_offload.c212
-rw-r--r--sound/soc/tegra/tegra_offload.h3
-rw-r--r--sound/soc/tegra/tegra_rt5639.c16
4 files changed, 301 insertions, 84 deletions
diff --git a/sound/soc/tegra/tegra30_avp.c b/sound/soc/tegra/tegra30_avp.c
index d28e25ab057c..aeefdd53fdee 100644
--- a/sound/soc/tegra/tegra30_avp.c
+++ b/sound/soc/tegra/tegra30_avp.c
@@ -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,
diff --git a/sound/soc/tegra/tegra_offload.c b/sound/soc/tegra/tegra_offload.c
index bdfe94e30add..660bb4739554 100644
--- a/sound/soc/tegra/tegra_offload.c
+++ b/sound/soc/tegra/tegra_offload.c
@@ -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",
diff --git a/sound/soc/tegra/tegra_offload.h b/sound/soc/tegra/tegra_offload.h
index 6a1d0cf1cb56..b67c19a5d714 100644
--- a/sound/soc/tegra/tegra_offload.h
+++ b/sound/soc/tegra/tegra_offload.h
@@ -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;
};
diff --git a/sound/soc/tegra/tegra_rt5639.c b/sound/soc/tegra/tegra_rt5639.c
index 467375e15770..b26096550c2d 100644
--- a/sound/soc/tegra/tegra_rt5639.c
+++ b/sound/soc/tegra/tegra_rt5639.c
@@ -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",