[PATCH] Sound: MSM soc : imported alsa for the MSM from codeaurora

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I had to make two little change to make it compile:
snd_ep = msm_rpc_connect_compatible(snd_rpc_ids.prog,
became:
snd_ep = msm_rpc_connect(snd_rpc_ids.prog,
and I also changed snd_rpc_ids.vers(with ifdefs)
to a known and working magick number:

I also had to change from ARCH_MSM_ARM11 to ARCH_MSM in the configuration

it still has serious runtime problems such as:
*Can produce kernel oops under theses conditions:
 start alsamixer and if the second bar is on 0 or 4,
 so it can play music with aplay,then increase the routing alsamixer bar
 to the max.
 Then decrease the routing bar to 4 or less
 Then It may have a null pointer problem
 That bug could be because it tries to route to route to speakers and
 handset at the same time(SND_DEVICE_HEADSET_AND_SPEAKER in android):
 that is to say it could be the same bug than here:
http://gitorious.org/replicant/msm7k/commit/370d37a088368ca8cc478e76c928a1ce6589495e
 but I need time to verify that
*can pannick(reboots the phone) if you send things to /dev/dsp when the
 oss emulation is activated
*only aplay works(mplayer,gstreamer don't work) for mplayer an ioctl
 didn't return...so it get stuck before playing.
 The explanation of the bug can be found here:
http://mailman.alsa-project.org/pipermail/alsa-devel/2009-November/022697.html

Note the following things:
*this patch depends on,and doesn't contain arch/arm/mach-msm/qdsp5
*I removed the support for more recents chips because of code-size issue
 in a mailing list

Signed-off-by: Denis 'GNUtoo' Carikli <GNUtoo@xxxxxxxxxx>
---
 sound/soc/Kconfig         |    1 +
 sound/soc/Makefile        |    1 +
 sound/soc/msm/Kconfig     |   23 ++
 sound/soc/msm/Makefile    |   11 +
 sound/soc/msm/msm-dai.c   |  143 ++++++++++
 sound/soc/msm/msm-pcm.c   |  643 +++++++++++++++++++++++++++++++++++++++++++++
 sound/soc/msm/msm-pcm.h   |  200 ++++++++++++++
 sound/soc/msm/msm7201.c   |  337 ++++++++++++++++++++++++
 sound/soc/msm/msm7k-pcm.c |  574 ++++++++++++++++++++++++++++++++++++++++
 9 files changed, 1933 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/msm/Kconfig
 create mode 100644 sound/soc/msm/Makefile
 create mode 100644 sound/soc/msm/msm-dai.c
 create mode 100644 sound/soc/msm/msm-pcm.c
 create mode 100644 sound/soc/msm/msm-pcm.h
 create mode 100644 sound/soc/msm/msm7201.c
 create mode 100644 sound/soc/msm/msm7k-pcm.c

diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index ef025c6..4b1a48f 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -32,6 +32,7 @@ source "sound/soc/omap/Kconfig"
 source "sound/soc/pxa/Kconfig"
 source "sound/soc/s3c24xx/Kconfig"
 source "sound/soc/sh/Kconfig"
+source "sound/soc/msm/Kconfig"
 
 # Supported codecs
 source "sound/soc/codecs/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 86a9b1f..ea754e5 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_SND_SOC)	+= omap/
 obj-$(CONFIG_SND_SOC)	+= pxa/
 obj-$(CONFIG_SND_SOC)	+= s3c24xx/
 obj-$(CONFIG_SND_SOC)	+= sh/
+obj-$(CONFIG_SND_SOC)	+= msm/
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
new file mode 100644
index 0000000..70f2f76
--- /dev/null
+++ b/sound/soc/msm/Kconfig
@@ -0,0 +1,23 @@
+menu "MSM SoC Audio support"
+
+config SND_MSM_SOC
+	tristate "SoC Audio for the MSM series chips"
+	depends on ARCH_MSM && SND_SOC
+	select MSM_ADSP
+	help
+	  To add support for ALSA PCM driver for MSM board.
+
+config SND_MSM_DAI_SOC
+	tristate "SoC CPU/CODEC DAI for the MSM chip"
+	depends on SND_MSM_SOC || SND_QSD_SOC
+	help
+	 To add support for ALSA PCM driver for MSM board.
+
+config SND_MSM_SOC_MSM7K
+        tristate "SoC Audio support for MSM7K"
+        depends on SND_MSM_SOC
+        help
+	 To add support for SoC audio on msm7k for msm72x1 or msm7x27
+
+
+endmenu
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
new file mode 100644
index 0000000..d2b38d3
--- /dev/null
+++ b/sound/soc/msm/Makefile
@@ -0,0 +1,11 @@
+# MSM CPU/CODEC DAI Support
+snd-soc-msm-dai-objs := msm-dai.o
+obj-$(CONFIG_SND_MSM_DAI_SOC) += snd-soc-msm-dai.o
+
+# MSM Platform Support
+snd-soc-msm-objs := msm-pcm.o msm7k-pcm.o
+obj-$(CONFIG_SND_MSM_SOC) += snd-soc-msm.o
+
+# MSM Machine Support
+snd-soc-msm7k-objs := msm7201.o
+obj-$(CONFIG_SND_MSM_SOC_MSM7K) += snd-soc-msm7k.o
diff --git a/sound/soc/msm/msm-dai.c b/sound/soc/msm/msm-dai.c
new file mode 100644
index 0000000..564e7fe
--- /dev/null
+++ b/sound/soc/msm/msm-dai.c
@@ -0,0 +1,143 @@
+/* sound/soc/msm/msm-dai.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * Derived from msm-pcm.c and msm7201.c.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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, you can find it at http://www.fsf.org.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include "msm-pcm.h"
+
+struct snd_soc_dai msm_dais[] = {
+{
+	.name = "CODEC_DAI",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = USE_CHANNELS_MIN,
+		.channels_max = USE_CHANNELS_MAX,
+		.rates = USE_RATE,
+		.rate_min = USE_RATE_MIN,
+		.rate_max = USE_RATE_MAX,
+		.formats = USE_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = USE_CHANNELS_MIN,
+		.channels_max = USE_CHANNELS_MAX,
+		.rate_min = USE_RATE_MIN,
+		.rates = USE_RATE,
+		.formats = USE_FORMATS,
+	},
+},
+{
+	.name = "CPU_DAI",
+	.id = 0,
+	.playback = {
+		.channels_min = USE_CHANNELS_MIN,
+		.channels_max = USE_CHANNELS_MAX,
+		.rates = USE_RATE,
+		.rate_min = USE_RATE_MIN,
+		.rate_max = USE_RATE_MAX,
+		.formats = USE_FORMATS,
+	},
+	.capture = {
+		.channels_min = USE_CHANNELS_MIN,
+		.channels_max = USE_CHANNELS_MAX,
+		.rate_min = USE_RATE_MIN,
+		.rates = USE_RATE,
+		.formats = USE_FORMATS,
+	},
+},
+};
+EXPORT_SYMBOL_GPL(msm_dais);
+
+int msm_pcm_probe(struct platform_device *devptr)
+{
+	struct snd_card *card;
+	struct snd_soc_codec *codec;
+	int ret;
+
+	struct snd_soc_device *socdev = platform_get_drvdata(devptr);
+
+	printk(KERN_ERR "msm_soc: create pcms\n");
+	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (codec == NULL)
+		return -ENOMEM;
+
+	codec->name = "MSM-CARD";
+	codec->owner = THIS_MODULE;
+	socdev->codec = codec;
+	mutex_init(&codec->mutex);
+
+	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 "msm_soc: failed to create pcms\n");
+		goto __nopcm;
+	}
+
+	card = socdev->codec->card;
+
+	ret = snd_soc_init_card(socdev);
+	if (ret < 0) {
+		printk(KERN_ERR "msm_soc: failed to register card\n");
+		goto __nodev;
+	}
+
+	return 0;
+
+__nodev:
+	snd_soc_free_pcms(socdev);
+__nopcm:
+	kfree(codec);
+	return ret;
+}
+
+struct snd_soc_codec_device soc_codec_dev_msm = {
+	.probe          = msm_pcm_probe,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_msm);
+
+
+static int __init msm_dai_init(void)
+{
+	return snd_soc_register_dais(msm_dais, ARRAY_SIZE(msm_dais));
+}
+
+static void __exit msm_dai_exit(void)
+{
+	snd_soc_unregister_dais(msm_dais, ARRAY_SIZE(msm_dais));
+}
+
+module_init(msm_dai_init);
+module_exit(msm_dai_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("MSM Codec/Cpu Dai driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-pcm.c b/sound/soc/msm/msm-pcm.c
new file mode 100644
index 0000000..90e200d
--- /dev/null
+++ b/sound/soc/msm/msm-pcm.c
@@ -0,0 +1,643 @@
+/* sound/soc/msm/msm-pcm.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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, you can find it at http://www.fsf.org.
+ */
+
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+
+#include "msm-pcm.h"
+
+#define MAX_DATA_SIZE 496
+#define AUDPP_ALSA_DECODER	(-1)
+
+#define DB_TABLE_INDEX		(50)
+
+#define audio_send_queue_recbs(prtd, cmd, len) \
+	msm_adsp_write(prtd->audrec, QDSP_uPAudRecBitStreamQueue, cmd, len)
+#define audio_send_queue_rec(prtd, cmd, len) \
+	msm_adsp_write(prtd->audrec, QDSP_uPAudRecCmdQueue, cmd, len)
+
+int intcnt;
+static int audio_dsp_send_buffer(struct msm_audio *prtd,
+			unsigned idx, unsigned len);
+
+struct audio_frame {
+	uint16_t count_low;
+	uint16_t count_high;
+	uint16_t bytes;
+	uint16_t unknown;
+	unsigned char samples[];
+} __attribute__ ((packed));
+
+/* Table contains dB to raw value mapping */
+static const unsigned decoder_db_table[] = {
+
+      31 , /* -50 dB */
+      35 ,      39 ,      44 ,      50 ,      56 ,
+      63 ,      70 ,      79 ,      89 ,      99 ,
+     112 ,     125 ,     141 ,     158 ,     177 ,
+     199 ,     223 ,     251 ,     281 ,     316 ,
+     354 ,     398 ,     446 ,     501 ,     562 ,
+     630 ,     707 ,     794 ,     891 ,     999 ,
+    1122 ,    1258 ,    1412 ,    1584 ,    1778 ,
+    1995 ,    2238 ,    2511 ,    2818 ,    3162 ,
+    3548 ,    3981 ,    4466 ,    5011 ,    5623 ,
+    6309 ,    7079 ,    7943 ,    8912 ,   10000 ,
+   11220 ,   12589 ,   14125 ,   15848 ,   17782 ,
+   19952 ,   22387 ,   25118 ,   28183 ,   31622 ,
+   35481 ,   39810 ,   44668 ,   50118 ,   56234 ,
+   63095 ,   70794 ,   79432 ,   89125 ,  100000 ,
+  112201 ,  125892 ,  141253 ,  158489 ,  177827 ,
+  199526 ,  223872 ,  251188 ,  281838 ,  316227 ,
+  354813 ,  398107 ,  446683 ,  501187 ,  562341 ,
+  630957 ,  707945 ,  794328 ,  891250 , 1000000 ,
+ 1122018 , 1258925 , 1412537 , 1584893 , 1778279 ,
+ 1995262 , 2238721 , 2511886 , 2818382 , 3162277 ,
+ 3548133   /*  51 dB */
+
+};
+
+static unsigned compute_db_raw(int db)
+{
+	unsigned reg_val = 0;        /* Computed result for correspondent db */
+	/* Check if the given db is out of range */
+	if (db <= MIN_DB)
+		return 0;
+	else if (db > MAX_DB)
+		db = MAX_DB;       /* If db is too high then set to max    */
+	reg_val = decoder_db_table[DB_TABLE_INDEX+db];
+	return reg_val;
+}
+
+int msm_audio_volume_update(unsigned id,
+				int volume, int pan)
+{
+	unsigned vol_raw;
+
+	vol_raw = compute_db_raw(volume);
+	printk(KERN_INFO "volume: %8x vol_raw: %8x \n", volume, vol_raw);
+	return audpp_set_volume_and_pan(id, vol_raw, pan);
+}
+EXPORT_SYMBOL(msm_audio_volume_update);
+
+void alsa_dsp_event(void *data, unsigned id, uint16_t *msg)
+{
+	struct msm_audio *prtd = data;
+	struct buffer *frame;
+	unsigned long flag;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:
+		break;
+	case AUDPP_MSG_SPA_BANDS:
+		break;
+	case AUDPP_MSG_HOST_PCM_INTF_MSG:{
+			unsigned id = msg[2];
+			unsigned idx = msg[3] - 1;
+			if (id != AUDPP_MSG_HOSTPCM_ID_ARM_RX) {
+				printk(KERN_ERR "bogus id\n");
+				break;
+			}
+			if (idx > 1) {
+				printk(KERN_ERR "bogus buffer idx\n");
+				break;
+			}
+			/* Update with actual sent buffer size */
+			if (prtd->out[idx].used != BUF_INVALID_LEN)
+				prtd->pcm_irq_pos += prtd->out[idx].used;
+
+			if (prtd->pcm_irq_pos > prtd->pcm_size)
+				prtd->pcm_irq_pos = prtd->pcm_count;
+
+			if (prtd->ops->playback)
+				prtd->ops->playback(prtd);
+
+			spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
+			if (prtd->running) {
+				prtd->out[idx].used = 0;
+				frame = prtd->out + prtd->out_tail;
+				if (frame->used) {
+					audio_dsp_send_buffer(prtd,
+							      prtd->out_tail,
+							      frame->used);
+					prtd->out_tail ^= 1;
+				} else {
+					prtd->out_needed++;
+				}
+				wake_up(&the_locks.write_wait);
+			}
+			spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag);
+			break;
+		}
+	case AUDPP_MSG_PCMDMAMISSED:
+		printk(KERN_ERR "alsa_dsp_event: PCMDMAMISSED %d\n", msg[0]);
+		break;
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			prtd->out_needed = 0;
+			prtd->running = 1;
+			audio_dsp_out_enable(prtd, 1);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			prtd->running = 0;
+		} else {
+			printk(KERN_ERR "alsa_dsp_event:CFG_MSG=%d\n", msg[0]);
+		}
+		break;
+	case EVENT_MSG_ID:
+		printk(KERN_INFO"alsa_dsp_event: arm9 event\n");
+		break;
+	default:
+		printk(KERN_ERR "alsa_dsp_event: UNKNOWN (%d)\n", id);
+	}
+}
+
+void alsa_audpre_dsp_event(void *data, unsigned id, size_t len,
+		      void (*getevent) (void *ptr, size_t len))
+{
+	uint16_t msg[MAX_DATA_SIZE/2];
+
+	if (len > MAX_DATA_SIZE) {
+		printk(KERN_ERR"audpre: event too large(%d bytes)\n", len);
+		return;
+	}
+	getevent(msg, len);
+
+	switch (id) {
+	case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
+		break;
+	case AUDPREPROC_MSG_ERROR_MSG_ID:
+		printk(KERN_ERR "audpre: err_index %d\n", msg[0]);
+		break;
+	case EVENT_MSG_ID:
+		printk(KERN_INFO"audpre: arm9 event\n");
+		break;
+	default:
+		printk(KERN_ERR "audpre: unknown event %d\n", id);
+	}
+}
+
+void audrec_dsp_event(void *data, unsigned id, size_t len,
+		      void (*getevent) (void *ptr, size_t len))
+{
+	struct msm_audio *prtd = data;
+	unsigned long flag;
+	uint16_t msg[MAX_DATA_SIZE/2];
+
+	if (len > MAX_DATA_SIZE) {
+		printk(KERN_ERR"audrec: event/msg too large(%d bytes)\n", len);
+		return;
+	}
+	getevent(msg, len);
+
+	switch (id) {
+	case AUDREC_MSG_CMD_CFG_DONE_MSG:
+		if (msg[0] & AUDREC_MSG_CFG_DONE_TYPE_0_UPDATE) {
+			if (msg[0] & AUDREC_MSG_CFG_DONE_TYPE_0_ENA)
+				audrec_encoder_config(prtd);
+			else
+				prtd->running = 0;
+		}
+		break;
+	case AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG:{
+			prtd->running = 1;
+			break;
+		}
+	case AUDREC_MSG_FATAL_ERR_MSG:
+		printk(KERN_ERR "audrec: ERROR %x\n", msg[0]);
+		break;
+	case AUDREC_MSG_PACKET_READY_MSG:
+		alsa_get_dsp_frames(prtd);
+		++intcnt;
+		if (prtd->channel_mode == 1) {
+			spin_lock_irqsave(&the_locks.read_dsp_lock, flag);
+			prtd->pcm_irq_pos += prtd->pcm_count;
+			if (prtd->pcm_irq_pos >= prtd->pcm_size)
+				prtd->pcm_irq_pos = 0;
+			spin_unlock_irqrestore(&the_locks.read_dsp_lock, flag);
+
+			if (prtd->ops->capture)
+				prtd->ops->capture(prtd);
+		} else if ((prtd->channel_mode == 0) && (intcnt % 2 == 0)) {
+			spin_lock_irqsave(&the_locks.read_dsp_lock, flag);
+			prtd->pcm_irq_pos += prtd->pcm_count;
+			if (prtd->pcm_irq_pos >= prtd->pcm_size)
+				prtd->pcm_irq_pos = 0;
+			spin_unlock_irqrestore(&the_locks.read_dsp_lock, flag);
+			if (prtd->ops->capture)
+				prtd->ops->capture(prtd);
+		}
+		break;
+	case EVENT_MSG_ID:
+		printk(KERN_INFO"audrec: arm9 event\n");
+		break;
+	default:
+		printk(KERN_ERR "audrec: unknown event %d\n", id);
+	}
+}
+
+struct msm_adsp_ops aud_pre_adsp_ops = {
+	.event = alsa_audpre_dsp_event,
+};
+
+struct msm_adsp_ops aud_rec_adsp_ops = {
+	.event = audrec_dsp_event,
+};
+
+int alsa_adsp_configure(struct msm_audio *prtd)
+{
+	int ret, i;
+
+	if (prtd->dir == SNDRV_PCM_STREAM_PLAYBACK) {
+		prtd->data = prtd->playback_substream->dma_buffer.area;
+		prtd->phys = prtd->playback_substream->dma_buffer.addr;
+	}
+	if (prtd->dir == SNDRV_PCM_STREAM_CAPTURE) {
+		prtd->data = prtd->capture_substream->dma_buffer.area;
+		prtd->phys = prtd->capture_substream->dma_buffer.addr;
+	}
+	if (!prtd->data) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	ret = audmgr_open(&prtd->audmgr);
+	if (ret)
+		goto err2;
+	if (prtd->dir == SNDRV_PCM_STREAM_PLAYBACK) {
+		prtd->out_buffer_size = PLAYBACK_DMASZ;
+		prtd->out_sample_rate = 44100;
+		prtd->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
+		prtd->out_weight = 100;
+
+		prtd->out[0].data = prtd->data + 0;
+		prtd->out[0].addr = prtd->phys + 0;
+		prtd->out[0].size = BUFSZ;
+		prtd->out[1].data = prtd->data + BUFSZ;
+		prtd->out[1].addr = prtd->phys + BUFSZ;
+		prtd->out[1].size = BUFSZ;
+	}
+	if (prtd->dir == SNDRV_PCM_STREAM_CAPTURE) {
+		prtd->samp_rate = RPC_AUD_DEF_SAMPLE_RATE_44100;
+		prtd->samp_rate_index = AUDREC_CMD_SAMP_RATE_INDX_44100;
+		prtd->channel_mode = AUDREC_CMD_STEREO_MODE_STEREO;
+		prtd->buffer_size = STEREO_DATA_SIZE;
+		prtd->type = AUDREC_CMD_TYPE_0_INDEX_WAV;
+		prtd->tx_agc_cfg.cmd_id = AUDPREPROC_CMD_CFG_AGC_PARAMS;
+		prtd->ns_cfg.cmd_id = AUDPREPROC_CMD_CFG_NS_PARAMS;
+		prtd->iir_cfg.cmd_id =
+		    AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS;
+
+		ret = msm_adsp_get("AUDPREPROCTASK",
+				   &prtd->audpre, &aud_pre_adsp_ops, prtd);
+		if (ret)
+			goto err3;
+		ret = msm_adsp_get("AUDRECTASK",
+				   &prtd->audrec, &aud_rec_adsp_ops, prtd);
+		if (ret) {
+			msm_adsp_put(prtd->audpre);
+			goto err3;
+		}
+		prtd->dsp_cnt = 0;
+		prtd->in_head = 0;
+		prtd->in_tail = 0;
+		prtd->in_count = 0;
+		for (i = 0; i < FRAME_NUM; i++) {
+			prtd->in[i].size = 0;
+			prtd->in[i].read = 0;
+		}
+	}
+
+	return 0;
+
+err3:
+	audmgr_close(&prtd->audmgr);
+
+err2:
+	prtd->data = NULL;
+err1:
+	return ret;
+}
+EXPORT_SYMBOL(alsa_adsp_configure);
+
+int alsa_audio_configure(struct msm_audio *prtd)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	if (prtd->enabled)
+		return 0;
+
+	/* refuse to start if we're not ready with first buffer */
+	if (!prtd->out[0].used)
+		return -EIO;
+
+	cfg.tx_rate = 0;
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+	cfg.def_method = RPC_AUD_DEF_METHOD_HOST_PCM;
+	cfg.codec = RPC_AUD_DEF_CODEC_PCM;
+	cfg.snd_method = RPC_SND_METHOD_MIDI;
+	rc = audmgr_enable(&prtd->audmgr, &cfg);
+	if (rc < 0)
+		return rc;
+
+	if (audpp_enable(AUDPP_ALSA_DECODER, alsa_dsp_event, prtd)) {
+		printk(KERN_ERR "audio: audpp_enable() failed\n");
+		audmgr_disable(&prtd->audmgr);
+		return -ENODEV;
+	}
+
+	prtd->enabled = 1;
+	return 0;
+}
+EXPORT_SYMBOL(alsa_audio_configure);
+
+ssize_t alsa_send_buffer(struct msm_audio *prtd, const char __user *buf,
+			  size_t count, loff_t *pos)
+{
+	unsigned long flag;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	int rc = 0;
+
+	mutex_lock(&the_locks.write_lock);
+	while (count > 0) {
+		frame = prtd->out + prtd->out_head;
+		rc = wait_event_interruptible(the_locks.write_wait,
+					      (frame->used == 0)
+					      || (prtd->stopped));
+		if (rc < 0)
+			break;
+		if (prtd->stopped) {
+			rc = -EBUSY;
+			break;
+		}
+		xfer = count > frame->size ? frame->size : count;
+		if (copy_from_user(frame->data, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+		frame->used = xfer;
+		prtd->out_head ^= 1;
+		count -= xfer;
+		buf += xfer;
+
+		spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
+		frame = prtd->out + prtd->out_tail;
+		if (frame->used && prtd->out_needed) {
+			audio_dsp_send_buffer(prtd, prtd->out_tail,
+					      frame->used);
+			prtd->out_tail ^= 1;
+			prtd->out_needed--;
+		}
+		spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag);
+	}
+	mutex_unlock(&the_locks.write_lock);
+	if (buf > start)
+		return buf - start;
+	return rc;
+}
+EXPORT_SYMBOL(alsa_send_buffer);
+
+int alsa_audio_disable(struct msm_audio *prtd)
+{
+	if (prtd->enabled) {
+		mutex_lock(&the_locks.lock);
+		prtd->enabled = 0;
+		audio_dsp_out_enable(prtd, 0);
+		wake_up(&the_locks.write_wait);
+		audpp_disable(AUDPP_ALSA_DECODER, prtd);
+		audmgr_disable(&prtd->audmgr);
+		prtd->out_needed = 0;
+		mutex_unlock(&the_locks.lock);
+	}
+	return 0;
+}
+EXPORT_SYMBOL(alsa_audio_disable);
+
+int alsa_audrec_disable(struct msm_audio *prtd)
+{
+	if (prtd->enabled) {
+		mutex_lock(&the_locks.lock);
+		prtd->enabled = 0;
+		alsa_rec_dsp_enable(prtd, 0);
+		wake_up(&the_locks.read_wait);
+		msm_adsp_disable(prtd->audpre);
+		msm_adsp_disable(prtd->audrec);
+		audmgr_disable(&prtd->audmgr);
+		prtd->out_needed = 0;
+		prtd->opened = 0;
+		mutex_unlock(&the_locks.lock);
+	}
+	return 0;
+}
+EXPORT_SYMBOL(alsa_audrec_disable);
+
+static int audio_dsp_read_buffer(struct msm_audio *prtd, uint32_t read_cnt)
+{
+	audrec_cmd_packet_ext_ptr cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_PACKET_EXT_PTR;
+	/* Both WAV and AAC use AUDREC_CMD_TYPE_0 */
+	cmd.type = AUDREC_CMD_TYPE_0;
+	cmd.curr_rec_count_msw = read_cnt >> 16;
+	cmd.curr_rec_count_lsw = read_cnt;
+
+	return audio_send_queue_recbs(prtd, &cmd, sizeof(cmd));
+}
+
+int audrec_encoder_config(struct msm_audio *prtd)
+{
+	audrec_cmd_arec0param_cfg cmd;
+	uint16_t *data = (void *)prtd->data;
+	unsigned n;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_AREC0PARAM_CFG;
+	cmd.ptr_to_extpkt_buffer_msw = prtd->phys >> 16;
+	cmd.ptr_to_extpkt_buffer_lsw = prtd->phys;
+	cmd.buf_len = FRAME_NUM;	/* Both WAV and AAC use 8 frames */
+	cmd.samp_rate_index = prtd->samp_rate_index;
+	/* 0 for mono, 1 for stereo */
+	cmd.stereo_mode = prtd->channel_mode;
+	cmd.rec_quality = 0x1C00;
+
+	/* prepare buffer pointers:
+	 * Mono: 1024 samples + 4 halfword header
+	 * Stereo: 2048 samples + 4 halfword header
+	 */
+
+	for (n = 0; n < FRAME_NUM; n++) {
+		prtd->in[n].data = data + 4;
+		data += (4 + (prtd->channel_mode ? 2048 : 1024));
+	}
+
+	return audio_send_queue_rec(prtd, &cmd, sizeof(cmd));
+}
+
+int audio_dsp_out_enable(struct msm_audio *prtd, int yes)
+{
+	audpp_cmd_pcm_intf cmd;
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_PCM_INTF_2;
+	cmd.object_num = AUDPP_CMD_PCM_INTF_OBJECT_NUM;
+	cmd.config = AUDPP_CMD_PCM_INTF_CONFIG_CMD_V;
+	cmd.intf_type = AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V;
+
+	if (yes) {
+		cmd.write_buf1LSW = prtd->out[0].addr;
+		cmd.write_buf1MSW = prtd->out[0].addr >> 16;
+		cmd.write_buf1_len = 0;
+		cmd.write_buf2LSW = prtd->out[1].addr;
+		cmd.write_buf2MSW = prtd->out[1].addr >> 16;
+		cmd.write_buf2_len = prtd->out[1].used;
+		cmd.arm_to_rx_flag = AUDPP_CMD_PCM_INTF_ENA_V;
+		cmd.weight_decoder_to_rx = prtd->out_weight;
+		cmd.weight_arm_to_rx = 1;
+		cmd.partition_number_arm_to_dsp = 0;
+		cmd.sample_rate = prtd->out_sample_rate;
+		cmd.channel_mode = prtd->out_channel_mode;
+	}
+	return audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+int alsa_buffer_read(struct msm_audio *prtd, void __user *buf,
+		      size_t count, loff_t *pos)
+{
+	unsigned long flag;
+	void *data;
+	uint32_t index;
+	uint32_t size;
+	int rc = 0;
+
+	mutex_lock(&the_locks.read_lock);
+	while (count > 0) {
+		rc = wait_event_interruptible(the_locks.read_wait,
+					      (prtd->in_count > 0)
+					      || prtd->stopped);
+		if (rc < 0)
+			break;
+
+		if (prtd->stopped) {
+			rc = -EBUSY;
+			break;
+		}
+
+		index = prtd->in_tail;
+		data = (uint8_t *) prtd->in[index].data;
+		size = prtd->in[index].size;
+		if (count >= size) {
+			if (copy_to_user(buf, data, size)) {
+				rc = -EFAULT;
+				break;
+			}
+			spin_lock_irqsave(&the_locks.read_dsp_lock, flag);
+			if (index != prtd->in_tail) {
+				/* overrun: data is invalid, we need to retry */
+				spin_unlock_irqrestore(&the_locks.read_dsp_lock,
+						       flag);
+				continue;
+			}
+			prtd->in[index].size = 0;
+			prtd->in_tail = (prtd->in_tail + 1) & (FRAME_NUM - 1);
+			prtd->in_count--;
+			spin_unlock_irqrestore(&the_locks.read_dsp_lock, flag);
+			count -= size;
+			buf += size;
+		} else {
+			break;
+		}
+	}
+	mutex_unlock(&the_locks.read_lock);
+	return rc;
+}
+EXPORT_SYMBOL(alsa_buffer_read);
+
+static int audio_dsp_send_buffer(struct msm_audio *prtd,
+					unsigned idx, unsigned len)
+{
+	audpp_cmd_pcm_intf_send_buffer cmd;
+	cmd.cmd_id = AUDPP_CMD_PCM_INTF_2;
+	cmd.host_pcm_object = AUDPP_CMD_PCM_INTF_OBJECT_NUM;
+	cmd.config = AUDPP_CMD_PCM_INTF_BUFFER_CMD_V;
+	cmd.intf_type = AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V;
+	cmd.dsp_to_arm_buf_id = 0;
+	cmd.arm_to_dsp_buf_id = idx + 1;
+	cmd.arm_to_dsp_buf_len = len;
+	return audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+int alsa_rec_dsp_enable(struct msm_audio *prtd, int enable)
+{
+	audrec_cmd_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_CFG;
+	cmd.type_0 = enable ? AUDREC_CMD_TYPE_0_ENA : AUDREC_CMD_TYPE_0_DIS;
+	cmd.type_0 |= (AUDREC_CMD_TYPE_0_UPDATE | prtd->type);
+	cmd.type_1 = 0;
+
+	return audio_send_queue_rec(prtd, &cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(alsa_rec_dsp_enable);
+
+void alsa_get_dsp_frames(struct msm_audio *prtd)
+{
+	struct audio_frame *frame;
+	uint32_t index = 0;
+	unsigned long flag;
+
+	if (prtd->type == AUDREC_CMD_TYPE_0_INDEX_WAV) {
+		index = prtd->in_head;
+
+		frame =
+		    (void *)(((char *)prtd->in[index].data) - sizeof(*frame));
+
+		spin_lock_irqsave(&the_locks.read_dsp_lock, flag);
+		prtd->in[index].size = frame->bytes;
+
+		prtd->in_head = (prtd->in_head + 1) & (FRAME_NUM - 1);
+
+		/* If overflow, move the tail index foward. */
+		if (prtd->in_head == prtd->in_tail)
+			prtd->in_tail = (prtd->in_tail + 1) & (FRAME_NUM - 1);
+		else
+			prtd->in_count++;
+
+		audio_dsp_read_buffer(prtd, prtd->dsp_cnt++);
+		spin_unlock_irqrestore(&the_locks.read_dsp_lock, flag);
+
+		wake_up(&the_locks.read_wait);
+	} else {
+		/* TODO AAC not supported yet. */
+	}
+}
+EXPORT_SYMBOL(alsa_get_dsp_frames);
diff --git a/sound/soc/msm/msm-pcm.h b/sound/soc/msm/msm-pcm.h
new file mode 100644
index 0000000..7563ef0
--- /dev/null
+++ b/sound/soc/msm/msm-pcm.h
@@ -0,0 +1,200 @@
+/* sound/soc/msm/msm-pcm.h
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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, you can find it at http://www.fsf.org.
+ */
+
+#ifndef _MSM_PCM_H
+#define _MSM_PCM_H
+
+
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audreccmdi.h>
+#include <mach/qdsp5/qdsp5audrecmsg.h>
+#include <mach/qdsp5/qdsp5audpreproccmdi.h>
+#include <mach/qdsp5/qdsp5audpreprocmsg.h>
+
+#include <../arch/arm/mach-msm/qdsp5/adsp.h>
+#include <../arch/arm/mach-msm/qdsp5/audmgr.h>
+
+
+#define FRAME_NUM               (8)
+#define FRAME_SIZE              (2052 * 2)
+#define MONO_DATA_SIZE          (2048)
+#define STEREO_DATA_SIZE        (MONO_DATA_SIZE * 2)
+#define CAPTURE_DMASZ           (FRAME_SIZE * FRAME_NUM)
+
+#define BUFSZ			(960 * 5)
+#define PLAYBACK_DMASZ 		(BUFSZ * 2)
+
+#define MSM_PLAYBACK_DEFAULT_VOLUME 0 /* 0dB */
+#define MSM_PLAYBACK_DEFAULT_PAN 0
+
+#define USE_FORMATS             SNDRV_PCM_FMTBIT_S16_LE
+#define USE_CHANNELS_MIN        1
+#define USE_CHANNELS_MAX        2
+/* Support unconventional sample rates 12000, 24000 as well */
+#define USE_RATE                \
+			(SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT)
+#define USE_RATE_MIN            8000
+#define USE_RATE_MAX            48000
+#define MAX_BUFFER_PLAYBACK_SIZE \
+				(4800*4)
+/* 2048 frames (Mono), 1024 frames (Stereo) */
+#define CAPTURE_SIZE		4096
+#define MAX_BUFFER_CAPTURE_SIZE (4096*4)
+#define MAX_PERIOD_SIZE         BUFSZ
+#define USE_PERIODS_MAX         1024
+#define USE_PERIODS_MIN		1
+
+
+#define MAX_DB			(16)
+#define MIN_DB			(-50)
+#define PCMPLAYBACK_DECODERID   5
+
+/* 0xFFFFFFFF Indicates not to be used for audio data copy */
+#define	BUF_INVALID_LEN		0xFFFFFFFF
+
+extern int copy_count;
+extern int intcnt;
+
+struct msm_volume {
+	bool update;
+	int volume; /* Volume parameter, in dB Scale */
+	int pan;
+};
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;
+	unsigned addr;
+};
+
+struct buffer_rec {
+	void *data;
+	unsigned int size;
+	unsigned int read;
+	unsigned int addr;
+};
+
+struct audio_locks {
+	struct mutex lock;
+	struct mutex write_lock;
+	struct mutex read_lock;
+	spinlock_t read_dsp_lock;
+	spinlock_t write_dsp_lock;
+	spinlock_t mixer_lock;
+	wait_queue_head_t read_wait;
+	wait_queue_head_t write_wait;
+};
+
+extern struct audio_locks the_locks;
+
+struct msm_audio_event_callbacks {
+	/* event is called from interrupt context when a message
+	 * arrives from the DSP.
+	*/
+	void (*playback)(void *);
+	void (*capture)(void *);
+};
+
+
+struct msm_audio {
+	struct buffer out[2];
+	struct buffer_rec in[8];
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed; /* number of buffers the dsp is waiting for */
+	atomic_t out_bytes;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+	uint32_t out_weight;
+	uint32_t out_buffer_size;
+
+	struct audmgr audmgr;
+	struct snd_pcm_substream *playback_substream;
+	struct snd_pcm_substream *capture_substream;
+
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+
+	unsigned int pcm_size;
+	unsigned int pcm_count;
+	unsigned int pcm_irq_pos;       /* IRQ position */
+	unsigned int pcm_buf_pos;       /* position in buffer */
+
+	struct msm_adsp_module *audpre;
+	struct msm_adsp_module *audrec;
+
+	/* configuration to use on next enable */
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+	uint32_t buffer_size; /* 2048 for mono, 4096 for stereo */
+	uint32_t type; /* 0 for PCM ,1 for AAC */
+	uint32_t dsp_cnt;
+	uint32_t in_head; /* next buffer dsp will write */
+	uint32_t in_tail; /* next buffer read() will read */
+	uint32_t in_count; /* number of buffers available to read() */
+
+	unsigned short samp_rate_index;
+
+	/* audpre settings */
+	audpreproc_cmd_cfg_agc_params tx_agc_cfg;
+	audpreproc_cmd_cfg_ns_params ns_cfg;
+	/* For different sample rate, the coeff might be different. *
+	* All the coeff should be passed from user space           */
+	audpreproc_cmd_cfg_iir_tuning_filter_params iir_cfg;
+
+	struct  msm_audio_event_callbacks *ops;
+
+	int dir;
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+};
+
+
+
+/* platform data */
+extern int audio_dsp_out_enable(struct msm_audio *prtd, int yes);
+extern struct snd_soc_platform msm_soc_platform;
+extern struct snd_soc_dai msm_dais[2];
+extern struct snd_soc_codec_device soc_codec_dev_msm;
+
+int audrec_encoder_config(struct msm_audio *prtd);
+extern void alsa_get_dsp_frames(struct msm_audio *prtd);
+extern int alsa_rec_dsp_enable(struct msm_audio *prtd, int enable);
+extern int alsa_audrec_disable(struct msm_audio *prtd);
+extern int alsa_audio_configure(struct msm_audio *prtd);
+extern int alsa_audio_disable(struct msm_audio *prtd);
+extern int alsa_adsp_configure(struct msm_audio *prtd);
+extern int alsa_buffer_read(struct msm_audio *prtd, void __user *buf,
+					size_t count, loff_t *pos);
+ssize_t alsa_send_buffer(struct msm_audio *prtd, const char __user *buf,
+					size_t count, loff_t *pos);
+int msm_audio_volume_update(unsigned id,
+				int volume, int pan);
+extern struct audio_locks the_locks;
+extern struct msm_volume msm_vol_ctl;
+
+#endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/msm7201.c b/sound/soc/msm/msm7201.c
new file mode 100644
index 0000000..977fbac
--- /dev/null
+++ b/sound/soc/msm/msm7201.c
@@ -0,0 +1,337 @@
+/* linux/sound/soc/msm/msm7201.c
+ *
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * 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, you can find it at http://www.fsf.org.
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+
+#include "msm-pcm.h"
+#include <asm/mach-types.h>
+#include <mach/msm_rpcrouter.h>
+
+static struct msm_rpc_endpoint *snd_ep;
+
+struct msm_snd_rpc_ids {
+	unsigned long   prog;
+	unsigned long   vers;
+	unsigned long   rpc_set_snd_device;
+	int device;
+};
+
+static struct msm_snd_rpc_ids snd_rpc_ids;
+
+static struct platform_device *msm_audio_snd_device;
+
+static int snd_msm_volume_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1; /* Volume Param, in dB */
+	uinfo->value.integer.min = MIN_DB;
+	uinfo->value.integer.max = MAX_DB;
+	return 0;
+}
+
+static int snd_msm_volume_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	spin_lock_irq(&the_locks.mixer_lock);
+	ucontrol->value.integer.value[0] = msm_vol_ctl.volume;
+	spin_unlock_irq(&the_locks.mixer_lock);
+	return 0;
+}
+
+static int snd_msm_volume_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int change;
+	int volume;
+
+	volume = ucontrol->value.integer.value[0];
+	spin_lock_irq(&the_locks.mixer_lock);
+	change = (msm_vol_ctl.volume != volume);
+	if (change) {
+		msm_vol_ctl.update = 1;
+		msm_vol_ctl.volume = volume;
+	}
+	spin_unlock_irq(&the_locks.mixer_lock);
+	return change;
+}
+
+static int snd_msm_device_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1; /* Device */
+
+	/*
+	 * The number of devices supported is 26 (0 to 25)
+	 */
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 25;
+	return 0;
+}
+
+static int snd_msm_device_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = (uint32_t)snd_rpc_ids.device;
+	return 0;
+}
+
+int msm_snd_init_rpc_ids(void)
+{
+	snd_rpc_ids.prog	= 0x30000002;
+#ifdef CONFIG_MSM_AMSS_VERSION_6225
+	//TODO: complete for other versions
+	snd_rpc_ids.vers	= 0xaa2b1a44;
+#else
+	//seem a new magich number...not in arch/arm/mach-msm and it seem to be for a new amss version
+	snd_rpc_ids.vers	= 0x00020001;
+#endif
+	/*
+	 * The magic number 2 corresponds to the rpc call
+	 * index for snd_set_device
+	 */
+	snd_rpc_ids.rpc_set_snd_device = 2;
+	return 0;
+}
+
+int msm_snd_rpc_connect(void)
+{
+	if (snd_ep) {
+		printk(KERN_INFO "%s: snd_ep already connected\n", __func__);
+		return 0;
+	}
+
+	/* Initialize rpc ids */
+	if (msm_snd_init_rpc_ids()) {
+		printk(KERN_ERR "%s: snd rpc ids initialization failed\n"
+			, __func__);
+		return -ENODATA;
+	}
+
+	snd_ep = msm_rpc_connect(snd_rpc_ids.prog,
+				snd_rpc_ids.vers, 0);
+	if (IS_ERR(snd_ep)) {
+		printk(KERN_ERR "%s: failed (compatible VERS = %ld)\n",
+				__func__, snd_rpc_ids.vers);
+		snd_ep = NULL;
+		return -EAGAIN;
+	}
+	return 0;
+}
+
+int msm_snd_rpc_close(void)
+{
+	int rc = 0;
+
+	if (IS_ERR(snd_ep)) {
+		printk(KERN_ERR "%s: snd handle unavailable, rc = %ld\n",
+				__func__, PTR_ERR(snd_ep));
+		return -EAGAIN;
+	}
+
+	rc = msm_rpc_close(snd_ep);
+	snd_ep = NULL;
+
+	if (rc < 0) {
+		printk(KERN_ERR "%s: close rpc failed! rc = %d\n",
+				__func__, rc);
+		return -EAGAIN;
+	} else
+		printk(KERN_INFO "rpc close success\n");
+
+	return rc;
+}
+
+static int snd_msm_device_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	int rc = 0;
+	struct snd_start_req {
+		struct rpc_request_hdr hdr;
+		uint32_t rpc_snd_device;
+		uint32_t snd_mute_ear_mute;
+		uint32_t snd_mute_mic_mute;
+		uint32_t callback_ptr;
+		uint32_t client_data;
+	} req;
+
+	snd_rpc_ids.device = (int)ucontrol->value.integer.value[0];
+	req.hdr.type = 0;
+	req.hdr.rpc_vers = 2;
+
+	req.rpc_snd_device = cpu_to_be32(snd_rpc_ids.device);
+	req.snd_mute_ear_mute = cpu_to_be32(1);
+	req.snd_mute_mic_mute = cpu_to_be32(0);
+	req.callback_ptr = -1;
+	req.client_data = cpu_to_be32(0);
+
+	req.hdr.prog = snd_rpc_ids.prog;
+	req.hdr.vers = snd_rpc_ids.vers;
+
+	rc = msm_rpc_call(snd_ep, snd_rpc_ids.rpc_set_snd_device ,
+			&req, sizeof(req), 5 * HZ);
+
+	if (rc < 0) {
+		printk(KERN_ERR "%s: snd rpc call failed! rc = %d\n",
+			__func__, rc);
+	} else
+		printk(KERN_INFO "snd device connected \n");
+
+	return rc;
+}
+
+/* Supported range -50dB to 18dB */
+static const DECLARE_TLV_DB_LINEAR(db_scale_linear, -5000, 1800);
+
+#define MSM_EXT(xname, xindex, fp_info, fp_get, fp_put, addr) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+  .name = xname, .index = xindex, \
+  .info = fp_info,\
+  .get = fp_get, .put = fp_put, \
+  .private_value = addr, \
+}
+
+#define MSM_EXT_TLV(xname, xindex, fp_info, fp_get, fp_put, addr, tlv_array) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+  .access = (SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+		SNDRV_CTL_ELEM_ACCESS_READWRITE), \
+  .name = xname, .index = xindex, \
+  .info = fp_info,\
+  .get = fp_get, .put = fp_put, .tlv.p = tlv_array, \
+  .private_value = addr, \
+}
+
+static struct snd_kcontrol_new snd_msm_controls[] = {
+	MSM_EXT_TLV("PCM Playback Volume", 0, snd_msm_volume_info, \
+	snd_msm_volume_get, snd_msm_volume_put, 0, db_scale_linear),
+	MSM_EXT("device", 1, snd_msm_device_info, snd_msm_device_get, \
+						 snd_msm_device_put, 0),
+};
+
+static int msm_new_mixer(struct snd_card *card)
+{
+	unsigned int idx;
+	int err;
+
+	printk(KERN_ERR "msm_soc:ALSA MSM Mixer Setting");
+	strcpy(card->mixername, "MSM Mixer");
+	for (idx = 0; idx < ARRAY_SIZE(snd_msm_controls); idx++) {
+		err = snd_ctl_add(card,
+				snd_ctl_new1(&snd_msm_controls[idx], NULL));
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+static int msm_soc_dai_init(struct snd_soc_codec *codec)
+{
+
+	int ret = 0;
+	ret = msm_new_mixer(codec->card);
+	if (ret < 0) {
+		printk(KERN_ERR "msm_soc:ALSA MSM Mixer Fail");
+	}
+
+	return ret;
+}
+
+
+static struct snd_soc_dai_link msm_dai = {
+	.name = "ASOC",
+	.stream_name = "ASOC",
+	.codec_dai = &msm_dais[0],
+	.cpu_dai = &msm_dais[1],
+	.init	= msm_soc_dai_init,
+};
+
+struct snd_soc_card snd_soc_card_msm = {
+	.name 		= "msm-audio",
+	.dai_link	= &msm_dai,
+	.num_links = 1,
+	.platform = &msm_soc_platform,
+};
+
+/* msm_audio audio subsystem */
+static struct snd_soc_device msm_audio_snd_devdata = {
+	.card = &snd_soc_card_msm,
+	.codec_dev = &soc_codec_dev_msm,
+};
+
+
+static int __init msm_audio_init(void)
+{
+	int ret;
+
+	msm_audio_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!msm_audio_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(msm_audio_snd_device, &msm_audio_snd_devdata);
+	msm_audio_snd_devdata.dev = &msm_audio_snd_device->dev;
+	ret = platform_device_add(msm_audio_snd_device);
+	if (ret) {
+		platform_device_put(msm_audio_snd_device);
+		return ret;
+	}
+	mutex_init(&the_locks.lock);
+	mutex_init(&the_locks.write_lock);
+	mutex_init(&the_locks.read_lock);
+	spin_lock_init(&the_locks.read_dsp_lock);
+	spin_lock_init(&the_locks.write_dsp_lock);
+	spin_lock_init(&the_locks.mixer_lock);
+	init_waitqueue_head(&the_locks.write_wait);
+	init_waitqueue_head(&the_locks.read_wait);
+	msm_vol_ctl.volume = MSM_PLAYBACK_DEFAULT_VOLUME;
+	msm_vol_ctl.pan = MSM_PLAYBACK_DEFAULT_PAN;
+
+	ret = msm_snd_rpc_connect();
+
+	return ret;
+}
+
+static void __exit msm_audio_exit(void)
+{
+	msm_snd_rpc_close();
+	platform_device_unregister(msm_audio_snd_device);
+}
+
+module_init(msm_audio_init);
+module_exit(msm_audio_exit);
+
+MODULE_DESCRIPTION("PCM module");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm7k-pcm.c b/sound/soc/msm/msm7k-pcm.c
new file mode 100644
index 0000000..38e8283
--- /dev/null
+++ b/sound/soc/msm/msm7k-pcm.c
@@ -0,0 +1,574 @@
+/* linux/sound/soc/msm/msm7k-pcm.c
+ *
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * 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, you can find it at http://www.fsf.org.
+ */
+
+
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+
+#include "msm-pcm.h"
+
+#define SND_DRIVER        "snd_msm"
+#define MAX_PCM_DEVICES	SNDRV_CARDS
+#define MAX_PCM_SUBSTREAMS 1
+
+struct snd_msm {
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+};
+
+int copy_count;
+
+struct audio_locks the_locks;
+EXPORT_SYMBOL(the_locks);
+struct msm_volume msm_vol_ctl;
+EXPORT_SYMBOL(msm_vol_ctl);
+
+
+static unsigned convert_dsp_samp_index(unsigned index)
+{
+	switch (index) {
+	case 48000:
+		return AUDREC_CMD_SAMP_RATE_INDX_48000;
+	case 44100:
+		return AUDREC_CMD_SAMP_RATE_INDX_44100;
+	case 32000:
+		return AUDREC_CMD_SAMP_RATE_INDX_32000;
+	case 24000:
+		return AUDREC_CMD_SAMP_RATE_INDX_24000;
+	case 22050:
+		return AUDREC_CMD_SAMP_RATE_INDX_22050;
+	case 16000:
+		return AUDREC_CMD_SAMP_RATE_INDX_16000;
+	case 12000:
+		return AUDREC_CMD_SAMP_RATE_INDX_12000;
+	case 11025:
+		return AUDREC_CMD_SAMP_RATE_INDX_11025;
+	case 8000:
+		return AUDREC_CMD_SAMP_RATE_INDX_8000;
+	default:
+		return AUDREC_CMD_SAMP_RATE_INDX_44100;
+	}
+}
+
+static unsigned convert_samp_rate(unsigned hz)
+{
+	switch (hz) {
+	case 48000:
+		return RPC_AUD_DEF_SAMPLE_RATE_48000;
+	case 44100:
+		return RPC_AUD_DEF_SAMPLE_RATE_44100;
+	case 32000:
+		return RPC_AUD_DEF_SAMPLE_RATE_32000;
+	case 24000:
+		return RPC_AUD_DEF_SAMPLE_RATE_24000;
+	case 22050:
+		return RPC_AUD_DEF_SAMPLE_RATE_22050;
+	case 16000:
+		return RPC_AUD_DEF_SAMPLE_RATE_16000;
+	case 12000:
+		return RPC_AUD_DEF_SAMPLE_RATE_12000;
+	case 11025:
+		return RPC_AUD_DEF_SAMPLE_RATE_11025;
+	case 8000:
+		return RPC_AUD_DEF_SAMPLE_RATE_8000;
+	default:
+		return RPC_AUD_DEF_SAMPLE_RATE_44100;
+	}
+}
+
+static struct snd_pcm_hardware msm_pcm_playback_hardware = {
+	.info =                 SNDRV_PCM_INFO_INTERLEAVED,
+	.formats =              USE_FORMATS,
+	.rates =                USE_RATE,
+	.rate_min =             USE_RATE_MIN,
+	.rate_max =             USE_RATE_MAX,
+	.channels_min =         USE_CHANNELS_MIN,
+	.channels_max =         USE_CHANNELS_MAX,
+	.buffer_bytes_max =     MAX_BUFFER_PLAYBACK_SIZE,
+	.period_bytes_min =     64,
+	.period_bytes_max =     MAX_PERIOD_SIZE,
+	.periods_min =          USE_PERIODS_MIN,
+	.periods_max =          USE_PERIODS_MAX,
+	.fifo_size =            0,
+};
+
+static struct snd_pcm_hardware msm_pcm_capture_hardware = {
+	.info =                 SNDRV_PCM_INFO_INTERLEAVED,
+	.formats =		USE_FORMATS,
+	.rates =		USE_RATE,
+	.rate_min =		USE_RATE_MIN,
+	.rate_max =		USE_RATE_MAX,
+	.channels_min =		USE_CHANNELS_MIN,
+	.channels_max =		USE_CHANNELS_MAX,
+	.buffer_bytes_max =	MAX_BUFFER_CAPTURE_SIZE,
+	.period_bytes_min =	CAPTURE_SIZE,
+	.period_bytes_max =	CAPTURE_SIZE,
+	.periods_min =		USE_PERIODS_MIN,
+	.periods_max =		USE_PERIODS_MAX,
+	.fifo_size =		0,
+};
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+	.count = ARRAY_SIZE(supported_sample_rates),
+	.list = supported_sample_rates,
+	.mask = 0,
+};
+
+static void playback_event_handler(void *data)
+{
+	struct msm_audio *prtd = data;
+	snd_pcm_period_elapsed(prtd->playback_substream);
+}
+
+static void capture_event_handler(void *data)
+{
+	struct msm_audio *prtd = data;
+	snd_pcm_period_elapsed(prtd->capture_substream);
+}
+
+static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+	prtd->pcm_buf_pos = 0;
+
+	/* rate and channels are sent to audio driver */
+	prtd->out_sample_rate = runtime->rate;
+	prtd->out_channel_mode = runtime->channels;
+
+	return 0;
+}
+
+static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	struct audmgr_config cfg;
+	int rc;
+
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+	prtd->pcm_buf_pos = 0;
+
+	/* rate and channels are sent to audio driver */
+	prtd->samp_rate = convert_samp_rate(runtime->rate);
+	prtd->samp_rate_index = convert_dsp_samp_index(runtime->rate);
+	prtd->channel_mode = (runtime->channels - 1);
+	prtd->buffer_size = prtd->channel_mode ? STEREO_DATA_SIZE : \
+							MONO_DATA_SIZE;
+
+	if (prtd->enabled == 1)
+		return 0;
+
+	prtd->type = AUDREC_CMD_TYPE_0_INDEX_WAV;
+
+	cfg.tx_rate = convert_samp_rate(runtime->rate);
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+	cfg.def_method = RPC_AUD_DEF_METHOD_RECORD;
+	cfg.codec = RPC_AUD_DEF_CODEC_PCM;
+	cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+	rc = audmgr_enable(&prtd->audmgr, &cfg);
+	if (rc < 0)
+		return rc;
+
+	if (msm_adsp_enable(prtd->audpre)) {
+		audmgr_disable(&prtd->audmgr);
+		return -ENODEV;
+	}
+	if (msm_adsp_enable(prtd->audrec)) {
+		msm_adsp_disable(prtd->audpre);
+		audmgr_disable(&prtd->audmgr);
+		return -ENODEV;
+	}
+	prtd->enabled = 1;
+	alsa_rec_dsp_enable(prtd, 1);
+
+	return 0;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static snd_pcm_uframes_t
+msm_pcm_playback_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	if (prtd->pcm_irq_pos == prtd->pcm_size)
+		prtd->pcm_irq_pos = 0;
+	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
+}
+
+static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
+		 int channel, snd_pcm_uframes_t hwoff, void __user *buf,
+						 snd_pcm_uframes_t frames)
+{
+	int rc = 0, rc1 = 0, rc2 = 0;
+	int fbytes = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = substream->runtime->private_data;
+
+	int monofbytes = 0;
+	char *bufferp = NULL;
+
+	fbytes = frames_to_bytes(runtime, frames);
+	monofbytes = fbytes / 2;
+	if (runtime->channels == 2) {
+		rc = alsa_buffer_read(prtd, buf, fbytes, NULL);
+	} else {
+		bufferp = buf;
+		rc1 = alsa_buffer_read(prtd, bufferp, monofbytes, NULL);
+		bufferp = buf + monofbytes ;
+		rc2 = alsa_buffer_read(prtd, bufferp, monofbytes, NULL);
+		rc = rc1 + rc2;
+	}
+	prtd->pcm_buf_pos += fbytes;
+	return rc;
+}
+
+static snd_pcm_uframes_t
+msm_pcm_capture_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
+}
+
+static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	alsa_audrec_disable(prtd);
+	audmgr_close(&prtd->audmgr);
+	msm_adsp_put(prtd->audrec);
+	msm_adsp_put(prtd->audpre);
+	kfree(prtd);
+
+	return 0;
+}
+
+struct  msm_audio_event_callbacks snd_msm_audio_ops = {
+	.playback = playback_event_handler,
+	.capture = capture_event_handler,
+};
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd;
+	int ret = 0;
+
+	prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
+	if (prtd == NULL) {
+		ret = -ENOMEM;
+		return ret;
+	}
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		msm_vol_ctl.update = 1; /* Update Volume, with Cached value */
+		runtime->hw = msm_pcm_playback_hardware;
+		prtd->dir = SNDRV_PCM_STREAM_PLAYBACK;
+		prtd->playback_substream = substream;
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		runtime->hw = msm_pcm_capture_hardware;
+		prtd->dir = SNDRV_PCM_STREAM_CAPTURE;
+		prtd->capture_substream = substream;
+	}
+	ret = snd_pcm_hw_constraint_list(runtime, 0,
+						SNDRV_PCM_HW_PARAM_RATE,
+						&constraints_sample_rates);
+	if (ret < 0)
+		goto out;
+	/* Ensure that buffer size is a multiple of period size */
+	ret = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		goto out;
+
+	prtd->ops = &snd_msm_audio_ops;
+	prtd->out[0].used = BUF_INVALID_LEN;
+	prtd->out_head = 1; /* point to second buffer on startup */
+	runtime->private_data = prtd;
+
+	ret = alsa_adsp_configure(prtd);
+	if (ret)
+		goto out;
+	copy_count = 0;
+	return 0;
+
+ out:
+	kfree(prtd);
+	return ret;
+}
+
+static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
+	snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+	int rc = 1;
+	int fbytes = 0;
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	fbytes = frames_to_bytes(runtime, frames);
+	rc = alsa_send_buffer(prtd, buf, fbytes, NULL);
+	++copy_count;
+	prtd->pcm_buf_pos += fbytes;
+	if (copy_count == 1) {
+		mutex_lock(&the_locks.lock);
+		alsa_audio_configure(prtd);
+		mutex_unlock(&the_locks.lock);
+	}
+	if ((prtd->running) && (msm_vol_ctl.update)) {
+		rc = msm_audio_volume_update(PCMPLAYBACK_DECODERID,
+				msm_vol_ctl.volume, msm_vol_ctl.pan);
+		msm_vol_ctl.update = 0;
+	}
+
+	return  rc;
+}
+
+static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	alsa_audio_disable(prtd);
+	audmgr_close(&prtd->audmgr);
+	kfree(prtd);
+
+	return 0;
+}
+
+
+static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
+	 snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_copy(substream, a, hwoff, buf, frames);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
+	return ret;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_close(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_close(substream);
+	return ret;
+}
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_prepare(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_prepare(substream);
+	return ret;
+}
+
+static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	snd_pcm_uframes_t ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_pointer(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_pointer(substream);
+	return ret;
+}
+
+int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	if (substream->pcm->device & 1) {
+		runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
+		runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
+	}
+	return 0;
+
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+	.open           = msm_pcm_open,
+	.copy		= msm_pcm_copy,
+	.hw_params	= msm_pcm_hw_params,
+	.close          = msm_pcm_close,
+	.ioctl          = snd_pcm_lib_ioctl,
+	.prepare        = msm_pcm_prepare,
+	.trigger        = msm_pcm_trigger,
+	.pointer        = msm_pcm_pointer,
+};
+
+
+
+static int msm_pcm_remove(struct platform_device *devptr)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(devptr);
+	snd_soc_free_pcms(socdev);
+	kfree(socdev->codec);
+	platform_set_drvdata(devptr, NULL);
+	return 0;
+}
+
+static int 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;
+	if (!stream)
+		size = PLAYBACK_DMASZ;
+	else
+		size = CAPTURE_DMASZ;
+
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+	buf->area = dma_alloc_coherent(pcm->card->dev, size,
+					   &buf->addr, GFP_KERNEL);
+	if (!buf->area)
+		return -ENOMEM;
+
+	buf->bytes = size;
+	return 0;
+}
+
+static void msm_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;
+		if (!substream)
+			continue;
+
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+
+		dma_free_coherent(pcm->card->dev, buf->bytes,
+				      buf->area, buf->addr);
+		buf->area = NULL;
+	}
+}
+
+static int msm_pcm_new(struct snd_card *card,
+			struct snd_soc_dai *codec_dai,
+			struct snd_pcm *pcm)
+{
+	int ret;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_32BIT_MASK;
+
+	if (codec_dai->playback.channels_min) {
+		ret = pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_PLAYBACK);
+		if (ret)
+			return ret;
+	}
+
+	if (codec_dai->capture.channels_min) {
+		ret = pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_CAPTURE);
+		if (ret)
+			msm_pcm_free_dma_buffers(pcm);
+	}
+	return ret;
+}
+
+struct snd_soc_platform msm_soc_platform = {
+	.name		= "msm-audio",
+	.remove         = msm_pcm_remove,
+	.pcm_ops 	= &msm_pcm_ops,
+	.pcm_new	= msm_pcm_new,
+	.pcm_free	= msm_pcm_free_dma_buffers,
+};
+EXPORT_SYMBOL(msm_soc_platform);
+
+static int __init msm_soc_platform_init(void)
+{
+	return snd_soc_register_platform(&msm_soc_platform);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	snd_soc_unregister_platform(&msm_soc_platform);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM module platform driver");
+MODULE_LICENSE("GPL v2");
_______________________________________________
Alsa-devel mailing list
Alsa-devel@xxxxxxxxxxxxxxxx
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux