summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorGary King <gking@nvidia.com>2010-05-28 16:38:08 -0700
committerGary King <gking@nvidia.com>2010-05-28 17:20:19 -0700
commit00686bd386d93d4b97016677f4cbea0045c07c8f (patch)
treee92f58c20691f65196b25230c7c4cb1131e9d52c /sound
parenta4b16260c8dbc8d9834c15a6b983917a2f5776f0 (diff)
[alsa] add ASoC device and stub codec for tegra SoCs
Change-Id: I34c6607d82e890d57180d4f97aa1537cf2aba4d8 Reviewed-on: http://git-master/r/1828 Reviewed-by: Gary King <gking@nvidia.com> Tested-by: Gary King <gking@nvidia.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/Kconfig1
-rw-r--r--sound/soc/Makefile1
-rw-r--r--sound/soc/tegra/Kconfig20
-rw-r--r--sound/soc/tegra/Makefile4
-rw-r--r--sound/soc/tegra/tegra_codec_rpc.c180
-rw-r--r--sound/soc/tegra/tegra_i2s.c109
-rw-r--r--sound/soc/tegra/tegra_pcm_rpc.c877
-rw-r--r--sound/soc/tegra/tegra_sndfx.h623
-rw-r--r--sound/soc/tegra/tegra_soc_audio.c171
-rw-r--r--sound/soc/tegra/tegra_transport.c840
-rw-r--r--sound/soc/tegra/tegra_transport.h431
11 files changed, 3257 insertions, 0 deletions
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index b1749bc67979..5a7c4e7320b0 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -35,6 +35,7 @@ source "sound/soc/pxa/Kconfig"
source "sound/soc/s3c24xx/Kconfig"
source "sound/soc/s6000/Kconfig"
source "sound/soc/sh/Kconfig"
+source "sound/soc/tegra/Kconfig"
source "sound/soc/txx9/Kconfig"
# Supported codecs
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 0c5eac01bf2e..a36fd1476860 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -13,4 +13,5 @@ obj-$(CONFIG_SND_SOC) += pxa/
obj-$(CONFIG_SND_SOC) += s3c24xx/
obj-$(CONFIG_SND_SOC) += s6000/
obj-$(CONFIG_SND_SOC) += sh/
+obj-$(CONFIG_SND_SOC) += tegra/
obj-$(CONFIG_SND_SOC) += txx9/
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
new file mode 100644
index 000000000000..db522f3f8265
--- /dev/null
+++ b/sound/soc/tegra/Kconfig
@@ -0,0 +1,20 @@
+config TEGRA_SND_SOC
+ tristate "Soc alsa driver for Tegra"
+ depends on ARCH_TEGRA
+ select TEGRA_PCM
+ select TEGRA_I2S
+ select TEGRA_GENERIC_CODEC
+ help
+ Say Y to support ALSA SoC for TEGRA
+
+config TEGRA_PCM
+ depends on TEGRA_SND_SOC
+ tristate "Tegra pcm callbacks"
+
+config TEGRA_I2S
+ depends on TEGRA_SND_SOC
+ tristate "Tegra I2S"
+
+config TEGRA_GENERIC_CODEC
+ depends on TEGRA_SND_SOC
+ tristate "Tegra Generic Audio Codec"
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
new file mode 100644
index 000000000000..81ef7784d5de
--- /dev/null
+++ b/sound/soc/tegra/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_TEGRA_PCM) += tegra_pcm_rpc.o
+obj-$(CONFIG_TEGRA_I2S) += tegra_i2s.o tegra_transport.o
+obj-$(CONFIG_TEGRA_GENERIC_CODEC) += tegra_soc_audio.o
+obj-$(CONFIG_TEGRA_GENERIC_CODEC) += tegra_codec_rpc.o \ No newline at end of file
diff --git a/sound/soc/tegra/tegra_codec_rpc.c b/sound/soc/tegra/tegra_codec_rpc.c
new file mode 100644
index 000000000000..ea97d0f91337
--- /dev/null
+++ b/sound/soc/tegra/tegra_codec_rpc.c
@@ -0,0 +1,180 @@
+/*
+ * sound/soc/tegra/tegra_codec_rpc.c
+ *
+ * ALSA SOC driver for NVIDIA Tegra SoCs
+ *
+ * Copyright (C) 2010 NVIDIA Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+
+#include "tegra_transport.h"
+
+static int tegra_generic_codec_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ return 0;
+}
+
+static int tegra_generic_codec_mute(struct snd_soc_dai *dai, int mute)
+{
+ return 0;
+}
+
+static int tegra_generic_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ return 0;
+}
+
+static int tegra_generic_codec_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+ int div_id, int div)
+{
+ return 0;
+}
+
+static int tegra_generic_codec_set_dai_pll(struct snd_soc_dai *codec_dai,
+ int pll_id, unsigned int freq_in, unsigned int freq_out)
+{
+ return 0;
+}
+
+static int tegra_generic_codec_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ return 0;
+}
+
+static struct snd_soc_dai_ops dit_stub_ops = {
+ .hw_params = tegra_generic_codec_hw_params,
+ .digital_mute = tegra_generic_codec_mute,
+ .set_fmt = tegra_generic_codec_set_dai_fmt,
+ .set_clkdiv = tegra_generic_codec_set_dai_clkdiv,
+ .set_pll = tegra_generic_codec_set_dai_pll,
+ .set_sysclk = tegra_generic_codec_set_dai_sysclk,
+};
+
+struct snd_soc_dai dit_stub_dai = {
+ .name = "tegra-codec-rpc",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = TEGRA_SAMPLE_RATES,
+ .formats = TEGRA_SAMPLE_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = TEGRA_SAMPLE_RATES,
+ .formats = TEGRA_SAMPLE_FORMATS,
+ },
+ .ops = &dit_stub_ops,
+};
+EXPORT_SYMBOL_GPL(dit_stub_dai);
+
+static int __init dit_modinit(void)
+{
+ return snd_soc_register_dai(&dit_stub_dai);
+}
+
+static void __exit dit_exit(void)
+{
+ snd_soc_unregister_dai(&dit_stub_dai);
+}
+
+module_init(dit_modinit);
+module_exit(dit_exit);
+
+static int codec_soc_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ int ret = 0;
+
+ socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+ if (!socdev->card->codec)
+ return -ENOMEM;
+
+ codec = socdev->card->codec;
+ mutex_init(&codec->mutex);
+
+ codec->name = "tegra-generic-codec";
+ codec->owner = THIS_MODULE;
+ codec->dai = &dit_stub_dai;
+ codec->num_dai = 1;
+ codec->write = NULL;
+ codec->read = NULL;
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+ /* Register PCMs. */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ printk(KERN_ERR "codec: failed to create pcms\n");
+ goto pcm_err;
+ }
+ /* Register Card. */
+ ret = snd_soc_init_card(socdev);
+ if (ret < 0) {
+ printk(KERN_ERR "codec: failed to register card\n");
+ goto card_err;
+ }
+
+ return ret;
+
+card_err:
+ snd_soc_free_pcms(socdev);
+pcm_err:
+ kfree(socdev->card->codec);
+
+ return ret;
+}
+
+static int codec_soc_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->card->codec;
+
+ if (!codec)
+ return 0;
+
+ snd_soc_free_pcms(socdev);
+ kfree(socdev->card->codec);
+
+ return 0;
+}
+
+#define codec_soc_suspend NULL
+#define codec_soc_resume NULL
+
+struct snd_soc_codec_device soc_codec_dev_tegra_generic_codec = {
+ .probe = codec_soc_probe,
+ .remove = codec_soc_remove,
+ .suspend = codec_soc_suspend,
+ .resume = codec_soc_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_tegra_generic_codec);
+
+/* Module information */
+MODULE_DESCRIPTION("Tegra Codec RPC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c
new file mode 100644
index 000000000000..2edb1033a399
--- /dev/null
+++ b/sound/soc/tegra/tegra_i2s.c
@@ -0,0 +1,109 @@
+/*
+ * sound/soc/tegra/tegra_i2s.c
+ *
+ * ALSA SOC driver for NVIDIA Tegra SoCs
+ *
+ * Copyright (C) 2010 NVIDIA Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/jiffies.h>
+#include <linux/io.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "mach/nvrm_linux.h"
+#include "nvrm_memmgr.h"
+#include "nvassert.h"
+#include "tegra_transport.h"
+
+extern struct snd_soc_dai tegra_i2s_rpc_dai;
+
+static int tegra_i2s_rpc_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ switch (params_rate(params)) {
+ case 8000:
+ case 11025:
+ case 16000:
+ case 22050:
+ case 24000:
+ case 32000:
+ case 44100:
+ case 48000:
+ case 88200:
+ case 96000:
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tegra_i2s_rpc_probe(struct platform_device *pdev,
+ struct snd_soc_dai *dai)
+{
+ return 0;
+}
+
+static struct snd_soc_dai_ops tegra_dai_ops = {
+ .hw_params = tegra_i2s_rpc_hw_params,
+};
+
+struct snd_soc_dai tegra_i2s_rpc_dai = {
+ .name = "tegra-i2s-rpc",
+ .id = 0,
+ .probe = tegra_i2s_rpc_probe,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = TEGRA_SAMPLE_RATES,
+ .formats = TEGRA_SAMPLE_FORMATS,
+ },
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = TEGRA_SAMPLE_RATES,
+ .formats = TEGRA_SAMPLE_FORMATS,
+ },
+ .ops = &tegra_dai_ops,
+};
+EXPORT_SYMBOL_GPL(tegra_i2s_rpc_dai);
+
+static int __init tegra_i2s_rpc_init(void)
+{
+ return snd_soc_register_dai(&tegra_i2s_rpc_dai);
+}
+module_init(tegra_i2s_rpc_init);
+
+static void __exit tegra_i2s_rpc_exit(void)
+{
+ snd_soc_unregister_dai(&tegra_i2s_rpc_dai);
+}
+module_exit(tegra_i2s_rpc_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("Tegra I2S RPC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/tegra/tegra_pcm_rpc.c b/sound/soc/tegra/tegra_pcm_rpc.c
new file mode 100644
index 000000000000..6b486d10110a
--- /dev/null
+++ b/sound/soc/tegra/tegra_pcm_rpc.c
@@ -0,0 +1,877 @@
+/*
+ * sound/soc/tegra/tegra_pcm_rpc.c
+ *
+ * ALSA SOC driver for NVIDIA Tegra SoCs
+ *
+ * Copyright (C) 2010 NVIDIA Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "tegra_transport.h"
+
+static struct tegra_audio_data* tegra_snd_cx = NULL;
+
+static const struct snd_pcm_hardware tegra_pcm_hardware = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE |\
+ SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP |\
+ SNDRV_PCM_INFO_MMAP_VALID,
+ .rates = TEGRA_SAMPLE_RATES,
+ .formats = TEGRA_SAMPLE_FORMATS,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = 32*1024,
+ .period_bytes_min = TEGRA_DEFAULT_BUFFER_SIZE,
+ .period_bytes_max = TEGRA_DEFAULT_BUFFER_SIZE,
+ .periods_min = 4,
+ .periods_max = 8,
+ .fifo_size = 8,
+};
+
+
+static int tegra_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+ return 0;
+}
+
+static int tegra_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ snd_pcm_set_runtime_buffer(substream, NULL);
+ return 0;
+}
+
+static int tegra_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ return 0;
+}
+
+static int play_thread( void *arg)
+{
+ struct snd_pcm_substream *substream = arg;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct pcm_runtime_data *prtd = substream->runtime->private_data;
+ NvError e;
+ int size;
+ int offset = 0;
+ int period_offset = 0;
+ int rtbuffersize = 0;
+ int buffer_to_prime = 0, buffer_in_queue = 0;
+ NvAudioFxBufferDescriptor abd;
+ NvAudioFxState state = NVALSA_INVALID_STATE;
+
+ wait_for_completion(&prtd->thread_comp);
+
+ rtbuffersize = frames_to_bytes(runtime, runtime->buffer_size);
+ buffer_to_prime = (rtbuffersize / TEGRA_DEFAULT_BUFFER_SIZE);
+
+ for (;;) {
+ switch (prtd->state) {
+ case SNDRV_PCM_TRIGGER_START:
+ state = NvAudioFxState_Run;
+ tegra_snd_cx->xrt_fxn.SetProperty(
+ prtd->stdoutpath->Stream,
+ NvAudioFxProperty_State,
+ sizeof(NvAudioFxState),
+ &state);
+ prtd->state = NVALSA_INVALID_STATE;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ state = NvAudioFxState_Stop;
+ tegra_snd_cx->xrt_fxn.SetProperty(
+ prtd->stdoutpath->Stream,
+ NvAudioFxProperty_State,
+ sizeof(NvAudioFxState),
+ &state);
+ prtd->state = NVALSA_INVALID_STATE;
+ default:
+ ;
+ }
+
+ if (kthread_should_stop())
+ break;
+
+ if ((prtd->audiofx_frames < runtime->control->appl_ptr) &&
+ (state != SNDRV_PCM_TRIGGER_STOP)) {
+ memset(&abd, 0, sizeof(NvAudioFxBufferDescriptor));
+
+ size = TEGRA_DEFAULT_BUFFER_SIZE;
+ if ((offset + size) > rtbuffersize) {
+ size = rtbuffersize - offset;
+ }
+
+ abd.hMixBuffer = prtd->mixer_buffer;
+ abd.Offset = offset;
+ abd.Size = size;
+ abd.Format.FormatTag = 1;
+ abd.Format.SampleRate = runtime->rate;
+ abd.Format.BitsPerSample = runtime->sample_bits;
+ abd.Format.Channels = runtime->channels;
+ abd.Format.ChannelMask = 0;
+ abd.Format.ValidBitsPerSample = 0;
+
+ e = tegra_snd_cx->xrt_fxn.StreamAddBuffer(
+ (NvAudioFxStreamHandle)prtd->stdoutpath->Stream,
+ &abd);
+ buffer_in_queue++;
+ offset += size;
+ if (offset >= rtbuffersize)
+ offset =0;
+
+ prtd->audiofx_frames += bytes_to_frames(runtime,
+ size);
+ }
+
+ if (buffer_in_queue == 0) {
+ DEFINE_WAIT(wq);
+ prepare_to_wait(&prtd->buf_wait, &wq, TASK_INTERRUPTIBLE);
+ schedule();
+ finish_wait(&prtd->buf_wait, &wq);
+ continue;
+ }
+
+ if ((buffer_to_prime == buffer_in_queue) ||
+ (prtd->audiofx_frames >= runtime->control->appl_ptr)) {
+ down(&prtd->buf_done_sem);
+
+ buffer_in_queue--;
+
+ if ((frames_to_bytes(runtime, prtd->cur_pos) +
+ TEGRA_DEFAULT_BUFFER_SIZE) > rtbuffersize) {
+ size = rtbuffersize -
+ frames_to_bytes(runtime, prtd->cur_pos);
+ } else {
+ size = TEGRA_DEFAULT_BUFFER_SIZE;
+ }
+
+ prtd->cur_pos += bytes_to_frames(runtime, size);
+
+ if (prtd->cur_pos < prtd->last_pos) {
+ period_offset = (runtime->buffer_size +
+ prtd->cur_pos) - prtd->last_pos;
+
+ } else {
+ period_offset = prtd->cur_pos - prtd->last_pos;
+ }
+
+ if (period_offset >= runtime->period_size) {
+ prtd->last_pos = prtd->cur_pos;
+ snd_pcm_period_elapsed(substream);
+
+ }
+
+ if (prtd->cur_pos >= runtime->buffer_size) {
+ prtd->cur_pos -= runtime->buffer_size;
+ }
+ }
+ }
+ while (buffer_in_queue > 0) {
+ down(&prtd->buf_done_sem);
+ buffer_in_queue--;
+ }
+ return 0;
+}
+
+static int rec_thread( void *arg )
+{
+ struct snd_pcm_substream *substream = arg;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct pcm_runtime_data *prtd = substream->runtime->private_data;
+ NvError e;
+ int size;
+ int offset = 0;
+ int period_offset = 0;
+ int rtbuffersize = 0;
+ int buffer_to_prime = 0, buffer_in_queue = 0;
+ NvAudioFxBufferDescriptor abd;
+ NvAudioFxState state = NVALSA_INVALID_STATE;
+ NvAudioFxPinFormatDescriptor pin_format;
+
+ wait_for_completion(&prtd->thread_comp);
+ rtbuffersize = frames_to_bytes(runtime, runtime->buffer_size);
+ buffer_to_prime = (rtbuffersize / TEGRA_DEFAULT_BUFFER_SIZE);
+
+ while (!prtd->shutdown_thrd ) {
+ switch (prtd->state) {
+ case SNDRV_PCM_TRIGGER_START:
+ pin_format.Format.FormatTag = 1;
+ pin_format.Format.SampleRate = runtime->rate;
+ pin_format.Format.BitsPerSample = runtime->sample_bits;
+ pin_format.Format.Channels = runtime->channels;
+ pin_format.Format.ChannelMask = 0;
+ pin_format.Format.ValidBitsPerSample = 0;
+ pin_format.Pin = NvAudioFxSourcePin;
+
+ e = tegra_snd_cx->xrt_fxn.SetProperty(
+ prtd->stdinpath->Convert,
+ NvAudioFxPinProperty_Format,
+ sizeof(NvAudioFxPinFormatDescriptor),
+ &pin_format);
+ if (e != NvSuccess) {
+ snd_printk(KERN_ERR"set_property failed!\n");
+ }
+
+ e = tegra_snd_cx->xrt_fxn.SetProperty(
+ prtd->stdinpath->Src,
+ NvAudioFxProperty_SampleRate,
+ sizeof(NvS32),
+ &pin_format.Format.SampleRate);
+ if (e != NvSuccess) {
+ snd_printk(KERN_ERR "set_property failed!\n");
+ }
+
+ state = NvAudioFxState_Run;
+ tegra_snd_cx->xrt_fxn.SetProperty(
+ prtd->stdinpath->Stream,
+ NvAudioFxProperty_State,
+ sizeof(NvAudioFxState),
+ &state);
+ prtd->state = NVALSA_INVALID_STATE;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ while (buffer_in_queue > 0) {
+ down(&prtd->buf_done_sem);
+ buffer_in_queue--;
+ }
+
+ state = NvAudioFxState_Stop;
+ tegra_snd_cx->xrt_fxn.SetProperty(
+ prtd->stdinpath->Stream,
+ NvAudioFxProperty_State,
+ sizeof(NvAudioFxState),
+ &state);
+ prtd->state = NVALSA_INVALID_STATE;
+ goto EXIT;
+ default:
+ ;
+ }
+
+ if ((state == NvAudioFxState_Run) &&
+ (buffer_in_queue < buffer_to_prime)) {
+ memset(&abd, 0, sizeof(NvAudioFxBufferDescriptor));
+
+ size = TEGRA_DEFAULT_BUFFER_SIZE;
+ if ((offset + size) > rtbuffersize) {
+ size = rtbuffersize - offset;
+ }
+
+ abd.hMixBuffer = prtd->mixer_buffer;
+ abd.Offset = offset;
+ abd.Size = size;
+ abd.Format.FormatTag = 1;
+ abd.Format.SampleRate = runtime->rate;
+ abd.Format.BitsPerSample = runtime->sample_bits;
+ abd.Format.Channels = runtime->channels;
+ abd.Format.ChannelMask = 0;
+
+ e = tegra_snd_cx->xrt_fxn.StreamAddBuffer(
+ (NvAudioFxStreamHandle)prtd->stdinpath->Stream, &abd);
+ buffer_in_queue++;
+ offset += size;
+
+ if (offset >= rtbuffersize)
+ offset =0;
+ }
+
+ if ((buffer_to_prime == buffer_in_queue) &&
+ ((runtime->status->hw_ptr - runtime->control->appl_ptr) <
+ (runtime->buffer_size -runtime->period_size))) {
+ down(&prtd->buf_done_sem);
+
+ buffer_in_queue--;
+
+ if ((frames_to_bytes(runtime, prtd->cur_pos) +
+ TEGRA_DEFAULT_BUFFER_SIZE) > rtbuffersize) {
+ size = rtbuffersize -
+ frames_to_bytes(runtime, prtd->cur_pos);
+ } else {
+ size = TEGRA_DEFAULT_BUFFER_SIZE;
+ }
+
+ prtd->cur_pos += bytes_to_frames(runtime, size);
+
+ if (prtd->cur_pos < prtd->last_pos) {
+ period_offset = (runtime->buffer_size +
+ prtd->cur_pos) - prtd->last_pos;
+ } else {
+ period_offset = prtd->cur_pos - prtd->last_pos;
+ }
+
+ if (period_offset >= runtime->period_size) {
+ prtd->last_pos = prtd->cur_pos;
+ snd_pcm_period_elapsed(substream);
+ }
+
+ if (prtd->cur_pos >= runtime->buffer_size) {
+ prtd->cur_pos -= runtime->buffer_size;
+ }
+ }
+ }
+EXIT:
+
+ while (!kthread_should_stop()) {
+ }
+
+ return 0;
+}
+
+static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct pcm_runtime_data *prtd = substream->runtime->private_data;
+ int ret = 0;
+ int state = prtd->state;
+
+ prtd->state = cmd;
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ prtd->cur_pos = 0;
+ prtd->last_pos = 0;
+ prtd->audiofx_frames = 0;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ prtd->timeout = PLAY_TIMEOUT;
+ else
+ prtd->timeout = REC_TIMEOUT;
+
+ if (state == NVALSA_INVALID_STATE)
+ complete(&prtd->thread_comp);
+ else
+ up(&prtd->buf_done_sem);
+ break;
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ prtd->timeout = PLAY_TIMEOUT;
+ }else{
+ prtd->timeout = REC_TIMEOUT;
+ }
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ prtd->timeout = NV_WAIT_INFINITE;
+ break;
+ default:
+ prtd->state = state;
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static snd_pcm_uframes_t
+tegra_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct pcm_runtime_data *prtd = runtime->private_data;
+ int size;
+
+ size = prtd->last_pos;
+ if (size >= runtime->buffer_size) {
+ prtd->last_pos = size - runtime->buffer_size;
+ size = 0;
+ }
+
+ return (size);
+}
+
+static int init_mixer(struct snd_pcm_substream *substream)
+{
+ NvError e = NvSuccess;
+ int ret = 0;
+
+ if (!tegra_snd_cx->mixer_handle) {
+ mutex_lock(&tegra_snd_cx->lock);
+ e = tegra_transport_init(&tegra_snd_cx->xrt_fxn);
+ mutex_unlock(&tegra_snd_cx->lock);
+
+ if (e != NvSuccess) {
+ snd_printk(KERN_ERR "tegra_transport_init failed \n");
+ return -EFAULT;
+ }
+
+ tegra_snd_cx->mixer_handle =
+ tegra_snd_cx->xrt_fxn.MixerOpen();
+
+ if (!tegra_snd_cx->mixer_handle) {
+ ret = -EFAULT;
+ goto fail;
+ }
+
+ e = tegra_audiofx_createfx(tegra_snd_cx);
+ if (e != NvSuccess) {
+ snd_printk(KERN_ERR "tegra_audiofx_createfx failed \n");
+ ret = -EFAULT;
+ goto fail;
+ }
+
+ tegra_snd_cx->mixer_buffer[0] =
+ tegra_snd_cx->xrt_fxn.MixerMapBuffer(
+ tegra_snd_cx->mixer_handle,
+ NvRmMemGetId(tegra_snd_cx->mem_handle[0]),
+ 0,
+ tegra_snd_cx->mapped_buf_size);
+
+ if (!tegra_snd_cx->mixer_buffer[0]) {
+ snd_printk(KERN_ERR"TransportMixerMapBuffer failed!\n");
+ }
+
+ tegra_snd_cx->mixer_buffer[1] =
+ tegra_snd_cx->xrt_fxn.MixerMapBuffer(
+ tegra_snd_cx->mixer_handle,
+ NvRmMemGetId(tegra_snd_cx->mem_handle[1]),
+ 0,
+ tegra_snd_cx->mapped_buf_size);
+
+ if (!tegra_snd_cx->mixer_buffer[1]) {
+ snd_printk(KERN_ERR"TransportMixerMapBuffer failed!\n");
+ }
+ }
+
+ return 0;
+fail:
+ snd_printk(KERN_ERR "init mixer failed \n");
+ if (tegra_snd_cx->mixer_handle) {
+ tegra_audiofx_destroyfx(tegra_snd_cx);
+
+ if (tegra_snd_cx->mixer_handle) {
+ tegra_snd_cx->xrt_fxn.MixerClose(
+ tegra_snd_cx->mixer_handle);
+ }
+ }
+ mutex_lock(&tegra_snd_cx->lock);
+ tegra_transport_deinit();
+ mutex_unlock(&tegra_snd_cx->lock);
+
+ return ret;
+}
+
+static int pcm_common_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct pcm_runtime_data *prtd = runtime->private_data;
+ NvAudioFxMessage message;
+ NvError e;
+
+ if (!prtd)
+ snd_printk(KERN_ERR "pcm_close called with prtd = NULL\n");
+
+ prtd->state = SNDRV_PCM_TRIGGER_STOP;
+
+ if (completion_done(&prtd->thread_comp) == 0)
+ complete(&prtd->thread_comp);
+
+ wake_up_all(&prtd->buf_wait);
+
+ if (prtd->play_thread)
+ kthread_stop(prtd->play_thread);
+
+ if (prtd->rec_thread)
+ kthread_stop(prtd->rec_thread);
+
+ prtd->shutdown_thrd = 1;
+ up(&prtd->buf_done_sem);
+
+ if (tegra_snd_cx->m_FxNotifier.Event & NvAudioFxEventBufferDone) {
+
+ memset(&message, 0, sizeof(NvAudioFxMessage));
+ message.Event = NvAudioFxEventBufferDone;
+ message.pContext = NULL;
+ if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ message.hFx = (NvAudioFxHandle)prtd->stdoutpath->Stream;
+ else
+ message.hFx = (NvAudioFxHandle)prtd->stdinpath->Stream;
+
+ e = tegra_snd_cx->xrt_fxn.SetProperty(
+ (NvAudioFxObjectHandle)tegra_snd_cx->m_FxNotifier.hNotifier,
+ NvAudioFxIoProperty_RemoveEvent,
+ sizeof(NvAudioFxMessage),
+ &message);
+
+ tegra_snd_cx->m_FxNotifier.Event &= ~(NvAudioFxEventBufferDone);
+ }
+
+ if (prtd->stdoutpath) {
+ tegra_audiofx_destroy_output(prtd->stdoutpath);
+ kfree(prtd->stdoutpath);
+ }
+
+ if (prtd->stdinpath) {
+ tegra_audiofx_destroy_input(prtd->stdinpath);
+ kfree(prtd->stdinpath);
+ }
+
+ if (prtd)
+ kfree(prtd);
+
+ return 0;
+}
+
+static int tegra_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct pcm_runtime_data *prtd;
+ int ret = 0;
+ NvError e = NvSuccess;
+ NvAudioFxMessage message;
+
+ prtd = kzalloc(sizeof(struct pcm_runtime_data), GFP_KERNEL);
+ if (prtd == NULL)
+ return -ENOMEM;
+
+ runtime->private_data = prtd;
+ snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware);
+ spin_lock_init(&prtd->lock);
+ prtd->timeout = INIT_TIMEOUT;
+ prtd->stdoutpath = 0;
+ prtd->stdinpath = 0;
+ prtd->state = NVALSA_INVALID_STATE;
+ prtd->stream = substream->stream;
+ prtd->shutdown_thrd = 0;
+
+ ret = init_mixer(substream);
+ if (ret)
+ goto fail;
+
+ init_completion(&prtd->thread_comp);
+ init_waitqueue_head(&prtd->buf_wait);
+ sema_init(&prtd->buf_done_sem, 0);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){
+ prtd->mixer_buffer = tegra_snd_cx->mixer_buffer[0];
+ prtd->stdoutpath = (StandardPath*)kzalloc(sizeof(StandardPath),
+ GFP_KERNEL);
+ if (prtd->stdoutpath == NULL) {
+ snd_printk(KERN_ERR "pcm_open kzalloc failed \n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ e = tegra_audiofx_create_output(tegra_snd_cx->m_hRm,
+ tegra_snd_cx->mixer_handle,
+ prtd->stdoutpath);
+ if (e != NvSuccess) {
+ snd_printk(KERN_ERR "audiofx_create_output failed \n");
+ ret = -EFAULT;
+ goto fail;
+ }
+
+ memset(&message, 0, sizeof(NvAudioFxMessage));
+ message.Event = NvAudioFxEventBufferDone;
+ message.hFx = (NvAudioFxHandle)prtd->stdoutpath->Stream;
+ message.pContext = prtd;
+
+ e = tegra_snd_cx->xrt_fxn.SetProperty(
+ (NvAudioFxObjectHandle)tegra_snd_cx->m_FxNotifier.hNotifier,
+ NvAudioFxIoProperty_AddEvent,
+ sizeof(NvAudioFxMessage),
+ &message);
+
+ if (e != NvSuccess) {
+ snd_printk(KERN_ERR "TransportSetProperty failed\n");
+ ret = -EFAULT;
+ goto fail;
+ }
+
+ tegra_snd_cx->m_FxNotifier.Event |= (NvAudioFxEventBufferDone);
+
+ prtd->play_thread = kthread_run(play_thread,
+ substream,
+ "%sthread",
+ "play");
+ if (IS_ERR(prtd->play_thread)) {
+ snd_printk(KERN_ERR "KTHREAD RUN FAIL\n");
+ ret = PTR_ERR(prtd->play_thread);
+ goto fail;
+ }
+ } else {
+ prtd->mixer_buffer = tegra_snd_cx->mixer_buffer[1];
+ prtd->stdinpath = (StandardPath*)kzalloc(sizeof(StandardPath),
+ GFP_KERNEL);
+ if (prtd->stdinpath == NULL) {
+ snd_printk(KERN_ERR "pcm_open kzalloc failed \n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+ e = tegra_audiofx_create_input(tegra_snd_cx->m_hRm,
+ tegra_snd_cx->mixer_handle,
+ prtd->stdinpath,
+ NvAudioInputSelect_Record);
+ if (e != NvSuccess) {
+ snd_printk(KERN_ERR "audiofx_create_input failed \n");
+ ret = -EFAULT;
+ goto fail;
+ }
+
+ memset(&message, 0, sizeof(NvAudioFxMessage));
+ message.Event = NvAudioFxEventBufferDone;
+ message.hFx = (NvAudioFxHandle)prtd->stdinpath->Stream;
+ message.pContext = prtd;
+
+ e = tegra_snd_cx->xrt_fxn.SetProperty(
+ (NvAudioFxObjectHandle)tegra_snd_cx->m_FxNotifier.hNotifier,
+ NvAudioFxIoProperty_AddEvent,
+ sizeof(NvAudioFxMessage),
+ &message);
+ if (e != NvSuccess) {
+ snd_printk(KERN_ERR "TransportSetProperty failed\n");
+ ret = -EFAULT;
+ goto fail;
+ }
+ tegra_snd_cx->m_FxNotifier.Event |= (NvAudioFxEventBufferDone);
+
+ prtd->rec_thread = kthread_run(rec_thread,
+ substream,
+ "%sthread",
+ "rec" );
+ if (IS_ERR(prtd->rec_thread)) {
+ snd_printk(KERN_ERR "Kthread Run Fail\n");
+ ret = PTR_ERR(prtd->rec_thread);
+ goto fail;
+ }
+ }
+ return ret;
+fail:
+ snd_printk(KERN_ERR "tegra_pcm_open - failed \n");
+ pcm_common_close(substream);
+ return ret;
+}
+
+static int tegra_pcm_close(struct snd_pcm_substream *substream)
+{
+ pcm_common_close(substream);
+ return 0;
+}
+
+static int tegra_pcm_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ int err = 0;
+ int size = 0;
+ char *vmalloc_area_ptr = NULL;
+ unsigned long start = 0;
+ unsigned long pfn = 0;
+
+ start = vma->vm_start;
+ vmalloc_area_ptr = substream->dma_buffer.area;
+ size = vma->vm_end - vma->vm_start;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ while (size > 0) {
+ pfn = vmalloc_to_pfn(vmalloc_area_ptr);
+ err = io_remap_pfn_range(vma, start, pfn,
+ PAGE_SIZE, vma->vm_page_prot);
+ if (err < 0) {
+ snd_printk(KERN_ERR "io_remap_pfn_range failed \n");
+ return err;
+ }
+ start += PAGE_SIZE;
+ vmalloc_area_ptr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ return err;
+}
+
+static int tegra_pcm_ack(struct snd_pcm_substream *substream)
+{
+ struct pcm_runtime_data *prtd = substream->runtime->private_data;
+
+ wake_up(&prtd->buf_wait);
+ return 0;
+}
+
+static struct snd_pcm_ops tegra_pcm_ops = {
+ .open = tegra_pcm_open,
+ .close = tegra_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = tegra_pcm_hw_params,
+ .hw_free = tegra_pcm_hw_free,
+ .prepare = tegra_pcm_prepare,
+ .trigger = tegra_pcm_trigger,
+ .pointer = tegra_pcm_pointer,
+ .mmap = tegra_pcm_mmap,
+ .ack = tegra_pcm_ack,
+};
+
+static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+ struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+ struct snd_dma_buffer *buf = &substream->dma_buffer;
+ size_t size = tegra_pcm_hardware.buffer_bytes_max;
+ void *virt_buf_ptr = NULL;
+ NvRmPhysAddr phy_address;
+ int ret = 0;
+ NvError e;
+ e = NvRmMemHandleCreate(tegra_snd_cx->m_hRm,
+ &tegra_snd_cx->mem_handle[stream],
+ size);
+
+ if (e == NvSuccess) {
+ e = NvRmMemAlloc(tegra_snd_cx->mem_handle[stream],
+ NULL,
+ 0,
+ PAGE_SIZE,
+ NvOsMemAttribute_Uncached);
+ }
+
+ if (e == NvSuccess) {
+ phy_address = (NvU32)(NvRmMemPin(tegra_snd_cx->mem_handle[stream]));
+ }
+
+ if (e != NvSuccess) {
+ NvRmMemHandleFree(tegra_snd_cx->mem_handle[stream]);
+ ret = -ENOMEM;
+ goto end;
+ }
+
+ e = NvRmMemMap(tegra_snd_cx->mem_handle[stream],
+ 0,
+ size,
+ NVOS_MEM_READ_WRITE,
+ (void**)&virt_buf_ptr);
+
+ if (e != NvSuccess) {
+ NvRmMemHandleFree(tegra_snd_cx->mem_handle[stream]);
+ ret = -ENOMEM;
+ goto end;
+ }
+
+ tegra_snd_cx->mapped_buf_size = size;
+
+ buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ buf->dev.dev = pcm->card->dev;
+ buf->private_data = NULL;
+ buf->area = virt_buf_ptr;
+ buf->bytes = size;
+ buf->addr = phy_address;
+end:
+ return ret;
+}
+
+static void DestroyMemoryHandle(NvRmMemHandle hMemHandle)
+{
+ if (hMemHandle != NULL) {
+ NvRmMemUnpin(hMemHandle);
+ NvRmMemHandleFree(hMemHandle);
+ }
+}
+
+static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+ struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+ struct snd_dma_buffer *buf = &substream->dma_buffer;
+
+ if (tegra_snd_cx->mixer_buffer[stream])
+ tegra_snd_cx->xrt_fxn.MixerUnmapBuffer(
+ tegra_snd_cx->mixer_buffer[stream]);
+
+ NvRmMemUnmap(tegra_snd_cx->mem_handle[stream],buf->area,buf->bytes);
+ DestroyMemoryHandle(tegra_snd_cx->mem_handle[stream]);
+}
+
+static void tegra_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+ struct snd_pcm_substream *substream;
+ struct snd_dma_buffer *buf;
+ int stream;
+ for (stream = 0; stream < 2; stream++) {
+ substream = pcm->streams[stream].substream;
+ buf = &substream->dma_buffer;
+ if (!buf) {
+ continue;
+ }
+ tegra_pcm_deallocate_dma_buffer(pcm ,stream);
+ }
+}
+
+
+static int tegra_pcm_new(struct snd_card *card,
+ struct snd_soc_dai *dai,
+ struct snd_pcm *pcm)
+{
+ int ret = 0;
+
+ tegra_snd_cx = kzalloc(sizeof(struct tegra_audio_data),
+ GFP_KERNEL);
+ if (tegra_snd_cx == NULL)
+ return -ENOMEM;
+
+ tegra_snd_cx->m_hRm = s_hRmGlobal;
+ mutex_init(&tegra_snd_cx->lock);
+
+ if (dai->playback.channels_min) {
+ ret = tegra_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret) {
+ goto out;
+ }
+ }
+
+ if (dai->capture.channels_min) {
+ ret = tegra_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_CAPTURE);
+ if (ret)
+ goto out;
+ }
+ return 0;
+
+out:
+ if (tegra_snd_cx)
+ kfree(tegra_snd_cx);
+ snd_printk(KERN_ERR "pcm_new failed\n");
+ return ret;
+}
+
+static int tegra_pcm_probe(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int tegra_pcm_remove(struct platform_device *pdev)
+{
+ if (tegra_snd_cx)
+ kfree(tegra_snd_cx);
+
+ return 0;
+}
+
+struct snd_soc_platform tegra_soc_platform = {
+ .name = "tegra-audio",
+ .probe = tegra_pcm_probe,
+ .remove = tegra_pcm_remove,
+ .pcm_ops = &tegra_pcm_ops,
+ .pcm_new = tegra_pcm_new,
+ .pcm_free = tegra_pcm_free_dma_buffers,
+};
+
+EXPORT_SYMBOL_GPL(tegra_soc_platform);
+
+static int __init tegra_soc_platform_init(void)
+{
+ return snd_soc_register_platform(&tegra_soc_platform);
+}
+
+module_init(tegra_soc_platform_init);
+
+static void __exit tegra_soc_platform_exit(void)
+{
+ snd_soc_unregister_platform(&tegra_soc_platform);
+}
+
+module_exit(tegra_soc_platform_exit);
+
+MODULE_DESCRIPTION("Tegra PCM RPC PCM output");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/tegra/tegra_sndfx.h b/sound/soc/tegra/tegra_sndfx.h
new file mode 100644
index 000000000000..5b59b7587a82
--- /dev/null
+++ b/sound/soc/tegra/tegra_sndfx.h
@@ -0,0 +1,623 @@
+/*
+ * Copyright (c) 2010 NVIDIA Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NVIDIA Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef INCLUDED_nvddk_audiofx_H
+#define INCLUDED_nvddk_audiofx_H
+
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+#include "nvrm_module.h"
+#include "nvrm_transport.h"
+#include "nvrm_init.h"
+
+/** @file
+ * @brief <b>NVIDIA Driver Development Kit: NvAudioFx APIs</b>
+ *
+ * @b Description: Declares Interface for NvAudioFx APIs.
+ */
+
+/**
+ * @brief API Object Handles.
+ *
+ * NvAudioFxObjectHandle is the base handle for every type in the API.
+ */
+
+typedef struct NvAudioFxObjectRec *NvAudioFxObjectHandle;
+
+typedef struct NvAudioFxRec *NvAudioFxHandle;
+
+typedef struct NvAudioFxMixBufferRec *NvAudioFxMixBufferHandle;
+
+typedef struct NvAudioFxMixerRec *NvAudioFxMixerHandle;
+
+typedef struct NvAudioFxNotifierRec *NvAudioFxNotifierHandle;
+
+typedef struct NvAudioFxStreamRec *NvAudioFxStreamHandle;
+
+/**
+ * @brief Object IDs.
+ */
+
+typedef NvS32 NvObjectId;
+#define NvObjectNullId (0x0)
+#define NvAudioFxObjectId (0x10000000)
+#define NvAudioFxId (0x11000000)
+#define NvAudioFxIoId (0x11100000)
+#define NvAudioFxPluginId (0x11200000)
+#define NvAudioFxMixBufferId (0x12000000)
+#define NvAudioFx3dGroupId (0x14000000)
+#define NvAudioFxNotifierId (0x30000000)
+#define NvAudioFxConvertId (0x11000001)
+#define NvAudioFxDrcId (0x11000002)
+#define NvAudioFxEqId (0x11000003)
+#define NvAudioFxMixerId (0x11000004)
+#define NvAudioFxMixId (0x11000005)
+#define NvAudioFxPeqId (0x11000006)
+#define NvAudioFxResizeId (0x11000007)
+#define NvAudioFxSplitId (0x11000008)
+#define NvAudioFxSpreaderId (0x11000009)
+#define NvAudioFxSrcId (0x1100000a)
+#define NvAudioFxSwitchId (0x1100000b)
+#define NvAudioFxVolumeId (0x1100000c)
+#define NvAudioFxStreamId (0x11100000)
+#define NvAudioFxSpdifId (0x11100001)
+#define NvAudioFxSilenceId (0x11100002)
+#define NvAudioFxI2s1Id (0x11110000)
+#define NvAudioFxI2s2Id (0x11110001)
+#define NvAudioFxPlaybackMixId (0x11300000)
+#define NvAudioFxPlaybackSplitId (0x11300001)
+#define NvAudioFxRecordMixId (0x11300002)
+#define NvAudioFxRecordSplitId (0x11300003)
+#define NvAudioFxSpdifPlaybackMixId (0x11300004)
+#define NvAudioFxSpdifRecordSplitId (0x11300005)
+#define NvAudioFxSpdifLoopbackSplitId (0x11300006)
+#define NvAudioFxSpdifVolumeId (0x1130000c)
+#define NvAudioFxMusicMixId (0x11300007)
+#define NvAudioFxMusicSplitId (0x11300008)
+#define NvAudioFxRingtoneMixId (0x11300009)
+#define NvAudioFxMusicVolumeId (0x1130000a)
+#define NvAudioFxRingtoneVolumeId (0x1130000b)
+#define NvAudioFxI2s1PlaybackMixId (0x11310000)
+#define NvAudioFxI2s1RecordSplitId (0x11310001)
+#define NvAudioFxI2s1LoopbackSplitId (0x11310002)
+#define NvAudioFxI2s1VolumeId (0x11310003)
+#define NvAudioFxI2s2PlaybackMixId (0x11311000)
+#define NvAudioFxI2s2RecordSplitId (0x11311001)
+#define NvAudioFxI2s2LoopbackSplitId (0x11311002)
+#define NvAudioFxI2s2VolumeId (0x11311003)
+
+//
+// Mixer
+// +------+
+// | |
+// | FX |--@ ScratchSource ------------+
+// | | |
+// +------+ |
+//
+// Source Sink
+// +------+ +------+
+// Copy Sink @--| |--@ Loopback Copy Sink @--| |--@ Loopback
+// | FX | | FX |
+// ----> Sink @--| |--@ Source ------> Sink @--| |--@ Source ---->
+// +------+ +------+
+//
+
+typedef NvS32 NvAudioFxPin;
+#define NvAudioFxScratchSourcePin (-4)
+#define NvAudioFxLoopbackPin (-3)
+#define NvAudioFxCopySinkPin (-2)
+#define NvAudioFxInvalidPin (-1)
+#define NvAudioFxSinkPin (0)
+#define NvAudioFxSourcePin (1)
+
+typedef NvS32 NvAudioFxProperty;
+#define NvAudioFxProperty_Attach (0x1000)
+#define NvAudioFxProperty_Detach (0x1010)
+#define NvAudioFxProperty_Format (0x1020)
+#define NvAudioFxProperty_Method (0x1030)
+#define NvAudioFxProperty_PowerState (0x1040)
+#define NvAudioFxProperty_SampleRate (0x1050)
+#define NvAudioFxProperty_State (0x1060)
+#define NvAudioFxPinProperty_Format (0x2000)
+#define NvAudioFxDrcProperty_Drc (0x3000)
+#define NvAudioFxEqProperty_Eq (0x4000)
+#define NvAudioFxI2sProperty_AllocChannel (0x4a01)
+#define NvAudioFxI2sProperty_InputAvailable (0x4a02)
+#define NvAudioFxI2sProperty_InputDisable (0x4a04)
+#define NvAudioFxI2sProperty_InputEnable (0x4a03)
+#define NvAudioFxI2sProperty_InputSelect (0x4a05)
+#define NvAudioFxI2sProperty_OutputAvailable (0x4a06)
+#define NvAudioFxI2sProperty_OutputDisable (0x4a08)
+#define NvAudioFxI2sProperty_OutputEnable (0x4a07)
+#define NvAudioFxI2sProperty_OutputSelect (0x4a09)
+#define NvAudioFxI2sProperty_IoDeviceVolume (0x4a0a)
+#define NvAudioFxIoProperty_AddEvent (0x5000)
+#define NvAudioFxIoProperty_Position (0x5010)
+#define NvAudioFxIoProperty_RemoveEvent (0x5020)
+#define NvAudioFxIoProperty_SetMappedPositionBuffer (0x5030)
+#define NvAudioFxMixerProperty_ProcessBufferSize (0x6000)
+#define NvAudioFxMixerProperty_ModeAvailable (0x6001)
+#define NvAudioFxMixerProperty_ModeDisable (0x6002)
+#define NvAudioFxMixerProperty_ModeEnable (0x6003)
+#define NvAudioFxMixerProperty_ModeSelect (0x6004)
+#define NvAudioFxMixProperty_Headroom (0x7000)
+#define NvAudioFxNotifierProperty_Connect (0x8000)
+#define NvAudioFxNotifierProperty_Disconnect (0x8010)
+#define NvAudioFxPeqProperty_Peq (0x9000)
+#define NvAudioFxResizeProperty_OutputSize (0xa000)
+#define NvAudioFxSpreaderProperty_Spreader (0xb000)
+#define NvAudioFxSrcProperty_SampleRateShift (0xc000)
+#define NvAudioFxVolumeProperty_Ramping (0xd000)
+#define NvAudioFxVolumeProperty_Volume (0xd010)
+
+// Description of the NvAudioFxProperty_Attach and
+// NvAudioFxProperty_Detach properties.
+
+typedef struct NvAudioFxConnectionDescriptorRec
+{
+ NvAudioFxHandle hSource;
+ NvAudioFxPin SourcePin;
+ NvAudioFxHandle hSink;
+ NvAudioFxPin SinkPin;
+} NvAudioFxConnectionDescriptor;
+
+// Audio format information of the stream or buffer.
+
+typedef struct NvAudioFxFormatRec
+{
+ NvU32 FormatTag;
+ NvU32 SampleRate;
+ NvU32 Channels;
+ NvU32 BitsPerSample;
+ NvU32 ChannelMask;
+ NvU32 ValidBitsPerSample;
+} NvAudioFxFormat;
+
+// Description of the Mode property.
+
+typedef NvS32 NvAudioFxMode;
+#define NvAudioFxMode_Normal (0x0)
+#define NvAudioFxMode_Bluetooth (0x1)
+#define NvAudioFxMode_Ringtone (0x2)
+#define NvAudioFxMode_InCall (0x4)
+#define NvAudioFxMode_Radio (0x8)
+#define NvAudioFxMode_All (0xffffffff)
+
+// Description of the position property.
+
+typedef NvU64 NvAudioFxPosition;
+
+// Description of supported power states in AudioFx.
+
+typedef NvS32 NvAudioFxPowerState;
+#define NvAudioFxPowerState_Low (0x1000)
+#define NvAudioFxPowerState_High (0x1010)
+#define NvAudioFxPowerState_Full (0x1020)
+#define NvAudioFxPowerState_Ready (0x1030)
+#define NvAudioFxPowerState_Off (0x1040)
+
+// Description of the supported priority states.
+
+typedef NvS32 NvAudioFxPriority;
+#define NvAudioFxPriority_Normal (0x1000)
+#define NvAudioFxPriority_Medium (0x1010)
+#define NvAudioFxPriority_High (0x1020)
+#define NvAudioFxPriority_Critical (0x1030)
+
+// Description of the NvAudioFxProperty_State property.
+
+typedef NvS32 NvAudioFxState;
+#define NvAudioFxState_Uninitialized (0x1000)
+#define NvAudioFxState_Initialized (0x1010)
+#define NvAudioFxState_Stop (0x1020)
+#define NvAudioFxState_Run (0x1030)
+#define NvAudioFxState_Pause (0x1040)
+#define NvAudioFxState_Disable (0x1050)
+#define NvAudioFxState_EndOfStream (0x1060)
+#define NvAudioFxState_Locked (0x1070)
+
+// Audio DRC information.
+
+typedef struct NvAudioFxDrcDescriptorRec
+{
+ NvS32 EnableDrc;
+ NvS32 NoiseGateThreshold;
+ NvS32 LowerCompThreshold;
+ NvS32 UpperCompThreshold;
+ NvS32 ClippingThreshold;
+} NvAudioFxDrcDescriptor;
+
+// Audio EQ information.
+#define NvAudioFxEqNumFilters (5)
+#define NvAudioFxEqNumChannels (2)
+
+// AudioFx Default Volume Settings
+#define NvAudioFxVolumeDefault (256)
+#define NvAudioFxVolumeMax (1024)
+
+typedef struct NvAudioFxEqDescriptorRec
+{
+ NvS32 dBGain[NvAudioFxEqNumChannels][NvAudioFxEqNumFilters];
+
+} NvAudioFxEqDescriptor;
+
+// Audio Spreader information.
+
+typedef struct NvAudioFxSpreaderDescriptorRec
+{
+ NvU32 SpeakerWidth;
+} NvAudioFxSpreaderDescriptor;
+
+typedef enum
+{
+ NvAudioFxIirFilter_Undefined,
+ NvAudioFxIirFilter_Bandpass,
+ NvAudioFxIirFilter_Highpass,
+ NvAudioFxIirFilter_Lowpass,
+ NvAudioFxIirFilter_Num,
+ NvAudioFxIirFilter_Force32 = 0x7FFFFFFF
+} NvAudioFxIirFilter;
+
+// IO Devices
+
+typedef NvS32 NvAudioFxIoDevice;
+
+// Default is configurable based on the device.
+#define NvAudioFxIoDevice_Default (0x0)
+#define NvAudioFxIoDevice_All (0xffffffff)
+
+// Inputs
+#define NvAudioFxIoDevice_BuiltInMic (0x1)
+#define NvAudioFxIoDevice_Mic (0x2)
+#define NvAudioFxIoDevice_LineIn (0x4)
+
+// Outputs
+#define NvAudioFxIoDevice_BuiltInSpeaker (0x100)
+#define NvAudioFxIoDevice_EarSpeaker (0x200)
+#define NvAudioFxIoDevice_LineOut (0x400)
+#define NvAudioFxIoDevice_HeadphoneOut (0x800)
+
+// Both
+#define NvAudioFxIoDevice_Aux (0x10000)
+#define NvAudioFxIoDevice_Phone (0x20000)
+#define NvAudioFxIoDevice_Radio (0x40000)
+#define NvAudioFxIoDevice_Bluetooth (0x80000)
+
+typedef struct NvAudioFxPeqDescriptorRec
+{
+ NvU32 Enable;
+ NvU32 FilterType[NvAudioFxIirFilter_Num];
+ NvS32 CenterFrequency[NvAudioFxIirFilter_Num];
+ NvS32 Bandwidth[NvAudioFxIirFilter_Num];
+ NvS32 dBGain[NvAudioFxIirFilter_Num];
+
+} NvAudioFxPeqDescriptor;
+
+// Audio pin-specific format information of the stream or buffer.
+
+typedef struct NvAudioFxPinFormatDescriptorRec
+{
+ NvAudioFxFormat Format;
+ NvAudioFxPin Pin;
+} NvAudioFxPinFormatDescriptor;
+
+// Audio volume information of the stream or buffer.
+
+typedef struct NvAudioFxVolumeDescriptorRec
+{
+ NvS32 LeftVolume;
+ NvS32 RightVolume;
+ NvU32 Mute;
+} NvAudioFxVolumeDescriptor;
+
+// Description of the IoDeviceVolume property.
+
+typedef struct NvAudioFxIoDeviceVolumeDescriptorRec
+{
+ NvAudioFxIoDevice IoDevice;
+ NvAudioFxVolumeDescriptor Volume;
+} NvAudioFxIoDeviceVolumeDescriptor;
+
+// Description of the NvAudioFxVoiceProperty_SetMappedPositionBuffer property.
+
+typedef struct NvAudioFxMappedBufferDescriptorRec
+{
+ NvAudioFxMixBufferHandle hMixBuffer;
+ NvU32 Offset;
+} NvAudioFxMappedBufferDescriptor;
+
+ /**
+ * @brief Defines the structure for adding a buffer to a stream.
+ */
+
+typedef struct NvAudioFxBufferDescriptorRec
+{
+
+ // A pointer which may be used for already mapped buffers.
+ void* pAddr;
+
+ // A physical address for accessing the buffer.
+ NvRmPhysAddr PhysicalAddr;
+
+ // The MixBuffer handle returned from NvAudioFxMixerMapBuffer.
+ NvAudioFxMixBufferHandle hMixBuffer;
+
+ // Buffer offset in bytes.
+ NvU32 Offset;
+
+ // Buffer size in bytes.
+ NvU32 Size;
+
+ // Size of non-Zero Fill data in buffer, usually same as Size
+ NvU32 ValidSize;
+
+ // The buffer format information.
+ NvAudioFxFormat Format;
+} NvAudioFxBufferDescriptor;
+
+// Description of the NvAudioFxNotifierProperty_Connect property.
+
+typedef struct NvAudioFxNotifierConnectionDescriptorRec
+{
+ NvU8 PortName[16];
+} NvAudioFxNotifierConnectionDescriptor;
+
+// Description of the NvAudioFxI2sProperty_AllocChannel property.
+
+typedef struct NvAudioFxI2sChannelDescriptorRec
+{
+ NvAudioFxPin Pin;
+ NvU32 Id;
+} NvAudioFxI2sChannelDescriptor;
+
+// Description of the NvAudioFxProperty_AddEvent and
+// NvAudioFxProperty_RemoveEvent properties.
+
+typedef NvS32 NvAudioFxEvent;
+#define NvAudioFxEventBufferDone (0x1)
+#define NvAudioFxEventStateChange (0x2)
+#define NvAudioFxEventFormatChange (0x4)
+#define NvAudioFxEventEndOfStream (0x8)
+#define NvAudioFxEventPowerStateChange (0x10)
+#define NvAudioFxEventIoChange (0x20)
+#define NvAudioFxEventControlChange (0x40)
+#define NvAudioFxEventAll (0xffffffff)
+
+typedef struct NvAudioFxMessageRec
+{
+ NvAudioFxEvent Event;
+ NvAudioFxHandle hFx;
+ void* pContext;
+} NvAudioFxMessage;
+
+typedef struct NvAudioFxBufferDoneMessageRec
+{
+ NvAudioFxMessage m;
+ NvAudioFxPosition Position;
+} NvAudioFxBufferDoneMessage;
+
+typedef struct NvAudioFxControlChangeMessageRec
+{
+ NvAudioFxMessage m;
+ NvAudioFxProperty Property;
+} NvAudioFxControlChangeMessage;
+
+typedef struct NvAudioFxIoDeviceControlChangeMessageRec
+{
+ NvAudioFxControlChangeMessage m;
+ NvAudioFxIoDevice IoDevice;
+} NvAudioFxIoDeviceControlChangeMessage;
+
+typedef struct NvAudioFxIoDeviceVolumeControlChangeMessageRec
+{
+ NvAudioFxControlChangeMessage m;
+ NvAudioFxIoDeviceVolumeDescriptor idv;
+} NvAudioFxIoDeviceVolumeControlChangeMessage;
+
+typedef struct NvAudioFxModeControlChangeMessageRec
+{
+ NvAudioFxControlChangeMessage m;
+ NvAudioFxMode Mode;
+} NvAudioFxModeControlChangeMessage;
+
+typedef struct NvAudioFxStateChangeMessageRec
+{
+ NvAudioFxMessage m;
+ NvAudioFxState State;
+} NvAudioFxStateChangeMessage;
+
+typedef struct NvAudioFxFormatChangeMessageRec
+{
+ NvAudioFxMessage m;
+ NvAudioFxFormat Format;
+} NvAudioFxFormatChangeMessage;
+
+typedef struct NvAudioFxPowerStateChangeMessageRec
+{
+ NvAudioFxMessage m;
+ NvAudioFxPowerState PowerState;
+} NvAudioFxPowerStateChangeMessage;
+
+typedef struct NvAudioFxIoChangeMessageRec
+{
+ NvAudioFxMessage m;
+ NvAudioFxProperty Property;
+ NvAudioFxConnectionDescriptor Connection;
+} NvAudioFxIoChangeMessage;
+
+ /**
+ * @brief Initializes and opens the AudioFX Mixer.
+ *
+ * @retval NvAudioFxMixerHandle A non-NULL value will be returned if the mixer
+ * is successfully opened.
+ */
+
+ NvAudioFxMixerHandle NvddkAudioFxMixerOpen(
+ void );
+
+ /**
+ * @brief Closes the AudioFX Mixer. This function frees the resources associated
+ * with the Mixer handle and cannot fail.
+ *
+ * @param hMixer A handle from NvAudioFxMixerOpen(). If hMixer is NULL or
+ * invalid, this API does nothing.
+ */
+
+ void NvddkAudioFxMixerClose(
+ NvAudioFxMixerHandle hMixer );
+
+ /**
+ * @brief Creates and initializes an AudioFX object.
+ *
+ * @param hMixer A handle from NvAudioFxMixerOpen(). If hMixer is NULL the
+ * object will be created by the Global Mixer. A NULL handle should only be
+ * used from the driver and not a normal client application.
+ * @param Id The ID of the object to create.
+ *
+ * @retval NvAudioFxObjectHandle A non-NULL value will be returned if the
+ * object is successfully created.
+ */
+
+ NvAudioFxObjectHandle NvddkAudioFxMixerCreateObject(
+ NvAudioFxMixerHandle hMixer,
+ NvObjectId Id );
+
+ /**
+ * @brief Destroys the AudioFX object.
+ *
+ * @param hObject A handle from NvAudioFxMixerCreateObject. If hObject is
+ * NULL, this API does nothing.
+ */
+
+ void NvddkAudioFxMixerDestroyObject(
+ NvAudioFxObjectHandle hObject );
+
+ /**
+ * @brief Maps a buffer to AudioFX address space.
+ */
+
+ NvAudioFxMixBufferHandle NvddkAudioFxMixerMapBuffer(
+ NvAudioFxMixerHandle hMixer,
+ NvU32 NvRmMemHandleId,
+ NvU32 Offset,
+ NvU32 Size );
+
+ /**
+ * @brief Unmaps a buffer from the AudioFX address space.
+ */
+
+ void NvddkAudioFxMixerUnmapBuffer(
+ NvAudioFxMixBufferHandle hMixBuffer );
+
+ /**
+ * @brief Adds a buffer to a Stream object.
+ *
+ * @param hStream Handle to the Stream object to add the buffer.
+ * @param pDescriptor Description of the buffer to add to the stream.
+ *
+ * @retval NvSuccess Indicates the operation succeeded.
+ */
+
+ NvError NvddkAudioFxStreamAddBuffer(
+ NvAudioFxStreamHandle hStream,
+ NvAudioFxBufferDescriptor * pDescriptor );
+
+/**
+ * @brief Get the property value from an AudioFX object.
+ *
+ * @param hObject Handle of the object to get the property value.
+ * @param Property The property of interest.
+ * @param Size Size of the descriptor.
+ * @param pDescriptor Holds the value of the current property.
+ *
+ * @retval NvSuccess Indicates the operation succeeded.
+ */
+
+ NvError NvddkAudioFxGetProperty(
+ NvAudioFxObjectHandle hObject,
+ NvAudioFxProperty Property,
+ NvU32 Size,
+ void* pProperty );
+
+/**
+ * @brief Set a property value on an AudioFX object.
+ *
+ * @param hObject Handle of the object to set the property on.
+ * @param Property The property of interest.
+ * @param Size Size of the property descriptor.
+ * @param pProperty Holds the value of the property to set.
+ *
+ * @retval NvSuccess Indicates the operation succeeded.
+ */
+
+ NvError NvddkAudioFxSetProperty(
+ NvAudioFxObjectHandle hObject,
+ NvAudioFxProperty Property,
+ NvU32 Size,
+ void* pProperty );
+
+/**
+ * @brief AVP API Function Table
+ */
+
+typedef struct NvddkAudioFxFxnTableRec
+{
+ NvAudioFxMixerHandle (*MixerOpen)(void);
+ void (*MixerClose)(NvAudioFxMixerHandle hMixer);
+ NvAudioFxObjectHandle (*MixerCreateObject)(NvAudioFxMixerHandle hMixer, NvObjectId Id);
+ void (*MixerDestroyObject)(NvAudioFxObjectHandle hObject);
+ NvAudioFxMixBufferHandle (*MixerMapBuffer)(NvAudioFxMixerHandle hMixer, NvU32 NvRmMemHandleId, NvU32 Offset, NvU32 Size);
+ void (*MixerUnmapBuffer)(NvAudioFxMixBufferHandle hMixBuffer);
+ NvError (*StreamAddBuffer)(NvAudioFxStreamHandle hStream, NvAudioFxBufferDescriptor* pDescriptor);
+ NvError (*GetProperty)(NvAudioFxObjectHandle hObject, NvAudioFxProperty Property, NvU32 Size, void* pProperty);
+ NvError (*SetProperty)(NvAudioFxObjectHandle hObject, NvAudioFxProperty Property, NvU32 Size, void* pProperty);
+
+} NvddkAudioFxFxnTable;
+
+static const NvU32 NvddkAudioFxFxnTableId = 0x6e766178; // 'nvax'
+
+typedef enum
+{
+ NvAudioFxIoctl_Generic = 5020,
+ NvAudioFxIoctl_ForceWord = 0x7FFFFFFF,
+
+} NvAudioFxIoctl;
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/sound/soc/tegra/tegra_soc_audio.c b/sound/soc/tegra/tegra_soc_audio.c
new file mode 100644
index 000000000000..19ca788d86fd
--- /dev/null
+++ b/sound/soc/tegra/tegra_soc_audio.c
@@ -0,0 +1,171 @@
+/*
+ * sound/soc/tegra/tegra_whistler.c
+ *
+ * ALSA SOC driver for NVIDIA Tegra SoCs
+ *
+ * Copyright (C) 2010 NVIDIA Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#define NV_DEBUG 0
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <linux/clk.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/scoop.h>
+#include <linux/io.h>
+#include "nvodm_query_discovery.h"
+#include "tegra_transport.h"
+
+struct codec_setup_data {
+ unsigned dem0_pin;
+ unsigned dem1_pin;
+ unsigned pdad_pin;
+ unsigned pdda_pin;
+};
+
+extern struct snd_soc_codec_device soc_codec_dev_tegra_generic_codec;
+extern struct snd_soc_dai dit_stub_dai;
+
+static struct platform_device *tegra_snd_device;
+NvU64 codec_guid;
+
+#define NVODM_CODEC_MAX_CLOCKS 3
+
+static unsigned int clock_frequencies[NVODM_CODEC_MAX_CLOCKS];
+
+static int set_clock_source_on_codec(NvU64 codec_guid,int IsEnable)
+{
+ const NvOdmPeripheralConnectivity *p_connectivity = NULL;
+ unsigned int clock_instances[NVODM_CODEC_MAX_CLOCKS];
+ unsigned int num_clocks;
+ p_connectivity = NvOdmPeripheralGetGuid(codec_guid);
+ if (p_connectivity == NULL)
+ return NV_FALSE;
+
+ if (IsEnable) {
+ if (!NvOdmExternalClockConfig(codec_guid, NV_FALSE,
+ clock_instances,
+ clock_frequencies, &num_clocks))
+ return NV_FALSE;
+ } else {
+ if (!NvOdmExternalClockConfig(codec_guid,
+ NV_TRUE,
+ clock_instances,
+ clock_frequencies,
+ &num_clocks));
+ return NV_FALSE;
+ }
+ return NV_TRUE;
+}
+
+static int tegra_whistler_hifi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ /* Set codec DAI configuration */
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ int ret;
+
+ ret = snd_soc_dai_set_fmt(codec_dai,SND_SOC_DAIFMT_I2S);
+
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_ops tegra_whistler_hifi_ops = {
+ .hw_params = tegra_whistler_hifi_hw_params,
+};
+
+static int tegra_wm8753_init(struct snd_soc_codec *codec)
+{
+ return 0;
+}
+
+extern struct snd_soc_dai tegra_i2s_rpc_dai;
+extern struct snd_soc_platform tegra_soc_platform;
+
+static struct snd_soc_dai_link tegra_whistler_dai = {
+ .name = "tegra-generic-codec",
+ .stream_name = "tegra-codec-rpc",
+ .cpu_dai = &tegra_i2s_rpc_dai,
+ .codec_dai = &dit_stub_dai,
+ .init = tegra_wm8753_init,
+ .ops = &tegra_whistler_hifi_ops,
+};
+
+static struct snd_soc_card tegra_whistler = {
+ .name = "tegra",
+ .platform = &tegra_soc_platform,
+ .dai_link = &tegra_whistler_dai,
+ .num_links = 1,
+};
+
+static struct snd_soc_device tegra_whistler_snd_devdata = {
+ .card = &tegra_whistler,
+ .codec_dev = &soc_codec_dev_tegra_generic_codec,
+};
+
+static int __init tegra_soc_init(void)
+{
+ int ret;
+ tegra_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!tegra_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(tegra_snd_device, &tegra_whistler_snd_devdata);
+ tegra_whistler_snd_devdata.dev = &tegra_snd_device->dev;
+
+ ret = platform_device_add(tegra_snd_device);
+ if (ret) {
+ snd_printk(KERN_ERR "tegra audio device could not be added \n");
+ platform_device_put(tegra_snd_device);
+ return ret;
+ }
+
+ codec_guid = NV_ODM_GUID('w','o','l','f','8','7','5','3');
+
+ set_clock_source_on_codec(codec_guid,NV_TRUE);
+ if (ret != 0)
+ platform_device_unregister(tegra_snd_device);
+
+ return ret;
+}
+
+static void __exit tegra_soc_exit(void)
+{
+ set_clock_source_on_codec(codec_guid,0);
+ platform_device_unregister(tegra_snd_device);
+}
+
+module_init(tegra_soc_init);
+module_exit(tegra_soc_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("Tegra SoC Sound");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/tegra/tegra_transport.c b/sound/soc/tegra/tegra_transport.c
new file mode 100644
index 000000000000..b7c8e71d1992
--- /dev/null
+++ b/sound/soc/tegra/tegra_transport.c
@@ -0,0 +1,840 @@
+/*
+ * sound/soc/tegra/tegra_transport.c
+ *
+ * ALSA SOC driver for NVIDIA Tegra SoCs
+ *
+ * Copyright (C) 2010 NVIDIA Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "tegra_transport.h"
+#include <linux/completion.h>
+
+#define transport_send_message(msg_type) \
+ message.Semaphore = 0; \
+ message.SendAck = 1; \
+ status = NvRmTransportSendMsg(atrans->hRmTransport, \
+ &message, \
+ sizeof(msg_type), \
+ TEGRA_TRANSPORT_SEND_TIMEOUT); \
+ if (status != NvSuccess) { \
+ snd_printk(KERN_ERR "NvRmTransportSendMsg failed!\n"); \
+ goto EXIT_WITH_ERROR; \
+ } \
+ wait_for_completion(&comp); \
+
+
+static AlsaTransport* atrans = 0;
+
+
+static NvAudioFxMixerHandle tegra_transport_mixer_open(void)
+{
+ NvError status = NvSuccess;
+ NvAudioFxMixerHandle hMixer = 0;
+ NvFxTransportMessageMixerOpen message;
+ struct completion comp;
+
+ init_completion(&comp);
+ message.Message = NVFXTRANSPORT_MESSAGE_MIXER_OPEN;
+ message.pPrivateData = (void*)&comp;
+ message.phMixer = &hMixer;
+
+ transport_send_message(NvFxTransportMessageMixerOpen);
+
+EXIT_WITH_ERROR:
+ return hMixer;
+}
+
+static void tegra_transport_mixer_close(NvAudioFxMixerHandle hMixer)
+{
+ NvError status = NvSuccess;
+ NvFxTransportMessageMixerClose message;
+ struct completion comp;
+
+ init_completion(&comp);
+ if (hMixer == NULL) {
+ snd_printk(KERN_ERR "NULL NvAudioFxMixerHandle!\n");
+ goto EXIT_WITH_ERROR;
+ }
+
+ message.Message = NVFXTRANSPORT_MESSAGE_MIXER_CLOSE;
+ message.pPrivateData = (void*)&comp;
+ message.hMixer = hMixer;
+
+ transport_send_message(NvFxTransportMessageMixerClose);
+
+EXIT_WITH_ERROR:
+ return;
+}
+
+static NvAudioFxObjectHandle tegra_transport_mixer_create_object(
+ NvAudioFxMixerHandle hMixer,
+ NvObjectId Id)
+{
+ NvError status = NvSuccess;
+ NvAudioFxObjectHandle hObject = 0;
+ NvFxTransportMessageCreateObject message;
+ struct completion comp;
+
+ init_completion(&comp);
+ message.Message = NVFXTRANSPORT_MESSAGE_CREATE_OBJECT;
+ message.pPrivateData = (void*)&comp;
+ message.hMixer = hMixer;
+ message.Id = Id;
+ message.phObject = &hObject;
+
+ transport_send_message(NvFxTransportMessageCreateObject);
+
+EXIT_WITH_ERROR:
+ return hObject;
+}
+
+static void tegra_transport_mixer_destroy_object(NvAudioFxObjectHandle hObject)
+{
+ NvError status = NvSuccess;
+ NvFxTransportMessageDestroyObject message;
+ struct completion comp;
+
+ init_completion(&comp);
+ message.Message = NVFXTRANSPORT_MESSAGE_DESTROY_OBJECT;
+ message.pPrivateData = (void*)&comp;
+ message.hObject = hObject;
+
+ transport_send_message(NvFxTransportMessageDestroyObject);
+
+EXIT_WITH_ERROR:
+ return;
+}
+
+static NvAudioFxMixBufferHandle tegra_transport_mixer_map_buffer(
+ NvAudioFxMixerHandle hMixer,
+ NvU32 NvRmMemHandleId,
+ NvU32 Offset,
+ NvU32 Size)
+{
+ NvError status = NvSuccess;
+ NvAudioFxMixBufferHandle mixer_buffer = 0;
+ NvFxTransportMessageMapBuffer message;
+ struct completion comp;
+
+ init_completion(&comp);
+ message.Message = NVFXTRANSPORT_MESSAGE_MAP_BUFFER;
+ message.pPrivateData = (void*)&comp;
+ message.hMixer = hMixer;
+ message.NvRmMemHandleId = NvRmMemHandleId;
+ message.Offset = Offset;
+ message.Size = Size;
+ message.phMixBuffer = &mixer_buffer;
+
+ transport_send_message(NvFxTransportMessageMapBuffer);
+EXIT_WITH_ERROR:
+ return mixer_buffer;
+}
+
+
+static void tegra_transport_mixer_unmap_buffer(
+ NvAudioFxMixBufferHandle mixer_buffer)
+{
+ NvError status = NvSuccess;
+ NvFxTransportMessageUnmapBuffer message;
+ struct completion comp;
+
+ init_completion(&comp);
+ message.Message = NVFXTRANSPORT_MESSAGE_UNMAP_BUFFER;
+ message.pPrivateData = (void*)&comp;
+ message.hMixBuffer = mixer_buffer;
+
+ transport_send_message(NvFxTransportMessageUnmapBuffer);
+
+EXIT_WITH_ERROR:
+ return;
+}
+
+static NvError tegra_transport_get_property(NvAudioFxObjectHandle hObject,
+ NvAudioFxProperty Property,
+ NvU32 Size,
+ void* pProperty)
+{
+ NvError status = NvSuccess;
+ NvError retStatus = NvSuccess;
+ NvFxTransportMessageGetProperty message;
+ struct completion comp;
+
+ if (FXTRANSPORT_MSG_BUFFER_PROPERTY_SIZE < Size) {
+ snd_printk(KERN_ERR "Property length too long!\n");
+ goto EXIT_WITH_ERROR;
+ }
+
+ init_completion(&comp);
+ message.Message = NVFXTRANSPORT_MESSAGE_GET_PROPERTY;
+ message.pPrivateData = (void*)&comp;
+ message.hObject = hObject;
+ message.Property = Property;
+ message.Size = Size;
+ message.pProperty = pProperty;
+ message.pReturnError = &retStatus;
+
+ transport_send_message(NvFxTransportMessageGetProperty);
+ goto EXIT;
+
+EXIT_WITH_ERROR:
+
+ retStatus = status;
+
+EXIT:
+ return retStatus;
+}
+
+static NvError tegra_transport_set_property(NvAudioFxObjectHandle hObject,
+ NvAudioFxProperty Property,
+ NvU32 Size,
+ void* pProperty)
+{
+ NvError status = NvSuccess;
+ NvError retStatus = NvSuccess;
+ NvFxTransportMessageSetProperty message;
+ struct completion comp;
+
+ if (FXTRANSPORT_MSG_BUFFER_PROPERTY_SIZE < Size) {
+ snd_printk(KERN_ERR "Property length too long!\n");
+ goto EXIT_WITH_ERROR;
+ }
+
+ init_completion(&comp);
+ message.Message = NVFXTRANSPORT_MESSAGE_SET_PROPERTY;
+ message.pPrivateData = (void*)&comp;
+ message.hObject = hObject;
+ message.Property = Property;
+ message.Size = Size;
+ NvOsMemcpy(message.PropertyData, pProperty, Size);
+ message.pReturnError = &retStatus;
+
+ transport_send_message(NvFxTransportMessageSetProperty);
+ goto EXIT;
+
+EXIT_WITH_ERROR:
+ retStatus = status;
+
+EXIT:
+ return retStatus;
+}
+
+static NvError tegra_transport_stream_add_buffer(NvAudioFxStreamHandle hStream,
+ NvAudioFxBufferDescriptor* pDescriptor)
+{
+ NvError status = NvSuccess;
+ NvError retStatus;
+ NvFxTransportMessageStreamAddBuffer message;
+ struct completion comp;
+
+ init_completion(&comp);
+ message.Message = NVFXTRANSPORT_MESSAGE_STREAM_ADD_BUFFER;
+ message.pPrivateData = (void*)&comp;
+ message.hStream = hStream;
+ message.Descriptor = *pDescriptor;
+ message.pReturnError = &retStatus;
+
+ transport_send_message(NvFxTransportMessageStreamAddBuffer);
+ goto EXIT;
+
+EXIT_WITH_ERROR:
+ retStatus = status;
+
+EXIT:
+ return retStatus;
+}
+
+static void AlsaTransportServiceThread(void *arg)
+{
+ NvError status = NvSuccess;
+ static NvFxTransportMessageResultBuffer in;
+ NvU32 messageSize = 0;
+ int retry = 0;
+#define transport_complete(comp) \
+ complete((struct completion*)comp);
+
+ while (retry < 5 ) {
+ status = NvRmTransportConnect(atrans->hRmTransport,
+ TEGRA_TRANSPORT_CONNECT_TIMEOUT);
+ if (status == NvSuccess)
+ break;
+ retry++;
+ }
+
+ if (status) {
+ snd_printk(KERN_ERR "AlsaTransportServiceThread: Failed to \
+ connect to remote end. Giving up ! \n");
+ atrans->TransportConnected = 0;
+ return;
+ }
+
+ atrans->TransportConnected = 1;
+
+ while (!atrans->ShutDown) {
+ NvOsSemaphoreWait(atrans->hServiceSema);
+ if (atrans->ShutDown)
+ break;
+
+ status = NvRmTransportRecvMsg(atrans->hRmTransport,
+ &in,
+ sizeof(NvFxTransportMessageResultBuffer),
+ &messageSize);
+ if (status == NvSuccess) {
+ switch (in.Message.Message) {
+ case NVFXTRANSPORT_MESSAGE_MIXER_OPEN: {
+ *in.MixerOpen.phMixer = in.MixerOpen.hMixer;
+ transport_complete(in.MixerOpen.pPrivateData);
+ }
+ break;
+
+ case NVFXTRANSPORT_MESSAGE_MIXER_CLOSE: {
+ transport_complete(in.MixerClose.pPrivateData);
+ }
+ break;
+
+ case NVFXTRANSPORT_MESSAGE_CREATE_OBJECT: {
+ *in.CreateObject.phObject =
+ in.CreateObject.hObject;
+ transport_complete(in.CreateObject.pPrivateData);
+ }
+ break;
+
+ case NVFXTRANSPORT_MESSAGE_DESTROY_OBJECT: {
+ transport_complete(in.DestroyObject.pPrivateData);
+ }
+ break;
+
+ case NVFXTRANSPORT_MESSAGE_MAP_BUFFER: {
+ *in.MapBuffer.phMixBuffer =
+ in.MapBuffer.hMixBuffer;
+ transport_complete(in.MapBuffer.pPrivateData);
+ }
+ break;
+
+ case NVFXTRANSPORT_MESSAGE_UNMAP_BUFFER: {
+ transport_complete(in.UnmapBuffer.pPrivateData);
+ }
+ break;
+
+ case NVFXTRANSPORT_MESSAGE_GET_PROPERTY: {
+ *in.GetProperty.pReturnError =
+ in.GetProperty.ReturnError;
+ if (in.GetProperty.ReturnError == NvSuccess) {
+ NvOsMemcpy(in.GetProperty.pProperty,
+ in.GetProperty.PropertyData,
+ in.GetProperty.Size);
+ }
+ transport_complete(in.GetProperty.pPrivateData);
+ }
+ break;
+
+ case NVFXTRANSPORT_MESSAGE_SET_PROPERTY: {
+ *in.SetProperty.pReturnError =
+ in.SetProperty.ReturnError;
+ transport_complete(in.SetProperty.pPrivateData);
+ }
+ break;
+
+ case NVFXTRANSPORT_MESSAGE_STREAM_ADD_BUFFER: {
+ *in.StreamAddBuffer.pReturnError =
+ in.StreamAddBuffer.ReturnError;
+ transport_complete(in.StreamAddBuffer.pPrivateData);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+}
+
+NvError tegra_transport_init(NvddkAudioFxFxnTable* xrt_fxns)
+{
+ NvError status = NvSuccess;
+
+ xrt_fxns->MixerOpen = tegra_transport_mixer_open;
+ xrt_fxns->MixerClose = tegra_transport_mixer_close;
+ xrt_fxns->MixerCreateObject = tegra_transport_mixer_create_object;
+ xrt_fxns->MixerDestroyObject = tegra_transport_mixer_destroy_object;
+ xrt_fxns->MixerMapBuffer = tegra_transport_mixer_map_buffer;
+ xrt_fxns->MixerUnmapBuffer = tegra_transport_mixer_unmap_buffer;
+ xrt_fxns->StreamAddBuffer = tegra_transport_stream_add_buffer;
+ xrt_fxns->GetProperty = tegra_transport_get_property;
+ xrt_fxns->SetProperty = tegra_transport_set_property;
+
+ /* Check if the FX Transport is already open.*/
+ if (atrans) {
+ spin_lock(&atrans->lock);
+ atrans->RefCount++;
+ spin_unlock(&atrans->lock);
+ goto EXIT;
+ }
+ /* Map a shared memory buffer.*/
+ atrans = (AlsaTransport*)kzalloc(sizeof(AlsaTransport),GFP_KERNEL);
+ if (!atrans) {
+ snd_printk(KERN_ERR "AlsaTransportInit kalloc failed! \n");
+ goto EXIT_WITH_ERROR;
+ }
+
+ spin_lock_init(&atrans->lock);
+ memset(atrans, 0, sizeof(AlsaTransport));
+ spin_lock(&atrans->lock);
+ atrans->RefCount++;
+ spin_unlock(&atrans->lock);
+
+ atrans->hRmDevice = s_hRmGlobal;
+
+ status = NvOsSemaphoreCreate(&atrans->hServiceSema, 0);
+ if (status != NvSuccess) {
+ snd_printk(KERN_ERR "NvOsSemaphoreCreate failed!\n");
+ goto EXIT_WITH_ERROR;
+ }
+
+ status = NvRmTransportOpen(atrans->hRmDevice,
+ "ALSA_TRANSPORT",
+ atrans->hServiceSema,
+ &atrans->hRmTransport);
+ if (status != NvSuccess) {
+ snd_printk(KERN_ERR "NvRmTransportOpen failed!\n");
+ goto EXIT_WITH_ERROR;
+ }
+
+ status = NvOsThreadCreate(AlsaTransportServiceThread,
+ NULL,
+ &atrans->hServiceThread);
+ if (status != NvSuccess) {
+ snd_printk(KERN_ERR "NvOsThreadCreate failed!\n");
+ goto EXIT_WITH_ERROR;
+ }
+
+ while (!atrans->TransportConnected) {
+ NvOsThreadYield();
+ }
+
+ goto EXIT;
+
+EXIT_WITH_ERROR:
+ if (atrans) {
+ tegra_transport_deinit();
+ }
+
+EXIT:
+ return status;
+}
+
+void tegra_transport_deinit(void)
+{
+ if (!atrans)
+ goto EXIT;
+
+ spin_lock(&atrans->lock);
+ atrans->RefCount--;
+
+ if (atrans->RefCount > 0){
+ spin_unlock(&atrans->lock);
+ goto EXIT;
+ }
+ spin_unlock(&atrans->lock);
+
+ atrans->ShutDown = 1;
+
+ if (atrans->hRmTransport) {
+ NvRmTransportClose(atrans->hRmTransport);
+ atrans->hRmTransport = 0;
+ atrans->TransportConnected = 0;
+ }
+
+ if (atrans->hServiceThread) {
+ NvOsSemaphoreSignal(atrans->hServiceSema);
+ NvOsThreadJoin(atrans->hServiceThread);
+ atrans->hServiceThread = 0;
+ }
+
+ if (atrans->hServiceSema) {
+ NvOsSemaphoreDestroy(atrans->hServiceSema);
+ atrans->hServiceSema = 0;
+ }
+ atrans->hRmDevice = 0;
+ kfree(atrans);
+ atrans = 0;
+
+EXIT:
+ return;
+}
+
+static void tegra_audiofx_notifier_thread(void *arg)
+{
+ struct tegra_audio_data *audio_context = (struct tegra_audio_data *)arg;
+ FxNotifier *m_FxNotifier = (FxNotifier*)&audio_context->m_FxNotifier;
+ NvError e;
+ int retry = 0;
+ NvU32 messageSize;
+ NvAudioFxMessage* message =
+ (NvAudioFxMessage*)m_FxNotifier->RcvMessageBuffer;
+
+ while (retry < 5) {
+ e = NvRmTransportConnect(m_FxNotifier->hTransport, 5000);
+ if (e == NvSuccess)
+ break;
+
+ retry++;
+ }
+ if (e != NvSuccess) {
+ snd_printk(KERN_ERR "NvRmTransportConnect failed!\n");
+ m_FxNotifier->Connected = 0;
+ goto EXIT;
+ }
+
+ m_FxNotifier->Connected = 1;
+ while (1) {
+ NvOsSemaphoreWait(m_FxNotifier->hTransportSemaphore);
+ if (m_FxNotifier->Exit) {
+ break;
+ }
+
+ e = NvRmTransportRecvMsg(m_FxNotifier->hTransport,
+ message,
+ 256,
+ &messageSize);
+ if (e == NvSuccess) {
+ switch (message->Event) {
+ case NvAudioFxEventBufferDone:{
+ NvAudioFxBufferDoneMessage* bdm =
+ (NvAudioFxBufferDoneMessage*)message;
+ struct pcm_runtime_data* prtd =
+ (struct pcm_runtime_data*)bdm->m.pContext;
+
+ up(&prtd->buf_done_sem);
+ }
+ break;
+
+ case NvAudioFxEventStateChange:
+ break;
+
+ default:
+ snd_printk(KERN_ERR"Unhandled event\n");
+ break;
+ }
+ }
+ }
+
+EXIT:
+ return;
+}
+
+NvError tegra_audiofx_createfx(struct tegra_audio_data *audio_context)
+{
+ NvAudioFxMixerHandle m_hMixer =
+ (NvAudioFxMixerHandle)audio_context->mixer_handle;
+
+ FxNotifier *m_FxNotifier = (FxNotifier*)&audio_context->m_FxNotifier;
+ NvRmDeviceHandle m_hRm = (NvRmDeviceHandle)audio_context->m_hRm;
+ NvError e = NvSuccess;
+ NvAudioFxNotifierConnectionDescriptor connectionDesciptor;
+ NvAudioFxMessage message;
+
+ memset(&connectionDesciptor,
+ 0,
+ sizeof(NvAudioFxNotifierConnectionDescriptor));
+ memset(&message, 0, sizeof(NvAudioFxMessage));
+
+ e = NvOsSemaphoreCreate(&m_FxNotifier->hTransportSemaphore, 0);
+ if (e != NvSuccess) {
+ snd_printk(KERN_ERR "NvOsSemaphoreCreate failed!\n");
+ goto EXIT_WITH_ERROR;
+ }
+
+ m_FxNotifier->hNotifier =
+ (NvAudioFxNotifierHandle)tegra_transport_mixer_create_object(
+ m_hMixer,
+ NvAudioFxNotifierId);
+ if (!m_FxNotifier->hNotifier) {
+ snd_printk(KERN_ERR "transport_mixer_create_object failed!\n");
+ goto EXIT_WITH_ERROR;
+ }
+
+ e = NvRmTransportOpen(m_hRm,
+ 0,
+ m_FxNotifier->hTransportSemaphore,
+ &m_FxNotifier->hTransport);
+ if (e != NvSuccess) {
+ snd_printk(KERN_ERR "NvRmTransportOpen failed!\n");
+ goto EXIT_WITH_ERROR;
+ }
+
+ NvRmTransportGetPortName(m_FxNotifier->hTransport,
+ (NvU8*)&connectionDesciptor.PortName,
+ sizeof(NvU8) * 16);
+
+ e = NvOsThreadCreate(tegra_audiofx_notifier_thread,
+ audio_context,
+ &m_FxNotifier->hTransportThread);
+ if (e != NvSuccess) {
+ snd_printk(KERN_ERR "NvOsThreadCreate failed!\n");
+ goto EXIT_WITH_ERROR;
+ }
+
+ e = tegra_transport_set_property(
+ (NvAudioFxObjectHandle)m_FxNotifier->hNotifier,
+ NvAudioFxNotifierProperty_Connect,
+ sizeof(NvAudioFxNotifierConnectionDescriptor),
+ &connectionDesciptor);
+ if (e != NvSuccess) {
+ snd_printk(KERN_ERR "tegra_transport_set_property failed!\n");
+ goto EXIT_WITH_ERROR;
+ }
+
+ goto EXIT;
+
+EXIT_WITH_ERROR:
+ tegra_audiofx_destroyfx(audio_context);
+
+EXIT:
+ return e;
+}
+
+void tegra_audiofx_destroyfx(struct tegra_audio_data *audio_context)
+{
+ FxNotifier *m_FxNotifier = (FxNotifier*)&audio_context->m_FxNotifier;
+
+ if (m_FxNotifier->Connected) {
+ m_FxNotifier->Exit = 1;
+ NvOsSemaphoreSignal(m_FxNotifier->hTransportSemaphore);
+ NvOsThreadJoin(m_FxNotifier->hTransportThread);
+ m_FxNotifier->hTransportThread = 0;
+ tegra_transport_set_property(
+ (NvAudioFxObjectHandle)m_FxNotifier->hNotifier,
+ NvAudioFxNotifierProperty_Disconnect,
+ 0,
+ 0);
+ }
+
+ if (m_FxNotifier->hTransport) {
+ NvRmTransportClose(m_FxNotifier->hTransport);
+ m_FxNotifier->hTransport = 0;
+ }
+
+ if (m_FxNotifier->hNotifier) {
+ tegra_transport_mixer_destroy_object(
+ (NvAudioFxObjectHandle)m_FxNotifier->hNotifier);
+ m_FxNotifier->hNotifier = 0;
+ }
+
+ if (m_FxNotifier->hTransportSemaphore) {
+ NvOsSemaphoreDestroy(m_FxNotifier->hTransportSemaphore);
+ m_FxNotifier->hTransportSemaphore = 0;
+ }
+
+ return;
+}
+
+#define audiofx_create_object(path_object, FxId) \
+ path_object = tegra_transport_mixer_create_object(hMixer, FxId); \
+ if(!path_object) { \
+ snd_printk(KERN_ERR "audiofx_create_object failed!"); \
+ }
+
+#define audiofx_path_connect(path_object, sink_object) \
+ connection.hSource = (NvAudioFxHandle)path_object, \
+ connection.SourcePin = NvAudioFxSourcePin; \
+ connection.SinkPin = NvAudioFxSinkPin; \
+ connection.hSink = (NvAudioFxHandle)sink_object; \
+ e = tegra_transport_set_property(path_object, \
+ NvAudioFxProperty_Attach, \
+ sizeof(NvAudioFxConnectionDescriptor), \
+ &connection); \
+ if(e != NvSuccess) { \
+ snd_printk(KERN_ERR "audiofx_path_connect failed!"); \
+ goto EXIT_WITH_ERROR; \
+ }
+
+NvError tegra_audiofx_create_output(NvRmDeviceHandle hRmDevice,
+ NvAudioFxMixerHandle hMixer,
+ StandardPath* pPath)
+{
+ NvError e = NvSuccess;
+ NvAudioFxConnectionDescriptor connection;
+
+ /* Standard Output
+ [stream]->[SRC]->[Convert]->[Resize]->[Volume]->Default Output
+ */
+
+ memset(pPath, 0, sizeof(StandardPath));
+
+ audiofx_create_object(pPath->Stream, NvAudioFxStreamId);
+ audiofx_create_object(pPath->Src, NvAudioFxSrcId);
+ audiofx_create_object(pPath->Convert, NvAudioFxConvertId);
+ audiofx_create_object(pPath->Resize, NvAudioFxResizeId);
+ audiofx_create_object(pPath->Volume, NvAudioFxVolumeId);
+
+ audiofx_path_connect(pPath->Stream, pPath->Src);
+ audiofx_path_connect(pPath->Src, pPath->Convert);
+ audiofx_path_connect(pPath->Convert, pPath->Resize);
+ audiofx_path_connect(pPath->Resize, pPath->Volume);
+
+ connection.hSource = (NvAudioFxHandle)pPath->Volume;
+ connection.SourcePin = NvAudioFxSourcePin;
+ connection.hSink = 0;
+ connection.SinkPin = NvAudioFxSinkPin;
+ e = tegra_transport_set_property(pPath->Volume,
+ NvAudioFxProperty_Attach,
+ sizeof(NvAudioFxConnectionDescriptor),
+ &connection);
+ if (e != NvSuccess) {
+ snd_printk(KERN_ERR "tegra_transport_set_property failed!\n");
+ goto EXIT_WITH_ERROR;
+ }
+
+ goto EXIT;
+
+EXIT_WITH_ERROR:
+
+ tegra_audiofx_destroy_output(pPath);
+
+EXIT:
+
+ return e;
+}
+
+NvError tegra_audiofx_destroy_output(StandardPath* pPath)
+{
+ if (pPath->Volume) {
+ tegra_transport_mixer_destroy_object(pPath->Volume);
+ pPath->Volume = 0;
+ }
+
+ if (pPath->Resize) {
+ tegra_transport_mixer_destroy_object(pPath->Resize);
+ pPath->Resize = 0;
+ }
+
+ if (pPath->Convert) {
+ tegra_transport_mixer_destroy_object(pPath->Convert);
+ pPath->Convert = 0;
+ }
+
+ if (pPath->Src) {
+ tegra_transport_mixer_destroy_object(pPath->Src);
+ pPath->Src = 0;
+ }
+
+ if (pPath->Stream) {
+ tegra_transport_mixer_destroy_object(pPath->Stream);
+ pPath->Stream = 0;
+ }
+
+ return NvSuccess;
+}
+
+NvError tegra_audiofx_create_input(NvRmDeviceHandle hRmDevice,
+ NvAudioFxMixerHandle hMixer,
+ StandardPath* pInput,
+ InputSelection InputSelect)
+{
+ NvError e = NvSuccess;
+ NvAudioFxConnectionDescriptor connection;
+
+ /*
+ Standard Input (record or loopback)
+
+ +--------+ (2) +--------+ (3) +---------+ (4) +--------+ (5)
+ +--| Stream |<----| Resize |<-----| Convert |<-----| SRC |<--From I2S
+ | | | | |<--+ | (opt.) | | (opt.) |
+ | +--------+ +--------+ | +---------+ +--------+
+ | (1) |
+ +------------------------------+
+
+ */
+
+ memset(pInput, 0, sizeof(StandardPath));
+
+ audiofx_create_object(pInput->Stream, NvAudioFxStreamId);
+ audiofx_create_object(pInput->Resize,NvAudioFxResizeId);
+ audiofx_create_object(pInput->Src,NvAudioFxSrcId);
+ audiofx_create_object(pInput->Convert,NvAudioFxConvertId);
+
+ /* Wire 1 */
+ connection.hSource = (NvAudioFxHandle)(pInput->Stream);
+ connection.SourcePin = NvAudioFxSourcePin;
+ connection.hSink = (NvAudioFxHandle)pInput->Resize;
+ connection.SinkPin = NvAudioFxCopySinkPin;
+ e = tegra_transport_set_property(pInput->Stream,
+ NvAudioFxProperty_Attach,
+ sizeof(NvAudioFxConnectionDescriptor),
+ &connection);
+ if (e != NvSuccess) {
+ snd_printk(KERN_ERR "tegra_transport_set_property failed!\n");
+ goto EXIT_WITH_ERROR;
+ }
+
+ audiofx_path_connect(pInput->Resize, pInput->Stream);
+ audiofx_path_connect(pInput->Convert, pInput->Resize);
+ audiofx_path_connect(pInput->Src, pInput->Convert);
+
+ /* Wire 5 */
+ connection.hSource = 0;
+ connection.SourcePin = (InputSelect == NvAudioInputSelect_Record) ?
+ NvAudioFxSourcePin : NvAudioFxLoopbackPin;
+ connection.hSink = (NvAudioFxHandle)pInput->Src;
+ connection.SinkPin = NvAudioFxSinkPin;
+ e = tegra_transport_set_property(0,
+ NvAudioFxProperty_Attach,
+ sizeof(NvAudioFxConnectionDescriptor),
+ &connection);
+ if (e != NvSuccess) {
+ snd_printk(KERN_ERR "tegra_transport_set_property failed!\n");
+ goto EXIT_WITH_ERROR;
+ }
+
+ goto EXIT;
+
+EXIT_WITH_ERROR:
+
+ tegra_audiofx_destroy_input(pInput);
+
+EXIT:
+
+ return e;
+}
+
+
+NvError tegra_audiofx_destroy_input(StandardPath* pInput)
+{
+ if (pInput->Src) {
+ tegra_transport_mixer_destroy_object(pInput->Src);
+ pInput->Src = 0;
+ }
+
+ if (pInput->Convert) {
+ tegra_transport_mixer_destroy_object(pInput->Convert);
+ pInput->Convert = 0;
+ }
+
+ if (pInput->Resize) {
+ tegra_transport_mixer_destroy_object(pInput->Resize);
+ pInput->Resize = 0;
+ }
+
+ if (pInput->Stream) {
+ tegra_transport_mixer_destroy_object(pInput->Stream);
+ pInput->Stream = 0;
+ }
+
+ return NvSuccess;
+}
+
diff --git a/sound/soc/tegra/tegra_transport.h b/sound/soc/tegra/tegra_transport.h
new file mode 100644
index 000000000000..0093fef6383b
--- /dev/null
+++ b/sound/soc/tegra/tegra_transport.h
@@ -0,0 +1,431 @@
+/*
+ * sound/soc/tegra/tegra_transport.h
+ *
+ * ALSA SOC driver for NVIDIA Tegra SoCs
+ *
+ * Copyright (C) 2010 NVIDIA Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _TEGRA_TRANSPORT_H_
+#define _TEGRA_TRANSPORT_H_
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/kthread.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <linux/mutex.h>
+
+#include <mach/nvrm_linux.h>
+#include "nvrm_memmgr.h"
+#include "nvassert.h"
+#include "nvrm_transport.h"
+#include "tegra_sndfx.h"
+
+
+#define INIT_TIMEOUT 5000
+#define PLAY_TIMEOUT 5000
+#define REC_TIMEOUT 5000
+#define WHISTLER_CODEC_ADDRESS 0x1a
+#define WHISTLER_CODEC_BUS 0
+#define NVALSA_BUFFER_COUNT 1
+#define TEGRA_DEFAULT_BUFFER_SIZE 8192
+#define NVALSA_INVALID_STATE -1
+#define TEGRA_SAMPLE_RATES (SNDRV_PCM_RATE_8000_48000)
+#define TEGRA_SAMPLE_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |\
+ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_BE)
+
+#define TEGRA_TRANSPORT_SEND_TIMEOUT 5000
+#define TEGRA_TRANSPORT_CONNECT_TIMEOUT 60000
+#define FXTRANSPORT_MSG_BUFFER_SIZE 256
+#define FXTRANSPORT_MSG_BUFFER_PROPERTY_SIZE FXTRANSPORT_MSG_BUFFER_SIZE - 32
+#define FXTRANSPORT_MSG_RESULT_DATA_SIZE FXTRANSPORT_MSG_BUFFER_SIZE - 32
+
+typedef enum {
+ NVFXTRANSPORT_MESSAGE_MIXER_OPEN = 0,
+ NVFXTRANSPORT_MESSAGE_MIXER_CLOSE,
+ NVFXTRANSPORT_MESSAGE_CREATE_OBJECT,
+ NVFXTRANSPORT_MESSAGE_DESTROY_OBJECT,
+ NVFXTRANSPORT_MESSAGE_MAP_BUFFER,
+ NVFXTRANSPORT_MESSAGE_UNMAP_BUFFER,
+ NVFXTRANSPORT_MESSAGE_GET_PROPERTY,
+ NVFXTRANSPORT_MESSAGE_SET_PROPERTY,
+ NVFXTRANSPORT_MESSAGE_STREAM_ADD_BUFFER,
+
+ NVFXTRANSPORT_MESSAGE_Force32 = 0x7FFFFFFF
+
+} NVFXTRANSPORT_MESSAGE;
+
+
+typedef struct NvFxTransportMessageRec {
+#define NVFXTRANSPORT_MESSAGE_VARS \
+ NVFXTRANSPORT_MESSAGE Message; \
+ NvOsSemaphoreHandle Semaphore; \
+ void* pPrivateData; \
+ NvU32 SendAck
+
+ NVFXTRANSPORT_MESSAGE_VARS;
+
+} NvFxTransportMessage;
+
+typedef struct NvFxTransportMessageResultRec {
+#define NVFXTRANSPORT_MESSAGE_RESULT_VARS \
+ NVFXTRANSPORT_MESSAGE Message; \
+ NvOsSemaphoreHandle Semaphore; \
+ void* pPrivateData
+
+ NVFXTRANSPORT_MESSAGE_RESULT_VARS;
+
+} NvFxTransportMessageResult;
+
+
+typedef struct NvFxTransportMessageMixerOpenRec {
+ NVFXTRANSPORT_MESSAGE_VARS;
+ NvAudioFxMixerHandle* phMixer;
+
+} NvFxTransportMessageMixerOpen;
+
+typedef struct NvFxTransportMessageResultMixerOpenRec {
+ NVFXTRANSPORT_MESSAGE_RESULT_VARS;
+ NvAudioFxMixerHandle hMixer;
+ NvAudioFxMixerHandle* phMixer;
+
+} NvFxTransportMessageResultMixerOpen;
+
+
+typedef struct NvFxTransportMessageMixerCloseRec {
+ NVFXTRANSPORT_MESSAGE_VARS;
+ NvAudioFxMixerHandle hMixer;
+
+} NvFxTransportMessageMixerClose;
+
+typedef NvFxTransportMessageResult NvFxTransportMessageResultMixerClose;
+
+
+typedef struct NvFxTransportMessageCreateObjectRec {
+ NVFXTRANSPORT_MESSAGE_VARS;
+ NvAudioFxMixerHandle hMixer;
+ NvObjectId Id;
+
+ NvAudioFxObjectHandle* phObject;
+
+} NvFxTransportMessageCreateObject;
+
+typedef struct NvFxTransportMessageResultCreateObjectRec {
+ NVFXTRANSPORT_MESSAGE_RESULT_VARS;
+ NvAudioFxObjectHandle hObject;
+ NvAudioFxObjectHandle* phObject;
+
+} NvFxTransportMessageResultCreateObject;
+
+
+typedef struct NvFxTransportMessageDestroyObjectRec {
+ NVFXTRANSPORT_MESSAGE_VARS;
+ NvAudioFxObjectHandle hObject;
+
+} NvFxTransportMessageDestroyObject;
+
+typedef NvFxTransportMessageResult NvFxTransportMessageResultDestroyObject;
+
+
+typedef struct NvFxTransportMessageMapBufferRec {
+ NVFXTRANSPORT_MESSAGE_VARS;
+ NvAudioFxMixerHandle hMixer;
+ NvU32 NvRmMemHandleId;
+ NvU32 Offset;
+ NvU32 Size;
+
+ NvAudioFxMixBufferHandle* phMixBuffer;
+
+} NvFxTransportMessageMapBuffer;
+
+typedef struct NvFxTransportMessageResultMapBufferRec {
+ NVFXTRANSPORT_MESSAGE_RESULT_VARS;
+ NvAudioFxMixBufferHandle hMixBuffer;
+ NvAudioFxMixBufferHandle* phMixBuffer;
+
+} NvFxTransportMessageResultMapBuffer;
+
+
+typedef struct NvFxTransportMessageUnmapBufferRec {
+ NVFXTRANSPORT_MESSAGE_VARS;
+ NvAudioFxMixBufferHandle hMixBuffer;
+
+} NvFxTransportMessageUnmapBuffer;
+
+typedef NvFxTransportMessageResult NvFxTransportMessageResultUnmapBuffer;
+
+
+typedef struct NvFxTransportMessageGetPropertyRec {
+ NVFXTRANSPORT_MESSAGE_VARS;
+ NvAudioFxObjectHandle hObject;
+ NvAudioFxProperty Property;
+ NvU32 Size;
+
+ void* pProperty;
+ NvError* pReturnError;
+
+} NvFxTransportMessageGetProperty;
+
+typedef struct NvFxTransportMessageResultGetPropertyRec {
+ NVFXTRANSPORT_MESSAGE_RESULT_VARS;
+ NvU32 Size;
+ NvError ReturnError;
+ void* pProperty;
+ NvError* pReturnError;
+ NvU8 PropertyData[FXTRANSPORT_MSG_BUFFER_PROPERTY_SIZE];
+
+} NvFxTransportMessageResultGetProperty;
+
+
+typedef struct NvFxTransportMessageSetPropertyRec {
+ NVFXTRANSPORT_MESSAGE_VARS;
+ NvAudioFxObjectHandle hObject;
+ NvAudioFxProperty Property;
+ NvU32 Size;
+ NvError* pReturnError;
+ NvU8 PropertyData[FXTRANSPORT_MSG_BUFFER_PROPERTY_SIZE];
+} NvFxTransportMessageSetProperty;
+
+typedef struct NvFxTransportMessageResultSetPropertyRec {
+ NVFXTRANSPORT_MESSAGE_RESULT_VARS;
+ NvError ReturnError;
+ NvError* pReturnError;
+
+} NvFxTransportMessageResultSetProperty;
+
+
+typedef struct NvFxTransportMessageStreamAddBufferRec {
+ NVFXTRANSPORT_MESSAGE_VARS;
+ NvAudioFxStreamHandle hStream;
+ NvAudioFxBufferDescriptor Descriptor;
+
+ NvError* pReturnError;
+
+} NvFxTransportMessageStreamAddBuffer;
+
+typedef struct NvFxTransportMessageResultStreamAddBufferRec {
+ NVFXTRANSPORT_MESSAGE_RESULT_VARS;
+ NvError ReturnError;
+ NvError* pReturnError;
+
+} NvFxTransportMessageResultStreamAddBuffer;
+
+typedef union NvFxTranspportMessageBuffer {
+ NvFxTransportMessage Message;
+ NvFxTransportMessageMixerOpen MixerOpen;
+ NvFxTransportMessageMixerClose MixerClose;
+ NvFxTransportMessageCreateObject CreateObject;
+ NvFxTransportMessageDestroyObject DestroyObject;
+ NvFxTransportMessageMapBuffer MapBuffer;
+ NvFxTransportMessageUnmapBuffer UnmapBuffer;
+ NvFxTransportMessageGetProperty GetProperty;
+ NvFxTransportMessageSetProperty SetProperty;
+ NvFxTransportMessageStreamAddBuffer StreamAddBuffer;
+
+} NvFxTransportMessageBuffer;
+
+typedef union NvFxTranspportMessageResultBuffer {
+ NvFxTransportMessageResult Message;
+ NvFxTransportMessageResultMixerOpen MixerOpen;
+ NvFxTransportMessageResultMixerClose MixerClose;
+ NvFxTransportMessageResultCreateObject CreateObject;
+ NvFxTransportMessageResultDestroyObject DestroyObject;
+ NvFxTransportMessageResultMapBuffer MapBuffer;
+ NvFxTransportMessageResultUnmapBuffer UnmapBuffer;
+ NvFxTransportMessageResultGetProperty GetProperty;
+ NvFxTransportMessageResultSetProperty SetProperty;
+ NvFxTransportMessageResultStreamAddBuffer StreamAddBuffer;
+
+} NvFxTransportMessageResultBuffer;
+
+typedef struct AlsaTransportRec {
+ NvddkAudioFxFxnTable* hFxnTable;
+ NvOsThreadHandle hServiceThread;
+ NvOsSemaphoreHandle hServiceSema;
+
+ NvRmDeviceHandle hRmDevice;
+ NvRmTransportHandle hRmTransport;
+
+ volatile NvU32 TransportConnected;
+ NvU32 RefCount;
+ NvU32 ShutDown;
+ spinlock_t lock;
+
+} AlsaTransport;
+
+
+enum {
+ /* Default Playback Path*/
+ GlobalFx_DefaultPlaybackMix = 0,
+ GlobalFx_DefaultPlaybackSplit,
+
+ /* I2S Playback Path*/
+ GlobalFx_I2sPlaybackMix,
+ GlobalFx_I2sPlaybackVolume,
+ GlobalFx_I2s,
+
+ /* I2S2 Playback Path*/
+ GlobalFx_I2s2PlaybackMix,
+ GlobalFx_I2s2PlaybackVolume,
+ GlobalFx_I2s2,
+
+ /* SPDIF Playback Path*/
+ GlobalFx_SpdifPlaybackMix,
+ GlobalFx_SpdifPlaybackVolume,
+ GlobalFx_Spdif,
+
+
+ /* Default Record Path*/
+ GlobalFx_DefaultRecordMix,
+ GlobalFx_DefaultRecordSplit,
+
+ /* I2S Record Path*/
+ GlobalFx_I2sRecordVolume,
+ GlobalFx_I2sRecordSplit,
+
+ /* I2S2 Record Path*/
+ GlobalFx_I2s2RecordVolume,
+ GlobalFx_I2s2RecordSplit,
+
+ /* SPDIF Record Path*/
+ GlobalFx_SpdifRecordVolume,
+ GlobalFx_SpdifRecordSplit,
+
+
+ /* Loopbacks*/
+ GlobalFx_I2sLoopbackSplit,
+ GlobalFx_I2s2LoopbackSplit,
+ GlobalFx_SpdifLoopbackSplit,
+
+
+ /* Music Path*/
+ GlobalFx_MusicMix,
+ GlobalFx_MusicEq,
+ GlobalFx_MusicDrc,
+ GlobalFx_MusicSpreader,
+ GlobalFx_MusicPeq,
+ GlobalFx_MusicVolume,
+ GlobalFx_MusicSplit,
+
+
+ /* Phone Path*/
+ GlobalFx_PhoneMix,
+ GlobalFx_PhoneSplit,
+
+ GlobalFx_Num
+
+};
+
+typedef struct GlobalFxListRec {
+ /* Default Playback Path*/
+ NvAudioFxObjectHandle hFx[GlobalFx_Num];
+} GlobalFxList;
+
+
+typedef struct FxNotifierRec {
+ NvAudioFxNotifierHandle hNotifier;
+ NvRmTransportHandle hTransport;
+ NvOsSemaphoreHandle hTransportSemaphore;
+ NvOsThreadHandle hTransportThread;
+
+ NvU32 Exit;
+ NvU32 Connected;
+ NvU8 RcvMessageBuffer[256];
+
+ NvAudioFxEvent Event;
+
+} FxNotifier;
+
+typedef enum {
+ NvAudioInputSelect_Record = 0,
+ NvAudioInputSelect_Loopback
+
+} InputSelection;
+
+typedef struct StandardPathRec {
+ NvAudioFxObjectHandle Stream;
+ NvAudioFxObjectHandle Src;
+ NvAudioFxObjectHandle Convert;
+ NvAudioFxObjectHandle Volume;
+ NvAudioFxObjectHandle Resize;
+
+ /*NvAudioFxVolumeDescriptor VolumeDesc;*/
+ /*NvU32 VolumeRamping;*/
+ /*StandardPosition StandardPosition;*/
+
+} StandardPath;
+
+typedef struct NvAudioBufferRec {
+ NvRmMemHandle hRmMem;
+ NvAudioFxMixBufferHandle hMixBuffer;
+ void* pVirtAddr;
+ NvU32 Size;
+} NvAudioBuffer;
+
+struct pcm_runtime_data {
+ spinlock_t lock;
+ struct task_struct *play_thread,*rec_thread;
+ int timeout;
+ int state;
+ int stream;
+ int shutdown_thrd;
+ unsigned int audiofx_frames;
+ struct completion thread_comp;
+ wait_queue_head_t buf_wait;
+ struct semaphore buf_done_sem;
+ StandardPath* stdoutpath;
+ StandardPath* stdinpath;
+ u64 cur_pos;
+ u64 last_pos;
+ NvAudioFxMixBufferHandle mixer_buffer;
+};
+
+struct tegra_audio_data {
+ NvddkAudioFxFxnTable xrt_fxn;
+ NvAudioFxMixerHandle mixer_handle;
+ FxNotifier m_FxNotifier;
+ NvRmDeviceHandle m_hRm;
+ unsigned int mapped_buf_size;
+ NvAudioFxMixBufferHandle mixer_buffer[2];
+ NvRmMemHandle mem_handle[2];
+ struct mutex lock;
+};
+
+
+NvError tegra_audiofx_createfx(struct tegra_audio_data *audio_context);
+void tegra_audiofx_destroyfx(struct tegra_audio_data *audio_context);
+NvError tegra_audiofx_create_output(NvRmDeviceHandle,
+ NvAudioFxMixerHandle,
+ StandardPath*);
+NvError tegra_audiofx_destroy_output(StandardPath* pPath);
+NvError tegra_audiofx_create_input(NvRmDeviceHandle hRmDevice,
+ NvAudioFxMixerHandle hMixer,
+ StandardPath* pPath,
+ InputSelection InputSelect);
+NvError tegra_audiofx_destroy_input(StandardPath* pPath);
+NvError tegra_transport_init(NvddkAudioFxFxnTable* FxTransportFxFxnTable);
+void tegra_transport_deinit(void);
+
+#endif