Merge "staging: ram_console: Fix section mismatches" into msm-3.0
diff --git a/AndroidKernel.mk b/AndroidKernel.mk
index 50db52c..cc94b69 100644
--- a/AndroidKernel.mk
+++ b/AndroidKernel.mk
@@ -17,7 +17,7 @@
 ifeq "$(KERNEL_USE_OF)" "y"
 KERNEL_ZIMG = $(KERNEL_OUT)/arch/arm/boot/zImage
 DTB_FILE = $(KERNEL_OUT)/arch/arm/boot/$(MSM_ARCH).dtb
-DTS_FILE = $(KERNEL_OUT)/../../../../../../kernel/arch/arm/boot/dts/$(MSM_ARCH).dts
+DTS_FILE = $(TOP)/kernel/arch/arm/boot/dts/$(MSM_ARCH).dts
 FULL_KERNEL = $(KERNEL_OUT)/arch/arm/boot/$(MSM_ARCH)-zImage
 DTC = $(KERNEL_OUT)/scripts/dtc/dtc
 
diff --git a/Documentation/mmc/00-INDEX b/Documentation/mmc/00-INDEX
index 93dd7a7..a9ba672 100644
--- a/Documentation/mmc/00-INDEX
+++ b/Documentation/mmc/00-INDEX
@@ -4,3 +4,5 @@
         - info on SD and MMC device attributes
 mmc-dev-parts.txt
         - info on SD and MMC device partitions
+mmc-async-req.txt
+        - info on mmc asynchronous requests
diff --git a/Documentation/mmc/mmc-async-req.txt b/Documentation/mmc/mmc-async-req.txt
new file mode 100644
index 0000000..ae1907b
--- /dev/null
+++ b/Documentation/mmc/mmc-async-req.txt
@@ -0,0 +1,87 @@
+Rationale
+=========
+
+How significant is the cache maintenance overhead?
+It depends. Fast eMMC and multiple cache levels with speculative cache
+pre-fetch makes the cache overhead relatively significant. If the DMA
+preparations for the next request are done in parallel with the current
+transfer, the DMA preparation overhead would not affect the MMC performance.
+The intention of non-blocking (asynchronous) MMC requests is to minimize the
+time between when an MMC request ends and another MMC request begins.
+Using mmc_wait_for_req(), the MMC controller is idle while dma_map_sg and
+dma_unmap_sg are processing. Using non-blocking MMC requests makes it
+possible to prepare the caches for next job in parallel with an active
+MMC request.
+
+MMC block driver
+================
+
+The mmc_blk_issue_rw_rq() in the MMC block driver is made non-blocking.
+The increase in throughput is proportional to the time it takes to
+prepare (major part of preparations are dma_map_sg() and dma_unmap_sg())
+a request and how fast the memory is. The faster the MMC/SD is the
+more significant the prepare request time becomes. Roughly the expected
+performance gain is 5% for large writes and 10% on large reads on a L2 cache
+platform. In power save mode, when clocks run on a lower frequency, the DMA
+preparation may cost even more. As long as these slower preparations are run
+in parallel with the transfer performance won't be affected.
+
+Details on measurements from IOZone and mmc_test
+================================================
+
+https://wiki.linaro.org/WorkingGroups/Kernel/Specs/StoragePerfMMC-async-req
+
+MMC core API extension
+======================
+
+There is one new public function mmc_start_req().
+It starts a new MMC command request for a host. The function isn't
+truly non-blocking. If there is an ongoing async request it waits
+for completion of that request and starts the new one and returns. It
+doesn't wait for the new request to complete. If there is no ongoing
+request it starts the new request and returns immediately.
+
+MMC host extensions
+===================
+
+There are two optional members in the mmc_host_ops -- pre_req() and
+post_req() -- that the host driver may implement in order to move work
+to before and after the actual mmc_host_ops.request() function is called.
+In the DMA case pre_req() may do dma_map_sg() and prepare the DMA
+descriptor, and post_req() runs the dma_unmap_sg().
+
+Optimize for the first request
+==============================
+
+The first request in a series of requests can't be prepared in parallel
+with the previous transfer, since there is no previous request.
+The argument is_first_req in pre_req() indicates that there is no previous
+request. The host driver may optimize for this scenario to minimize
+the performance loss. A way to optimize for this is to split the current
+request in two chunks, prepare the first chunk and start the request,
+and finally prepare the second chunk and start the transfer.
+
+Pseudocode to handle is_first_req scenario with minimal prepare overhead:
+
+if (is_first_req && req->size > threshold)
+   /* start MMC transfer for the complete transfer size */
+   mmc_start_command(MMC_CMD_TRANSFER_FULL_SIZE);
+
+   /*
+    * Begin to prepare DMA while cmd is being processed by MMC.
+    * The first chunk of the request should take the same time
+    * to prepare as the "MMC process command time".
+    * If prepare time exceeds MMC cmd time
+    * the transfer is delayed, guesstimate max 4k as first chunk size.
+    */
+    prepare_1st_chunk_for_dma(req);
+    /* flush pending desc to the DMAC (dmaengine.h) */
+    dma_issue_pending(req->dma_desc);
+
+    prepare_2nd_chunk_for_dma(req);
+    /*
+     * The second issue_pending should be called before MMC runs out
+     * of the first chunk. If the MMC runs out of the first data chunk
+     * before this call, the transfer is delayed.
+     */
+    dma_issue_pending(req->dma_desc);
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index 9672d2c..58aece2 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -176,3 +176,5 @@
 CONFIG_MSM_N_WAY_SMD=y
 CONFIG_MSM_N_WAY_SMSM=y
 CONFIG_MSM_SMD_LOGGING=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index dd8cb16..446423d 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -49,6 +49,7 @@
 CONFIG_BT_MSM_PINTEST=y
 CONFIG_MSM_RPC_VIBRATOR=y
 CONFIG_PM8XXX_RPC_VIBRATOR=y
+CONFIG_MSM_SPM_V2=y
 CONFIG_ARM_THUMBEE=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index 199b91f..642d843 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -50,6 +50,7 @@
 CONFIG_BT_MSM_PINTEST=y
 CONFIG_MSM_RPC_VIBRATOR=y
 CONFIG_PM8XXX_RPC_VIBRATOR=y
+CONFIG_MSM_SPM_V2=y
 CONFIG_ARM_THUMBEE=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
diff --git a/arch/arm/mach-msm/acpuclock-7201.c b/arch/arm/mach-msm/acpuclock-7201.c
index 7ad3f65..5a21407 100644
--- a/arch/arm/mach-msm/acpuclock-7201.c
+++ b/arch/arm/mach-msm/acpuclock-7201.c
@@ -187,7 +187,7 @@
 	{ 0, 61440, ACPU_PLL_1, 1, 3,  7680, 3, 1,  61440 },
 	{ 1, 122880, ACPU_PLL_1, 1, 1,  15360, 3, 2,  61440 },
 	{ 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 3,  61440 },
-	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
 	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
 	{ 0, 400000, ACPU_PLL_4, 6, 1, 50000, 3, 4, 122880 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
@@ -217,7 +217,7 @@
 	{ 0, 61440, ACPU_PLL_1, 1, 3,  7680, 3, 1, 61440 },
 	{ 1, 122880, ACPU_PLL_1, 1, 1,  15360, 3, 2, 61440 },
 	{ 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 3, 61440 },
-	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
 	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
 	{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
@@ -232,7 +232,7 @@
 	{ 0, 65536, ACPU_PLL_1, 1, 3,  8192, 3, 1, 49152 },
 	{ 1, 98304, ACPU_PLL_1, 1, 1,  12288, 3, 2, 49152 },
 	{ 1, 196608, ACPU_PLL_1, 1, 0, 24576, 3, 3, 98304 },
-	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
 	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
 	{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
@@ -247,7 +247,7 @@
 	{ 0, 61440, ACPU_PLL_1, 1, 3,  7680, 3, 1,  61440 },
 	{ 1, 122880, ACPU_PLL_1, 1, 1,  15360, 3, 2,  61440 },
 	{ 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 3,  61440 },
-	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
 	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
 	{ 0, 400000, ACPU_PLL_2, 2, 2, 50000, 3, 4, 122880 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
@@ -261,7 +261,7 @@
 	{ 0, 61440, ACPU_PLL_1, 1, 11,  7680, 3, 1,  61440 },
 	{ 1, 122880, ACPU_PLL_1, 1, 5,  15360, 3, 2,  61440 },
 	{ 1, 245760, ACPU_PLL_1, 1, 2, 30720, 3, 3,  61440 },
-	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
 	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
 	{ 0, 400000, ACPU_PLL_4, 6, 1, 50000, 3, 4, 122880 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
@@ -291,7 +291,7 @@
 	{ 0, 61440, ACPU_PLL_1, 1, 11,  7680, 3, 1, 61440 },
 	{ 1, 122880, ACPU_PLL_1, 1, 5,  15360, 3, 2, 61440 },
 	{ 1, 245760, ACPU_PLL_1, 1, 2, 30720, 3, 3, 61440 },
-	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
 	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
 	{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
@@ -300,13 +300,13 @@
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
-/* 7x27aa PLL4 @ 1008MHz with CDMA capable modem */
+/* 7627aa PLL4 @ 1008MHz with CDMA capable modem */
 static struct clkctl_acpu_speed pll0_960_pll1_589_pll2_1200_pll4_1008[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 24576 },
 	{ 0, 65536, ACPU_PLL_1, 1, 8,  8192, 3, 1, 49152 },
 	{ 1, 98304, ACPU_PLL_1, 1, 5,  12288, 3, 2, 49152 },
 	{ 1, 196608, ACPU_PLL_1, 1, 2, 24576, 3, 3, 98304 },
-	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
 	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
 	{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
@@ -315,13 +315,13 @@
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
-/* 7x25a PLL2 @ 1200MHz with GSM capable modem */
+/* 7625a PLL2 @ 1200MHz with GSM capable modem */
 static struct clkctl_acpu_speed pll0_960_pll1_737_pll2_1200_25a[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
 	{ 0, 61440, ACPU_PLL_1, 1, 11,  7680, 3, 1,  61440 },
 	{ 1, 122880, ACPU_PLL_1, 1, 5,  15360, 3, 2,  61440 },
 	{ 1, 245760, ACPU_PLL_1, 1, 2, 30720, 3, 3,  61440 },
-	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
 	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
 	{ 0, 400000, ACPU_PLL_2, 2, 2, 50000, 3, 4, 122880 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 0a56dd2..7e5e2f8 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -208,7 +208,7 @@
 static struct delayed_work ul_timeout_work;
 static int ul_packet_written;
 static atomic_t ul_ondemand_vote = ATOMIC_INIT(0);
-static struct clk *dfab_clk;
+static struct clk *dfab_clk, *xo_clk;
 static DEFINE_RWLOCK(ul_wakeup_lock);
 static DECLARE_WORK(kickoff_ul_wakeup, kickoff_ul_wakeup_func);
 static int bam_connection_is_active;
@@ -1690,6 +1690,9 @@
 	rc = clk_prepare_enable(dfab_clk);
 	if (rc)
 		DMUX_LOG_KERR("bam_dmux vote for dfab failed rc = %d\n", rc);
+	rc = clk_prepare_enable(xo_clk);
+	if (rc)
+		DMUX_LOG_KERR("bam_dmux vote for xo failed rc = %d\n", rc);
 	dfab_is_on = 1;
 	mutex_unlock(&dfab_status_lock);
 }
@@ -1705,6 +1708,7 @@
 		return;
 	}
 	clk_disable_unprepare(dfab_clk);
+	clk_disable_unprepare(xo_clk);
 	dfab_is_on = 0;
 	mutex_unlock(&dfab_status_lock);
 }
@@ -2099,6 +2103,11 @@
 	if (bam_mux_initialized)
 		return 0;
 
+	xo_clk = clk_get(&pdev->dev, "xo");
+	if (IS_ERR(xo_clk)) {
+		pr_err("%s: did not get xo clock\n", __func__);
+		return PTR_ERR(xo_clk);
+	}
 	dfab_clk = clk_get(&pdev->dev, "bus_clk");
 	if (IS_ERR(dfab_clk)) {
 		pr_err("%s: did not get dfab clock\n", __func__);
diff --git a/arch/arm/mach-msm/bms-batterydata.c b/arch/arm/mach-msm/bms-batterydata.c
index 4287153..ea2a9f6 100644
--- a/arch/arm/mach-msm/bms-batterydata.c
+++ b/arch/arm/mach-msm/bms-batterydata.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,19 +12,19 @@
 
 #include <linux/mfd/pm8xxx/pm8921-bms.h>
 
-static struct single_row_lut fcc_temp = {
+static struct single_row_lut palladium_1500_fcc_temp = {
 	.x	= {-30, -20, -10, 0, 10, 25, 40, 60},
 	.y	= {1103, 1179, 1284, 1330, 1420, 1511, 1541, 1571},
 	.cols	= 8,
 };
 
-static struct single_row_lut fcc_sf = {
+static struct single_row_lut palladium_1500_fcc_sf = {
 	.x	= {100, 200, 300, 400, 500},
 	.y	= {97, 93, 93, 90, 87},
 	.cols	= 5,
 };
 
-static struct pc_sf_lut pc_sf = {
+static struct pc_sf_lut palladium_1500_pc_sf = {
 	.rows		= 10,
 	.cols		= 5,
 	.cycles		= {100, 200, 300, 400, 500},
@@ -43,7 +43,7 @@
 	},
 };
 
-static struct pc_temp_ocv_lut  pc_temp_ocv = {
+static struct pc_temp_ocv_lut palladium_1500_pc_temp_ocv = {
 	.rows		= 29,
 	.cols		= 8,
 	.temp		= {-30, -20, -10, 0, 10, 25, 40, 60},
@@ -84,10 +84,81 @@
 	},
 };
 
-struct pm8921_bms_battery_data  palladium_1500_data = {
+struct pm8921_bms_battery_data palladium_1500_data = {
 	.fcc			= 1500,
-	.fcc_temp_lut		= &fcc_temp,
-	.fcc_sf_lut		= &fcc_sf,
-	.pc_temp_ocv_lut	= &pc_temp_ocv,
-	.pc_sf_lut		= &pc_sf,
+	.fcc_temp_lut		= &palladium_1500_fcc_temp,
+	.fcc_sf_lut		= &palladium_1500_fcc_sf,
+	.pc_temp_ocv_lut	= &palladium_1500_pc_temp_ocv,
+	.pc_sf_lut		= &palladium_1500_pc_sf,
+};
+
+static struct single_row_lut desay_5200_fcc_temp = {
+	.x		= {-20, 0, 25, 40},
+	.y		= {5690, 5722, 5722, 5727},
+	.cols	= 4
+};
+
+static struct single_row_lut desay_5200_fcc_sf = {
+	.x		= {0},
+	.y		= {100},
+	.cols	= 1
+};
+
+static struct pc_temp_ocv_lut desay_5200_pc_temp_ocv = {
+	.rows		= 29,
+	.cols		= 4,
+	.temp		= {-20, 0, 25, 40},
+	.percent	= {100, 95, 90, 85, 80, 75, 70, 65, 60, 55,
+				50, 45, 40, 35, 30, 25, 20, 15, 10, 9, 8,
+				7, 6, 5, 4, 3, 2, 1, 0
+	},
+	.ocv		= {
+				{4185, 4184, 4181, 4178},
+				{4103, 4117, 4120, 4119},
+				{4044, 4067, 4074, 4073},
+				{3987, 4019, 4031, 4030},
+				{3941, 3974, 3992, 3992},
+				{3902, 3936, 3958, 3957},
+				{3866, 3901, 3926, 3926},
+				{3835, 3870, 3891, 3896},
+				{3811, 3842, 3855, 3858},
+				{3792, 3818, 3827, 3827},
+				{3776, 3795, 3806, 3806},
+				{3762, 3778, 3789, 3790},
+				{3748, 3765, 3777, 3777},
+				{3735, 3752, 3767, 3765},
+				{3720, 3739, 3756, 3754},
+				{3704, 3726, 3743, 3736},
+				{3685, 3712, 3723, 3716},
+				{3664, 3697, 3695, 3689},
+				{3623, 3672, 3669, 3664},
+				{3611, 3666, 3666, 3661},
+				{3597, 3659, 3662, 3658},
+				{3579, 3648, 3657, 3653},
+				{3559, 3630, 3644, 3639},
+				{3532, 3600, 3612, 3606},
+				{3497, 3558, 3565, 3559},
+				{3450, 3500, 3504, 3498},
+				{3380, 3417, 3421, 3416},
+				{3265, 3287, 3296, 3293},
+				{3000, 3000, 3000, 3000}
+	},
+};
+
+static struct pc_sf_lut desay_5200_pc_sf = {
+	.rows		= 1,
+	.cols		= 1,
+	.cycles		= {0},
+	.percent	= {100},
+	.sf			= {
+				{100}
+	},
+};
+
+struct pm8921_bms_battery_data desay_5200_data = {
+	.fcc			= 5200,
+	.fcc_temp_lut		= &desay_5200_fcc_temp,
+	.fcc_sf_lut		= &desay_5200_fcc_sf,
+	.pc_temp_ocv_lut	= &desay_5200_pc_temp_ocv,
+	.pc_sf_lut		= &desay_5200_pc_sf,
 };
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index 109ed2c..486ebd3 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -332,17 +332,15 @@
 };
 
 static struct camera_vreg_t apq_8064_back_cam_vreg[] = {
-	{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
-	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
-	{"cam_vio", REG_VS, 0, 0, 0},
 	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
+	{"cam_vio", REG_VS, 0, 0, 0},
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
 	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
 };
 
 static struct camera_vreg_t apq_8064_front_cam_vreg[] = {
-	{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
-	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
 	{"cam_vio", REG_VS, 0, 0, 0},
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
 	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
 	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
 };
@@ -403,13 +401,23 @@
 	.i2c_mux_mode = MODE_L,
 };
 
+static struct i2c_board_info imx074_actuator_i2c_info = {
+	I2C_BOARD_INFO("imx074_act", 0x11),
+};
+
+static struct msm_actuator_info imx074_actuator_info = {
+	.board_info     = &imx074_actuator_i2c_info,
+	.bus_id         = APQ_8064_GSBI4_QUP_I2C_BUS_ID,
+	.vcm_pwd        = 0,
+	.vcm_enable     = 1,
+};
+
 static struct msm_camera_i2c_conf apq8064_front_cam_i2c_conf = {
 	.use_i2c_mux = 1,
 	.mux_dev = &msm8960_device_i2c_mux_gsbi4,
 	.i2c_mux_mode = MODE_L,
 };
 
-#ifdef CONFIG_IMX074
 static struct msm_camera_sensor_flash_data flash_imx074 = {
 	.flash_type	= MSM_CAMERA_FLASH_NONE,
 };
@@ -429,10 +437,37 @@
 	.sensor_platform_info = &sensor_board_info_imx074,
 	.csi_if	= 1,
 	.camera_type = BACK_CAMERA_2D,
+	.actuator_info = &imx074_actuator_info
 };
-#endif
 
-#ifdef CONFIG_OV2720
+static struct camera_vreg_t apq_8064_mt9m114_vreg[] = {
+	{"cam_vio", REG_VS, 0, 0, 0},
+	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
+	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
+};
+
+static struct msm_camera_sensor_flash_data flash_mt9m114 = {
+	.flash_type = MSM_CAMERA_FLASH_NONE
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_mt9m114 = {
+	.mount_angle = 90,
+	.cam_vreg = apq_8064_mt9m114_vreg,
+	.num_vreg = ARRAY_SIZE(apq_8064_mt9m114_vreg),
+	.gpio_conf = &apq8064_front_cam_gpio_conf,
+	.i2c_conf = &apq8064_front_cam_i2c_conf,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9m114_data = {
+	.sensor_name = "mt9m114",
+	.pdata = &msm_camera_csi_device_data[1],
+	.flash_data = &flash_mt9m114,
+	.sensor_platform_info = &sensor_board_info_mt9m114,
+	.csi_if = 1,
+	.camera_type = FRONT_CAMERA_2D,
+};
+
 static struct msm_camera_sensor_flash_data flash_ov2720 = {
 	.flash_type	= MSM_CAMERA_FLASH_NONE,
 };
@@ -453,8 +488,6 @@
 	.csi_if	= 1,
 	.camera_type = FRONT_CAMERA_2D,
 };
-#endif
-
 
 void __init apq8064_init_cam(void)
 {
@@ -473,18 +506,18 @@
 
 #ifdef CONFIG_I2C
 static struct i2c_board_info apq8064_camera_i2c_boardinfo[] = {
-#ifdef CONFIG_IMX074
 	{
 	I2C_BOARD_INFO("imx074", 0x1A),
 	.platform_data = &msm_camera_sensor_imx074_data,
 	},
-#endif
-#ifdef CONFIG_OV2720
+	{
+	I2C_BOARD_INFO("mt9m114", 0x48),
+	.platform_data = &msm_camera_sensor_mt9m114_data,
+	},
 	{
 	I2C_BOARD_INFO("ov2720", 0x6C),
 	.platform_data = &msm_camera_sensor_ov2720_data,
 	},
-#endif
 };
 
 struct msm_camera_board_info apq8064_camera_board_info = {
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index c08df19..206bebd 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -621,8 +621,9 @@
 				ARRAY_SIZE(cyts_gpio_configs));
 
 #ifdef CONFIG_USB_EHCI_MSM_HSIC
-	msm_gpiomux_install(apq8064_hsic_configs,
-			ARRAY_SIZE(apq8064_hsic_configs));
+	if (machine_is_apq8064_mtp())
+		msm_gpiomux_install(apq8064_hsic_configs,
+				ARRAY_SIZE(apq8064_hsic_configs));
 #endif
 
 	if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid())
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
index 0357c40..213215e 100644
--- a/arch/arm/mach-msm/board-8064-gpu.c
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -122,6 +122,31 @@
 	},
 };
 
+static const char *kgsl_3d0_iommu0_ctx_names[] = {
+	"gfx3d_user",
+	/* priv_ctx goes here */
+};
+
+static const char *kgsl_3d0_iommu1_ctx_names[] = {
+	"gfx3d1_user",
+	/* priv_ctx goes here */
+};
+
+static struct kgsl_device_iommu_data kgsl_3d0_iommu_data[] = {
+	{
+		.iommu_ctx_names = kgsl_3d0_iommu0_ctx_names,
+		.iommu_ctx_count = ARRAY_SIZE(kgsl_3d0_iommu0_ctx_names),
+		.physstart = 0x07C00000,
+		.physend = 0x07C00000 + SZ_1M - 1,
+	},
+	{
+		.iommu_ctx_names = kgsl_3d0_iommu1_ctx_names,
+		.iommu_ctx_count = ARRAY_SIZE(kgsl_3d0_iommu1_ctx_names),
+		.physstart = 0x07D00000,
+		.physend = 0x07D00000 + SZ_1M - 1,
+	},
+};
+
 static struct kgsl_device_platform_data kgsl_3d0_pdata = {
 	.pwrlevel = {
 		{
@@ -154,8 +179,8 @@
 #ifdef CONFIG_MSM_BUS_SCALING
 	.bus_scale_table = &grp3d_bus_scale_pdata,
 #endif
-	.iommu_user_ctx_name = "gfx3d_user",
-	.iommu_priv_ctx_name = NULL,
+	.iommu_data = kgsl_3d0_iommu_data,
+	.iommu_count = ARRAY_SIZE(kgsl_3d0_iommu_data),
 };
 
 struct platform_device device_kgsl_3d0 = {
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 27952f4..bd5f703 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -122,6 +122,8 @@
 	PM8921_GPIO_OUTPUT(20, 0, HIGH),
 	PM8921_GPIO_INPUT(35, PM_GPIO_PULL_UP_1P5),
 	PM8921_GPIO_INPUT(38, PM_GPIO_PULL_UP_1P5),
+	/* TABLA CODEC RESET */
+	PM8921_GPIO_OUTPUT(34, 1, MED),
 };
 
 static struct pm8xxx_gpio_init pm8921_mtp_kp_gpios[] __initdata = {
@@ -354,6 +356,7 @@
 
 static struct pm8921_bms_platform_data
 apq8064_pm8921_bms_pdata __devinitdata = {
+	.battery_type	= BATT_UNKNOWN,
 	.r_sense		= 10,
 	.i_test			= 2500,
 	.v_failure		= 3000,
@@ -426,5 +429,9 @@
 	if (machine_is_apq8064_rumi3()) {
 		apq8064_pm8921_irq_pdata.devirq = 0;
 		apq8064_pm8821_irq_pdata.devirq = 0;
+	} else if (machine_is_apq8064_mtp()) {
+		apq8064_pm8921_bms_pdata.battery_type = BATT_PALLADIUM;
+	} else if (machine_is_apq8064_liquid()) {
+		apq8064_pm8921_bms_pdata.battery_type = BATT_DESAY;
 	}
 }
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index caee8ba..247b230 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -27,8 +27,9 @@
 };
 VREG_CONSUMERS(L2) = {
 	REGULATOR_SUPPLY("8921_l2",		NULL),
-	REGULATOR_SUPPLY("mipi_csi_vdd",	"4-001a"),
-	REGULATOR_SUPPLY("mipi_csi_vdd",	"4-006c"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.0"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.1"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.2"),
 	REGULATOR_SUPPLY("lvds_pll_vdda",	"lvds.0"),
 	REGULATOR_SUPPLY("dsi1_pll_vdda",	"mipi_dsi.1"),
 };
@@ -41,8 +42,6 @@
 VREG_CONSUMERS(L4) = {
 	REGULATOR_SUPPLY("8921_l4",		NULL),
 	REGULATOR_SUPPLY("HSUSB_1p8",		"msm_otg"),
-	REGULATOR_SUPPLY("HSUSB_1p8",		"msm_ehci_host.0"),
-	REGULATOR_SUPPLY("HSUSB_1p8",		"msm_ehci_host.1"),
 	REGULATOR_SUPPLY("iris_vddxo",		"wcnss_wlan.0"),
 };
 VREG_CONSUMERS(L5) = {
@@ -60,6 +59,7 @@
 VREG_CONSUMERS(L8) = {
 	REGULATOR_SUPPLY("8921_l8",		NULL),
 	REGULATOR_SUPPLY("cam_vana",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vana",		"4-0048"),
 	REGULATOR_SUPPLY("cam_vana",		"4-006c"),
 };
 VREG_CONSUMERS(L9) = {
@@ -76,6 +76,7 @@
 };
 VREG_CONSUMERS(L12) = {
 	REGULATOR_SUPPLY("cam_vdig",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vdig",		"4-0048"),
 	REGULATOR_SUPPLY("cam_vdig",		"4-006c"),
 	REGULATOR_SUPPLY("8921_l12",		NULL),
 };
@@ -88,6 +89,7 @@
 VREG_CONSUMERS(L16) = {
 	REGULATOR_SUPPLY("8921_l16",		NULL),
 	REGULATOR_SUPPLY("cam_vaf",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vaf",		"4-0048"),
 	REGULATOR_SUPPLY("cam_vaf",		"4-006c"),
 };
 VREG_CONSUMERS(L17) = {
@@ -103,7 +105,8 @@
 	REGULATOR_SUPPLY("8921_l23",		NULL),
 	REGULATOR_SUPPLY("pll_vdd",		"pil_qdsp6v4.1"),
 	REGULATOR_SUPPLY("pll_vdd",		"pil_qdsp6v4.2"),
-
+	REGULATOR_SUPPLY("HSUSB_1p8",		"msm_ehci_host.0"),
+	REGULATOR_SUPPLY("HSUSB_1p8",		"msm_ehci_host.1"),
 };
 VREG_CONSUMERS(L24) = {
 	REGULATOR_SUPPLY("8921_l24",		NULL),
@@ -187,6 +190,7 @@
 VREG_CONSUMERS(LVS5) = {
 	REGULATOR_SUPPLY("8921_lvs5",		NULL),
 	REGULATOR_SUPPLY("cam_vio",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vio",		"4-0048"),
 	REGULATOR_SUPPLY("cam_vio",		"4-006c"),
 };
 VREG_CONSUMERS(LVS6) = {
@@ -218,6 +222,7 @@
 };
 VREG_CONSUMERS(EXT_5V) = {
 	REGULATOR_SUPPLY("ext_5v",		NULL),
+	REGULATOR_SUPPLY("vbus",		"msm_ehci_host.0"),
 };
 VREG_CONSUMERS(EXT_MPP8) = {
 	REGULATOR_SUPPLY("ext_mpp8",		NULL),
@@ -507,7 +512,7 @@
 	RPM_LDO(L6,  0, 1, 0, 2950000, 2950000, NULL,          0,     0),
 	RPM_LDO(L7,  0, 1, 0, 1850000, 2950000, NULL,          0,     0),
 	RPM_LDO(L8,  0, 1, 0, 2800000, 2800000, NULL,          0,     0),
-	RPM_LDO(L9,  0, 1, 0, 2850000, 2850000, NULL,          0,     0),
+	RPM_LDO(L9,  0, 1, 0, 3000000, 3000000, NULL,          0,     0),
 	RPM_LDO(L10, 0, 1, 0, 2900000, 2900000, NULL,          0,     0),
 	RPM_LDO(L11, 0, 1, 0, 3000000, 3000000, NULL,          0,     0),
 	RPM_LDO(L12, 0, 1, 0, 1200000, 1200000, "8921_s4",     0,     0),
diff --git a/arch/arm/mach-msm/board-8064-storage.c b/arch/arm/mach-msm/board-8064-storage.c
index 9069039..41be3e7 100644
--- a/arch/arm/mach-msm/board-8064-storage.c
+++ b/arch/arm/mach-msm/board-8064-storage.c
@@ -51,7 +51,7 @@
 		.name = "sdc_vdd",
 		.high_vol_level = 2950000,
 		.low_vol_level = 2950000,
-		.hpm_uA = 600000, /* 600mA */
+		.hpm_uA = 800000, /* 800mA */
 	}
 };
 
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index cc3b3cc..2f94a2e 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -475,6 +475,19 @@
 	.power_budget		= 750,
 };
 
+static struct msm_usb_host_platform_data msm_ehci_host_pdata = {
+	.power_budget = 500,
+};
+
+static void __init apq8064_ehci_host_init(void)
+{
+	if (machine_is_apq8064_liquid()) {
+		apq8064_device_ehci_host3.dev.platform_data =
+				&msm_ehci_host_pdata;
+		platform_device_register(&apq8064_device_ehci_host3);
+	}
+}
+
 #define TABLA_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS + NR_PM8921_IRQS)
 
 /* Micbias setting is based on 8660 CDP/MTP/FLUID requirement
@@ -629,7 +642,7 @@
 	/* T6 Object */
 	0, 0, 0, 0, 0, 0,
 	/* T38 Object */
-	14, 0, 0, 24, 1, 12, 0, 0, 0, 0,
+	14, 1, 0, 22, 2, 12, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -637,14 +650,14 @@
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0,
 	/* T7 Object */
-	100, 16, 50,
+	100, 10, 50,
 	/* T8 Object */
-	25, 0, 20, 20, 0, 0, 20, 50, 0, 0,
+	25, 0, 20, 20, 0, 0, 0, 0, 0, 0,
 	/* T9 Object */
 	131, 0, 0, 26, 42, 0, 32, 80, 2, 5,
 	0, 5, 5, 0, 10, 30, 10, 10, 255, 2,
-	85, 5, 10, 10, 10, 10, 135, 55, 70, 40,
-	10, 5, 0, 0, 0,
+	85, 5, 0, 5, 9, 5, 12, 35, 70, 40,
+	20, 5, 0, 0, 0,
 	/* T18 Object */
 	0, 0,
 	/* T24 Object */
@@ -662,14 +675,14 @@
 	0, 0, 0, 0, 0, 0, 0, 64, 0, 8,
 	16,
 	/* T46 Object */
-	64, 0, 20, 20, 0, 0, 0, 0, 0,
+	68, 0, 16, 16, 0, 0, 0, 0, 0,
 	/* T47 Object */
 	0, 0, 0, 0, 0, 0, 3, 64, 66, 0,
 	/* T48 Object */
 	31, 64, 64, 0, 0, 0, 0, 0, 0, 0,
-	48, 40, 0, 10, 10, 0, 0, 100, 10, 80,
-	0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
-	52, 0, 12, 0, 17, 0, 1, 0, 0, 0,
+	32, 40, 0, 10, 10, 0, 0, 100, 10, 90,
+	0, 0, 0, 0, 0, 0, 0, 10, 1, 10,
+	52, 10, 12, 0, 33, 0, 1, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0,
 	/* T56 Object */
@@ -677,8 +690,8 @@
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	2, 99, 33, 0, 149, 24, 193, 255, 255, 255,
-	255,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0,
 };
 
 #define MXT_TS_GPIO_IRQ			6
@@ -1477,7 +1490,6 @@
 	&apq8064_device_otg,
 	&apq8064_device_gadget_peripheral,
 	&apq8064_device_hsusb_host,
-	&apq8064_device_hsic_host,
 	&android_usb_device,
 	&msm_device_wcnss_wlan,
 #ifdef CONFIG_ANDROID_PMEM
@@ -1862,9 +1874,13 @@
 	if (machine_is_apq8064_liquid())
 		msm_otg_pdata.mhl_enable = true;
 	apq8064_device_otg.dev.platform_data = &msm_otg_pdata;
-	apq8064_device_hsic_host.dev.platform_data = &msm_hsic_pdata;
+	apq8064_ehci_host_init();
 	apq8064_init_buses();
 	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
+	if (machine_is_apq8064_mtp()) {
+		apq8064_device_hsic_host.dev.platform_data = &msm_hsic_pdata;
+		device_initialize(&apq8064_device_hsic_host.dev);
+	}
 	apq8064_pm8xxx_gpio_mpp_init();
 	apq8064_init_mmc();
 
@@ -1921,8 +1937,7 @@
 	spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
 	apq8064_init_fb();
 	apq8064_init_gpu();
-	platform_add_devices(msm_footswitch_devices,
-			     msm_num_footswitch_devices);
+	platform_add_devices(apq8064_fs_devices, apq8064_num_fs_devices);
 	apq8064_init_cam();
 
 	if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid())
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
index 47a381a..f82c43c 100644
--- a/arch/arm/mach-msm/board-8930-camera.c
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -349,7 +349,6 @@
 };
 
 static struct camera_vreg_t msm_8930_back_cam_vreg[] = {
-	{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
 	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
 	{"cam_vio", REG_LDO, 1800000, 1800000, 16000},
 	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
@@ -357,7 +356,6 @@
 };
 
 static struct camera_vreg_t msm_8930_front_cam_vreg[] = {
-	{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
 	{"cam_vio", REG_LDO, 1800000, 1800000, 16000},
 	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
 	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
@@ -446,7 +444,6 @@
 };
 
 static struct camera_vreg_t msm_8930_mt9m114_vreg[] = {
-	{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
 	{"cam_vio", REG_LDO, 1800000, 1800000, 16000},
 	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
 	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
@@ -494,7 +491,6 @@
 };
 
 static struct camera_vreg_t msm_8930_s5k3l1yx_vreg[] = {
-	{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
 	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
 	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
 	{"cam_vio", REG_LDO, 1800000, 1800000, 16000},
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index e6b342f..a840877 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -623,9 +623,15 @@
 	if (on == prev_on)
 		return 0;
 
-	if (!reg_ext_5v)
-		reg_ext_5v = regulator_get(&hdmi_msm_device.dev,
-			"hdmi_mvs");
+	if (!reg_ext_5v) {
+		reg_ext_5v = regulator_get(&hdmi_msm_device.dev, "hdmi_mvs");
+		if (IS_ERR(reg_ext_5v)) {
+			pr_err("'%s' regulator not found, rc=%ld\n",
+				"hdmi_mvs", IS_ERR(reg_ext_5v));
+			reg_ext_5v = NULL;
+			return -ENODEV;
+		}
+	}
 
 	if (on) {
 		rc = regulator_enable(reg_ext_5v);
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index 3f9f976..e19cde0 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -273,6 +273,7 @@
 };
 
 static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
+	.battery_type	= BATT_UNKNOWN,
 	.r_sense		= 10,
 	.i_test			= 2500,
 	.v_failure		= 3000,
@@ -310,4 +311,8 @@
 				&msm8930_ssbi_pm8038_pdata;
 	pm8038_platform_data.num_regulators
 		= msm8930_pm8038_regulator_pdata_len;
+	if (machine_is_apq8064_mtp())
+		pm8921_bms_pdata.battery_type = BATT_PALLADIUM;
+	else if (machine_is_apq8064_liquid())
+		pm8921_bms_pdata.battery_type = BATT_DESAY;
 }
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator.c
index 2f9fdcd..3a6a30d 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator.c
@@ -30,10 +30,9 @@
 	REGULATOR_SUPPLY("8038_l2",		NULL),
 	REGULATOR_SUPPLY("iris_vdddig",		"wcnss_wlan.0"),
 	REGULATOR_SUPPLY("dsi_vdda",		"mipi_dsi.1"),
-	REGULATOR_SUPPLY("mipi_csi_vdd",	"4-001a"),
-	REGULATOR_SUPPLY("mipi_csi_vdd",	"4-006c"),
-	REGULATOR_SUPPLY("mipi_csi_vdd",	"4-0048"),
-	REGULATOR_SUPPLY("mipi_csi_vdd",        "4-0020"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.0"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.1"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.2"),
 };
 VREG_CONSUMERS(L3) = {
 	REGULATOR_SUPPLY("8038_l3",		NULL),
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index a094ba5..ad71007 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -971,12 +971,54 @@
 #ifdef CONFIG_USB_MSM_OTG_72K
 static struct msm_otg_platform_data msm_otg_pdata;
 #else
+#ifdef CONFIG_MSM_BUS_SCALING
+/* Bandwidth requests (zero) if no vote placed */
+static struct msm_bus_vectors usb_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+/* Bus bandwidth requests in Bytes/sec */
+static struct msm_bus_vectors usb_max_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 60000000,		/* At least 480Mbps on bus. */
+		.ib = 960000000,	/* MAX bursts rate */
+	},
+};
+
+static struct msm_bus_paths usb_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(usb_init_vectors),
+		usb_init_vectors,
+	},
+	{
+		ARRAY_SIZE(usb_max_vectors),
+		usb_max_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata usb_bus_scale_pdata = {
+	usb_bus_scale_usecases,
+	ARRAY_SIZE(usb_bus_scale_usecases),
+	.name = "usb",
+};
+#endif
+
 static struct msm_otg_platform_data msm_otg_pdata = {
 	.mode			= USB_OTG,
 	.otg_control		= OTG_PMIC_CONTROL,
 	.phy_type		= SNPS_28NM_INTEGRATED_PHY,
 	.pmic_id_irq		= PM8038_USB_ID_IN_IRQ(PM8038_IRQ_BASE),
 	.power_budget		= 750,
+#ifdef CONFIG_MSM_BUS_SCALING
+	.bus_scale_table	= &usb_bus_scale_pdata,
+#endif
 };
 #endif
 
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index 87cb105..42c09fb 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -420,7 +420,6 @@
 };
 
 static struct camera_vreg_t msm_8960_back_cam_vreg[] = {
-	{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
 	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
 	{"cam_vio", REG_VS, 0, 0, 0},
 	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
@@ -428,7 +427,6 @@
 };
 
 static struct camera_vreg_t msm_8960_front_cam_vreg[] = {
-	{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
 	{"cam_vio", REG_VS, 0, 0, 0},
 	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
 	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
@@ -517,7 +515,6 @@
 };
 
 static struct camera_vreg_t msm_8960_mt9m114_vreg[] = {
-	{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
 	{"cam_vio", REG_VS, 0, 0, 0},
 	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
 	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
@@ -565,7 +562,6 @@
 };
 
 static struct camera_vreg_t msm_8960_s5k3l1yx_vreg[] = {
-	{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
 	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
 	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
 	{"cam_vio", REG_VS, 0, 0, 0},
diff --git a/arch/arm/mach-msm/board-8960-display.c b/arch/arm/mach-msm/board-8960-display.c
index 9a98058..37a988a 100644
--- a/arch/arm/mach-msm/board-8960-display.c
+++ b/arch/arm/mach-msm/board-8960-display.c
@@ -879,9 +879,16 @@
 	if (on == prev_on)
 		return 0;
 
-	if (!reg_8921_hdmi_mvs)
+	if (!reg_8921_hdmi_mvs) {
 		reg_8921_hdmi_mvs = regulator_get(&hdmi_msm_device.dev,
-			"hdmi_mvs");
+					"hdmi_mvs");
+		if (IS_ERR(reg_8921_hdmi_mvs)) {
+			pr_err("'%s' regulator not found, rc=%ld\n",
+				"hdmi_mvs", IS_ERR(reg_8921_hdmi_mvs));
+			reg_8921_hdmi_mvs = NULL;
+			return -ENODEV;
+		}
+	}
 
 	if (on) {
 		rc = regulator_enable(reg_8921_hdmi_mvs);
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 744709c..e3646ed 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -88,6 +88,12 @@
 			PM_GPIO_STRENGTH_HIGH, \
 			PM_GPIO_FUNC_NORMAL, 0, 0)
 
+#define PM8XXX_GPIO_OUTPUT_STRENGTH(_gpio, _val, _out_strength) \
+	PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, PM_GPIO_VIN_S4, \
+			_out_strength, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
 /* Initial PM8921 GPIO configurations */
 static struct pm8xxx_gpio_init pm8921_gpios[] __initdata = {
 	PM8XXX_GPIO_OUTPUT_VIN(6, 1, PM_GPIO_VIN_VPH),	 /* MHL power EN_N */
@@ -104,6 +110,8 @@
 	PM8XXX_GPIO_INPUT(26,	    PM_GPIO_PULL_UP_30), /* SD_CARD_DET_N */
 	PM8XXX_GPIO_OUTPUT(43,	    PM_GPIO_PULL_UP_30), /* DISP_RESET_N */
 	PM8XXX_GPIO_OUTPUT(42, 0),                      /* USB 5V reg enable */
+	/* TABLA CODEC RESET */
+	PM8XXX_GPIO_OUTPUT_STRENGTH(34, 1, PM_GPIO_STRENGTH_MED)
 };
 
 /* Initial PM8921 MPP configurations */
@@ -431,6 +439,7 @@
 };
 
 static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
+	.battery_type	= BATT_UNKNOWN,
 	.r_sense		= 10,
 	.i_test			= 2500,
 	.v_failure		= 3000,
@@ -593,5 +602,8 @@
 	if (machine_is_msm8960_liquid()) {
 		pm8921_platform_data.keypad_pdata = &keypad_data_liquid;
 		pm8921_platform_data.leds_pdata = &pm8xxx_leds_pdata_liquid;
+		pm8921_platform_data.bms_pdata->battery_type = BATT_DESAY;
+	} else if (machine_is_msm8960_mtp()) {
+		pm8921_platform_data.bms_pdata->battery_type = BATT_PALLADIUM;
 	}
 }
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index 0f05af5..d98ae56 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -30,10 +30,9 @@
 VREG_CONSUMERS(L2) = {
 	REGULATOR_SUPPLY("8921_l2",		NULL),
 	REGULATOR_SUPPLY("dsi_vdda",		"mipi_dsi.1"),
-	REGULATOR_SUPPLY("mipi_csi_vdd",	"4-001a"),
-	REGULATOR_SUPPLY("mipi_csi_vdd",	"4-006c"),
-	REGULATOR_SUPPLY("mipi_csi_vdd",	"4-0048"),
-	REGULATOR_SUPPLY("mipi_csi_vdd",	"4-0020"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.0"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.1"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.2"),
 };
 VREG_CONSUMERS(L3) = {
 	REGULATOR_SUPPLY("8921_l3",		NULL),
@@ -527,7 +526,7 @@
 	RPM_LDO(L6,	 0, 1, 0, 2950000, 2950000, NULL,      0, 0),
 	RPM_LDO(L7,	 1, 1, 0, 1850000, 2950000, NULL,      10000, 10000),
 	RPM_LDO(L8,	 0, 1, 0, 2800000, 3000000, NULL,      0, 0),
-	RPM_LDO(L9,	 0, 1, 0, 2850000, 2850000, NULL,      0, 0),
+	RPM_LDO(L9,	 0, 1, 0, 3000000, 3000000, NULL,      0, 0),
 	RPM_LDO(L10,	 0, 1, 0, 3000000, 3000000, NULL,      0, 0),
 	RPM_LDO(L11,	 0, 1, 0, 2850000, 2850000, NULL,      0, 0),
 	RPM_LDO(L12,	 0, 1, 0, 1200000, 1200000, "8921_s4", 0, 0),
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index b99ce8a..cb6674c 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -1716,6 +1716,63 @@
 	255,
 };
 
+/* configuration data for mxt1386e on 3D SKU using V2.1 firmware */
+static const u8 mxt1386e_config_data_3d[] = {
+	/* T6 Object */
+	0, 0, 0, 0, 0, 0,
+	/* T38 Object */
+	13, 1, 0, 23, 2, 12, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0,
+	/* T7 Object */
+	100, 10, 50,
+	/* T8 Object */
+	25, 0, 20, 20, 0, 0, 0, 0, 0, 0,
+	/* T9 Object */
+	131, 0, 0, 26, 42, 0, 32, 80, 2, 5,
+	0, 5, 5, 0, 10, 30, 10, 10, 175, 4,
+	127, 7, 26, 21, 17, 19, 143, 35, 207, 40,
+	20, 5, 54, 49, 0,
+	/* T18 Object */
+	0, 0,
+	/* T24 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0,
+	/* T25 Object */
+	0, 0, 72, 113, 168, 97,
+	/* T27 Object */
+	0, 0, 0, 0, 0, 0, 0,
+	/* T40 Object */
+	0, 0, 0, 0, 0,
+	/* T42 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	/* T43 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0,
+	/* T46 Object */
+	68, 0, 16, 16, 0, 0, 0, 0, 0,
+	/* T47 Object */
+	0, 0, 0, 0, 0, 0, 3, 64, 66, 0,
+	/* T48 Object */
+	31, 64, 64, 0, 0, 0, 0, 0, 0, 0,
+	32, 50, 0, 10, 10, 0, 0, 100, 10, 90,
+	0, 0, 0, 0, 0, 0, 0, 10, 1, 30,
+	52, 10, 5, 0, 33, 0, 1, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0,
+	/* T56 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0,
+};
+
 #define MXT_TS_GPIO_IRQ			11
 #define MXT_TS_LDO_EN_GPIO		50
 #define MXT_TS_RESET_GPIO		52
@@ -1744,7 +1801,7 @@
 	gpio_free(MXT_TS_LDO_EN_GPIO);
 }
 
-static struct mxt_config_info mxt_config_array[] = {
+static struct mxt_config_info mxt_config_array_2d[] = {
 	{
 		.config		= mxt1386_config_data,
 		.config_length	= ARRAY_SIZE(mxt1386_config_data),
@@ -1771,9 +1828,9 @@
 	},
 };
 
-static struct mxt_platform_data mxt_platform_data = {
-	.config_array		= mxt_config_array,
-	.config_array_size	= ARRAY_SIZE(mxt_config_array),
+static struct mxt_platform_data mxt_platform_data_2d = {
+	.config_array		= mxt_config_array_2d,
+	.config_array_size	= ARRAY_SIZE(mxt_config_array_2d),
 	.x_size			= 1365,
 	.y_size			= 767,
 	.irqflags		= IRQF_TRIGGER_FALLING,
@@ -1782,10 +1839,31 @@
 	.irq_gpio		= MXT_TS_GPIO_IRQ,
 };
 
+static struct mxt_config_info mxt_config_array_3d[] = {
+	{
+		.config		= mxt1386e_config_data_3d,
+		.config_length	= ARRAY_SIZE(mxt1386e_config_data_3d),
+		.family_id	= 0xA0,
+		.variant_id	= 0x7,
+		.version	= 0x21,
+		.build		= 0xAA,
+	},
+};
+
+static struct mxt_platform_data mxt_platform_data_3d = {
+	.config_array		= mxt_config_array_3d,
+	.config_array_size	= ARRAY_SIZE(mxt_config_array_3d),
+	.x_size			= 1919,
+	.y_size			= 1199,
+	.irqflags		= IRQF_TRIGGER_FALLING,
+	.i2c_pull_up		= true,
+	.reset_gpio		= MXT_TS_RESET_GPIO,
+	.irq_gpio		= MXT_TS_GPIO_IRQ,
+};
+
 static struct i2c_board_info mxt_device_info[] __initdata = {
 	{
 		I2C_BOARD_INFO("atmel_mxt_ts", 0x5b),
-		.platform_data = &mxt_platform_data,
 		.irq = MSM_GPIO_TO_INT(MXT_TS_GPIO_IRQ),
 	},
 };
@@ -2463,6 +2541,15 @@
 	else
 		pr_err("unmatched machine ID in register_i2c_devices\n");
 
+	if (machine_is_msm8960_liquid()) {
+		if (SOCINFO_VERSION_MAJOR(socinfo_get_platform_version()) == 3)
+			mxt_device_info[0].platform_data =
+						&mxt_platform_data_3d;
+		else
+			mxt_device_info[0].platform_data =
+						&mxt_platform_data_2d;
+	}
+
 	/* Run the array and install devices as appropriate */
 	for (i = 0; i < ARRAY_SIZE(msm8960_i2c_devices); ++i) {
 		if (msm8960_i2c_devices[i].machs & mach_mask)
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index 77af5e2..06fbb7b 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -603,7 +603,7 @@
 	.pmic_gpio_enable  = 1,
 	.sensor_pwd     = GPIO_SKU3_CAM_5MP_SHDN_N,
 	.vcm_pwd        = GPIO_SKU3_CAM_5MP_CAM_DRIVER_PWDN,
-	.vcm_enable     = 0,
+	.vcm_enable     = 1,
 	.pdata          = &msm_camera_device_data_rear,
 	.flash_data     = &flash_ov5647,
 	.sensor_platform_info   = &ov5647_sensor_7627a_info,
diff --git a/arch/arm/mach-msm/board-msm7627a-storage.c b/arch/arm/mach-msm/board-msm7627a-storage.c
index a10d81a..88a519d 100644
--- a/arch/arm/mach-msm/board-msm7627a-storage.c
+++ b/arch/arm/mach-msm/board-msm7627a-storage.c
@@ -26,6 +26,7 @@
 	|| defined(CONFIG_MMC_MSM_SDC3_SUPPORT)\
 	|| defined(CONFIG_MMC_MSM_SDC4_SUPPORT))
 
+#define MAX_SDCC_CONTROLLER 4
 static unsigned long vreg_sts, gpio_sts;
 
 struct sdcc_gpio {
@@ -152,7 +153,7 @@
 		gpio_sdc1_hw_det = 42;
 }
 
-static struct regulator *sdcc_vreg_data[ARRAY_SIZE(sdcc_cfg_data)];
+static struct regulator *sdcc_vreg_data[MAX_SDCC_CONTROLLER];
 static int msm_sdcc_setup_gpio(int dev_id, unsigned int enable)
 {
 	int rc = 0;
@@ -377,14 +378,14 @@
 #endif
 	/* SDIO WLAN slot */
 #ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
-	if (mmc_regulator_init(2, "mmc", 2850000))
+	if (mmc_regulator_init(2, "smps3", 1800000))
 		return;
 	msm_add_sdcc(2, &sdc2_plat_data);
 #endif
 	/* Not Used */
 #if (defined(CONFIG_MMC_MSM_SDC4_SUPPORT)\
 		&& !defined(CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT))
-	if (mmc_regulator_init(4, "mmc", 2850000))
+	if (mmc_regulator_init(4, "smps3", 1800000))
 		return;
 	msm_add_sdcc(4, &sdc4_plat_data);
 #endif
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 8188e08..5996388 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -4887,6 +4887,7 @@
 	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_qdsp6v4.1"),
 	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_qdsp6v4.2"),
 	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_gss"),
+	CLK_LOOKUP("xo",		cxo_clk.c,	"BAM_RMNT"),
 	CLK_LOOKUP("pll2",		pll2_clk.c,	NULL),
 	CLK_LOOKUP("pll8",		pll8_clk.c,	NULL),
 	CLK_LOOKUP("pll4",		pll4_clk.c,	NULL),
@@ -4981,6 +4982,7 @@
 	CLK_LOOKUP("mem_clk",		rpm_msg_ram_p_clk.c,	""),
 	CLK_LOOKUP("core_clk",		amp_clk.c,		""),
 	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-001a"),
+	CLK_LOOKUP("cam_clk",		cam1_clk.c,	"4-0048"),
 	CLK_LOOKUP("cam_clk",		cam1_clk.c,	"4-006c"),
 	CLK_LOOKUP("csi_src_clk",	csi0_src_clk.c,		"msm_csid.0"),
 	CLK_LOOKUP("csi_src_clk",	csi1_src_clk.c,		"msm_csid.1"),
@@ -5034,6 +5036,7 @@
 	CLK_LOOKUP("lut_clk",		lut_mdp_clk.c,	"footswitch-8x60.4"),
 	CLK_LOOKUP("core_clk",		rot_clk.c,	"msm_rotator.0"),
 	CLK_LOOKUP("core_clk",		rot_clk.c,	"footswitch-8x60.6"),
+	CLK_LOOKUP("tv_src_clk",	tv_src_clk.c,	"footswitch-8x60.4"),
 	CLK_LOOKUP("tv_src_clk",	tv_src_clk.c,		""),
 	CLK_LOOKUP("tv_src_div_clk",	tv_src_div_clk.c,	""),
 	CLK_LOOKUP("core_clk",		vcodec_clk.c,		"msm_vidc.0"),
@@ -5080,7 +5083,7 @@
 	CLK_LOOKUP("vfe_pclk",		vfe_p_clk.c,		"msm_vfe.0"),
 	CLK_LOOKUP("iface_clk",		vfe_p_clk.c,	"footswitch-8x60.8"),
 	CLK_LOOKUP("vpe_pclk",		vpe_p_clk.c,		""),
-	CLK_LOOKUP("iface_pclk",	vpe_p_clk.c,	"footswitch-8x60.9"),
+	CLK_LOOKUP("iface_clk",		vpe_p_clk.c,	"footswitch-8x60.9"),
 
 	CLK_LOOKUP("bit_clk",		mi2s_bit_clk.c,		"msm-dai-q6.6"),
 	CLK_LOOKUP("osr_clk",		mi2s_osr_clk.c,		"msm-dai-q6.6"),
@@ -5161,6 +5164,7 @@
 	CLK_LOOKUP("xo",		pxo_clk.c,	"pil_qdsp6v4.0"),
 	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_qdsp6v4.1"),
 	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_qdsp6v4.2"),
+	CLK_LOOKUP("xo",		cxo_clk.c,	"BAM_RMNT"),
 	CLK_LOOKUP("pll2",		pll2_clk.c,	NULL),
 	CLK_LOOKUP("pll8",		pll8_clk.c,	NULL),
 	CLK_LOOKUP("pll4",		pll4_clk.c,	NULL),
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index df9c152..9e4268f 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -663,7 +663,7 @@
 		.c = { \
 			.dbg_name = #name, \
 			.ops = &clk_ops_rcg_9615, \
-			VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000), \
+			VDD_DIG_FMAX_MAP2(LOW, 26000000, NOMINAL, 52000000), \
 			CLK_INIT(name.c), \
 		}, \
 	}
@@ -682,7 +682,10 @@
 	F_SDC( 17070000, pll8,  1, 2,  45),
 	F_SDC( 20210000, pll8,  1, 1,  19),
 	F_SDC( 24000000, pll8,  4, 1,   4),
+	F_SDC( 38400000, pll8,  2, 1,   5),
 	F_SDC( 48000000, pll8,  4, 1,   2),
+	F_SDC( 64000000, pll8,  3, 1,   2),
+	F_SDC( 76800000, pll8,  1, 1,   5),
 	F_END
 };
 
@@ -1622,6 +1625,7 @@
 
 static struct clk_lookup msm_clocks_9615[] = {
 	CLK_LOOKUP("xo",	cxo_clk.c,	"msm_otg"),
+	CLK_LOOKUP("xo",	cxo_clk.c,	"BAM_RMNT"),
 	CLK_LOOKUP("pll0",	pll0_clk.c,	NULL),
 	CLK_LOOKUP("pll8",	pll8_clk.c,	NULL),
 	CLK_LOOKUP("pll14",	pll14_clk.c,	NULL),
diff --git a/arch/arm/mach-msm/clock-rpm.c b/arch/arm/mach-msm/clock-rpm.c
index fc2e83f..ae87bb7 100644
--- a/arch/arm/mach-msm/clock-rpm.c
+++ b/arch/arm/mach-msm/clock-rpm.c
@@ -187,12 +187,6 @@
 	return false;
 }
 
-static unsigned long rpm_branch_clk_get_rate(struct clk *clk)
-{
-	struct rpm_clk *r = to_rpm_clk(clk);
-	return r->last_set_khz * 1000;
-}
-
 struct clk_ops clk_ops_rpm = {
 	.enable = rpm_clk_enable,
 	.disable = rpm_clk_disable,
@@ -207,5 +201,4 @@
 	.enable = rpm_clk_enable,
 	.disable = rpm_clk_disable,
 	.is_local = rpm_clk_is_local,
-	.get_rate = rpm_branch_clk_get_rate,
 };
diff --git a/arch/arm/mach-msm/clock-rpm.h b/arch/arm/mach-msm/clock-rpm.h
index 27afd6f..2f4a17c 100644
--- a/arch/arm/mach-msm/clock-rpm.h
+++ b/arch/arm/mach-msm/clock-rpm.h
@@ -80,6 +80,7 @@
 			.ops = &clk_ops_rpm_branch, \
 			.flags = CLKFLAG_SKIP_AUTO_OFF, \
 			.dbg_name = #name, \
+			.rate = (rate), \
 			CLK_INIT(name.c), \
 		}, \
 	}; \
@@ -94,6 +95,7 @@
 			.ops = &clk_ops_rpm_branch, \
 			.flags = CLKFLAG_SKIP_AUTO_OFF, \
 			.dbg_name = #active, \
+			.rate = (rate), \
 			CLK_INIT(active.c), \
 		}, \
 	};
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 6b79fab..ca85a0a 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -31,6 +31,7 @@
 #include <linux/ion.h>
 #include "clock.h"
 #include "devices.h"
+#include "footswitch.h"
 #include "msm_watchdog.h"
 #include "rpm_stats.h"
 #include "rpm_log.h"
@@ -67,6 +68,10 @@
 #define MSM_HSUSB1_PHYS		0x12500000
 #define MSM_HSUSB1_SIZE		SZ_4K
 
+/* Address of HS USB3 */
+#define MSM_HSUSB3_PHYS		0x12520000
+#define MSM_HSUSB3_SIZE		SZ_4K
+
 static struct msm_watchdog_pdata msm_watchdog_pdata = {
 	.pet_time = 10000,
 	.bark_time = 11000,
@@ -649,6 +654,30 @@
 	},
 };
 
+static struct resource resources_ehci_host3[] = {
+{
+		.start  = MSM_HSUSB3_PHYS,
+		.end    = MSM_HSUSB3_PHYS + MSM_HSUSB3_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = USB3_HS_IRQ,
+		.end    = USB3_HS_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device apq8064_device_ehci_host3 = {
+	.name           = "msm_ehci_host",
+	.id             = 0,
+	.num_resources  = ARRAY_SIZE(resources_ehci_host3),
+	.resource       = resources_ehci_host3,
+	.dev            = {
+		.dma_mask               = &dma_mask,
+		.coherent_dma_mask      = 0xffffffff,
+	},
+};
+
 /* MSM Video core device */
 #ifdef CONFIG_MSM_BUS_SCALING
 static struct msm_bus_vectors vidc_init_vectors[] = {
@@ -1230,6 +1259,17 @@
 	.resource       = msm_gss_resources,
 };
 
+struct platform_device *apq8064_fs_devices[] = {
+	FS_8X60(FS_ROT,    "fs_rot"),
+	FS_8X60(FS_IJPEG,  "fs_ijpeg"),
+	FS_8X60(FS_VFE,    "fs_vfe"),
+	FS_8X60(FS_VPE,    "fs_vpe"),
+	FS_8X60(FS_GFX3D,  "fs_gfx3d"),
+	FS_8X60(FS_VED,    "fs_ved"),
+	FS_8X60(FS_VCAP,   "fs_vcap"),
+};
+unsigned apq8064_num_fs_devices = ARRAY_SIZE(apq8064_fs_devices);
+
 static struct clk_lookup msm_clocks_8064_dummy[] = {
 	CLK_DUMMY("pll2",		PLL2,		NULL, 0),
 	CLK_DUMMY("pll8",		PLL8,		NULL, 0),
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 4d4b88f..19a8db7 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -2291,6 +2291,20 @@
 	},
 };
 
+static const char *kgsl_3d0_iommu_ctx_names[] = {
+	"gfx3d_user",
+	/* priv_ctx goes here */
+};
+
+static struct kgsl_device_iommu_data kgsl_3d0_iommu_data[] = {
+	{
+		.iommu_ctx_names = kgsl_3d0_iommu_ctx_names,
+		.iommu_ctx_count = ARRAY_SIZE(kgsl_3d0_iommu_ctx_names),
+		.physstart = 0x07C00000,
+		.physend = 0x07C00000 + SZ_1M - 1,
+	},
+};
+
 static struct kgsl_device_platform_data kgsl_3d0_pdata = {
 	.pwrlevel = {
 		{
@@ -2327,8 +2341,8 @@
 #ifdef CONFIG_MSM_BUS_SCALING
 	.bus_scale_table = &grp3d_bus_scale_pdata,
 #endif
-	.iommu_user_ctx_name = "gfx3d_user",
-	.iommu_priv_ctx_name = NULL,
+	.iommu_data = kgsl_3d0_iommu_data,
+	.iommu_count = ARRAY_SIZE(kgsl_3d0_iommu_data),
 };
 
 struct platform_device msm_kgsl_3d0 = {
@@ -2356,6 +2370,19 @@
 	},
 };
 
+static const char *kgsl_2d0_iommu_ctx_names[] = {
+	"gfx2d0_2d0",
+};
+
+static struct kgsl_device_iommu_data kgsl_2d0_iommu_data[] = {
+	{
+		.iommu_ctx_names = kgsl_2d0_iommu_ctx_names,
+		.iommu_ctx_count = ARRAY_SIZE(kgsl_2d0_iommu_ctx_names),
+		.physstart = 0x07D00000,
+		.physend = 0x07D00000 + SZ_1M - 1,
+	},
+};
+
 static struct kgsl_device_platform_data kgsl_2d0_pdata = {
 	.pwrlevel = {
 		{
@@ -2380,8 +2407,8 @@
 #ifdef CONFIG_MSM_BUS_SCALING
 	.bus_scale_table = &grp2d0_bus_scale_pdata,
 #endif
-	.iommu_user_ctx_name = "gfx2d0_2d0",
-	.iommu_priv_ctx_name = NULL,
+	.iommu_data = kgsl_2d0_iommu_data,
+	.iommu_count = ARRAY_SIZE(kgsl_2d0_iommu_data),
 };
 
 struct platform_device msm_kgsl_2d0 = {
@@ -2394,6 +2421,19 @@
 	},
 };
 
+static const char *kgsl_2d1_iommu_ctx_names[] = {
+	"gfx2d1_2d1",
+};
+
+static struct kgsl_device_iommu_data kgsl_2d1_iommu_data[] = {
+	{
+		.iommu_ctx_names = kgsl_2d1_iommu_ctx_names,
+		.iommu_ctx_count = ARRAY_SIZE(kgsl_2d1_iommu_ctx_names),
+		.physstart = 0x07E00000,
+		.physend = 0x07E00000 + SZ_1M - 1,
+	},
+};
+
 static struct resource kgsl_2d1_resources[] = {
 	{
 		.name = KGSL_2D1_REG_MEMORY,
@@ -2433,8 +2473,8 @@
 #ifdef CONFIG_MSM_BUS_SCALING
 	.bus_scale_table = &grp2d1_bus_scale_pdata,
 #endif
-	.iommu_user_ctx_name = "gfx2d1_2d1",
-	.iommu_priv_ctx_name = NULL,
+	.iommu_data = kgsl_2d1_iommu_data,
+	.iommu_count = ARRAY_SIZE(kgsl_2d1_iommu_data),
 };
 
 struct platform_device msm_kgsl_2d1 = {
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 4e05cc1..6da7b8f 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -110,6 +110,7 @@
 extern struct platform_device apq8064_device_gadget_peripheral;
 extern struct platform_device apq8064_device_hsusb_host;
 extern struct platform_device apq8064_device_hsic_host;
+extern struct platform_device apq8064_device_ehci_host3;
 
 extern struct platform_device msm_device_i2c;
 
@@ -241,6 +242,8 @@
 
 extern struct platform_device *msm_footswitch_devices[];
 extern unsigned msm_num_footswitch_devices;
+extern struct platform_device *apq8064_fs_devices[];
+extern unsigned apq8064_num_fs_devices;
 
 extern struct platform_device fsm_qfp_fuse_device;
 
diff --git a/arch/arm/mach-msm/footswitch-8x60.c b/arch/arm/mach-msm/footswitch-8x60.c
index 5c10463..4609a4b 100644
--- a/arch/arm/mach-msm/footswitch-8x60.c
+++ b/arch/arm/mach-msm/footswitch-8x60.c
@@ -99,8 +99,8 @@
 					clock->reset_rate : DEFAULT_RATE;
 			rc = clk_set_rate(clock->clk, rate);
 			if (rc && rc != -ENOSYS) {
-				pr_err("Failed to set %s rate to %lu Hz.\n",
-					clock->name, clock->rate);
+				pr_err("Failed to set %s %s rate to %lu Hz.\n",
+				       fs->desc.name, clock->name, clock->rate);
 				for (clock--; clock >= fs->clk_data; clock--) {
 					if (clock->enabled)
 						clk_disable_unprepare(
@@ -131,8 +131,8 @@
 		if (clock->enabled)
 			clk_disable_unprepare(clock->clk);
 		if (clock->rate && clk_set_rate(clock->clk, clock->rate))
-			pr_err("Failed to restore %s rate to %lu Hz.\n",
-				clock->name, clock->rate);
+			pr_err("Failed to restore %s %s rate to %lu Hz.\n",
+			       fs->desc.name, clock->name, clock->rate);
 	}
 }
 
@@ -167,14 +167,14 @@
 	if (fs->bus_port0) {
 		rc = msm_bus_axi_portunhalt(fs->bus_port0);
 		if (rc) {
-			pr_err("Port 0 unhalt failed.\n");
+			pr_err("%s port 0 unhalt failed.\n", fs->desc.name);
 			goto err;
 		}
 	}
 	if (fs->bus_port1) {
 		rc = msm_bus_axi_portunhalt(fs->bus_port1);
 		if (rc) {
-			pr_err("Port 1 unhalt failed.\n");
+			pr_err("%s port 1 unhalt failed.\n", fs->desc.name);
 			goto err_port2_halt;
 		}
 	}
@@ -252,14 +252,14 @@
 	if (fs->bus_port0) {
 		rc = msm_bus_axi_porthalt(fs->bus_port0);
 		if (rc) {
-			pr_err("Port 0 halt failed.\n");
+			pr_err("%s port 0 halt failed.\n", fs->desc.name);
 			goto err;
 		}
 	}
 	if (fs->bus_port1) {
 		rc = msm_bus_axi_porthalt(fs->bus_port1);
 		if (rc) {
-			pr_err("Port 1 halt failed.\n");
+			pr_err("%s port 1 halt failed.\n", fs->desc.name);
 			goto err_port2_halt;
 		}
 	}
@@ -329,7 +329,7 @@
 	if (fs->bus_port0) {
 		rc = msm_bus_axi_portunhalt(fs->bus_port0);
 		if (rc) {
-			pr_err("Port 0 unhalt failed.\n");
+			pr_err("%s port 0 unhalt failed.\n", fs->desc.name);
 			goto err;
 		}
 	}
@@ -404,7 +404,7 @@
 	if (fs->bus_port0) {
 		rc = msm_bus_axi_porthalt(fs->bus_port0);
 		if (rc) {
-			pr_err("Port 0 halt failed.\n");
+			pr_err("%s port 0 halt failed.\n", fs->desc.name);
 			goto err;
 		}
 	}
@@ -635,7 +635,8 @@
 		clock->clk = clk_get(&pdev->dev, clock->name);
 		if (IS_ERR(clock->clk)) {
 			rc = PTR_ERR(clock->clk);
-			pr_err("clk_get(%s) failed\n", clock->name);
+			pr_err("%s clk_get(%s) failed\n", fs->desc.name,
+			       clock->name);
 			goto err;
 		}
 		if (!strncmp(clock->name, "core_clk", 8))
diff --git a/arch/arm/mach-msm/footswitch-pcom.c b/arch/arm/mach-msm/footswitch-pcom.c
index 340f19b..f8e84fc 100644
--- a/arch/arm/mach-msm/footswitch-pcom.c
+++ b/arch/arm/mach-msm/footswitch-pcom.c
@@ -205,14 +205,14 @@
 		fs->src_clk = clk_get(dev, "core_clk");
 	}
 	if (IS_ERR(fs->src_clk)) {
-		pr_err("clk_get(src_clk) failed\n");
+		pr_err("%s clk_get(src_clk) failed\n", fs->desc.name);
 		rc = PTR_ERR(fs->src_clk);
 		goto err_src_clk;
 	}
 
 	fs->core_clk = clk_get(dev, "core_clk");
 	if (IS_ERR(fs->core_clk)) {
-		pr_err("clk_get(core_clk) failed\n");
+		pr_err("%s clk_get(core_clk) failed\n", fs->desc.name);
 		rc = PTR_ERR(fs->core_clk);
 		goto err_core_clk;
 	}
@@ -220,7 +220,7 @@
 	if (fs->has_ahb_clk) {
 		fs->ahb_clk = clk_get(dev, "iface_clk");
 		if (IS_ERR(fs->ahb_clk)) {
-			pr_err("clk_get(iface_clk) failed\n");
+			pr_err("%s clk_get(iface_clk) failed\n", fs->desc.name);
 			rc = PTR_ERR(fs->ahb_clk);
 			goto err_ahb_clk;
 		}
diff --git a/arch/arm/mach-msm/include/mach/msm_adsp.h b/arch/arm/mach-msm/include/mach/msm_adsp.h
index bbae6c1..e40c07d 100644
--- a/arch/arm/mach-msm/include/mach/msm_adsp.h
+++ b/arch/arm/mach-msm/include/mach/msm_adsp.h
@@ -1,7 +1,7 @@
 /* include/asm-arm/arch-msm/msm_adsp.h
  *
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2010, 2012 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
@@ -52,6 +52,14 @@
 		   unsigned queue_id,
 		   void *data, size_t len);
 
+/*Explicitly gererate adsp event */
+int msm_adsp_generate_event(void *data,
+			struct msm_adsp_module *mod,
+			unsigned event_id,
+			unsigned event_length,
+			unsigned event_size,
+			void *msg);
+
 #define ADSP_MESSAGE_ID 0xFFFF
 
 /* Command Queue Indexes */
diff --git a/arch/arm/mach-msm/include/mach/msm_rtb.h b/arch/arm/mach-msm/include/mach/msm_rtb.h
index a75ab91..5eea63f 100644
--- a/arch/arm/mach-msm/include/mach/msm_rtb.h
+++ b/arch/arm/mach-msm/include/mach/msm_rtb.h
@@ -13,13 +13,18 @@
 #ifndef __MSM_RTB_H__
 #define __MSM_RTB_H__
 
+/*
+ * These numbers are used from the kernel command line and sysfs
+ * to control filtering. Remove items from here with extreme caution
+ */
 enum logk_event_type {
 	LOGK_NONE = 0,
-	LOGK_READL,
-	LOGK_WRITEL,
-	LOGK_LOGBUF,
-	LOGK_HOTPLUG,
-	LOGK_OTHER,
+	LOGK_READL = 1,
+	LOGK_WRITEL = 2,
+	LOGK_LOGBUF = 3,
+	LOGK_HOTPLUG = 4,
+	LOGK_CTXID = 5,
+	LOGK_OTHER = 31,
 };
 
 struct msm_rtb_platform_data {
diff --git a/arch/arm/mach-msm/include/mach/qpnp.h b/arch/arm/mach-msm/include/mach/qpnp.h
new file mode 100644
index 0000000..1d2e440
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qpnp.h
@@ -0,0 +1,19 @@
+ /* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#include <linux/spmi.h>
+
+struct resource *qpnp_get_resource(struct spmi_device *dev,
+				   unsigned int node_idx, unsigned int type,
+				   unsigned int res_num);
+int qpnp_get_irq(struct spmi_device *dev, unsigned int node_idx,
+					  unsigned int res_num);
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index e1d4459..215fdb3 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -103,7 +103,7 @@
 
 static inline int cpu_is_msm7x27(void)
 {
-#ifdef CONFIG_ARCH_MSM7X27
+#if defined(CONFIG_ARCH_MSM7X27) && !defined(CONFIG_ARCH_MSM7X27A)
 	enum msm_cpu cpu = socinfo_get_msm_cpu();
 
 	BUG_ON(cpu == MSM_CPU_UNKNOWN);
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index dcf9f12..8e74238 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -43,7 +43,7 @@
  */
 unsigned int msm_shared_ram_phys = 0x00100000;
 
-static void msm_map_io(struct map_desc *io_desc, int size)
+static void __init msm_map_io(struct map_desc *io_desc, int size)
 {
 	int i;
 
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 15ea8ba..538dbbe 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -756,7 +756,7 @@
 	pkt->length = pkt_size;
 
 	mutex_lock(&xprt_info->tx_lock);
-	ret = xprt_info->xprt->write(pkt, pkt_size, 0);
+	ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
 	mutex_unlock(&xprt_info->tx_lock);
 
 	release_pkt(pkt);
@@ -933,7 +933,8 @@
 	list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
 		mutex_lock(&fwd_xprt_info->tx_lock);
 		if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
-			fwd_xprt_info->xprt->write(pkt, pkt->length, 0);
+			fwd_xprt_info->xprt->write(pkt, pkt->length,
+						   fwd_xprt_info->xprt);
 		mutex_unlock(&fwd_xprt_info->tx_lock);
 	}
 	mutex_unlock(&xprt_info_list_lock);
@@ -984,7 +985,7 @@
 		pr_err("%s: DST in the same cluster\n", __func__);
 		return 0;
 	}
-	fwd_xprt_info->xprt->write(pkt, pkt->length, 0);
+	fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
 	mutex_unlock(&fwd_xprt_info->tx_lock);
 	mutex_unlock(&rt_entry->lock);
 	mutex_unlock(&routing_table_lock);
@@ -1713,7 +1714,7 @@
 	mutex_lock(&rt_entry->lock);
 	xprt_info = rt_entry->xprt_info;
 	mutex_lock(&xprt_info->tx_lock);
-	ret = xprt_info->xprt->write(pkt, pkt->length, 0);
+	ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
 	mutex_unlock(&xprt_info->tx_lock);
 	mutex_unlock(&rt_entry->lock);
 	mutex_unlock(&routing_table_lock);
@@ -2070,7 +2071,7 @@
 	mutex_lock(&xprt_info_list_lock);
 	list_for_each_entry_safe(xprt_info, tmp_xprt_info,
 				 &xprt_info_list, list) {
-		xprt_info->xprt->close();
+		xprt_info->xprt->close(xprt_info->xprt);
 		list_del(&xprt_info->list);
 		kfree(xprt_info);
 	}
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index b125185..bd10ea7 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -150,11 +150,13 @@
 	uint32_t link_id;
 	void *priv;
 
-	int (*read_avail)(void);
-	int (*read)(void *data, uint32_t len);
-	int (*write_avail)(void);
-	int (*write)(void *data, uint32_t len, enum write_data_type type);
-	int (*close)(void);
+	int (*read_avail)(struct msm_ipc_router_xprt *xprt);
+	int (*read)(void *data, uint32_t len,
+		    struct msm_ipc_router_xprt *xprt);
+	int (*write_avail)(struct msm_ipc_router_xprt *xprt);
+	int (*write)(void *data, uint32_t len,
+		     struct msm_ipc_router_xprt *xprt);
+	int (*close)(struct msm_ipc_router_xprt *xprt);
 };
 
 extern struct completion msm_ipc_remote_router_up;
diff --git a/arch/arm/mach-msm/ipc_router_smd_xprt.c b/arch/arm/mach-msm/ipc_router_smd_xprt.c
index 997d4b5..6960d2e 100644
--- a/arch/arm/mach-msm/ipc_router_smd_xprt.c
+++ b/arch/arm/mach-msm/ipc_router_smd_xprt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -38,14 +38,21 @@
 
 #define MIN_FRAG_SZ (IPC_ROUTER_HDR_SIZE + sizeof(union rr_control_msg))
 
+#define NUM_SMD_XPRTS 2
+#define XPRT_NAME_LEN (SMD_MAX_CH_NAME_LEN + 12)
+
 struct msm_ipc_router_smd_xprt {
 	struct msm_ipc_router_xprt xprt;
-
 	smd_channel_t *channel;
+	struct workqueue_struct *smd_xprt_wq;
+	wait_queue_head_t write_avail_wait_q;
+	struct rr_packet *in_pkt;
+	int is_partial_in_pkt;
+	struct delayed_work read_work;
+	spinlock_t ss_reset_lock;	/*Subsystem reset lock*/
+	int ss_reset;
 };
 
-static struct msm_ipc_router_smd_xprt smd_remote_xprt;
-
 struct msm_ipc_router_smd_xprt_work {
 	struct msm_ipc_router_xprt *xprt;
 	struct work_struct work;
@@ -54,24 +61,45 @@
 static void smd_xprt_read_data(struct work_struct *work);
 static void smd_xprt_open_event(struct work_struct *work);
 static void smd_xprt_close_event(struct work_struct *work);
-static DECLARE_DELAYED_WORK(work_read_data, smd_xprt_read_data);
-static struct workqueue_struct *smd_xprt_workqueue;
 
-static wait_queue_head_t write_avail_wait_q;
-static struct rr_packet *in_pkt;
-static int is_partial_in_pkt;
+struct msm_ipc_router_smd_xprt_config {
+	char ch_name[SMD_MAX_CH_NAME_LEN];
+	char xprt_name[XPRT_NAME_LEN];
+	uint32_t edge;
+	uint32_t link_id;
+};
 
-static DEFINE_SPINLOCK(modem_reset_lock);
-static int modem_reset;
+struct msm_ipc_router_smd_xprt_config smd_xprt_cfg[] = {
+	{"RPCRPY_CNTL", "ipc_rtr_smd_rpcrpy_cntl", SMD_APPS_MODEM, 1},
+	{"IPCRTR", "ipc_rtr_smd_ipcrtr", SMD_APPS_MODEM, 1},
+};
 
-static int msm_ipc_router_smd_remote_write_avail(void)
+static struct msm_ipc_router_smd_xprt smd_remote_xprt[NUM_SMD_XPRTS];
+
+static int find_smd_xprt_cfg(const char *name)
 {
-	return smd_write_avail(smd_remote_xprt.channel);
+	int i;
+
+	for (i = 0; i < NUM_SMD_XPRTS; i++) {
+		if (!strncmp(name, smd_xprt_cfg[i].ch_name, 20))
+			return i;
+	}
+
+	return -ENODEV;
+}
+
+static int msm_ipc_router_smd_remote_write_avail(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_smd_xprt *smd_xprtp =
+		container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
+
+	return smd_write_avail(smd_xprtp->channel);
 }
 
 static int msm_ipc_router_smd_remote_write(void *data,
 					   uint32_t len,
-					   uint32_t type)
+					   struct msm_ipc_router_xprt *xprt)
 {
 	struct rr_packet *pkt = (struct rr_packet *)data;
 	struct sk_buff *ipc_rtr_pkt;
@@ -79,6 +107,8 @@
 	int offset, sz_written = 0;
 	int ret, num_retries = 0;
 	unsigned long flags;
+	struct msm_ipc_router_smd_xprt *smd_xprtp =
+		container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
 
 	if (!pkt)
 		return -EINVAL;
@@ -87,81 +117,92 @@
 		return -EINVAL;
 
 	align_sz = ALIGN_SIZE(pkt->length);
-	while ((ret = smd_write_start(smd_remote_xprt.channel,
+	while ((ret = smd_write_start(smd_xprtp->channel,
 				      (len + align_sz))) < 0) {
-		spin_lock_irqsave(&modem_reset_lock, flags);
-		if (modem_reset) {
-			spin_unlock_irqrestore(&modem_reset_lock, flags);
-			pr_err("%s: Modem reset\n", __func__);
+		spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+		if (smd_xprtp->ss_reset) {
+			spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
+						flags);
+			pr_err("%s: %s chnl reset\n", __func__, xprt->name);
 			return -ENETRESET;
 		}
-		spin_unlock_irqrestore(&modem_reset_lock, flags);
+		spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
 		if (num_retries >= 5) {
-			pr_err("%s: Error %d @ smd_write_start\n",
-				__func__, ret);
+			pr_err("%s: Error %d @smd_write_start for %s\n",
+				__func__, ret, xprt->name);
 			return ret;
 		}
 		msleep(50);
+		num_retries++;
 	}
 
 	D("%s: Ready to write\n", __func__);
 	skb_queue_walk(pkt->pkt_fragment_q, ipc_rtr_pkt) {
 		offset = 0;
 		while (offset < ipc_rtr_pkt->len) {
-			if (!smd_write_avail(smd_remote_xprt.channel))
-				smd_enable_read_intr(smd_remote_xprt.channel);
+			if (!smd_write_avail(smd_xprtp->channel))
+				smd_enable_read_intr(smd_xprtp->channel);
 
-			wait_event(write_avail_wait_q,
-				(smd_write_avail(smd_remote_xprt.channel) ||
-				modem_reset));
-			smd_disable_read_intr(smd_remote_xprt.channel);
-			spin_lock_irqsave(&modem_reset_lock, flags);
-			if (modem_reset) {
-				spin_unlock_irqrestore(&modem_reset_lock,
-							flags);
-				pr_err("%s: Modem reset\n", __func__);
+			wait_event(smd_xprtp->write_avail_wait_q,
+				(smd_write_avail(smd_xprtp->channel) ||
+				smd_xprtp->ss_reset));
+			smd_disable_read_intr(smd_xprtp->channel);
+			spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+			if (smd_xprtp->ss_reset) {
+				spin_unlock_irqrestore(
+					&smd_xprtp->ss_reset_lock, flags);
+				pr_err("%s: %s chnl reset\n",
+					__func__, xprt->name);
 				return -ENETRESET;
 			}
-			spin_unlock_irqrestore(&modem_reset_lock, flags);
+			spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
+						flags);
 
-			sz_written = smd_write_segment(smd_remote_xprt.channel,
-					  ipc_rtr_pkt->data + offset,
-					  (ipc_rtr_pkt->len - offset), 0);
+			sz_written = smd_write_segment(smd_xprtp->channel,
+					ipc_rtr_pkt->data + offset,
+					(ipc_rtr_pkt->len - offset), 0);
 			offset += sz_written;
 			sz_written = 0;
 		}
-		D("%s: Wrote %d bytes\n", __func__, offset);
+		D("%s: Wrote %d bytes over %s\n",
+		  __func__, offset, xprt->name);
 	}
 
 	if (align_sz) {
-		if (smd_write_avail(smd_remote_xprt.channel) < align_sz)
-			smd_enable_read_intr(smd_remote_xprt.channel);
+		if (smd_write_avail(smd_xprtp->channel) < align_sz)
+			smd_enable_read_intr(smd_xprtp->channel);
 
-		wait_event(write_avail_wait_q,
-			((smd_write_avail(smd_remote_xprt.channel) >=
-			 align_sz) || modem_reset));
-		smd_disable_read_intr(smd_remote_xprt.channel);
-		spin_lock_irqsave(&modem_reset_lock, flags);
-		if (modem_reset) {
-			spin_unlock_irqrestore(&modem_reset_lock, flags);
-			pr_err("%s: Modem reset\n", __func__);
+		wait_event(smd_xprtp->write_avail_wait_q,
+			((smd_write_avail(smd_xprtp->channel) >=
+			 align_sz) || smd_xprtp->ss_reset));
+		smd_disable_read_intr(smd_xprtp->channel);
+		spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+		if (smd_xprtp->ss_reset) {
+			spin_unlock_irqrestore(
+				&smd_xprtp->ss_reset_lock, flags);
+			pr_err("%s: %s chnl reset\n",
+				__func__, xprt->name);
 			return -ENETRESET;
 		}
-		spin_unlock_irqrestore(&modem_reset_lock, flags);
+		spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
+					flags);
 
-		smd_write_segment(smd_remote_xprt.channel,
+		smd_write_segment(smd_xprtp->channel,
 				  &align_data, align_sz, 0);
-		D("%s: Wrote %d align bytes\n", __func__, align_sz);
+		D("%s: Wrote %d align bytes over %s\n",
+		  __func__, align_sz, xprt->name);
 	}
-	if (!smd_write_end(smd_remote_xprt.channel))
+	if (!smd_write_end(smd_xprtp->channel))
 		D("%s: Finished writing\n", __func__);
 	return len;
 }
 
-static int msm_ipc_router_smd_remote_close(void)
+static int msm_ipc_router_smd_remote_close(struct msm_ipc_router_xprt *xprt)
 {
-	smsm_change_state(SMSM_APPS_STATE, SMSM_RPCINIT, 0);
-	return smd_close(smd_remote_xprt.channel);
+	struct msm_ipc_router_smd_xprt *smd_xprtp =
+		container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
+
+	return smd_close(smd_xprtp->channel);
 }
 
 static void smd_xprt_read_data(struct work_struct *work)
@@ -170,90 +211,97 @@
 	struct sk_buff *ipc_rtr_pkt;
 	void *data;
 	unsigned long flags;
+	struct delayed_work *rwork = to_delayed_work(work);
+	struct msm_ipc_router_smd_xprt *smd_xprtp =
+		container_of(rwork, struct msm_ipc_router_smd_xprt, read_work);
 
-	spin_lock_irqsave(&modem_reset_lock, flags);
-	if (modem_reset) {
-		spin_unlock_irqrestore(&modem_reset_lock, flags);
-		release_pkt(in_pkt);
-		is_partial_in_pkt = 0;
-		pr_err("%s: Modem reset\n", __func__);
+	spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+	if (smd_xprtp->ss_reset) {
+		spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
+		if (smd_xprtp->in_pkt)
+			release_pkt(smd_xprtp->in_pkt);
+		smd_xprtp->is_partial_in_pkt = 0;
+		pr_err("%s: %s channel reset\n",
+			__func__, smd_xprtp->xprt.name);
 		return;
 	}
-	spin_unlock_irqrestore(&modem_reset_lock, flags);
+	spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
 
 	D("%s pkt_size: %d, read_avail: %d\n", __func__,
-		smd_cur_packet_size(smd_remote_xprt.channel),
-		smd_read_avail(smd_remote_xprt.channel));
-	while ((pkt_size = smd_cur_packet_size(smd_remote_xprt.channel)) &&
-		smd_read_avail(smd_remote_xprt.channel)) {
-		if (!is_partial_in_pkt) {
-			in_pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
-			if (!in_pkt) {
+		smd_cur_packet_size(smd_xprtp->channel),
+		smd_read_avail(smd_xprtp->channel));
+	while ((pkt_size = smd_cur_packet_size(smd_xprtp->channel)) &&
+		smd_read_avail(smd_xprtp->channel)) {
+		if (!smd_xprtp->is_partial_in_pkt) {
+			smd_xprtp->in_pkt = kzalloc(sizeof(struct rr_packet),
+						    GFP_KERNEL);
+			if (!smd_xprtp->in_pkt) {
 				pr_err("%s: Couldn't alloc rr_packet\n",
 					__func__);
 				return;
 			}
 
-			in_pkt->pkt_fragment_q = kmalloc(
-						  sizeof(struct sk_buff_head),
-						  GFP_KERNEL);
-			if (!in_pkt->pkt_fragment_q) {
+			smd_xprtp->in_pkt->pkt_fragment_q =
+				kmalloc(sizeof(struct sk_buff_head),
+					GFP_KERNEL);
+			if (!smd_xprtp->in_pkt->pkt_fragment_q) {
 				pr_err("%s: Couldn't alloc pkt_fragment_q\n",
 					__func__);
-				kfree(in_pkt);
+				kfree(smd_xprtp->in_pkt);
 				return;
 			}
-			skb_queue_head_init(in_pkt->pkt_fragment_q);
-			is_partial_in_pkt = 1;
+			skb_queue_head_init(smd_xprtp->in_pkt->pkt_fragment_q);
+			smd_xprtp->is_partial_in_pkt = 1;
 			D("%s: Allocated rr_packet\n", __func__);
 		}
 
 		if (((pkt_size >= MIN_FRAG_SZ) &&
-		     (smd_read_avail(smd_remote_xprt.channel) < MIN_FRAG_SZ)) ||
+		     (smd_read_avail(smd_xprtp->channel) < MIN_FRAG_SZ)) ||
 		    ((pkt_size < MIN_FRAG_SZ) &&
-		     (smd_read_avail(smd_remote_xprt.channel) < pkt_size)))
+		     (smd_read_avail(smd_xprtp->channel) < pkt_size)))
 			return;
 
-		sz = smd_read_avail(smd_remote_xprt.channel);
+		sz = smd_read_avail(smd_xprtp->channel);
 		do {
 			ipc_rtr_pkt = alloc_skb(sz, GFP_KERNEL);
 			if (!ipc_rtr_pkt) {
 				if (sz <= (PAGE_SIZE/2)) {
-					queue_delayed_work(smd_xprt_workqueue,
-						   &work_read_data,
-						   msecs_to_jiffies(100));
+					queue_delayed_work(
+						smd_xprtp->smd_xprt_wq,
+						&smd_xprtp->read_work,
+						msecs_to_jiffies(100));
 					return;
 				}
 				sz = sz / 2;
 			}
 		} while (!ipc_rtr_pkt);
 
-		D("%s: Allocated the sk_buff of size %d\n",
-			__func__, sz);
+		D("%s: Allocated the sk_buff of size %d\n", __func__, sz);
 		data = skb_put(ipc_rtr_pkt, sz);
-		sz_read = smd_read(smd_remote_xprt.channel, data, sz);
+		sz_read = smd_read(smd_xprtp->channel, data, sz);
 		if (sz_read != sz) {
-			pr_err("%s: Couldn't read completely\n", __func__);
+			pr_err("%s: Couldn't read %s completely\n",
+				__func__, smd_xprtp->xprt.name);
 			kfree_skb(ipc_rtr_pkt);
-			release_pkt(in_pkt);
-			is_partial_in_pkt = 0;
+			release_pkt(smd_xprtp->in_pkt);
+			smd_xprtp->is_partial_in_pkt = 0;
 			return;
 		}
-		skb_queue_tail(in_pkt->pkt_fragment_q, ipc_rtr_pkt);
-		in_pkt->length += sz_read;
+		skb_queue_tail(smd_xprtp->in_pkt->pkt_fragment_q, ipc_rtr_pkt);
+		smd_xprtp->in_pkt->length += sz_read;
 		if (sz_read != pkt_size)
-			is_partial_in_pkt = 1;
+			smd_xprtp->is_partial_in_pkt = 1;
 		else
-			is_partial_in_pkt = 0;
+			smd_xprtp->is_partial_in_pkt = 0;
 
-		if (!is_partial_in_pkt) {
+		if (!smd_xprtp->is_partial_in_pkt) {
 			D("%s: Packet size read %d\n",
-				__func__, in_pkt->length);
-			msm_ipc_router_xprt_notify(&smd_remote_xprt.xprt,
-					   IPC_ROUTER_XPRT_EVENT_DATA,
-					   (void *)in_pkt);
-			release_pkt(in_pkt);
-			in_pkt = NULL;
+			  __func__, smd_xprtp->in_pkt->length);
+			msm_ipc_router_xprt_notify(&smd_xprtp->xprt,
+						IPC_ROUTER_XPRT_EVENT_DATA,
+						(void *)smd_xprtp->in_pkt);
+			release_pkt(smd_xprtp->in_pkt);
+			smd_xprtp->in_pkt = NULL;
 		}
 	}
 }
@@ -265,7 +313,8 @@
 
 	msm_ipc_router_xprt_notify(xprt_work->xprt,
 				IPC_ROUTER_XPRT_EVENT_OPEN, NULL);
-	D("%s: Notified IPC Router of OPEN Event\n", __func__);
+	D("%s: Notified IPC Router of %s OPEN\n",
+	   __func__, xprt_work->xprt->name);
 	kfree(xprt_work);
 }
 
@@ -276,28 +325,34 @@
 
 	msm_ipc_router_xprt_notify(xprt_work->xprt,
 				IPC_ROUTER_XPRT_EVENT_CLOSE, NULL);
-	D("%s: Notified IPC Router of CLOSE Event\n", __func__);
+	D("%s: Notified IPC Router of %s CLOSE\n",
+	   __func__, xprt_work->xprt->name);
 	kfree(xprt_work);
 }
 
 static void msm_ipc_router_smd_remote_notify(void *_dev, unsigned event)
 {
 	unsigned long flags;
+	struct msm_ipc_router_smd_xprt *smd_xprtp;
 	struct msm_ipc_router_smd_xprt_work *xprt_work;
 
+	smd_xprtp = (struct msm_ipc_router_smd_xprt *)_dev;
+	if (!smd_xprtp)
+		return;
+
 	switch (event) {
 	case SMD_EVENT_DATA:
-		if (smd_read_avail(smd_remote_xprt.channel))
-			queue_delayed_work(smd_xprt_workqueue,
-					   &work_read_data, 0);
-		if (smd_write_avail(smd_remote_xprt.channel))
-			wake_up(&write_avail_wait_q);
+		if (smd_read_avail(smd_xprtp->channel))
+			queue_delayed_work(smd_xprtp->smd_xprt_wq,
+					   &smd_xprtp->read_work, 0);
+		if (smd_write_avail(smd_xprtp->channel))
+			wake_up(&smd_xprtp->write_avail_wait_q);
 		break;
 
 	case SMD_EVENT_OPEN:
-		spin_lock_irqsave(&modem_reset_lock, flags);
-		modem_reset = 0;
-		spin_unlock_irqrestore(&modem_reset_lock, flags);
+		spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+		smd_xprtp->ss_reset = 0;
+		spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
 		xprt_work = kmalloc(sizeof(struct msm_ipc_router_smd_xprt_work),
 				    GFP_ATOMIC);
 		if (!xprt_work) {
@@ -305,16 +360,16 @@
 				__func__, event);
 			return;
 		}
-		xprt_work->xprt = &smd_remote_xprt.xprt;
+		xprt_work->xprt = &smd_xprtp->xprt;
 		INIT_WORK(&xprt_work->work, smd_xprt_open_event);
-		queue_work(smd_xprt_workqueue, &xprt_work->work);
+		queue_work(smd_xprtp->smd_xprt_wq, &xprt_work->work);
 		break;
 
 	case SMD_EVENT_CLOSE:
-		spin_lock_irqsave(&modem_reset_lock, flags);
-		modem_reset = 1;
-		spin_unlock_irqrestore(&modem_reset_lock, flags);
-		wake_up(&write_avail_wait_q);
+		spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+		smd_xprtp->ss_reset = 1;
+		spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
+		wake_up(&smd_xprtp->write_avail_wait_q);
 		xprt_work = kmalloc(sizeof(struct msm_ipc_router_smd_xprt_work),
 				    GFP_ATOMIC);
 		if (!xprt_work) {
@@ -322,9 +377,9 @@
 				__func__, event);
 			return;
 		}
-		xprt_work->xprt = &smd_remote_xprt.xprt;
+		xprt_work->xprt = &smd_xprtp->xprt;
 		INIT_WORK(&xprt_work->work, smd_xprt_close_event);
-		queue_work(smd_xprt_workqueue, &xprt_work->work);
+		queue_work(smd_xprtp->smd_xprt_wq, &xprt_work->work);
 		break;
 	}
 }
@@ -332,50 +387,93 @@
 static int msm_ipc_router_smd_remote_probe(struct platform_device *pdev)
 {
 	int rc;
+	int id;		/*Index into the smd_xprt_cfg table*/
 
-	smd_xprt_workqueue = create_singlethread_workqueue("smd_xprt");
-	if (!smd_xprt_workqueue)
-		return -ENOMEM;
+	id = find_smd_xprt_cfg(pdev->name);
+	if (id < 0) {
+		pr_err("%s: called for unknown ch %s\n",
+			__func__, pdev->name);
+		return id;
+	}
 
-	smd_remote_xprt.xprt.name = "msm_ipc_router_smd_xprt";
-	smd_remote_xprt.xprt.link_id = 1;
-	smd_remote_xprt.xprt.read_avail = NULL;
-	smd_remote_xprt.xprt.read = NULL;
-	smd_remote_xprt.xprt.write_avail =
+	smd_remote_xprt[id].smd_xprt_wq =
+		create_singlethread_workqueue(pdev->name);
+	if (!smd_remote_xprt[id].smd_xprt_wq) {
+		pr_err("%s: WQ creation failed for %s\n",
+			__func__, pdev->name);
+		return -EFAULT;
+	}
+
+	smd_remote_xprt[id].xprt.name = smd_xprt_cfg[id].xprt_name;
+	smd_remote_xprt[id].xprt.link_id = smd_xprt_cfg[id].link_id;
+	smd_remote_xprt[id].xprt.read_avail = NULL;
+	smd_remote_xprt[id].xprt.read = NULL;
+	smd_remote_xprt[id].xprt.write_avail =
 		msm_ipc_router_smd_remote_write_avail;
-	smd_remote_xprt.xprt.write = msm_ipc_router_smd_remote_write;
-	smd_remote_xprt.xprt.close = msm_ipc_router_smd_remote_close;
-	smd_remote_xprt.xprt.priv = NULL;
+	smd_remote_xprt[id].xprt.write = msm_ipc_router_smd_remote_write;
+	smd_remote_xprt[id].xprt.close = msm_ipc_router_smd_remote_close;
+	smd_remote_xprt[id].xprt.priv = NULL;
 
-	init_waitqueue_head(&write_avail_wait_q);
+	init_waitqueue_head(&smd_remote_xprt[id].write_avail_wait_q);
+	smd_remote_xprt[id].in_pkt = NULL;
+	smd_remote_xprt[id].is_partial_in_pkt = 0;
+	INIT_DELAYED_WORK(&smd_remote_xprt[id].read_work, smd_xprt_read_data);
+	spin_lock_init(&smd_remote_xprt[id].ss_reset_lock);
+	smd_remote_xprt[id].ss_reset = 0;
 
-	rc = smd_open("RPCRPY_CNTL", &smd_remote_xprt.channel, NULL,
-		      msm_ipc_router_smd_remote_notify);
+	rc = smd_named_open_on_edge(smd_xprt_cfg[id].ch_name,
+				    smd_xprt_cfg[id].edge,
+				    &smd_remote_xprt[id].channel,
+				    &smd_remote_xprt[id],
+				    msm_ipc_router_smd_remote_notify);
 	if (rc < 0) {
-		destroy_workqueue(smd_xprt_workqueue);
+		pr_err("%s: Channel open failed for %s\n",
+			__func__, smd_xprt_cfg[id].ch_name);
+		destroy_workqueue(smd_remote_xprt[id].smd_xprt_wq);
 		return rc;
 	}
 
-	smd_disable_read_intr(smd_remote_xprt.channel);
+	smd_disable_read_intr(smd_remote_xprt[id].channel);
 
 	smsm_change_state(SMSM_APPS_STATE, 0, SMSM_RPCINIT);
 
 	return 0;
 }
 
-static struct platform_driver msm_ipc_router_smd_remote_driver = {
-	.probe		= msm_ipc_router_smd_remote_probe,
-	.driver		= {
-			.name	= "RPCRPY_CNTL",
-			.owner	= THIS_MODULE,
+static struct platform_driver msm_ipc_router_smd_remote_driver[] = {
+	{
+		.probe		= msm_ipc_router_smd_remote_probe,
+		.driver		= {
+				.name	= "RPCRPY_CNTL",
+				.owner	= THIS_MODULE,
+		},
+	},
+	{
+		.probe		= msm_ipc_router_smd_remote_probe,
+		.driver		= {
+				.name	= "IPCRTR",
+				.owner	= THIS_MODULE,
+		},
 	},
 };
 
 static int __init msm_ipc_router_smd_init(void)
 {
-	return platform_driver_register(&msm_ipc_router_smd_remote_driver);
+	int i, ret, rc = 0;
+	BUG_ON(ARRAY_SIZE(msm_ipc_router_smd_remote_driver) != NUM_SMD_XPRTS);
+	BUG_ON(ARRAY_SIZE(smd_xprt_cfg) != NUM_SMD_XPRTS);
+	for (i = 0; i < NUM_SMD_XPRTS; i++) {
+		ret = platform_driver_register(
+				&msm_ipc_router_smd_remote_driver[i]);
+		if (ret) {
+			pr_err("%s: Failed to register platform driver for"
+			       " xprt%d. Continuing...\n", __func__, i);
+			rc = ret;
+		}
+	}
+	return rc;
 }
 
 module_init(msm_ipc_router_smd_init);
-MODULE_DESCRIPTION("RPC Router SMD XPRT");
+MODULE_DESCRIPTION("IPC Router SMD XPRT");
 MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/jtag.c b/arch/arm/mach-msm/jtag.c
index b75fb38..a2ec89b 100644
--- a/arch/arm/mach-msm/jtag.c
+++ b/arch/arm/mach-msm/jtag.c
@@ -33,6 +33,9 @@
 #define CPMR_ETMCLKEN		(0x8)
 
 
+uint32_t msm_jtag_save_cntr[NR_CPUS];
+uint32_t msm_jtag_restore_cntr[NR_CPUS];
+
 struct dbg_ctx {
 	uint8_t		arch;
 	bool		arch_supported;
@@ -1015,6 +1018,10 @@
 
 	cpu = raw_smp_processor_id();
 
+	msm_jtag_save_cntr[cpu]++;
+	/* ensure counter is updated before moving forward */
+	mb();
+
 	if (dbg.arch_supported)
 		dbg_save_state(cpu);
 	if (etm.arch_supported)
@@ -1027,6 +1034,10 @@
 
 	cpu = raw_smp_processor_id();
 
+	msm_jtag_restore_cntr[cpu]++;
+	/* ensure counter is updated before moving forward */
+	mb();
+
 	if (dbg.arch_supported)
 		dbg_restore_state(cpu);
 	if (etm.arch_supported)
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
index 34bc415..7e538b4 100644
--- a/arch/arm/mach-msm/mdm2.c
+++ b/arch/arm/mach-msm/mdm2.c
@@ -48,7 +48,7 @@
 
 static int mdm_debug_on;
 static int first_power_on = 1;
-static int hsic_peripheral_status = 1;
+static int hsic_peripheral_status;
 static DEFINE_MUTEX(hsic_status_lock);
 
 static void mdm_peripheral_connect(struct mdm_modem_drv *mdm_drv)
diff --git a/arch/arm/mach-msm/pil-gss.c b/arch/arm/mach-msm/pil-gss.c
index 2b4dae1..26b97fa 100644
--- a/arch/arm/mach-msm/pil-gss.c
+++ b/arch/arm/mach-msm/pil-gss.c
@@ -43,14 +43,8 @@
 #define GSS_CLAMP_ENA		(MSM_CLK_CTL_BASE + 0x2C68)
 #define GSS_CXO_SRC_CTL		(MSM_CLK_CTL_BASE + 0x2C74)
 
-#define PLL5_MODE		(MSM_CLK_CTL_BASE + 0x30E0)
-#define PLL5_L_VAL		(MSM_CLK_CTL_BASE + 0x30E4)
-#define PLL5_M_VAL		(MSM_CLK_CTL_BASE + 0x30E8)
-#define PLL5_N_VAL		(MSM_CLK_CTL_BASE + 0x30EC)
-#define PLL5_CONFIG		(MSM_CLK_CTL_BASE + 0x30F4)
 #define PLL5_STATUS		(MSM_CLK_CTL_BASE + 0x30F8)
 #define PLL_ENA_GSS		(MSM_CLK_CTL_BASE + 0x3480)
-#define PLL_ENA_RPM		(MSM_CLK_CTL_BASE + 0x34A0)
 
 #define PLL5_VOTE		BIT(5)
 #define PLL_STATUS		BIT(16)
@@ -273,10 +267,18 @@
 	struct gss_data *drv = dev_get_drvdata(pil->dev);
 	int ret;
 
-	ret = pas_shutdown(PAS_GSS);
-	if (ret)
+	/*
+	 * CXO is used in the secure shutdown code to configure the processor
+	 * for low power mode.
+	 */
+	ret = clk_prepare_enable(drv->xo);
+	if (ret) {
+		dev_err(pil->dev, "Failed to enable XO\n");
 		return ret;
+	}
 
+	ret = pas_shutdown(PAS_GSS);
+	clk_disable_unprepare(drv->xo);
 	remove_gss_proxy_votes_now(drv);
 
 	return ret;
@@ -322,63 +324,6 @@
 	.shutdown = pil_gss_shutdown_trusted,
 };
 
-static void configure_gss_pll(struct gss_data *drv)
-{
-	u32 regval, is_pll_enabled;
-
-	/* Check if PLL5 is enabled by FSM. */
-	is_pll_enabled = readl_relaxed(PLL5_STATUS) & PLL_STATUS;
-	if (!is_pll_enabled) {
-		/* Enable XO reference for PLL5 */
-		clk_prepare_enable(drv->xo);
-
-		/*
-		 * Assert a vote to hold PLL5 on in RPM register until other
-		 * voters are in place.
-		 */
-		regval = readl_relaxed(PLL_ENA_RPM);
-		regval |= PLL5_VOTE;
-		writel_relaxed(regval, PLL_ENA_RPM);
-
-		/* Ref clk = 27MHz and program pll5 to 288MHz */
-		writel_relaxed(0xF, PLL5_L_VAL);
-		writel_relaxed(0x0, PLL5_M_VAL);
-		writel_relaxed(0x1, PLL5_N_VAL);
-
-		regval = readl_relaxed(PLL5_CONFIG);
-		/* Disable the MN accumulator and enable the main output. */
-		regval &= ~BIT(22);
-		regval |= BIT(23);
-
-		/* Set pre-divider and post-divider values to 1 and 1 */
-		regval &= ~BIT(19);
-		regval &= ~(BIT(21)|BIT(20));
-
-		/* Set VCO frequency */
-		regval &= ~(BIT(17)|BIT(16));
-		writel_relaxed(regval, PLL5_CONFIG);
-
-		regval = readl_relaxed(PLL5_MODE);
-		/* De-assert reset to FSM */
-		regval &= ~BIT(21);
-		writel_relaxed(regval, PLL5_MODE);
-
-		/* Program bias count */
-		regval &= ~(0x3F << 14);
-		regval |= (0x1 << 14);
-		writel_relaxed(regval, PLL5_MODE);
-
-		/* Program lock count */
-		regval &= ~(0x3F << 8);
-		regval |= (0x8 << 8);
-		writel_relaxed(regval, PLL5_MODE);
-
-		/* Enable PLL FSM voting */
-		regval |= BIT(20);
-		writel_relaxed(regval, PLL5_MODE);
-	}
-}
-
 static int __devinit pil_gss_probe(struct platform_device *pdev)
 {
 	struct gss_data *drv;
@@ -429,9 +374,6 @@
 
 	INIT_DELAYED_WORK(&drv->work, remove_gss_proxy_votes);
 
-	/* FIXME: Remove when PLL is configured by bootloaders. */
-	configure_gss_pll(drv);
-
 	ret = msm_pil_register(desc);
 	if (ret) {
 		flush_delayed_work_sync(&drv->work);
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index b3c6d1e..ad235de 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -655,6 +655,10 @@
 	void *entry;
 	bool collapsed = 0;
 	int ret;
+	unsigned int saved_gic_cpu_ctrl;
+
+	saved_gic_cpu_ctrl = readl_relaxed(MSM_QGIC_CPU_BASE + GIC_CPU_CTRL);
+	mb();
 
 	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
 		pr_info("CPU%u: %s: notify_rpm %d\n",
@@ -686,7 +690,9 @@
 #endif
 		cpu_init();
 		writel(0xF0, MSM_QGIC_CPU_BASE + GIC_CPU_PRIMASK);
-		writel(1, MSM_QGIC_CPU_BASE + GIC_CPU_CTRL);
+		writel_relaxed(saved_gic_cpu_ctrl,
+				MSM_QGIC_CPU_BASE + GIC_CPU_CTRL);
+		mb();
 		local_fiq_enable();
 	}
 
diff --git a/arch/arm/mach-msm/pmu.c b/arch/arm/mach-msm/pmu.c
index 81d4e5b..1f82468 100644
--- a/arch/arm/mach-msm/pmu.c
+++ b/arch/arm/mach-msm/pmu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -14,24 +14,28 @@
 #include <asm/pmu.h>
 #include <mach/irqs.h>
 
-static struct resource cpu_pmu_resource = {
-	.start = INT_ARMQC_PERFMON,
-	.end = INT_ARMQC_PERFMON,
-	.flags	= IORESOURCE_IRQ,
+static struct resource cpu_pmu_resource[] = {
+	{
+		.start = INT_ARMQC_PERFMON,
+		.end = INT_ARMQC_PERFMON,
+		.flags	= IORESOURCE_IRQ,
+	},
 };
 
 #ifdef CONFIG_CPU_HAS_L2_PMU
-static struct resource l2_pmu_resource = {
-	.start = SC_SICL2PERFMONIRPTREQ,
-	.end = SC_SICL2PERFMONIRPTREQ,
-	.flags = IORESOURCE_IRQ,
+static struct resource l2_pmu_resource[] = {
+	{
+		.start = SC_SICL2PERFMONIRPTREQ,
+		.end = SC_SICL2PERFMONIRPTREQ,
+		.flags = IORESOURCE_IRQ,
+	},
 };
 
 static struct platform_device l2_pmu_device = {
 	.name		= "l2-arm-pmu",
 	.id		= ARM_PMU_DEVICE_L2,
-	.resource	= &l2_pmu_resource,
-	.num_resources	= 1,
+	.resource	= l2_pmu_resource,
+	.num_resources	= ARRAY_SIZE(l2_pmu_resource),
 };
 
 #endif
@@ -39,8 +43,8 @@
 static struct platform_device cpu_pmu_device = {
 	.name		= "cpu-arm-pmu",
 	.id		= ARM_PMU_DEVICE_CPU,
-	.resource	= &cpu_pmu_resource,
-	.num_resources	= 1,
+	.resource	= cpu_pmu_resource,
+	.num_resources	= ARRAY_SIZE(cpu_pmu_resource),
 };
 
 static struct platform_device *pmu_devices[] = {
diff --git a/arch/arm/mach-msm/qdsp5/adsp.c b/arch/arm/mach-msm/qdsp5/adsp.c
index 33c5a53..1bf2a55 100644
--- a/arch/arm/mach-msm/qdsp5/adsp.c
+++ b/arch/arm/mach-msm/qdsp5/adsp.c
@@ -3,7 +3,7 @@
  * Register/Interrupt access for userspace aDSP library.
  *
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  * Author: Iliyan Malchev <ibm@android.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -280,6 +280,7 @@
 	int rc = 0;
 	static uint32_t init_info_cmd_sent;
 
+	mutex_lock(&adsp_info.lock);
 	if (!init_info_cmd_sent) {
 		init_waitqueue_head(&adsp_info.init_info_wait);
 		msm_get_init_info();
@@ -288,10 +289,13 @@
 			5 * HZ);
 		if (!rc) {
 			MM_ERR("INIT_INFO failed\n");
+			mutex_unlock(&adsp_info.lock);
 			return -ETIMEDOUT;
+
 		}
 		init_info_cmd_sent++;
 	}
+	mutex_unlock(&adsp_info.lock);
 
 	module = find_adsp_module_by_name(&adsp_info, name);
 	if (!module)
@@ -1016,16 +1020,49 @@
 
 int adsp_set_clkrate(struct msm_adsp_module *module, unsigned long clk_rate)
 {
+	if (!module)
+		return -EINVAL;
+
 	if (module->clk && clk_rate)
 		return clk_set_rate(module->clk, clk_rate);
 
 	return -EINVAL;
 }
 
+int msm_adsp_generate_event(void *data,
+			struct msm_adsp_module *mod,
+			unsigned event_id,
+			unsigned event_length,
+			unsigned event_size,
+			void *msg)
+{
+	unsigned long flags;
+	void (*func)(void *, size_t);
+
+	if (!mod)
+		return -EINVAL;
+
+	if (event_size == sizeof(uint32_t))
+		func = read_event_32;
+	else if (event_size == sizeof(uint16_t))
+		func = read_event_16;
+	else
+		return -EINVAL;
+
+	spin_lock_irqsave(&adsp_cmd_lock, flags);
+	read_event_addr = msg;
+	mod->ops->event(data, event_id, event_length, func);
+	spin_unlock_irqrestore(&adsp_cmd_lock, flags);
+	return 0;
+}
+
 int msm_adsp_enable(struct msm_adsp_module *module)
 {
 	int rc = 0;
 
+	if (!module)
+		return -EINVAL;
+
 	MM_INFO("enable '%s'state[%d] id[%d]\n",
 				module->name, module->state, module->id);
 
@@ -1078,6 +1115,9 @@
 {
 	int rc = 0;
 
+	if (!module)
+		return -EINVAL;
+
 	mutex_lock(&module->lock);
 
 	rc = rpc_adsp_rtos_app_to_modem(RPC_ADSP_RTOS_CMD_DISABLE_EVENT_RSP,
@@ -1092,6 +1132,9 @@
 {
 	int rc = 0;
 
+	if (!module)
+		return -EINVAL;
+
 	switch (module->state) {
 	case ADSP_STATE_DISABLED:
 		MM_DBG("module '%s' already disabled\n", module->name);
@@ -1117,6 +1160,10 @@
 int msm_adsp_disable(struct msm_adsp_module *module)
 {
 	int rc;
+
+	if (!module)
+		return -EINVAL;
+
 	MM_INFO("disable '%s'\n", module->name);
 	mutex_lock(&module->lock);
 	rc = msm_adsp_disable_locked(module);
@@ -1157,6 +1204,7 @@
 
 	spin_lock_init(&adsp_cmd_lock);
 	spin_lock_init(&adsp_write_lock);
+	mutex_init(&adsp_info.lock);
 
 	rc = request_irq(INT_ADSP, adsp_irq_handler, IRQF_TRIGGER_RISING,
 			 "adsp", 0);
diff --git a/arch/arm/mach-msm/qdsp5/adsp.h b/arch/arm/mach-msm/qdsp5/adsp.h
index 0ef27b9..8e5a4f3 100644
--- a/arch/arm/mach-msm/qdsp5/adsp.h
+++ b/arch/arm/mach-msm/qdsp5/adsp.h
@@ -1,7 +1,7 @@
 /* arch/arm/mach-msm/qdsp5/adsp.h
  *
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2010, 2012 Code Aurora Forum. All rights reserved.
  * Author: Iliyan Malchev <ibm@android.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -117,6 +117,7 @@
 	struct adsp_rtos_mp_mtoa_init_info_type	*init_info_ptr;
 	wait_queue_head_t	init_info_wait;
 	unsigned 		init_info_state;
+	struct mutex lock;
 };
 
 #define RPC_ADSP_RTOS_ATOM_NULL_PROC 0
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac.c b/arch/arm/mach-msm/qdsp5/audio_aac.c
index 5e1e655..de756eb 100644
--- a/arch/arm/mach-msm/qdsp5/audio_aac.c
+++ b/arch/arm/mach-msm/qdsp5/audio_aac.c
@@ -4,7 +4,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2008-2009, 2011 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2009, 2011-2012 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
@@ -298,6 +298,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
@@ -672,24 +673,31 @@
 
 static void audio_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->reserved = 0;
 	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	atomic_set(&audio->out_bytes, 0);
 }
 
 static void audio_flush_pcm_buf(struct audio *audio)
 {
 	uint8_t index;
+	unsigned long flags;
 
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
 		audio->in[index].used = 0;
 	audio->buf_refresh = 0;
 	audio->read_next = 0;
 	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static int audaac_validate_usr_config(struct msm_audio_aac_config *config)
@@ -990,7 +998,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audio_disable(audio);
-		audio->stopped = 1;
 		audio_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac_in.c b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
index c9e60d8..456a8ff 100644
--- a/arch/arm/mach-msm/qdsp5/audio_aac_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
@@ -2,7 +2,7 @@
  *
  * aac audio input device
  *
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This code is based in part on arch/arm/mach-msm/qdsp5v2/audio_aac_in.c,
  * Copyright (C) 2008 Google, Inc.
@@ -320,9 +320,10 @@
 
 		audaac_in_dsp_enable(audio, 0);
 
-		wake_up(&audio->wait);
 		wait_event_interruptible_timeout(audio->wait_enable,
 				audio->running == 0, 1*HZ);
+		audio->stopped = 1;
+		wake_up(&audio->wait);
 		msm_adsp_disable(audio->audrec);
 		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
 			msm_adsp_disable(audio->audpre);
@@ -697,21 +698,23 @@
 	 * sleep and knowing that system is not able
 	 * to process io request at the moment
 	 */
-	wake_up(&audio->write_wait);
-	mutex_lock(&audio->write_lock);
-	audaac_in_flush(audio);
-	mutex_unlock(&audio->write_lock);
 	wake_up(&audio->wait);
 	mutex_lock(&audio->read_lock);
-	audaac_out_flush(audio);
+	audaac_in_flush(audio);
 	mutex_unlock(&audio->read_lock);
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audaac_out_flush(audio);
+	mutex_unlock(&audio->write_lock);
 }
 
 static void audaac_in_flush(struct audio_aac_in *audio)
 {
 	int i;
+	unsigned long flags;
 
 	audio->dsp_cnt = 0;
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->in_head = 0;
 	audio->in_tail = 0;
 	audio->in_count = 0;
@@ -720,6 +723,7 @@
 		audio->in[i].size = 0;
 		audio->in[i].read = 0;
 	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
 	MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
 	atomic_set(&audio->in_bytes, 0);
@@ -729,15 +733,18 @@
 static void audaac_out_flush(struct audio_aac_in *audio)
 {
 	int i;
+	unsigned long flags;
 
 	audio->out_head = 0;
-	audio->out_tail = 0;
 	audio->out_count = 0;
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->out_tail = 0;
 	for (i = OUT_FRAME_NUM-1; i >= 0; i--) {
 		audio->out[i].size = 0;
 		audio->out[i].read = 0;
 		audio->out[i].used = 0;
 	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 /* ------------------- device --------------------- */
@@ -777,7 +784,6 @@
 	}
 	case AUDIO_STOP: {
 		rc = audaac_in_disable(audio);
-		audio->stopped = 1;
 		break;
 	}
 	case AUDIO_FLUSH: {
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb.c b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
index 476a63d..d66a270 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
@@ -2,7 +2,7 @@
  *
  * amrnb audio decoder device
  *
- * Copyright (c) 2008-2009, 2011 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2009, 2011-2012 Code Aurora Forum. All rights reserved.
  *
  * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5/audio_mp3.c
  *
@@ -302,6 +302,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
@@ -628,24 +629,31 @@
 
 static void audamrnb_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	atomic_set(&audio->out_bytes, 0);
 }
 
 static void audamrnb_flush_pcm_buf(struct audio *audio)
 {
 	uint8_t index;
+	unsigned long flags;
 
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
 		audio->in[index].used = 0;
 
 	audio->buf_refresh = 0;
 	audio->read_next = 0;
 	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static void audamrnb_ioport_reset(struct audio *audio)
@@ -876,7 +884,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audamrnb_disable(audio);
-		audio->stopped = 1;
 		audamrnb_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrwb.c b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
index e811731..b566c60 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrwb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
@@ -6,7 +6,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009, 2011 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009, 2011-2012 Code Aurora Forum. All rights reserved.
  *
  * All source code in this file is licensed under the following license except
  * where indicated.
@@ -299,6 +299,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
@@ -616,25 +617,32 @@
 
 static void audamrwb_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->reserved = 0;
 	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	atomic_set(&audio->out_bytes, 0);
 }
 
 static void audamrwb_flush_pcm_buf(struct audio *audio)
 {
 	uint8_t index;
+	unsigned long flags;
 
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
 		audio->in[index].used = 0;
 
 	audio->buf_refresh = 0;
 	audio->read_next = 0;
 	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static void audamrwb_ioport_reset(struct audio *audio)
@@ -865,7 +873,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audamrwb_disable(audio);
-		audio->stopped = 1;
 		audamrwb_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc.c b/arch/arm/mach-msm/qdsp5/audio_evrc.c
index 3c39b6d..86035db 100644
--- a/arch/arm/mach-msm/qdsp5/audio_evrc.c
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc.c
@@ -1,6 +1,6 @@
 /* arch/arm/mach-msm/audio_evrc.c
  *
- * Copyright (c) 2008-2009, 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2009, 2011-2012 Code Aurora Forum. All rights reserved.
  *
  * This code also borrows from audio_aac.c, which is
  * Copyright (C) 2008 Google, Inc.
@@ -291,6 +291,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
@@ -615,24 +616,30 @@
 
 static void audevrc_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	atomic_set(&audio->out_bytes, 0);
 }
 
 static void audevrc_flush_pcm_buf(struct audio *audio)
 {
 	uint8_t index;
+	unsigned long flags;
 
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
 		audio->in[index].used = 0;
-
 	audio->buf_refresh = 0;
 	audio->read_next = 0;
 	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static void audevrc_ioport_reset(struct audio *audio)
@@ -863,7 +870,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audevrc_disable(audio);
-		audio->stopped = 1;
 		audevrc_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
index 7a5536a..0bdbf5d 100644
--- a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
@@ -2,7 +2,7 @@
  *
  * evrc audio input device
  *
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This code is based in part on arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c,
  * Copyright (C) 2008 Google, Inc.
@@ -281,6 +281,8 @@
 		wake_up(&audio->wait);
 		wait_event_interruptible_timeout(audio->wait_enable,
 				audio->running == 0, 1*HZ);
+		audio->stopped = 1;
+		wake_up(&audio->wait);
 		msm_adsp_disable(audio->audrec);
 		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
 			msm_adsp_disable(audio->audpre);
@@ -655,21 +657,23 @@
 	 * sleep and knowing that system is not able
 	 * to process io request at the moment
 	 */
-	wake_up(&audio->write_wait);
-	mutex_lock(&audio->write_lock);
-	audevrc_in_flush(audio);
-	mutex_unlock(&audio->write_lock);
 	wake_up(&audio->wait);
 	mutex_lock(&audio->read_lock);
-	audevrc_out_flush(audio);
+	audevrc_in_flush(audio);
 	mutex_unlock(&audio->read_lock);
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audevrc_out_flush(audio);
+	mutex_unlock(&audio->write_lock);
 }
 
 static void audevrc_in_flush(struct audio_evrc_in *audio)
 {
 	int i;
+	unsigned long flags;
 
 	audio->dsp_cnt = 0;
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->in_head = 0;
 	audio->in_tail = 0;
 	audio->in_count = 0;
@@ -678,6 +682,7 @@
 		audio->in[i].size = 0;
 		audio->in[i].read = 0;
 	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
 	MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
 	atomic_set(&audio->in_bytes, 0);
@@ -687,15 +692,18 @@
 static void audevrc_out_flush(struct audio_evrc_in *audio)
 {
 	int i;
+	unsigned long flags;
 
 	audio->out_head = 0;
-	audio->out_tail = 0;
 	audio->out_count = 0;
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->out_tail = 0;
 	for (i = OUT_FRAME_NUM-1; i >= 0; i--) {
 		audio->out[i].size = 0;
 		audio->out[i].read = 0;
 		audio->out[i].used = 0;
 	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 /* ------------------- device --------------------- */
@@ -735,7 +743,6 @@
 	}
 	case AUDIO_STOP: {
 		rc = audevrc_in_disable(audio);
-		audio->stopped = 1;
 		break;
 	}
 	case AUDIO_FLUSH: {
diff --git a/arch/arm/mach-msm/qdsp5/audio_mp3.c b/arch/arm/mach-msm/qdsp5/audio_mp3.c
index c4b464a..f6fa62a 100644
--- a/arch/arm/mach-msm/qdsp5/audio_mp3.c
+++ b/arch/arm/mach-msm/qdsp5/audio_mp3.c
@@ -4,7 +4,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, 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
@@ -368,6 +368,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
@@ -853,12 +854,16 @@
 
 static void audio_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->reserved = 0;
 	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	atomic_set(&audio->out_bytes, 0);
 }
 
@@ -885,13 +890,15 @@
 static void audio_flush_pcm_buf(struct audio *audio)
 {
 	uint8_t index;
+	unsigned long flags;
 
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
 		audio->in[index].used = 0;
-
 	audio->buf_refresh = 0;
 	audio->read_next = 0;
 	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static void audio_ioport_reset(struct audio *audio)
@@ -1366,7 +1373,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audio_disable(audio);
-		audio->stopped = 1;
 		audio_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_mvs.c b/arch/arm/mach-msm/qdsp5/audio_mvs.c
index 9c27485..5ccd18b 100644
--- a/arch/arm/mach-msm/qdsp5/audio_mvs.c
+++ b/arch/arm/mach-msm/qdsp5/audio_mvs.c
@@ -25,7 +25,7 @@
 
 #define MVS_PROG 0x30000014
 #define MVS_VERS 0x00030001
-#define MVS_VERS_COMP_VER2 0x00020001
+#define MVS_VERS_COMP_VER2 0x00060001
 #define MVS_VERS_COMP_VER3 0x00030001
 
 
@@ -67,6 +67,8 @@
 #define MVS_FRAME_MODE_G711_DL 10
 #define MVS_FRAME_MODE_PCM_UL 13
 #define MVS_FRAME_MODE_PCM_DL 14
+#define MVS_FRAME_MODE_PCM_WB_UL 23
+#define MVS_FRAME_MODE_PCM_WB_DL 24
 #define MVS_FRAME_MODE_G729A_UL 17
 #define MVS_FRAME_MODE_G729A_DL 18
 #define MVS_FRAME_MODE_G711A_UL 19
@@ -404,6 +406,11 @@
 		audio->frame_mode = MVS_FRAME_MODE_PCM_DL;
 		break;
 	}
+	case MVS_MODE_PCM_WB: {
+		audio->rate_type = MVS_AMR_MODE_UNDEF;
+		audio->frame_mode = MVS_FRAME_MODE_PCM_WB_DL;
+		break;
+	}
 	case MVS_MODE_IS127:
 	case MVS_MODE_IS733:
 	case MVS_MODE_4GV_NB:
diff --git a/arch/arm/mach-msm/qdsp5/audio_out.c b/arch/arm/mach-msm/qdsp5/audio_out.c
index 7c56037..7d33e05 100644
--- a/arch/arm/mach-msm/qdsp5/audio_out.c
+++ b/arch/arm/mach-msm/qdsp5/audio_out.c
@@ -247,6 +247,7 @@
 
 		audpp_disable(-1, audio);
 
+		audio->stopped = 1;
 		wake_up(&audio->wait);
 		audmgr_disable(&audio->audmgr);
 		audio->out_needed = 0;
@@ -519,7 +520,6 @@
 		break;
 	case AUDIO_STOP:
 		rc = audio_disable(audio);
-		audio->stopped = 1;
 		break;
 	case AUDIO_FLUSH:
 		if (audio->stopped) {
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm.c b/arch/arm/mach-msm/qdsp5/audio_pcm.c
index 02103fc..6468e93 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm.c
@@ -1,7 +1,7 @@
 
 /* audio_pcm.c - pcm audio decoder driver
  *
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  *
  * Based on the mp3 decoder driver in arch/arm/mach-msm/qdsp5/audio_mp3.c
  *
@@ -336,6 +336,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		msm_adsp_disable(audio->audplay);
 		audpp_disable(audio->dec_id, audio);
@@ -639,12 +640,16 @@
 
 static void audio_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->reserved = 0;
 	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	atomic_set(&audio->out_bytes, 0);
 }
 
@@ -1041,7 +1046,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audio_disable(audio);
-		audio->stopped = 1;
 		audio_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
index 81813a0..16c70ce 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
@@ -218,6 +218,7 @@
 
 		audpcm_in_dsp_enable(audio, 0);
 
+		audio->stopped = 1;
 		wake_up(&audio->wait);
 
 		msm_adsp_disable(audio->audrec);
@@ -613,7 +614,6 @@
 	}
 	case AUDIO_STOP:
 		rc = audpcm_in_disable(audio);
-		audio->stopped = 1;
 		break;
 	case AUDIO_FLUSH:
 		if (audio->stopped) {
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp.c b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
index b12e713..2be5144 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
@@ -2,7 +2,7 @@
  *
  * qcelp 13k audio decoder device
  *
- * Copyright (c) 2008-2009, 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2009, 2011-2012 Code Aurora Forum. All rights reserved.
  *
  * This code is based in part on audio_mp3.c, which is
  * Copyright (C) 2008 Google, Inc.
@@ -288,6 +288,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
@@ -612,23 +613,30 @@
 
 static void audqcelp_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static void audqcelp_flush_pcm_buf(struct audio *audio)
 {
 	uint8_t index;
+	unsigned long flags;
 
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
 		audio->in[index].used = 0;
 
 	audio->buf_refresh = 0;
 	audio->read_next = 0;
 	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static void audqcelp_ioport_reset(struct audio *audio)
@@ -859,7 +867,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audqcelp_disable(audio);
-		audio->stopped = 1;
 		audqcelp_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
index a339825..a79f721 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
@@ -2,7 +2,7 @@
  *
  * qcelp audio input device
  *
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This code is based in part on arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c,
  * Copyright (C) 2008 Google, Inc.
@@ -279,9 +279,10 @@
 
 		audqcelp_in_dsp_enable(audio, 0);
 
-		wake_up(&audio->wait);
 		wait_event_interruptible_timeout(audio->wait_enable,
 				audio->running == 0, 1*HZ);
+		audio->stopped = 1;
+		wake_up(&audio->wait);
 		msm_adsp_disable(audio->audrec);
 		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
 			msm_adsp_disable(audio->audpre);
@@ -657,29 +658,32 @@
 	 * sleep and knowing that system is not able
 	 * to process io request at the moment
 	 */
-	wake_up(&audio->write_wait);
-	mutex_lock(&audio->write_lock);
-	audqcelp_in_flush(audio);
-	mutex_unlock(&audio->write_lock);
 	wake_up(&audio->wait);
 	mutex_lock(&audio->read_lock);
-	audqcelp_out_flush(audio);
+	audqcelp_in_flush(audio);
 	mutex_unlock(&audio->read_lock);
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audqcelp_out_flush(audio);
+	mutex_unlock(&audio->write_lock);
 }
 
 static void audqcelp_in_flush(struct audio_qcelp_in *audio)
 {
 	int i;
+	unsigned long flags;
 
+	audio->eos_ack = 0;
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->dsp_cnt = 0;
 	audio->in_head = 0;
 	audio->in_tail = 0;
 	audio->in_count = 0;
-	audio->eos_ack = 0;
 	for (i = FRAME_NUM-1; i >= 0; i--) {
 		audio->in[i].size = 0;
 		audio->in[i].read = 0;
 	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
 	MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
 	atomic_set(&audio->in_bytes, 0);
@@ -689,15 +693,18 @@
 static void audqcelp_out_flush(struct audio_qcelp_in *audio)
 {
 	int i;
+	unsigned long flags;
 
 	audio->out_head = 0;
-	audio->out_tail = 0;
 	audio->out_count = 0;
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->out_tail = 0;
 	for (i = OUT_FRAME_NUM-1; i >= 0; i--) {
 		audio->out[i].size = 0;
 		audio->out[i].read = 0;
 		audio->out[i].used = 0;
 	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 /* ------------------- device --------------------- */
@@ -737,7 +744,6 @@
 	}
 	case AUDIO_STOP: {
 		rc = audqcelp_in_disable(audio);
-		audio->stopped = 1;
 		break;
 	}
 	case AUDIO_FLUSH: {
diff --git a/arch/arm/mach-msm/qdsp5/audio_voicememo.c b/arch/arm/mach-msm/qdsp5/audio_voicememo.c
index b7e8e1c..7a962b2 100644
--- a/arch/arm/mach-msm/qdsp5/audio_voicememo.c
+++ b/arch/arm/mach-msm/qdsp5/audio_voicememo.c
@@ -266,7 +266,9 @@
 		audio->in[index].used = 0;
 
 	audio->read_next = 0;
+	mutex_lock(&audio->dsp_lock);
 	audio->fill_next = 0;
+	mutex_unlock(&audio->dsp_lock);
 }
 
 static void audvoicememo_ioport_reset(struct audio_voicememo *audio)
@@ -387,6 +389,7 @@
 		rc = msm_rpc_write(audio->sndept, &rhdr, sizeof(rhdr));
 		wait_event_timeout(audio->wait, audio->stopped == 0,
 				1 * HZ);
+		audio->stopped = 1;
 		wake_up(&audio->read_wait);
 		audmgr_disable(&audio->audmgr);
 		audio->enabled = 0;
@@ -536,12 +539,14 @@
 					callback time\n");
 		else if (rec_status == RPC_VOC_REC_STAT_AUTO_STOP) {
 			MM_DBG(" Voice Record AUTO STOP\n");
+			mutex_lock(&audio->lock);
+			audio->stopped = 1;
 			wake_up(&audio->read_wait);
 			audmgr_disable(&audio->audmgr);
-			audio->stopped = 1;
 			audvoicememo_ioport_reset(audio);
 			audio->stopped = 0;
 			audio->enabled = 0;
+			mutex_unlock(&audio->lock);
 		}
 			break;
 		}
@@ -648,7 +653,6 @@
 	case AUDIO_STOP: {
 			MM_DBG("AUDIO_STOP\n");
 			rc = audvoicememo_disable(audio);
-			audio->stopped = 1;
 			audvoicememo_ioport_reset(audio);
 			audio->stopped = 0;
 			MM_DBG("AUDIO_STOP rc %d\n", rc);
diff --git a/arch/arm/mach-msm/qdsp5/audio_wma.c b/arch/arm/mach-msm/qdsp5/audio_wma.c
index cf2ade4..674ee4f 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wma.c
@@ -1,6 +1,6 @@
 /* audio_wma.c - wma audio decoder driver
  *
- * Copyright (c) 2009, 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009, 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5/audio_mp3.c
  *
@@ -306,6 +306,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
@@ -659,11 +660,15 @@
 
 static void audio_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->reserved = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	atomic_set(&audio->out_bytes, 0);
 }
 
@@ -671,11 +676,15 @@
 {
 	uint8_t index;
 
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
 		audio->in[index].used = 0;
 	audio->buf_refresh = 0;
 	audio->read_next = 0;
 	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static void audio_ioport_reset(struct audio *audio)
@@ -905,7 +914,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audio_disable(audio);
-		audio->stopped = 1;
 		audio_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audio_wmapro.c b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
index d9b384a..c2a0b93 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wmapro.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
@@ -4,7 +4,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  *
  * All source code in this file is licensed under the following license except
  * where indicated.
@@ -301,6 +301,7 @@
 			rc = -EFAULT;
 		else
 			rc = 0;
+		audio->stopped = 1;
 		wake_up(&audio->write_wait);
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
@@ -648,23 +649,30 @@
 
 static void audio_flush(struct audio *audio)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	audio->out[0].used = 0;
 	audio->out[1].used = 0;
 	audio->out_head = 0;
 	audio->out_tail = 0;
 	audio->reserved = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 	atomic_set(&audio->out_bytes, 0);
 }
 
 static void audio_flush_pcm_buf(struct audio *audio)
 {
 	uint8_t index;
+	unsigned long flags;
 
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
 		audio->in[index].used = 0;
 	audio->buf_refresh = 0;
 	audio->read_next = 0;
 	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static void audio_ioport_reset(struct audio *audio)
@@ -894,7 +902,6 @@
 	case AUDIO_STOP:
 		MM_DBG("AUDIO_STOP\n");
 		rc = audio_disable(audio);
-		audio->stopped = 1;
 		audio_ioport_reset(audio);
 		audio->stopped = 0;
 		break;
diff --git a/arch/arm/mach-msm/qdsp5/audpp.c b/arch/arm/mach-msm/qdsp5/audpp.c
index 3e834d8..2dbb5dc0 100644
--- a/arch/arm/mach-msm/qdsp5/audpp.c
+++ b/arch/arm/mach-msm/qdsp5/audpp.c
@@ -4,7 +4,7 @@
  * common code to deal with the AUDPP dsp task (audio postproc)
  *
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2010, 2012 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
@@ -124,6 +124,8 @@
 	uint16_t avsync[CH_COUNT * AUDPP_CLNT_MAX_COUNT + 1];
 	struct audpp_event_callback *cb_tbl[MAX_EVENT_CALLBACK_CLIENTS];
 
+	spinlock_t avsync_lock;
+
 	wait_queue_head_t event_wait;
 };
 
@@ -237,13 +239,24 @@
 	}
 }
 
+static void audpp_fake_event(struct audpp_state *audpp, int id,
+			     unsigned event, unsigned arg)
+{
+	uint16_t msg[1];
+	msg[0] = arg;
+	audpp->func[id] (audpp->private[id], event, msg);
+}
+
 static void audpp_dsp_event(void *data, unsigned id, size_t len,
 			    void (*getevent) (void *ptr, size_t len))
 {
 	struct audpp_state *audpp = data;
+	unsigned long flags;
 	uint16_t msg[8];
+	int cid = 0;
 
 	if (id == AUDPP_MSG_AVSYNC_MSG) {
+		spin_lock_irqsave(&audpp->avsync_lock, flags);
 		getevent(audpp->avsync, sizeof(audpp->avsync));
 
 		/* mask off any channels we're not watching to avoid
@@ -252,6 +265,7 @@
 		 * we next read...
 		 */
 		audpp->avsync[0] &= audpp->avsync_mask;
+		spin_unlock_irqrestore(&audpp->avsync_lock, flags);
 		return;
 	}
 
@@ -278,13 +292,28 @@
 	case AUDPP_MSG_CFG_MSG:
 		if (msg[0] == AUDPP_MSG_ENA_ENA) {
 			MM_INFO("ENABLE\n");
-			audpp->enabled = 1;
-			audpp_broadcast(audpp, id, msg);
+			if (!audpp->enabled) {
+				audpp->enabled = 1;
+				audpp_broadcast(audpp, id, msg);
+			} else {
+				cid = msg[1];
+				audpp_fake_event(audpp, cid,
+					id, AUDPP_MSG_ENA_ENA);
+			}
+
 		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
-			MM_INFO("DISABLE\n");
-			audpp->enabled = 0;
-			wake_up(&audpp->event_wait);
-			audpp_broadcast(audpp, id, msg);
+			if (audpp->open_count == 0) {
+				MM_INFO("DISABLE\n");
+				audpp->enabled = 0;
+				wake_up(&audpp->event_wait);
+				audpp_broadcast(audpp, id, msg);
+			} else {
+				cid = msg[1];
+				audpp_fake_event(audpp, cid,
+					id, AUDPP_MSG_ENA_DIS);
+				audpp->func[cid] = NULL;
+				audpp->private[cid] = NULL;
+			}
 		} else {
 			MM_ERR("invalid config msg %d\n", msg[0]);
 		}
@@ -307,17 +336,10 @@
 	.event = audpp_dsp_event,
 };
 
-static void audpp_fake_event(struct audpp_state *audpp, int id,
-			     unsigned event, unsigned arg)
-{
-	uint16_t msg[1];
-	msg[0] = arg;
-	audpp->func[id] (audpp->private[id], event, msg);
-}
-
 int audpp_enable(int id, audpp_event_func func, void *private)
 {
 	struct audpp_state *audpp = &the_audpp_state;
+	uint16_t msg[8];
 	int res = 0;
 
 	if (id < -1 || id > 4)
@@ -350,12 +372,15 @@
 		msm_adsp_enable(audpp->mod);
 		audpp_dsp_config(1);
 	} else {
-		unsigned long flags;
-		local_irq_save(flags);
-		if (audpp->enabled)
-			audpp_fake_event(audpp, id,
-					 AUDPP_MSG_CFG_MSG, AUDPP_MSG_ENA_ENA);
-		local_irq_restore(flags);
+		if (audpp->enabled) {
+			msg[0] = AUDPP_MSG_ENA_ENA;
+			msg[1] = id;
+			res = msm_adsp_generate_event(audpp, audpp->mod,
+					 AUDPP_MSG_CFG_MSG, sizeof(msg),
+					 sizeof(uint16_t), (void *)msg);
+			if (res < 0)
+				goto out;
+		}
 	}
 
 	res = 0;
@@ -368,7 +393,7 @@
 void audpp_disable(int id, void *private)
 {
 	struct audpp_state *audpp = &the_audpp_state;
-	unsigned long flags;
+	uint16_t msg[8];
 	int rc;
 
 	if (id < -1 || id > 4)
@@ -384,11 +409,13 @@
 	if (audpp->private[id] != private)
 		goto out;
 
-	local_irq_save(flags);
-	audpp_fake_event(audpp, id, AUDPP_MSG_CFG_MSG, AUDPP_MSG_ENA_DIS);
-	audpp->func[id] = NULL;
-	audpp->private[id] = NULL;
-	local_irq_restore(flags);
+	msg[0] = AUDPP_MSG_ENA_DIS;
+	msg[1] = id;
+	rc = msm_adsp_generate_event(audpp, audpp->mod,
+				 AUDPP_MSG_CFG_MSG, sizeof(msg),
+				 sizeof(uint16_t), (void *)msg);
+	if (rc < 0)
+		goto out;
 
 	if (--audpp->open_count == 0) {
 		MM_DBG("disable\n");
@@ -420,13 +447,13 @@
 	if (BAD_ID(id))
 		return;
 
-	local_irq_save(flags);
+	spin_lock_irqsave(&the_audpp_state.avsync_lock, flags);
 	if (rate)
 		the_audpp_state.avsync_mask |= (1 << id);
 	else
 		the_audpp_state.avsync_mask &= (~(1 << id));
 	the_audpp_state.avsync[0] &= the_audpp_state.avsync_mask;
-	local_irq_restore(flags);
+	spin_unlock_irqrestore(&the_audpp_state.avsync_lock, flags);
 
 	cmd.cmd_id = AUDPP_CMD_AVSYNC;
 	cmd.object_number = id;
@@ -438,7 +465,8 @@
 
 unsigned audpp_avsync_sample_count(int id)
 {
-	uint16_t *avsync = the_audpp_state.avsync;
+	struct audpp_state *audpp = &the_audpp_state;
+	uint16_t *avsync = audpp->avsync;
 	unsigned val;
 	unsigned long flags;
 	unsigned mask;
@@ -448,12 +476,12 @@
 
 	mask = 1 << id;
 	id = id * AUDPP_AVSYNC_INFO_SIZE + 2;
-	local_irq_save(flags);
+	spin_lock_irqsave(&audpp->avsync_lock, flags);
 	if (avsync[0] & mask)
 		val = (avsync[id] << 16) | avsync[id + 1];
 	else
 		val = 0;
-	local_irq_restore(flags);
+	spin_unlock_irqrestore(&audpp->avsync_lock, flags);
 
 	return val;
 }
@@ -461,7 +489,8 @@
 
 unsigned audpp_avsync_byte_count(int id)
 {
-	uint16_t *avsync = the_audpp_state.avsync;
+	struct audpp_state *audpp = &the_audpp_state;
+	uint16_t *avsync = audpp->avsync;
 	unsigned val;
 	unsigned long flags;
 	unsigned mask;
@@ -471,12 +500,12 @@
 
 	mask = 1 << id;
 	id = id * AUDPP_AVSYNC_INFO_SIZE + 5;
-	local_irq_save(flags);
+	spin_lock_irqsave(&audpp->avsync_lock, flags);
 	if (avsync[0] & mask)
 		val = (avsync[id] << 16) | avsync[id + 1];
 	else
 		val = 0;
-	local_irq_restore(flags);
+	spin_unlock_irqrestore(&audpp->avsync_lock, flags);
 
 	return val;
 }
@@ -826,6 +855,8 @@
 
 	init_waitqueue_head(&audpp->event_wait);
 
+	spin_lock_init(&audpp->avsync_lock);
+
 	for (idx = 0; idx < audpp->dec_database->num_dec; idx++) {
 		audpp->dec_info_table[idx].codec = -1;
 		audpp->dec_info_table[idx].pid = 0;
diff --git a/arch/arm/mach-msm/scm-pas.c b/arch/arm/mach-msm/scm-pas.c
index 747b585..e0d0dd8 100644
--- a/arch/arm/mach-msm/scm-pas.c
+++ b/arch/arm/mach-msm/scm-pas.c
@@ -190,10 +190,7 @@
 
 static int __init scm_pas_init(void)
 {
-	/* TODO: Remove once bus scaling driver is in place */
-	if (!cpu_is_apq8064())
-		scm_perf_client = msm_bus_scale_register_client(
-				&scm_pas_bus_pdata);
+	scm_perf_client = msm_bus_scale_register_client(&scm_pas_bus_pdata);
 	if (!scm_perf_client)
 		pr_warn("unable to register bus client\n");
 	scm_bus_clk = clk_get_sys("scm", "bus_clk");
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index a1bf280..9b10ffd 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -604,7 +604,7 @@
 
 arch_initcall(socinfo_init_sysdev);
 
-void *setup_dummy_socinfo(void)
+static void * __init setup_dummy_socinfo(void)
 {
 	if (machine_is_msm8960_rumi3() || machine_is_msm8960_sim() ||
 	    machine_is_msm8960_cdp())
diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c
index 14536f6..946899d 100644
--- a/arch/arm/mm/context.c
+++ b/arch/arm/mm/context.c
@@ -17,6 +17,8 @@
 #include <asm/thread_notify.h>
 #include <asm/tlbflush.h>
 
+#include <mach/msm_rtb.h>
+
 static DEFINE_RAW_SPINLOCK(cpu_asid_lock);
 unsigned int cpu_last_asid = ASID_FIRST_VERSION;
 #ifdef CONFIG_SMP
@@ -25,6 +27,7 @@
 
 static void write_contextidr(u32 contextidr)
 {
+	uncached_logk(LOGK_CTXID, (void *)contextidr);
 	asm("mcr	p15, 0, %0, c13, c0, 1" : : "r" (contextidr));
 	isb();
 }
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 7d28604..371d319 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -52,8 +52,8 @@
 #define MAX_EQUIP_ID 12
 
 /* Maximum number of pkt reg supported at initialization*/
-extern unsigned int diag_max_registration;
-extern unsigned int diag_threshold_registration;
+extern unsigned int diag_max_reg;
+extern unsigned int diag_threshold_reg;
 
 #define APPEND_DEBUG(ch) \
 do {							\
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index e24d896..efba92b 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -60,8 +60,8 @@
 static unsigned int max_clients = 15;
 static unsigned int threshold_client_limit = 30;
 /* This is the maximum number of pkt registrations supported at initialization*/
-unsigned int diag_max_registration = 600;
-unsigned int diag_threshold_registration = 750;
+unsigned int diag_max_reg = 600;
+unsigned int diag_threshold_reg = 750;
 
 /* Timer variables */
 static struct timer_list drain_timer;
@@ -230,7 +230,7 @@
 	}
 #endif /* DIAG over USB */
 	/* Delete the pkt response table entry for the exiting process */
-	for (i = 0; i < diag_max_registration; i++)
+	for (i = 0; i < diag_max_reg; i++)
 			if (driver->table[i].process_id == current->tgid)
 					driver->table[i].process_id = 0;
 
@@ -286,13 +286,13 @@
 	mutex_lock(&driver->diagchar_mutex);
 	/* reset polling flag */
 	driver->polling_reg_flag = 0;
-	for (i = 0; i < diag_max_registration; i++) {
+	for (i = 0; i < diag_max_reg; i++) {
 		if (driver->table[i].client_id == proc_num) {
 			driver->table[i].process_id = 0;
 		}
 	}
 	/* re-scan the registration table */
-	for (i = 0; i < diag_max_registration; i++) {
+	for (i = 0; i < diag_max_reg; i++) {
 		if (diag_find_polling_reg(i) == 1) {
 			driver->polling_reg_flag = 1;
 			break;
@@ -335,7 +335,7 @@
 		struct bindpkt_params_per_process *pkt_params =
 			 (struct bindpkt_params_per_process *) ioarg;
 		mutex_lock(&driver->diagchar_mutex);
-		for (i = 0; i < diag_max_registration; i++) {
+		for (i = 0; i < diag_max_reg; i++) {
 			if (driver->table[i].process_id == 0) {
 				diag_add_reg(i, pkt_params->params,
 						&success, &count_entries);
@@ -347,19 +347,20 @@
 				}
 			}
 		}
-		if (i < diag_threshold_registration) {
+		if (i < diag_threshold_reg) {
 			/* Increase table size by amount required */
-			diag_max_registration += pkt_params->count -
+			diag_max_reg += pkt_params->count -
 							 count_entries;
 			/* Make sure size doesnt go beyond threshold */
-			if (diag_max_registration > diag_threshold_registration)
-				diag_max_registration =
-						 diag_threshold_registration;
+			if (diag_max_reg > diag_threshold_reg) {
+				diag_max_reg = diag_threshold_reg;
+				pr_info("diag: best case memory allocation\n");
+			}
 			temp_buf = krealloc(driver->table,
-					 diag_max_registration*sizeof(struct
+					 diag_max_reg*sizeof(struct
 					 diag_master_table), GFP_KERNEL);
 			if (!temp_buf) {
-				diag_max_registration -= pkt_params->count -
+				diag_max_reg -= pkt_params->count -
 							 count_entries;
 				pr_alert("diag: Insufficient memory for reg.");
 				mutex_unlock(&driver->diagchar_mutex);
@@ -367,7 +368,7 @@
 			} else {
 				driver->table = temp_buf;
 			}
-			for (j = i; j < diag_max_registration; j++) {
+			for (j = i; j < diag_max_reg; j++) {
 				diag_add_reg(j, pkt_params->params,
 						&success, &count_entries);
 				if (pkt_params->count > count_entries) {
@@ -377,6 +378,7 @@
 					return success;
 				}
 			}
+			mutex_unlock(&driver->diagchar_mutex);
 		} else {
 			mutex_unlock(&driver->diagchar_mutex);
 			pr_err("Max size reached, Pkt Registration failed for"
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 079e04b..7f26856 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -598,7 +598,7 @@
 	}
 
 	pr_debug("diag: %d %d %d", cmd_code, subsys_id, subsys_cmd_code);
-	for (i = 0; i < diag_max_registration; i++) {
+	for (i = 0; i < diag_max_reg; i++) {
 		entry = driver->table[i];
 		if (entry.process_id != NO_PROCESS) {
 			if (entry.cmd_code == cmd_code && entry.subsys_id ==
@@ -1374,7 +1374,7 @@
 							, GFP_KERNEL)) == NULL)
 		goto err;
 	if (driver->table == NULL &&
-	     (driver->table = kzalloc(diag_max_registration*
+	     (driver->table = kzalloc(diag_max_reg*
 		      sizeof(struct diag_master_table),
 		       GFP_KERNEL)) == NULL)
 		goto err;
diff --git a/drivers/char/hw_random/msm_rng.c b/drivers/char/hw_random/msm_rng.c
index d72e9b6..d1a9fe6 100644
--- a/drivers/char/hw_random/msm_rng.c
+++ b/drivers/char/hw_random/msm_rng.c
@@ -242,9 +242,6 @@
 
 static int __init msm_rng_init(void)
 {
-	if (cpu_is_apq8064())
-		return -ENODEV;
-
 	return platform_driver_register(&rng_driver);
 }
 
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index ad0c7b1..347ab88 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -206,16 +206,13 @@
 	if (ion_carveout_request_region(carveout_heap))
 		return -EINVAL;
 
-	if (ION_IS_CACHED(flags))
-		ret_value = remap_pfn_range(vma, vma->vm_start,
-			       __phys_to_pfn(buffer->priv_phys) + vma->vm_pgoff,
-			       vma->vm_end - vma->vm_start,
-			       vma->vm_page_prot);
-	else
-		ret_value = remap_pfn_range(vma, vma->vm_start,
-			       __phys_to_pfn(buffer->priv_phys) + vma->vm_pgoff,
-					vma->vm_end - vma->vm_start,
-					pgprot_noncached(vma->vm_page_prot));
+	if (!ION_IS_CACHED(flags))
+		vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+	ret_value =  remap_pfn_range(vma, vma->vm_start,
+			__phys_to_pfn(buffer->priv_phys) + vma->vm_pgoff,
+			vma->vm_end - vma->vm_start,
+			vma->vm_page_prot);
 
 	if (ret_value)
 		ion_carveout_release_region(carveout_heap);
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index a6b0cf6..ff561dc 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -450,18 +450,14 @@
 			return -EINVAL;
 		}
 
-		 if (ION_IS_CACHED(flags))
-			ret_value =  remap_pfn_range(vma, vma->vm_start,
-				__phys_to_pfn(buffer->priv_phys) +
-				vma->vm_pgoff,
-				vma->vm_end - vma->vm_start,
-				vma->vm_page_prot);
-		else
-			ret_value = remap_pfn_range(vma, vma->vm_start,
-				__phys_to_pfn(buffer->priv_phys) +
-				vma->vm_pgoff,
-				vma->vm_end - vma->vm_start,
-				pgprot_noncached(vma->vm_page_prot));
+		if (!ION_IS_CACHED(flags))
+			vma->vm_page_prot = pgprot_writecombine(
+							vma->vm_page_prot);
+
+		ret_value =  remap_pfn_range(vma, vma->vm_start,
+			__phys_to_pfn(buffer->priv_phys) + vma->vm_pgoff,
+			vma->vm_end - vma->vm_start,
+			vma->vm_page_prot);
 
 		if (ret_value)
 			ion_cp_release_region(cp_heap);
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index d37a811..2f9e80c 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -136,7 +136,7 @@
 		return -EINVAL;
 
 	if (!ION_IS_CACHED(flags))
-		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+		vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
 
 	for (i = 0; i < data->nrpages; i++)
 		if (vm_insert_page(vma, vma->vm_start + i * PAGE_SIZE,
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 1806886..7e684c0 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -229,6 +229,19 @@
 #define A3XX_VBIF_FIXED_SORT_EN 0x300C
 #define A3XX_VBIF_FIXED_SORT_SEL0 0x300D
 #define A3XX_VBIF_FIXED_SORT_SEL1 0x300E
+#define A3XX_VBIF_ABIT_SORT 0x301C
+#define A3XX_VBIF_ABIT_SORT_CONF 0x301D
+#define A3XX_VBIF_GATE_OFF_WRREQ_EN 0x302A
+#define A3XX_VBIF_IN_RD_LIM_CONF0 0x302C
+#define A3XX_VBIF_IN_RD_LIM_CONF1 0x302D
+#define A3XX_VBIF_IN_WR_LIM_CONF0 0x3030
+#define A3XX_VBIF_IN_WR_LIM_CONF1 0x3031
+#define A3XX_VBIF_OUT_RD_LIM_CONF0 0x3034
+#define A3XX_VBIF_OUT_WR_LIM_CONF0 0x3035
+#define A3XX_VBIF_DDR_OUT_MAX_BURST 0x3036
+#define A3XX_VBIF_ARB_CTL 0x303C
+#define A3XX_VBIF_OUT_AXI_AOOO_EN 0x305E
+#define A3XX_VBIF_OUT_AXI_AOOO 0x305F
 
 /* Bit flags for RBBM_CTL */
 #define RBBM_RBBM_CTL_RESET_PWR_CTR1  (1 << 1)
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index f68bc41..6525d9b 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -130,7 +130,7 @@
 /* Use shadow RAM */
 #define HLSQ_SHADOW_BASE		(0x10000+SSIZE*2)
 
-#define REG_TO_MEM_LOOP_COUNT_SHIFT	15
+#define REG_TO_MEM_LOOP_COUNT_SHIFT	18
 
 #define BUILD_PC_DRAW_INITIATOR(prim_type, source_select, index_size, \
 	vis_cull_mode) \
@@ -1109,11 +1109,13 @@
 
 	/* Constant save */
 	cmd = rmw_regtomem(cmd, A3XX_SP_VS_CTRL_REG1, 0x000003ff,
-			   17, (HLSQ_SHADOW_BASE + 0x2000) / 4,
+			   2 + REG_TO_MEM_LOOP_COUNT_SHIFT,
+			   (HLSQ_SHADOW_BASE + 0x2000) / 4,
 			   drawctxt->constant_save_commands[1].gpuaddr);
 
 	cmd = rmw_regtomem(cmd, A3XX_SP_FS_CTRL_REG1, 0x000003ff,
-			   17, (HLSQ_SHADOW_BASE + 0x2000 + SSIZE) / 4,
+			   2 + REG_TO_MEM_LOOP_COUNT_SHIFT,
+			   (HLSQ_SHADOW_BASE + 0x2000 + SSIZE) / 4,
 			   drawctxt->constant_save_commands[2].gpuaddr);
 
 	cmd = rmw_regtomem(cmd, A3XX_SP_FS_OBJ_OFFSET_REG, 0x00ff0000,
@@ -2546,14 +2548,29 @@
 		0x00000001);
 	msleep(20);
 
-	/*
-	 * enable fixed master AXI port of 0x0 for all clients to keep
-	 * traffic from going to random places
-	 */
+	/* Set up 16 deep read/write request queues */
 
-	adreno_regwrite(device, A3XX_VBIF_FIXED_SORT_EN, 0x0001003F);
-	adreno_regwrite(device, A3XX_VBIF_FIXED_SORT_SEL0, 0x00000000);
-	adreno_regwrite(device, A3XX_VBIF_FIXED_SORT_SEL1, 0x00000000);
+	adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010);
+	adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010);
+	adreno_regwrite(device, A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010);
+	adreno_regwrite(device, A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010);
+	adreno_regwrite(device, A3XX_VBIF_DDR_OUT_MAX_BURST, 0x00000303);
+	adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010);
+	adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010);
+
+	/* Enable WR-REQ */
+	adreno_regwrite(device, A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x000000FF);
+
+	/* Set up round robin arbitration between both AXI ports */
+	adreno_regwrite(device, A3XX_VBIF_ARB_CTL, 0x00000030);
+
+	/* Set up AOOO */
+	adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003C);
+	adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO, 0x003C003C);
+
+	/* Enable 1K sort */
+	adreno_regwrite(device, A3XX_VBIF_ABIT_SORT, 0x000000FF);
+	adreno_regwrite(device, A3XX_VBIF_ABIT_SORT_CONF, 0x000000A4);
 
 	/* Make all blocks contribute to the GPU BUSY perf counter */
 	adreno_regwrite(device, A3XX_RBBM_GPU_BUSY_MASKED, 0xFFFFFFFF);
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 1135adb..3e8aac3 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -199,7 +199,7 @@
 	if (ts_diff == 0)
 		return 0;
 
-	return ((ts_diff > 0) || (ts_diff < -20000)) ? 1 : -1;
+	return ((ts_diff > 0) || (ts_diff < -25000)) ? 1 : -1;
 }
 
 static inline void
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index a16b954..97b5ef1 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -398,11 +398,11 @@
 				enum kgsl_deviceid id)
 {
 	unsigned int result = 0;
-	struct kgsl_gpummu_pt *gpummu_pt = (struct kgsl_gpummu_pt *)
-						pt->priv;
+	struct kgsl_gpummu_pt *gpummu_pt;
 
 	if (pt == NULL)
 		return 0;
+	gpummu_pt = pt->priv;
 
 	spin_lock(&pt->lock);
 	if (gpummu_pt->tlb_flags && (1<<id)) {
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index e4e561c..194067b 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -24,11 +24,23 @@
 #include "kgsl_mmu.h"
 #include "kgsl_sharedmem.h"
 
+/*
+ * On APQ8064, KGSL can control a maximum of 4 IOMMU devices: 2 user and 2
+ * priv domains, 1 each for each of the AXI ports attached to the GPU.  8660
+ * and 8960 have only one AXI port, so maximum allowable IOMMU devices for those
+ * chips is 2.
+ */
+
+#define KGSL_IOMMU_MAX_DEV 4
+
+struct kgsl_iommu_device {
+	struct device *dev;
+	int attached;
+};
+
 struct kgsl_iommu {
-	struct device *iommu_user_dev;
-	int iommu_user_dev_attached;
-	struct device *iommu_priv_dev;
-	int iommu_priv_dev_attached;
+	struct kgsl_iommu_device dev[KGSL_IOMMU_MAX_DEV];
+	int dev_count;
 };
 
 static int kgsl_iommu_pt_equal(struct kgsl_pagetable *pt,
@@ -58,89 +70,101 @@
 {
 	struct iommu_domain *domain;
 	struct kgsl_iommu *iommu = mmu->priv;
+	int i;
 
 	BUG_ON(mmu->hwpagetable == NULL);
 	BUG_ON(mmu->hwpagetable->priv == NULL);
 
 	domain = mmu->hwpagetable->priv;
 
-	if (iommu->iommu_user_dev_attached) {
-		iommu_detach_device(domain, iommu->iommu_user_dev);
-		iommu->iommu_user_dev_attached = 0;
+	for (i = 0; i < iommu->dev_count; i++) {
+		iommu_detach_device(domain, iommu->dev[i].dev);
+		iommu->dev[i].attached = 0;
 		KGSL_MEM_INFO(mmu->device,
-				"iommu %p detached from user dev of MMU: %p\n",
-				domain, mmu);
-	}
-	if (iommu->iommu_priv_dev_attached) {
-		iommu_detach_device(domain, iommu->iommu_priv_dev);
-		iommu->iommu_priv_dev_attached = 0;
-		KGSL_MEM_INFO(mmu->device,
-				"iommu %p detached from priv dev of MMU: %p\n",
-				domain, mmu);
+			"iommu %p detached from user dev of MMU: %p\n",
+			domain, mmu);
 	}
 }
 
 static int kgsl_attach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
 {
 	struct iommu_domain *domain;
-	int ret = 0;
 	struct kgsl_iommu *iommu = mmu->priv;
+	int i, ret = 0;
 
 	BUG_ON(mmu->hwpagetable == NULL);
 	BUG_ON(mmu->hwpagetable->priv == NULL);
 
 	domain = mmu->hwpagetable->priv;
 
-	if (iommu->iommu_user_dev && !iommu->iommu_user_dev_attached) {
-		ret = iommu_attach_device(domain, iommu->iommu_user_dev);
-		if (ret) {
-			KGSL_MEM_ERR(mmu->device,
-			"Failed to attach device, err %d\n", ret);
-			goto done;
-		}
-		iommu->iommu_user_dev_attached = 1;
-		KGSL_MEM_INFO(mmu->device,
-				"iommu %p attached to user dev of MMU: %p\n",
+	for (i = 0; i < iommu->dev_count; i++) {
+		if (iommu->dev[i].attached == 0) {
+			ret = iommu_attach_device(domain, iommu->dev[i].dev);
+			if (ret) {
+				KGSL_MEM_ERR(mmu->device,
+					"Failed to attach device, err %d\n",
+						ret);
+				goto done;
+			}
+
+			iommu->dev[i].attached = 1;
+			KGSL_MEM_INFO(mmu->device,
+				"iommu %p detached from user dev of MMU: %p\n",
 				domain, mmu);
-	}
-	if (iommu->iommu_priv_dev && !iommu->iommu_priv_dev_attached) {
-		ret = iommu_attach_device(domain, iommu->iommu_priv_dev);
-		if (ret) {
-			KGSL_MEM_ERR(mmu->device,
-				"Failed to attach device, err %d\n", ret);
-			iommu_detach_device(domain, iommu->iommu_user_dev);
-			iommu->iommu_user_dev_attached = 0;
-			goto done;
 		}
-		iommu->iommu_priv_dev_attached = 1;
-		KGSL_MEM_INFO(mmu->device,
-				"iommu %p attached to priv dev of MMU: %p\n",
-				domain, mmu);
 	}
+
 done:
 	return ret;
 }
 
+static int _get_iommu_ctxs(struct kgsl_iommu *iommu, struct kgsl_device *device,
+	struct kgsl_device_iommu_data *data)
+{
+	int i;
+
+	for (i = 0; i < data->iommu_ctx_count; i++) {
+		if (iommu->dev_count >= KGSL_IOMMU_MAX_DEV) {
+			KGSL_CORE_ERR("Tried to attach too many IOMMU "
+				"devices\n");
+			return -ENOMEM;
+		}
+
+		if (!data->iommu_ctx_names[i])
+			continue;
+
+		iommu->dev[iommu->dev_count].dev =
+			msm_iommu_get_ctx(data->iommu_ctx_names[i]);
+		if (iommu->dev[iommu->dev_count].dev == NULL) {
+			KGSL_CORE_ERR("Failed to iommu dev handle for "
+				"device %s\n", data->iommu_ctx_names[i]);
+			return -EINVAL;
+		}
+
+		iommu->dev_count++;
+	}
+
+	return 0;
+}
+
 static int kgsl_get_iommu_ctxt(struct kgsl_iommu *iommu,
 				struct kgsl_device *device)
 {
-	int status = 0;
 	struct platform_device *pdev =
 		container_of(device->parentdev, struct platform_device, dev);
 	struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
-	if (pdata_dev->iommu_user_ctx_name)
-		iommu->iommu_user_dev = msm_iommu_get_ctx(
-					pdata_dev->iommu_user_ctx_name);
-	if (pdata_dev->iommu_priv_ctx_name)
-		iommu->iommu_priv_dev = msm_iommu_get_ctx(
-					pdata_dev->iommu_priv_ctx_name);
-	if (!iommu->iommu_user_dev) {
-		KGSL_CORE_ERR("Failed to get user iommu dev handle for "
-				"device %s\n",
-				pdata_dev->iommu_user_ctx_name);
-		status = -EINVAL;
+	int i, ret = 0;
+
+	/* Go through the IOMMU data and attach all the domains */
+
+	for (i = 0; i < pdata_dev->iommu_count; i++) {
+		ret = _get_iommu_ctxs(iommu, device,
+			&pdata_dev->iommu_data[i]);
+		if (ret)
+			break;
 	}
-	return status;
+
+	return ret;
 }
 
 static void kgsl_iommu_setstate(struct kgsl_device *device,
@@ -182,8 +206,6 @@
 		return -ENOMEM;
 	}
 
-	iommu->iommu_priv_dev_attached = 0;
-	iommu->iommu_user_dev_attached = 0;
 	status = kgsl_get_iommu_ctxt(iommu, device);
 	if (status) {
 		kfree(iommu);
diff --git a/drivers/hwmon/msm_adc.c b/drivers/hwmon/msm_adc.c
index b8d581e..39bfc3a 100644
--- a/drivers/hwmon/msm_adc.c
+++ b/drivers/hwmon/msm_adc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1380,7 +1380,7 @@
 	},
 };
 
-static int msm_adc_probe(struct platform_device *pdev)
+static int __devinit msm_adc_probe(struct platform_device *pdev)
 {
 	struct msm_adc_platform_data *pdata = pdev->dev.platform_data;
 	struct msm_adc_drv *msm_adc;
diff --git a/drivers/hwmon/pm8xxx-adc.c b/drivers/hwmon/pm8xxx-adc.c
index 5f8faee..0902c61 100644
--- a/drivers/hwmon/pm8xxx-adc.c
+++ b/drivers/hwmon/pm8xxx-adc.c
@@ -165,6 +165,7 @@
 };
 
 static struct pm8xxx_adc *pmic_adc;
+static struct regulator *pa_therm;
 
 static struct pm8xxx_adc_scale_fn adc_scale_fn[] = {
 	[ADC_SCALE_DEFAULT] = {pm8xxx_adc_scale_default},
@@ -238,26 +239,21 @@
 
 static int32_t pm8xxx_adc_patherm_power(bool on)
 {
-	static struct regulator *pa_therm;
-	struct pm8xxx_adc *adc_pmic = pmic_adc;
 	int rc = 0;
-	if (on) {
-		pa_therm = regulator_get(adc_pmic->dev,
-						"pa_therm");
-		if (IS_ERR(pa_therm)) {
-			rc = PTR_ERR(pa_therm);
-			pr_err("failed to request pa_therm vreg "
-					"with error %d\n", rc);
-			return rc;
-		}
 
+	if (!pa_therm) {
+		pr_err("pm8xxx adc pa_therm not valid\n");
+		return -EINVAL;
+	}
+
+	if (on) {
 		rc = regulator_set_voltage(pa_therm,
 				PM8XXX_ADC_PA_THERM_VREG_UV_MIN,
 				PM8XXX_ADC_PA_THERM_VREG_UV_MAX);
 		if (rc < 0) {
 			pr_err("failed to set the voltage for "
 					"pa_therm with error %d\n", rc);
-			goto fail;
+			return rc;
 		}
 
 		rc = regulator_set_optimum_mode(pa_therm,
@@ -265,25 +261,25 @@
 		if (rc < 0) {
 			pr_err("failed to set optimum mode for "
 					"pa_therm with error %d\n", rc);
-			goto fail;
+			return rc;
 		}
 
-		if (regulator_enable(pa_therm)) {
-			pr_err("failed to enable pa_therm vreg with "
-						"error %d\n", rc);
-			goto fail;
+		rc = regulator_enable(pa_therm);
+		if (rc < 0) {
+			pr_err("failed to enable pa_therm vreg "
+					"with error %d\n", rc);
+			return rc;
 		}
 	} else {
-		if (pa_therm != NULL) {
-			regulator_disable(pa_therm);
-			regulator_put(pa_therm);
+		rc = regulator_disable(pa_therm);
+		if (rc < 0) {
+			pr_err("failed to disable pa_therm vreg "
+					"with error %d\n", rc);
+			return rc;
 		}
 	}
 
 	return rc;
-fail:
-	regulator_put(pa_therm);
-	return rc;
 }
 
 static int32_t pm8xxx_adc_channel_power_enable(uint32_t channel,
@@ -293,7 +289,7 @@
 
 	switch (channel)
 	case ADC_MPP_1_AMUX8:
-		pm8xxx_adc_patherm_power(power_cntrl);
+		rc = pm8xxx_adc_patherm_power(power_cntrl);
 
 	return rc;
 }
@@ -769,6 +765,9 @@
 	struct pm8xxx_adc *adc_pmic = pmic_adc;
 	int rc = 0;
 
+	if (!pm8xxx_adc_initialized)
+		return -ENODEV;
+
 	if (!adc_pmic->mpp_base) {
 		rc = -EINVAL;
 		pr_info("PM8xxx MPP base invalid with error %d\n", rc);
@@ -1138,6 +1137,10 @@
 	wake_lock_destroy(&adc_pmic->adc_wakelock);
 	platform_set_drvdata(pdev, NULL);
 	pmic_adc = NULL;
+	if (!pa_therm) {
+		regulator_put(pa_therm);
+		pa_therm = NULL;
+	}
 	for (i = 0; i < adc_pmic->adc_num_board_channel; i++)
 		device_remove_file(adc_pmic->dev,
 				&adc_pmic->sens_attr[i].dev_attr);
@@ -1252,6 +1255,13 @@
 		dev_err(&pdev->dev, "failed to initialize pm8xxx hwmon adc\n");
 	}
 	adc_pmic->hwmon = hwmon_device_register(adc_pmic->dev);
+
+	pa_therm = regulator_get(adc_pmic->dev, "pa_therm");
+	if (IS_ERR(pa_therm)) {
+		rc = PTR_ERR(pa_therm);
+		pr_err("failed to request pa_therm vreg with error %d\n", rc);
+		pa_therm = NULL;
+	}
 	return 0;
 }
 
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index 476300c..793f063 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -2609,7 +2609,7 @@
 
 		} else
 			retval = -EINVAL;
-
+		break;
 	case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
 		retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
 		if (retval < 0) {
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index 1c4f616..5ec2932 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -2582,6 +2582,7 @@
 {
 	struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
 	int retval = 0;
+	int cnt = 0;
 	unsigned char xfr_buf[XFR_REG_NUM];
 	signed char cRmssiThreshold;
 	signed char ioc;
@@ -2712,6 +2713,69 @@
 		ctrl->value = GET_REG_FIELD(radio->registers[IOCTRL],
 			IOC_ANTENNA_OFFSET, IOC_ANTENNA_MASK);
 		break;
+	case V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD:
+		size = 0x04;
+		xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
+		xfr_buf[1] = ON_CHANNEL_TH_MSB;
+		xfr_buf[2] = ON_CHANNEL_TH_LSB;
+		retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
+		if (retval < 0) {
+			pr_err("%s: Failed to write\n", __func__);
+			return retval;
+		}
+		/*Wait for the XFR interrupt */
+		msleep(TAVARUA_DELAY*10);
+		retval = tavarua_read_registers(radio, XFRDAT0, 4);
+		if (retval < 0) {
+			pr_err("%s: On Ch. DET: Read failure\n", __func__);
+			return retval;
+		}
+		for (cnt = 0; cnt < 4; cnt++)
+			FMDBG("On-Channel data set is : 0x%x\t",
+				(int)radio->registers[XFRDAT0+cnt]);
+
+		ctrl->value =	LSH_DATA(radio->registers[XFRDAT0],   24) |
+				LSH_DATA(radio->registers[XFRDAT0+1], 16) |
+				LSH_DATA(radio->registers[XFRDAT0+2],  8) |
+				(radio->registers[XFRDAT0+3]);
+		FMDBG("The On Channel Threshold value is : 0x%x", ctrl->value);
+		break;
+	case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
+		size = 0x04;
+		xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
+		xfr_buf[1] = OFF_CHANNEL_TH_MSB;
+		xfr_buf[2] = OFF_CHANNEL_TH_LSB;
+		retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
+		if (retval < 0) {
+			pr_err("%s: Failed to write\n", __func__);
+			return retval;
+		}
+		/*Wait for the XFR interrupt */
+		msleep(TAVARUA_DELAY*10);
+		retval = tavarua_read_registers(radio, XFRDAT0, 4);
+		if (retval < 0) {
+			pr_err("%s: Off Ch. DET: Read failure\n", __func__);
+			return retval;
+		}
+		for (cnt = 0; cnt < 4; cnt++)
+			FMDBG("Off-channel data set is : 0x%x\t",
+				(int)radio->registers[XFRDAT0+cnt]);
+
+		ctrl->value =	LSH_DATA(radio->registers[XFRDAT0],   24) |
+				LSH_DATA(radio->registers[XFRDAT0+1], 16) |
+				LSH_DATA(radio->registers[XFRDAT0+2],  8) |
+				(radio->registers[XFRDAT0+3]);
+		FMDBG("The Off Channel Threshold value is : 0x%x", ctrl->value);
+		break;
+	/*
+	 * These IOCTL's are place holders to keep the
+	 * driver compatible with change in frame works for IRIS
+	 */
+	case V4L2_CID_PRIVATE_SINR_THRESHOLD:
+	case V4L2_CID_PRIVATE_SINR_SAMPLES:
+	case V4L2_CID_PRIVATE_IRIS_GET_SINR:
+		retval = 0;
+		break;
 	default:
 		retval = -EINVAL;
 	}
@@ -3090,7 +3154,7 @@
 		SET_REG_FIELD(radio->registers[IOCTRL], ctrl->value,
 					IOC_ANTENNA_OFFSET, IOC_ANTENNA_MASK);
 		break;
-	case V4L2_CID_PRIVATE_TAVARUA_ON_CHANNEL_THRESHOLD:
+	case V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD:
 		size = 0x04;
 		/* Poking the value of ON Channel Threshold value */
 		xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
@@ -3110,39 +3174,13 @@
 		retval = tavarua_write_registers(radio, XFRCTRL,
 				xfr_buf, size+3);
 		if (retval < 0) {
-			FMDBG("Failed to write\n");
-			return retval;
-		}
-		/*Wait for the XFR interrupt */
-		msleep(TAVARUA_DELAY*15);
-
-		for (cnt = 0; cnt < 5; cnt++) {
-			xfr_buf[cnt] = 0;
-			radio->registers[XFRDAT0+cnt] = 0x0;
-		}
-
-		/* Peeking Regs 0x88C2-0x88C4 */
-		size = 0x04;
-		xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
-		xfr_buf[1] = ON_CHANNEL_TH_MSB;
-		xfr_buf[2] = ON_CHANNEL_TH_LSB;
-		retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
-		if (retval < 0) {
 			pr_err("%s: Failed to write\n", __func__);
 			return retval;
 		}
 		/*Wait for the XFR interrupt */
 		msleep(TAVARUA_DELAY*10);
-		retval = tavarua_read_registers(radio, XFRDAT0, 4);
-		if (retval < 0) {
-			pr_err("%s: On Ch. DET: Read failure\n", __func__);
-			return retval;
-		}
-		for (cnt = 0; cnt < 4; cnt++)
-			FMDBG("On-Channel data set is : 0x%x\t",
-				(int)radio->registers[XFRDAT0+cnt]);
 		break;
-	case V4L2_CID_PRIVATE_TAVARUA_OFF_CHANNEL_THRESHOLD:
+	case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
 		size = 0x04;
 		/* Poking the value of OFF Channel Threshold value */
 		xfr_buf[0] = (XFR_POKE_MODE | (size << 1));
@@ -3167,32 +3205,6 @@
 		}
 		/*Wait for the XFR interrupt */
 		msleep(TAVARUA_DELAY*10);
-
-		for (cnt = 0; cnt < 5; cnt++) {
-			xfr_buf[cnt] = 0;
-			radio->registers[XFRDAT0+cnt] = 0x0;
-		}
-
-		/* Peeking Regs 0x88C2-0x88C4 */
-		size = 0x04;
-		xfr_buf[0] = (XFR_PEEK_MODE | (size << 1));
-		xfr_buf[1] = OFF_CHANNEL_TH_MSB;
-		xfr_buf[2] = OFF_CHANNEL_TH_LSB;
-		retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, 3);
-		if (retval < 0) {
-			pr_err("%s: Failed to write\n", __func__);
-			return retval;
-		}
-		/*Wait for the XFR interrupt */
-		msleep(TAVARUA_DELAY*10);
-		retval = tavarua_read_registers(radio, XFRDAT0, 4);
-		if (retval < 0) {
-			pr_err("%s: Off Ch. DET: Read failure\n", __func__);
-			return retval;
-		}
-		for (cnt = 0; cnt < 4; cnt++)
-			FMDBG("Off-channel data set is : 0x%x\t",
-				(int)radio->registers[XFRDAT0+cnt]);
 		break;
 	/* TX Controls */
 
@@ -3264,6 +3276,8 @@
 	case V4L2_CID_PRIVATE_RDS_GRP_COUNTERS:
 	case V4L2_CID_PRIVATE_SET_NOTCH_FILTER:
 	case V4L2_CID_PRIVATE_TAVARUA_DO_CALIBRATION:
+	case V4L2_CID_PRIVATE_SINR_THRESHOLD:
+	case V4L2_CID_PRIVATE_SINR_SAMPLES:
 		retval = 0;
 		break;
 	default:
diff --git a/drivers/media/video/msm/actuators/imx074_act.c b/drivers/media/video/msm/actuators/imx074_act.c
index fab3a21..78eef72 100644
--- a/drivers/media/video/msm/actuators/imx074_act.c
+++ b/drivers/media/video/msm/actuators/imx074_act.c
@@ -244,6 +244,10 @@
 		.f_pix_den = 10,
 		.total_f_dist_num = 197681,
 		.total_f_dist_den = 1000,
+		.hor_view_angle_num = 548,
+		.hor_view_angle_den = 10,
+		.ver_view_angle_num = 425,
+		.ver_view_angle_den = 10,
 	},
 
 	/* Initialize scenario */
diff --git a/drivers/media/video/msm/csi/msm_csid.c b/drivers/media/video/msm/csi/msm_csid.c
index 7a0ee4d..d247467 100644
--- a/drivers/media/video/msm/csi/msm_csid.c
+++ b/drivers/media/video/msm/csi/msm_csid.c
@@ -138,6 +138,10 @@
 	{"csi_pclk", -1},
 };
 
+static struct camera_vreg_t csid_vreg_info[] = {
+	{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
+};
+
 static int msm_csid_init(struct v4l2_subdev *sd, uint32_t *csid_version)
 {
 	int rc = 0;
@@ -155,11 +159,25 @@
 		return rc;
 	}
 
+	rc = msm_camera_config_vreg(&csid_dev->pdev->dev, csid_vreg_info,
+		ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 1);
+	if (rc < 0) {
+		pr_err("%s: regulator on failed\n", __func__);
+		goto vreg_config_failed;
+	}
+
+	rc = msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_vreg_info,
+		ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 1);
+	if (rc < 0) {
+		pr_err("%s: regulator enable failed\n", __func__);
+		goto vreg_enable_failed;
+	}
+
 	rc = msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info,
 		csid_dev->csid_clk, ARRAY_SIZE(csid_clk_info), 1);
 	if (rc < 0) {
-		iounmap(csid_dev->base);
-		return rc;
+		pr_err("%s: regulator enable failed\n", __func__);
+		goto clk_enable_failed;
 	}
 
 #if DBG_CSID
@@ -167,8 +185,17 @@
 #endif
 
 	*csid_version = csid_dev->hw_version;
-
 	return 0;
+
+clk_enable_failed:
+	msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_vreg_info,
+		ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 0);
+vreg_enable_failed:
+	msm_camera_config_vreg(&csid_dev->pdev->dev, csid_vreg_info,
+		ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 0);
+vreg_config_failed:
+	iounmap(csid_dev->base);
+	return rc;
 }
 
 static int msm_csid_release(struct v4l2_subdev *sd)
@@ -183,6 +210,12 @@
 	msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info,
 		csid_dev->csid_clk, ARRAY_SIZE(csid_clk_info), 0);
 
+	msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_vreg_info,
+		ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 0);
+
+	msm_camera_config_vreg(&csid_dev->pdev->dev, csid_vreg_info,
+		ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 0);
+
 	iounmap(csid_dev->base);
 	return 0;
 }
diff --git a/drivers/media/video/msm/csi/msm_csid.h b/drivers/media/video/msm/csi/msm_csid.h
index f90abf2..105cd49 100644
--- a/drivers/media/video/msm/csi/msm_csid.h
+++ b/drivers/media/video/msm/csi/msm_csid.h
@@ -23,6 +23,7 @@
 	struct resource *mem;
 	struct resource *irq;
 	struct resource *io;
+	struct regulator *csi_vdd;
 	void __iomem *base;
 	struct mutex mutex;
 	uint32_t hw_version;
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
index 6be3f2d..8049975 100644
--- a/drivers/mfd/pm8921-core.c
+++ b/drivers/mfd/pm8921-core.c
@@ -427,9 +427,26 @@
 	NCP("8921_ncp", 0x090),
 };
 
+/*
+ * PM8917 adds 6 LDOs and a boost regulator beyond those available on PM8921.
+ * It also replaces SMPS 3 with FTSMPS 3.  PM8917 does not have an NCP.
+ */
+static struct pm8xxx_vreg pm8917_regulator_data[] = {
+	/*   name	     pc_name	    ctrl   test   hpm_min */
+	PLDO("8917_l30",     "8917_l30_pc", 0x0A3, 0x0A4, LDO_150),
+	PLDO("8917_l31",     "8917_l31_pc", 0x0A5, 0x0A6, LDO_150),
+	PLDO("8917_l32",     "8917_l32_pc", 0x0A7, 0x0A8, LDO_150),
+	PLDO("8917_l33",     "8917_l33_pc", 0x0C6, 0x0C7, LDO_150),
+	PLDO("8917_l34",     "8917_l34_pc", 0x0D2, 0x0D3, LDO_150),
+	PLDO("8917_l35",     "8917_l35_pc", 0x0D4, 0x0D5, LDO_300),
+
+	/*    name          ctrl */
+	BOOST("8917_boost", 0x04B),
+};
+
 #define MAX_NAME_COMPARISON_LEN 32
 
-static int __devinit match_regulator(
+static int __devinit match_regulator(enum pm8xxx_version version,
 	struct pm8xxx_regulator_core_platform_data *core_data, char *name)
 {
 	int found = 0;
@@ -452,6 +469,25 @@
 			break;
 		}
 	}
+	if (version == PM8XXX_VERSION_8917) {
+		for (i = 0; i < ARRAY_SIZE(pm8917_regulator_data); i++) {
+			if (pm8917_regulator_data[i].rdesc.name
+			    && strncmp(pm8917_regulator_data[i].rdesc.name,
+					name, MAX_NAME_COMPARISON_LEN) == 0) {
+				core_data->is_pin_controlled = false;
+				core_data->vreg = &pm8917_regulator_data[i];
+				found = 1;
+				break;
+			} else if (pm8917_regulator_data[i].rdesc_pc.name
+			      && strncmp(pm8917_regulator_data[i].rdesc_pc.name,
+					name, MAX_NAME_COMPARISON_LEN) == 0) {
+				core_data->is_pin_controlled = true;
+				core_data->vreg = &pm8917_regulator_data[i];
+				found = 1;
+				break;
+			}
+		}
+	}
 
 	if (!found)
 		pr_err("could not find a match for regulator: %s\n", name);
@@ -466,8 +502,11 @@
 	int ret = 0;
 	struct mfd_cell *mfd_regulators;
 	struct pm8xxx_regulator_core_platform_data *cdata;
+	enum pm8xxx_version version;
 	int i;
 
+	version = pm8xxx_get_version(pmic->dev);
+
 	/* Add one device for each regulator used by the board. */
 	mfd_regulators = kzalloc(sizeof(struct mfd_cell)
 				 * (pdata->num_regulators), GFP_KERNEL);
@@ -488,6 +527,8 @@
 	}
 	for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
 		mutex_init(&regulator_data[i].pc_lock);
+	for (i = 0; i < ARRAY_SIZE(pm8917_regulator_data); i++)
+		mutex_init(&pm8917_regulator_data[i].pc_lock);
 
 	for (i = 0; i < pdata->num_regulators; i++) {
 		if (!pdata->regulator_pdatas[i].init_data.constraints.name) {
@@ -495,7 +536,7 @@
 			ret = -EINVAL;
 			goto bail;
 		}
-		if (!match_regulator(&cdata[i],
+		if (!match_regulator(version, &cdata[i],
 		      pdata->regulator_pdatas[i].init_data.constraints.name)) {
 			ret = -ENODEV;
 			goto bail;
@@ -519,6 +560,8 @@
 bail:
 	for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
 		mutex_destroy(&regulator_data[i].pc_lock);
+	for (i = 0; i < ARRAY_SIZE(pm8917_regulator_data); i++)
+		mutex_destroy(&pm8917_regulator_data[i].pc_lock);
 	kfree(mfd_regulators);
 	kfree(cdata);
 	return ret;
@@ -908,6 +951,9 @@
 		if (pmic->mfd_regulators) {
 			for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
 				mutex_destroy(&regulator_data[i].pc_lock);
+			for (i = 0; i < ARRAY_SIZE(pm8917_regulator_data); i++)
+				mutex_destroy(
+					&pm8917_regulator_data[i].pc_lock);
 		}
 		kfree(pmic->mfd_regulators);
 		kfree(pmic->regulator_cdata);
diff --git a/drivers/mfd/pm8xxx-irq.c b/drivers/mfd/pm8xxx-irq.c
index 14c9ec4..17b518e 100644
--- a/drivers/mfd/pm8xxx-irq.c
+++ b/drivers/mfd/pm8xxx-irq.c
@@ -102,6 +102,7 @@
 		goto bail;
 	}
 
+	cp &= ~PM_IRQF_WRITE;
 	rc = pm8xxx_writeb(chip->dev,
 			SSBI_REG_ADDR_IRQ_CONFIG(chip->base_addr), cp);
 	if (rc)
@@ -127,7 +128,10 @@
 		pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
 		goto bail;
 	}
-
+	/*
+	 * Set the write bit here as this could be a unrequested irq
+	 * whose PM_IRQF_WRITE bit is not set
+	 */
 	cp |= PM_IRQF_WRITE;
 	rc = pm8xxx_writeb(chip->dev,
 			SSBI_REG_ADDR_IRQ_CONFIG(chip->base_addr), cp);
@@ -222,7 +226,7 @@
 	irq_bit = pmirq % 8;
 
 	if (chip->config[pmirq] == 0) {
-		pr_warn("masking rouge irq=%d pmirq=%d\n", d->irq, pmirq);
+		pr_warn("masking rogue irq=%d pmirq=%d\n", d->irq, pmirq);
 		chip->config[pmirq] = irq_bit << PM_IRQF_BITS_SHIFT;
 	}
 
@@ -242,7 +246,7 @@
 	irq_bit = pmirq % 8;
 
 	if (chip->config[pmirq] == 0) {
-		pr_warn("mask acking rouge irq=%d pmirq=%d\n", d->irq, pmirq);
+		pr_warn("mask acking rogue irq=%d pmirq=%d\n", d->irq, pmirq);
 		chip->config[pmirq] = irq_bit << PM_IRQF_BITS_SHIFT;
 	}
 
@@ -295,6 +299,12 @@
 			chip->config[pmirq] &= ~PM_IRQF_MASK_FE;
 	}
 
+	/*
+	 * The PM_IRQF_WRITE flag serves as an indication that this interrupt
+	 * been requested
+	 */
+	chip->config[pmirq] |= PM_IRQF_WRITE;
+
 	config = chip->config[pmirq] | PM_IRQF_CLR;
 	return pm8xxx_write_config_irq(chip, block, config);
 }
diff --git a/drivers/mfd/wcd9310-core.c b/drivers/mfd/wcd9310-core.c
index 56774e9..d1d9132 100644
--- a/drivers/mfd/wcd9310-core.c
+++ b/drivers/mfd/wcd9310-core.c
@@ -267,15 +267,6 @@
 static int tabla_reset(struct tabla *tabla)
 {
 	int ret;
-	struct pm_gpio param = {
-		.direction      = PM_GPIO_DIR_OUT,
-		.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
-		.output_value   = 1,
-		.pull	   = PM_GPIO_PULL_NO,
-		.vin_sel	= PM_GPIO_VIN_S4,
-		.out_strength   = PM_GPIO_STRENGTH_MED,
-		.function       = PM_GPIO_FUNC_NORMAL,
-	};
 
 	if (tabla->reset_gpio) {
 		ret = gpio_request(tabla->reset_gpio, "CDC_RESET");
@@ -286,10 +277,6 @@
 			return ret;
 		}
 
-		ret = pm8xxx_gpio_config(tabla->reset_gpio, &param);
-		if (ret)
-			pr_err("%s: Failed to configure gpio\n", __func__);
-
 		gpio_direction_output(tabla->reset_gpio, 1);
 		msleep(20);
 		gpio_direction_output(tabla->reset_gpio, 0);
@@ -665,7 +652,7 @@
 	struct tabla_i2c *tabla;
 
 	tabla = get_i2c_tabla_device_info(reg);
-	if (tabla->client == NULL) {
+	if (tabla == NULL || tabla->client == NULL) {
 		pr_err("failed to get device info\n");
 		return -ENODEV;
 	}
@@ -702,7 +689,7 @@
 	u8 i = 0;
 
 	tabla = get_i2c_tabla_device_info(reg);
-	if (tabla->client == NULL) {
+	if (tabla == NULL || tabla->client == NULL) {
 		pr_err("failed to get device info\n");
 		return -ENODEV;
 	}
@@ -771,12 +758,12 @@
 	if (!pdata) {
 		dev_dbg(&client->dev, "no platform data?\n");
 		ret = -EINVAL;
-		goto fail;
+		goto err_tabla;
 	}
 	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
 		dev_dbg(&client->dev, "can't talk I2C?\n");
 		ret = -EIO;
-		goto fail;
+		goto err_tabla;
 	}
 	tabla->dev = &client->dev;
 	tabla->reset_gpio = pdata->reset_gpio;
@@ -982,11 +969,9 @@
 
 	tabla = slim_get_devicedata(pdev);
 	tabla_deinit_slimslave(tabla);
-	tabla_device_exit(tabla);
 	tabla_disable_supplies(tabla);
 	slim_remove_device(tabla->slim_slave);
-	kfree(tabla);
-
+	tabla_device_exit(tabla);
 	return 0;
 }
 
diff --git a/drivers/mfd/wcd9310-slimslave.c b/drivers/mfd/wcd9310-slimslave.c
index dd586fa..12ac27f 100644
--- a/drivers/mfd/wcd9310-slimslave.c
+++ b/drivers/mfd/wcd9310-slimslave.c
@@ -236,7 +236,7 @@
 		 */
 		if ((slave_port_id >
 				SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID) &&
-			(slave_port_id <
+			(slave_port_id <=
 			 SB_PGD_RX_PORT_MULTI_CHANNEL_0_END_PORT_ID)) {
 				payload_rx = payload_rx  |
 				(1 <<
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 43eb169..0066cd8 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -627,6 +627,13 @@
 	  TrustZone Operating Environment (TZBSP) using Secure Channel
 	  Manager (SCM) interface.
 
+config QSEECOM
+	tristate "Qualcomm Secure Execution Communicator driver"
+	help
+	  Provides a communication interface between userspace and
+	  Qualcomm Secure Execution Environment (QSEE) using Secure Channel
+	  Manager (SCM) interface.
+
 config QFP_FUSE
 	tristate "QFPROM Fuse Read/Write support"
 	help
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 6b5fdcc..fb78f4e 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -64,4 +64,5 @@
 	+= msm_migrate_pages.o
 obj-$(CONFIG_PMIC8058_XOADC) += pmic8058-xoadc.o
 obj-$(CONFIG_TZCOM) += tzcom.o
+obj-$(CONFIG_QSEECOM) += qseecom.o
 obj-$(CONFIG_QFP_FUSE) += qfp_fuse.o
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
new file mode 100644
index 0000000..e4c3152
--- /dev/null
+++ b/drivers/misc/qseecom.c
@@ -0,0 +1,1490 @@
+/* Qualcomm Secure Execution Environment Communicator (QSEECOM) driver
+ *
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#define pr_fmt(fmt) "QSEECOM: %s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/cdev.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/ion.h>
+#include <linux/types.h>
+#include <linux/clk.h>
+#include <linux/qseecom.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include <mach/scm.h>
+#include <mach/peripheral-loader.h>
+#include "qseecom_legacy.h"
+
+#define QSEECOM_DEV			"qseecom"
+#define QSEOS_VERSION_13		0x13
+#define QSEOS_VERSION_14		0x14
+#define QSEOS_CHECK_VERSION_CMD		0x00001803;
+
+enum qseecom_command_scm_resp_type {
+	QSEOS_APP_ID = 0xEE01,
+	QSEOS_LISTENER_ID
+};
+
+enum qseecom_qceos_cmd_id {
+	QSEOS_APP_START_COMMAND      = 0x01,
+	QSEOS_APP_SHUTDOWN_COMMAND,
+	QSEOS_APP_LOOKUP_COMMAND,
+	QSEOS_REGISTER_LISTENER,
+	QSEOS_DEREGISTER_LISTENER,
+	QSEOS_CLIENT_SEND_DATA_COMMAND,
+	QSEOS_LISTENER_DATA_RSP_COMMAND,
+	QSEOS_CMD_MAX     = 0xEFFFFFFF
+};
+
+enum qseecom_qceos_cmd_status {
+	QSEOS_RESULT_SUCCESS = 0,
+	QSEOS_RESULT_INCOMPLETE,
+	QSEOS_RESULT_FAILURE  = 0xFFFFFFFF
+};
+
+__packed struct qseecom_check_app_ireq {
+	uint32_t qsee_cmd_id;
+	char     app_name[MAX_APP_NAME_SIZE];
+};
+
+__packed struct qseecom_load_app_ireq {
+	uint32_t qsee_cmd_id;
+	uint32_t mdt_len;		/* Length of the mdt file */
+	uint32_t img_len;		/* Length of .bxx and .mdt files */
+	uint32_t phy_addr;		/* phy addr of the start of image */
+	char     app_name[MAX_APP_NAME_SIZE];	/* application name*/
+};
+
+__packed struct qseecom_unload_app_ireq {
+	uint32_t qsee_cmd_id;
+	uint32_t  app_id;
+};
+
+__packed struct qseecom_register_listener_ireq {
+	uint32_t qsee_cmd_id;
+	uint32_t listener_id;
+	void *sb_ptr;
+	uint32_t sb_len;
+};
+
+__packed struct qseecom_unregister_listener_ireq {
+	uint32_t qsee_cmd_id;
+	uint32_t  listener_id;
+};
+
+__packed struct qseecom_client_send_data_ireq {
+	uint32_t qsee_cmd_id;
+	uint32_t app_id;
+	void *req_ptr;
+	uint32_t req_len;
+	void *rsp_ptr;   /* First 4 bytes should always be the return status */
+	uint32_t rsp_len;
+};
+
+/* send_data resp */
+__packed struct qseecom_client_listener_data_irsp {
+	uint32_t qsee_cmd_id;
+	uint32_t listener_id;
+};
+
+/*
+ * struct qseecom_command_scm_resp - qseecom response buffer
+ * @cmd_status: value from enum tz_sched_cmd_status
+ * @sb_in_rsp_addr: points to physical location of response
+ *                buffer
+ * @sb_in_rsp_len: length of command response
+ */
+__packed struct qseecom_command_scm_resp {
+	uint32_t result;
+	enum qseecom_command_scm_resp_type resp_type;
+	unsigned int data;
+};
+
+static struct class *driver_class;
+static dev_t qseecom_device_no;
+static struct cdev qseecom_cdev;
+
+/* Data structures used in legacy support */
+static void *pil;
+static uint32_t pil_ref_cnt;
+static DEFINE_MUTEX(pil_access_lock);
+
+static DEFINE_MUTEX(send_msg_lock);
+static DEFINE_MUTEX(qsee_bw_mutex);
+static DEFINE_MUTEX(app_access_lock);
+
+static int qsee_bw_count;
+static struct clk *qseecom_bus_clk;
+static uint32_t qsee_perf_client;
+
+struct qseecom_registered_listener_list {
+	struct list_head                 list;
+	struct qseecom_register_listener_req svc;
+	u8  *sb_reg_req;
+	u8 *sb_virt;
+	s32 sb_phys;
+	size_t sb_length;
+	struct ion_handle *ihandle; /* Retrieve phy addr */
+
+	wait_queue_head_t          rcv_req_wq;
+	int                        rcv_req_flag;
+};
+
+struct qseecom_registered_app_list {
+	struct list_head                 list;
+	u32  app_id;
+	u32  ref_cnt;
+};
+
+struct qseecom_control {
+	struct ion_client *ion_clnt;		/* Ion client */
+	struct list_head  registered_listener_list_head;
+	spinlock_t        registered_listener_list_lock;
+
+	struct list_head  registered_app_list_head;
+	spinlock_t        registered_app_list_lock;
+
+	wait_queue_head_t send_resp_wq;
+	int               send_resp_flag;
+
+	uint32_t          qseos_version;
+};
+
+struct qseecom_client_handle {
+	u32  app_id;
+	u8 *sb_virt;
+	s32 sb_phys;
+	uint32_t user_virt_sb_base;
+	size_t sb_length;
+	struct ion_handle *ihandle;		/* Retrieve phy addr */
+};
+
+struct qseecom_listener_handle {
+	u32               id;
+};
+
+static struct qseecom_control qseecom;
+
+struct qseecom_dev_handle {
+	bool               service;
+	union {
+		struct qseecom_client_handle client;
+		struct qseecom_listener_handle listener;
+	};
+	bool released;
+	int               abort;
+	wait_queue_head_t abort_wq;
+	atomic_t          ioctl_count;
+};
+
+static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data,
+		struct qseecom_register_listener_req svc)
+{
+	struct qseecom_registered_listener_list *ptr;
+	int unique = 1;
+	unsigned long flags;
+
+	spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
+	list_for_each_entry(ptr, &qseecom.registered_listener_list_head, list) {
+		if (ptr->svc.listener_id == svc.listener_id) {
+			pr_err("Service id: %u is already registered\n",
+					ptr->svc.listener_id);
+			unique = 0;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
+	return unique;
+}
+
+static struct qseecom_registered_listener_list *__qseecom_find_svc(
+						int32_t listener_id)
+{
+	struct qseecom_registered_listener_list *entry = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
+	list_for_each_entry(entry, &qseecom.registered_listener_list_head, list)
+	{
+		if (entry->svc.listener_id == listener_id)
+			break;
+	}
+	spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
+	return entry;
+}
+
+static int __qseecom_set_sb_memory(struct qseecom_registered_listener_list *svc,
+				struct qseecom_dev_handle *handle,
+				struct qseecom_register_listener_req *listener)
+{
+	int ret = 0;
+	unsigned int flags = 0;
+	struct qseecom_register_listener_ireq req;
+	struct qseecom_command_scm_resp resp;
+	ion_phys_addr_t pa;
+
+	/* Get the handle of the shared fd */
+	svc->ihandle = ion_import_fd(qseecom.ion_clnt, listener->ifd_data_fd);
+	if (svc->ihandle == NULL) {
+		pr_err("Ion client could not retrieve the handle\n");
+		return -ENOMEM;
+	}
+
+	/* Get the physical address of the ION BUF */
+	ret = ion_phys(qseecom.ion_clnt, svc->ihandle, &pa, &svc->sb_length);
+
+	/* Populate the structure for sending scm call to load image */
+	svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
+							svc->ihandle, flags);
+	svc->sb_phys = pa;
+
+	if (qseecom.qseos_version == QSEOS_VERSION_14) {
+		req.qsee_cmd_id = QSEOS_REGISTER_LISTENER;
+		req.listener_id = svc->svc.listener_id;
+		req.sb_len = svc->sb_length;
+		req.sb_ptr = (void *)svc->sb_phys;
+
+		resp.result = QSEOS_RESULT_INCOMPLETE;
+
+		ret = scm_call(SCM_SVC_TZSCHEDULER, 1,  &req,
+					sizeof(req), &resp, sizeof(resp));
+		if (ret) {
+			pr_err("qseecom_scm_call failed with err: %d\n", ret);
+			return -EINVAL;
+		}
+
+		if (resp.result != QSEOS_RESULT_SUCCESS) {
+			pr_err("Error SB registration req: resp.result = %d\n",
+					resp.result);
+			return -EPERM;
+		}
+	} else {
+		struct qseecom_command cmd;
+		struct qseecom_response resp;
+		struct qse_pr_init_sb_req_s sb_init_req;
+		struct qse_pr_init_sb_rsp_s sb_init_rsp;
+
+		svc->sb_reg_req = kzalloc((sizeof(sb_init_req) +
+					sizeof(sb_init_rsp)), GFP_KERNEL);
+
+		sb_init_req.pr_cmd = TZ_SCHED_CMD_ID_REGISTER_LISTENER;
+		sb_init_req.listener_id = svc->svc.listener_id;
+		sb_init_req.sb_len = svc->sb_length;
+		sb_init_req.sb_ptr = svc->sb_phys;
+
+		memcpy(svc->sb_reg_req, &sb_init_req, sizeof(sb_init_req));
+
+		/* It will always be a new cmd from this method */
+		cmd.cmd_type = TZ_SCHED_CMD_NEW;
+		cmd.sb_in_cmd_addr = (u8 *)(virt_to_phys(svc->sb_reg_req));
+		cmd.sb_in_cmd_len = sizeof(sb_init_req);
+
+		resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
+
+		ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &cmd, sizeof(cmd)
+				, &resp, sizeof(resp));
+
+		if (ret) {
+			pr_err("qseecom_scm_call failed with err: %d\n", ret);
+			return -EINVAL;
+		}
+
+		if (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
+			pr_err("SB registration fail resp.cmd_status %d\n",
+							resp.cmd_status);
+			return -EINVAL;
+		}
+		memset(svc->sb_virt, 0, svc->sb_length);
+	}
+	return 0;
+}
+
+static int qseecom_register_listener(struct qseecom_dev_handle *data,
+					void __user *argp)
+{
+	int ret = 0;
+	unsigned long flags;
+	struct qseecom_register_listener_req rcvd_lstnr;
+	struct qseecom_registered_listener_list *new_entry;
+
+	ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr));
+	if (ret) {
+		pr_err("copy_from_user failed\n");
+		return ret;
+	}
+
+	if (!__qseecom_is_svc_unique(data, rcvd_lstnr)) {
+		pr_err("Service is not unique and is already registered\n");
+		return ret;
+	}
+
+	ret = copy_to_user(argp, &rcvd_lstnr, sizeof(rcvd_lstnr));
+	if (ret) {
+		pr_err("copy_to_user failed\n");
+		return ret;
+	}
+
+	new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
+	if (!new_entry) {
+		pr_err("kmalloc failed\n");
+		return -ENOMEM;
+	}
+	memcpy(&new_entry->svc, &rcvd_lstnr, sizeof(rcvd_lstnr));
+	new_entry->rcv_req_flag = 0;
+
+	new_entry->svc.listener_id = rcvd_lstnr.listener_id;
+	new_entry->sb_length = rcvd_lstnr.sb_size;
+	if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) {
+		pr_err("qseecom_set_sb_memoryfailed\n");
+		kzfree(new_entry);
+		return -ENOMEM;
+	}
+	data->listener.id = rcvd_lstnr.listener_id;
+	data->service = true;
+	init_waitqueue_head(&new_entry->rcv_req_wq);
+
+	spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
+	list_add_tail(&new_entry->list, &qseecom.registered_listener_list_head);
+	spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
+	return ret;
+}
+
+static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
+{
+	int ret = 0;
+	unsigned long flags;
+	uint32_t unmap_mem = 0;
+	struct qseecom_register_listener_ireq req;
+	struct qseecom_registered_listener_list *ptr_svc = NULL;
+	struct qseecom_command_scm_resp resp;
+	struct ion_handle *ihandle = NULL;		/* Retrieve phy addr */
+
+	if (qseecom.qseos_version == QSEOS_VERSION_14) {
+		req.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
+		req.listener_id = data->listener.id;
+		resp.result = QSEOS_RESULT_INCOMPLETE;
+
+		ret = scm_call(SCM_SVC_TZSCHEDULER, 1,  &req,
+					sizeof(req), &resp, sizeof(resp));
+		if (ret) {
+			pr_err("qseecom_scm_call failed with err: %d\n", ret);
+			return ret;
+		}
+
+		if (resp.result != QSEOS_RESULT_SUCCESS) {
+			pr_err("SB deregistartion: result=%d\n", resp.result);
+			return -EPERM;
+		}
+	} else {
+		struct qse_pr_init_sb_req_s sb_init_req;
+		struct qseecom_command cmd;
+		struct qseecom_response resp;
+		struct qseecom_registered_listener_list *svc;
+
+		svc = __qseecom_find_svc(data->listener.id);
+		sb_init_req.pr_cmd = TZ_SCHED_CMD_ID_REGISTER_LISTENER;
+		sb_init_req.listener_id = data->listener.id;
+		sb_init_req.sb_len = 0;
+		sb_init_req.sb_ptr = 0;
+
+		memcpy(svc->sb_reg_req, &sb_init_req, sizeof(sb_init_req));
+
+		/* It will always be a new cmd from this method */
+		cmd.cmd_type = TZ_SCHED_CMD_NEW;
+		cmd.sb_in_cmd_addr = (u8 *)(virt_to_phys(svc->sb_reg_req));
+		cmd.sb_in_cmd_len = sizeof(sb_init_req);
+		resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
+
+		ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &cmd, sizeof(cmd),
+					&resp, sizeof(resp));
+		if (ret) {
+			pr_err("qseecom_scm_call failed with err: %d\n", ret);
+			return ret;
+		}
+		kzfree(svc->sb_reg_req);
+		if (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
+			pr_err("Error with SB initialization\n");
+			return -EPERM;
+		}
+	}
+	data->abort = 1;
+	spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
+	list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head,
+			list) {
+		if (ptr_svc->svc.listener_id == data->listener.id) {
+			wake_up_all(&ptr_svc->rcv_req_wq);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
+
+	while (atomic_read(&data->ioctl_count) > 1) {
+		if (wait_event_interruptible(data->abort_wq,
+				atomic_read(&data->ioctl_count) <= 1)) {
+			pr_err("Interrupted from abort\n");
+			ret = -ERESTARTSYS;
+			break;
+		}
+	}
+
+	spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
+	list_for_each_entry(ptr_svc,
+			&qseecom.registered_listener_list_head,
+			list)
+	{
+		if (ptr_svc->svc.listener_id == data->listener.id) {
+			if (ptr_svc->sb_virt) {
+				unmap_mem = 1;
+				ihandle = ptr_svc->ihandle;
+				}
+			list_del(&ptr_svc->list);
+			kzfree(ptr_svc);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
+
+	/* Unmap the memory */
+	if (unmap_mem) {
+		if (!IS_ERR_OR_NULL(ihandle)) {
+			ion_unmap_kernel(qseecom.ion_clnt, ihandle);
+			ion_free(qseecom.ion_clnt, ihandle);
+			}
+	}
+	data->released = true;
+	return ret;
+}
+
+static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
+						void __user *argp)
+{
+	ion_phys_addr_t pa;
+	int32_t ret;
+	unsigned int flags = 0;
+	struct qseecom_set_sb_mem_param_req req;
+	uint32_t len;
+
+	/* Copy the relevant information needed for loading the image */
+	if (__copy_from_user(&req, (void __user *)argp, sizeof(req)))
+		return -EFAULT;
+
+	if (qseecom.qseos_version == QSEOS_VERSION_13) {
+		long pil_error;
+		mutex_lock(&pil_access_lock);
+		if (pil_ref_cnt == 0) {
+			pil = pil_get("tzapps");
+			if (IS_ERR(pil)) {
+				pr_err("Playready PIL image load failed\n");
+				pil_error = PTR_ERR(pil);
+				pil = NULL;
+				pr_debug("tzapps image load FAILED\n");
+				mutex_unlock(&pil_access_lock);
+				return pil_error;
+			}
+		}
+		pil_ref_cnt++;
+		mutex_unlock(&pil_access_lock);
+	}
+	/* Get the handle of the shared fd */
+	data->client.ihandle = ion_import_fd(qseecom.ion_clnt, req.ifd_data_fd);
+	if (IS_ERR_OR_NULL(data->client.ihandle)) {
+		pr_err("Ion client could not retrieve the handle\n");
+		return -ENOMEM;
+	}
+	/* Get the physical address of the ION BUF */
+	ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
+	/* Populate the structure for sending scm call to load image */
+	data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
+							data->client.ihandle,
+							flags);
+	data->client.sb_phys = pa;
+	data->client.sb_length = req.sb_len;
+	data->client.user_virt_sb_base = req.virt_sb_base;
+	return 0;
+}
+
+
+static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data)
+{
+	int ret;
+	ret = (qseecom.send_resp_flag != 0);
+	return ret || data->abort;
+}
+
+static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
+					struct qseecom_command_scm_resp *resp)
+{
+	int ret = 0;
+	uint32_t lstnr;
+	unsigned long flags;
+	struct qseecom_client_listener_data_irsp send_data_rsp;
+	struct qseecom_registered_listener_list *ptr_svc = NULL;
+
+
+	while (resp->result == QSEOS_RESULT_INCOMPLETE) {
+		lstnr = resp->data;
+		/*
+		 * Wake up blocking lsitener service with the lstnr id
+		 */
+		spin_lock_irqsave(&qseecom.registered_listener_list_lock,
+					flags);
+		list_for_each_entry(ptr_svc,
+				&qseecom.registered_listener_list_head, list) {
+			if (ptr_svc->svc.listener_id == lstnr) {
+				ptr_svc->rcv_req_flag = 1;
+				wake_up_interruptible(&ptr_svc->rcv_req_wq);
+				break;
+			}
+		}
+		spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
+				flags);
+		if (ptr_svc->svc.listener_id != lstnr) {
+			pr_warning("Service requested for does on exist\n");
+			return -ERESTARTSYS;
+		}
+		pr_debug("waking up rcv_req_wq and "
+				"waiting for send_resp_wq\n");
+		if (wait_event_interruptible(qseecom.send_resp_wq,
+				__qseecom_listener_has_sent_rsp(data))) {
+			pr_warning("Interrupted: exiting send_cmd loop\n");
+			return -ERESTARTSYS;
+		}
+
+		if (data->abort) {
+			pr_err("Aborting driver\n");
+			return -ENODEV;
+		}
+		qseecom.send_resp_flag = 0;
+		send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
+		send_data_rsp.listener_id  = lstnr ;
+
+		ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
+					(const void *)&send_data_rsp,
+					sizeof(send_data_rsp), resp,
+					sizeof(*resp));
+		if (ret) {
+			pr_err("qseecom_scm_call failed with err: %d\n", ret);
+			return ret;
+		}
+	}
+	return ret;
+}
+
+static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
+{
+	struct qseecom_registered_app_list *entry = NULL;
+	unsigned long flags = 0;
+	u32 app_id = 0;
+	struct ion_handle *ihandle;	/* Ion handle */
+	struct qseecom_load_img_req load_img_req;
+	int32_t ret;
+	ion_phys_addr_t pa = 0;
+	uint32_t len;
+	struct qseecom_command_scm_resp resp;
+	struct qseecom_check_app_ireq req;
+	/* Copy the relevant information needed for loading the image */
+	if (__copy_from_user(&load_img_req,
+				(void __user *)argp,
+				sizeof(struct qseecom_load_img_req))) {
+		pr_err("copy_from_user failed\n");
+		return -EFAULT;
+	}
+
+	req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
+	memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
+
+	/*  SCM_CALL  to check if app_id for the mentioned app exists */
+	ret = scm_call(SCM_SVC_TZSCHEDULER, 1,  &req,
+				sizeof(struct qseecom_check_app_ireq),
+				&resp, sizeof(resp));
+
+	if (resp.result == QSEOS_RESULT_FAILURE)
+		app_id = 0;
+	else
+		app_id = resp.data;
+
+	if (app_id) {
+		pr_warn("App id already exists\n");
+		spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
+		list_for_each_entry(entry,
+				&qseecom.registered_app_list_head, list){
+			if (entry->app_id == app_id) {
+				entry->ref_cnt++;
+				break;
+			}
+		}
+		spin_unlock_irqrestore(
+				&qseecom.registered_app_list_lock, flags);
+	} else {
+		struct qseecom_load_app_ireq load_req;
+
+		pr_warn("App id does not exist\n");
+		/* Get the handle of the shared fd */
+		ihandle = ion_import_fd(qseecom.ion_clnt,
+					load_img_req.ifd_data_fd);
+		if (IS_ERR_OR_NULL(ihandle)) {
+			pr_err("Ion client could not retrieve the handle\n");
+			return -ENOMEM;
+		}
+
+		/* Get the physical address of the ION BUF */
+		ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
+
+		/* Populate the structure for sending scm call to load image */
+		load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
+		load_req.mdt_len = load_img_req.mdt_len;
+		load_req.img_len = load_img_req.img_len;
+		load_req.phy_addr = pa;
+
+		/*  SCM_CALL  to load the app and get the app_id back */
+		ret = scm_call(SCM_SVC_TZSCHEDULER, 1,  &load_req,
+				sizeof(struct qseecom_load_app_ireq),
+				&resp, sizeof(resp));
+
+		if (resp.result == QSEOS_RESULT_INCOMPLETE) {
+			ret = __qseecom_process_incomplete_cmd(data, &resp);
+			if (ret) {
+				pr_err("process_incomplete_cmd failed err: %d\n",
+						ret);
+				if (!IS_ERR_OR_NULL(ihandle))
+					ion_free(qseecom.ion_clnt, ihandle);
+				return ret;
+			}
+		}
+		if (resp.result != QSEOS_RESULT_SUCCESS) {
+			pr_err("scm_call failed resp.result != QSEOS_RESULT_SUCCESS\n");
+			if (!IS_ERR_OR_NULL(ihandle))
+				ion_free(qseecom.ion_clnt, ihandle);
+			return -EFAULT;
+		}
+
+		app_id = resp.data;
+
+		entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+		if (!entry) {
+			pr_err("kmalloc failed\n");
+			return -ENOMEM;
+		}
+		entry->app_id = app_id;
+		entry->ref_cnt = 1;
+
+		/* Deallocate the handle */
+		if (!IS_ERR_OR_NULL(ihandle))
+			ion_free(qseecom.ion_clnt, ihandle);
+
+		spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
+		list_add_tail(&entry->list, &qseecom.registered_app_list_head);
+		spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
+					flags);
+	}
+	data->client.app_id = app_id;
+	load_img_req.app_id = app_id;
+	if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
+		pr_err("copy_to_user failed\n");
+		kzfree(entry);
+		return -EFAULT;
+	}
+	return 0;
+}
+
+static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
+{
+	wake_up_all(&qseecom.send_resp_wq);
+	while (atomic_read(&data->ioctl_count) > 1) {
+		if (wait_event_interruptible(data->abort_wq,
+					atomic_read(&data->ioctl_count) <= 1)) {
+			pr_err("Interrupted from abort\n");
+			return -ERESTARTSYS;
+			break;
+		}
+	}
+	/* Set unload app */
+	return 1;
+}
+
+static int qseecom_unload_app(struct qseecom_dev_handle *data)
+{
+	unsigned long flags;
+	int ret = 0;
+	struct qseecom_command_scm_resp resp;
+	struct qseecom_registered_app_list *ptr_app;
+	uint32_t unload = 0;
+
+	if (qseecom.qseos_version == QSEOS_VERSION_14) {
+		spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
+		list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
+								list) {
+			if (ptr_app->app_id == data->client.app_id) {
+				if (ptr_app->ref_cnt == 1) {
+					unload = __qseecom_cleanup_app(data);
+					list_del(&ptr_app->list);
+					kzfree(ptr_app);
+					break;
+				} else {
+					ptr_app->ref_cnt--;
+					break;
+				}
+			}
+		}
+		spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
+								flags);
+	}
+	if (!IS_ERR_OR_NULL(data->client.ihandle)) {
+		ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
+		ion_free(qseecom.ion_clnt, data->client.ihandle);
+	}
+
+	if ((unload) && (qseecom.qseos_version == QSEOS_VERSION_14)) {
+		struct qseecom_unload_app_ireq req;
+
+		/* Populate the structure for sending scm call to load image */
+		req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
+		req.app_id = data->client.app_id;
+
+		/* SCM_CALL to unload the app */
+		ret = scm_call(SCM_SVC_TZSCHEDULER, 1,  &req,
+				sizeof(struct qseecom_unload_app_ireq),
+				&resp, sizeof(resp));
+		if (ret) {
+			pr_err("Fail to unload APP\n");
+			return -EFAULT;
+		}
+		if (resp.result == QSEOS_RESULT_INCOMPLETE) {
+			ret = __qseecom_process_incomplete_cmd(data, &resp);
+			if (ret) {
+				pr_err("process_incomplete_cmd fail err: %d\n",
+						ret);
+				return ret;
+			}
+		}
+	}
+
+	if (qseecom.qseos_version == QSEOS_VERSION_13) {
+		data->abort = 1;
+		wake_up_all(&qseecom.send_resp_wq);
+		while (atomic_read(&data->ioctl_count) > 0) {
+			if (wait_event_interruptible(data->abort_wq,
+					atomic_read(&data->ioctl_count) <= 0)) {
+				pr_err("Interrupted from abort\n");
+				ret = -ERESTARTSYS;
+				break;
+			}
+		}
+		mutex_lock(&pil_access_lock);
+		if (pil_ref_cnt == 1)
+			pil_put(pil);
+		pil_ref_cnt--;
+		mutex_unlock(&pil_access_lock);
+	}
+	data->released = true;
+	return ret;
+}
+
+static uint32_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data,
+						uint32_t virt)
+{
+	return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
+}
+
+static int __qseecom_send_cmd_legacy(struct qseecom_dev_handle *data,
+				struct qseecom_send_cmd_req *req)
+{
+	int ret = 0;
+	unsigned long flags;
+	u32 reqd_len_sb_in = 0;
+	struct qseecom_command cmd;
+	struct qseecom_response resp;
+
+
+	if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
+		pr_err("cmd buffer or response buffer is null\n");
+		return -EINVAL;
+	}
+
+	if (req->cmd_req_len <= 0 ||
+		req->resp_len <= 0 ||
+		req->cmd_req_len > data->client.sb_length ||
+		req->resp_len > data->client.sb_length) {
+		pr_err("cmd buffer length or "
+				"response buffer length not valid\n");
+		return -EINVAL;
+	}
+
+	reqd_len_sb_in = req->cmd_req_len + req->resp_len;
+	if (reqd_len_sb_in > data->client.sb_length) {
+		pr_debug("Not enough memory to fit cmd_buf and "
+			"resp_buf. Required: %u, Available: %u\n",
+				reqd_len_sb_in, data->client.sb_length);
+		return -ENOMEM;
+	}
+	cmd.cmd_type = TZ_SCHED_CMD_NEW;
+	cmd.sb_in_cmd_addr = (u8 *) data->client.sb_phys;
+	cmd.sb_in_cmd_len = req->cmd_req_len;
+
+	resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
+	resp.sb_in_rsp_addr = (u8 *)data->client.sb_phys + req->cmd_req_len;
+	resp.sb_in_rsp_len = req->resp_len;
+
+	ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *)&cmd,
+					sizeof(cmd), &resp, sizeof(resp));
+
+	if (ret) {
+		pr_err("qseecom_scm_call_legacy failed with err: %d\n", ret);
+		return ret;
+	}
+
+	while (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
+		/*
+		 * If cmd is incomplete, get the callback cmd out from SB out
+		 * and put it on the list
+		 */
+		struct qseecom_registered_listener_list *ptr_svc = NULL;
+		/*
+		 * We don't know which service can handle the command. so we
+		 * wake up all blocking services and let them figure out if
+		 * they can handle the given command.
+		 */
+		spin_lock_irqsave(&qseecom.registered_listener_list_lock,
+					flags);
+		list_for_each_entry(ptr_svc,
+				&qseecom.registered_listener_list_head, list) {
+				ptr_svc->rcv_req_flag = 1;
+				wake_up_interruptible(&ptr_svc->rcv_req_wq);
+		}
+		spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
+				flags);
+
+		pr_debug("waking up rcv_req_wq and "
+				"waiting for send_resp_wq\n");
+		if (wait_event_interruptible(qseecom.send_resp_wq,
+				__qseecom_listener_has_sent_rsp(data))) {
+			pr_warning("qseecom Interrupted: exiting send_cmd loop\n");
+			return -ERESTARTSYS;
+		}
+
+		if (data->abort) {
+			pr_err("Aborting driver\n");
+			return -ENODEV;
+		}
+		qseecom.send_resp_flag = 0;
+		cmd.cmd_type = TZ_SCHED_CMD_PENDING;
+		ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *)&cmd,
+					sizeof(cmd), &resp, sizeof(resp));
+		if (ret) {
+			pr_err("qseecom_scm_call failed with err: %d\n", ret);
+			return ret;
+		}
+	}
+	return ret;
+}
+
+static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
+				struct qseecom_send_cmd_req *req)
+{
+	int ret = 0;
+	u32 reqd_len_sb_in = 0;
+	struct qseecom_client_send_data_ireq send_data_req;
+	struct qseecom_command_scm_resp resp;
+
+	if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
+		pr_err("cmd buffer or response buffer is null\n");
+		return -EINVAL;
+	}
+
+	if (req->cmd_req_len <= 0 ||
+		req->resp_len <= 0 ||
+		req->cmd_req_len > data->client.sb_length ||
+		req->resp_len > data->client.sb_length) {
+		pr_err("cmd buffer length or "
+				"response buffer length not valid\n");
+		return -EINVAL;
+	}
+
+	reqd_len_sb_in = req->cmd_req_len + req->resp_len;
+	if (reqd_len_sb_in > data->client.sb_length) {
+		pr_debug("Not enough memory to fit cmd_buf and "
+			"resp_buf. Required: %u, Available: %u\n",
+				reqd_len_sb_in, data->client.sb_length);
+		return -ENOMEM;
+	}
+
+	send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
+	send_data_req.app_id = data->client.app_id;
+	send_data_req.req_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
+					(uint32_t)req->cmd_req_buf));
+	send_data_req.req_len = req->cmd_req_len;
+	send_data_req.rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data,
+					(uint32_t)req->resp_buf));
+	send_data_req.rsp_len = req->resp_len;
+
+	ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_data_req,
+					sizeof(send_data_req),
+					&resp, sizeof(resp));
+	if (ret) {
+		pr_err("qseecom_scm_call failed with err: %d\n", ret);
+		return ret;
+	}
+
+	if (resp.result == QSEOS_RESULT_INCOMPLETE) {
+		ret = __qseecom_process_incomplete_cmd(data, &resp);
+		if (ret) {
+			pr_err("process_incomplete_cmd failed err: %d\n", ret);
+			return ret;
+		}
+	}
+	return ret;
+}
+
+
+static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
+{
+	int ret = 0;
+	struct qseecom_send_cmd_req req;
+
+	ret = copy_from_user(&req, argp, sizeof(req));
+	if (ret) {
+		pr_err("copy_from_user failed\n");
+		return ret;
+	}
+	if (qseecom.qseos_version == QSEOS_VERSION_14)
+		ret = __qseecom_send_cmd(data, &req);
+	else
+		ret = __qseecom_send_cmd_legacy(data, &req);
+	if (ret)
+		return ret;
+
+	pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
+			req.resp_len, req.resp_buf);
+	return ret;
+}
+
+static int __qseecom_send_cmd_req_clean_up(
+			struct qseecom_send_modfd_cmd_req *req)
+{
+	char *field;
+	uint32_t *update;
+	int ret = 0;
+	int i = 0;
+
+	for (i = 0; i < MAX_ION_FD; i++) {
+		if (req->ifd_data[i].fd != 0) {
+			field = (char *)req->cmd_req_buf +
+					req->ifd_data[i].cmd_buf_offset;
+			update = (uint32_t *) field;
+			*update = 0;
+		}
+	}
+	return ret;
+}
+
+static int __qseecom_update_with_phy_addr(
+			struct qseecom_send_modfd_cmd_req *req)
+{
+	struct ion_handle *ihandle;
+	char *field;
+	uint32_t *update;
+	ion_phys_addr_t pa;
+	int ret = 0;
+	int i = 0;
+	uint32_t length;
+
+	for (i = 0; i < MAX_ION_FD; i++) {
+		if (req->ifd_data[i].fd != 0) {
+			/* Get the handle of the shared fd */
+			ihandle = ion_import_fd(qseecom.ion_clnt,
+						req->ifd_data[i].fd);
+			if (IS_ERR_OR_NULL(ihandle)) {
+				pr_err("Ion client can't retrieve the handle\n");
+				return -ENOMEM;
+			}
+			field = (char *) req->cmd_req_buf +
+						req->ifd_data[i].cmd_buf_offset;
+			update = (uint32_t *) field;
+
+			/* Populate the cmd data structure with the phys_addr */
+			ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &length);
+			if (ret)
+				return -ENOMEM;
+
+			*update = (uint32_t)pa;
+			/* Deallocate the handle */
+			if (!IS_ERR_OR_NULL(ihandle))
+				ion_free(qseecom.ion_clnt, ihandle);
+		}
+	}
+	return ret;
+}
+
+static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
+					void __user *argp)
+{
+	int ret = 0;
+	struct qseecom_send_modfd_cmd_req req;
+	struct qseecom_send_cmd_req send_cmd_req;
+
+	ret = copy_from_user(&req, argp, sizeof(req));
+	if (ret) {
+		pr_err("copy_from_user failed\n");
+		return ret;
+	}
+	send_cmd_req.cmd_req_buf = req.cmd_req_buf;
+	send_cmd_req.cmd_req_len = req.cmd_req_len;
+	send_cmd_req.resp_buf = req.resp_buf;
+	send_cmd_req.resp_len = req.resp_len;
+
+	ret = __qseecom_update_with_phy_addr(&req);
+	if (ret)
+		return ret;
+	if (qseecom.qseos_version == QSEOS_VERSION_14)
+		ret = __qseecom_send_cmd(data, &send_cmd_req);
+	else
+		ret = __qseecom_send_cmd_legacy(data, &send_cmd_req);
+	__qseecom_send_cmd_req_clean_up(&req);
+
+	if (ret)
+		return ret;
+
+	pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
+			req.resp_len, req.resp_buf);
+	return ret;
+}
+
+static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
+		struct qseecom_registered_listener_list *svc)
+{
+	int ret;
+	ret = (svc->rcv_req_flag != 0);
+	return ret || data->abort;
+}
+
+static int qseecom_receive_req(struct qseecom_dev_handle *data)
+{
+	int ret = 0;
+	struct qseecom_registered_listener_list *this_lstnr;
+
+	this_lstnr = __qseecom_find_svc(data->listener.id);
+	while (1) {
+		if (wait_event_interruptible(this_lstnr->rcv_req_wq,
+				__qseecom_listener_has_rcvd_req(data,
+				this_lstnr))) {
+			pr_warning("Interrupted: exiting wait_rcv_req loop\n");
+			/* woken up for different reason */
+			return -ERESTARTSYS;
+		}
+
+		if (data->abort) {
+			pr_err("Aborting driver!\n");
+			return -ENODEV;
+		}
+		this_lstnr->rcv_req_flag = 0;
+		if (qseecom.qseos_version == QSEOS_VERSION_13) {
+			if (*((uint32_t *)this_lstnr->sb_virt) != 0)
+				break;
+		} else {
+			break;
+		}
+	}
+	return ret;
+}
+
+static int qseecom_send_resp(void)
+{
+	qseecom.send_resp_flag = 1;
+	wake_up_interruptible(&qseecom.send_resp_wq);
+	return 0;
+}
+
+static int qseecom_get_qseos_version(struct qseecom_dev_handle *data,
+						void __user *argp)
+{
+	struct qseecom_qseos_version_req req;
+
+	if (copy_from_user(&req, argp, sizeof(req))) {
+		pr_err("copy_from_user failed");
+		return -EINVAL;
+	}
+	req.qseos_version = qseecom.qseos_version;
+	if (copy_to_user(argp, &req, sizeof(req))) {
+		pr_err("copy_to_user failed");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int qsee_vote_for_clock(void)
+{
+	int ret = 0;
+
+	if (!qsee_perf_client)
+		return -EINVAL;
+
+	mutex_lock(&qsee_bw_mutex);
+	if (!qsee_bw_count) {
+		ret = msm_bus_scale_client_update_request(
+				qsee_perf_client, 1);
+		if (ret) {
+			pr_err("Bandwidth request failed (%d)\n", ret);
+		} else {
+			ret = clk_enable(qseecom_bus_clk);
+			if (ret)
+				pr_err("Clock enable failed\n");
+		}
+	}
+	if (ret)
+		msm_bus_scale_client_update_request(qsee_perf_client, 0);
+	else
+		qsee_bw_count++;
+
+	mutex_unlock(&qsee_bw_mutex);
+	return ret;
+}
+
+static void qsee_disable_clock_vote(void)
+{
+	if (!qsee_perf_client)
+		return ;
+
+	mutex_lock(&qsee_bw_mutex);
+	if (qsee_bw_count > 0) {
+		if (qsee_bw_count-- == 1) {
+			msm_bus_scale_client_update_request(qsee_perf_client,
+							0);
+			clk_disable(qseecom_bus_clk);
+		}
+	}
+	mutex_unlock(&qsee_bw_mutex);
+}
+
+
+static long qseecom_ioctl(struct file *file, unsigned cmd,
+		unsigned long arg)
+{
+	int ret = 0;
+	struct qseecom_dev_handle *data = file->private_data;
+	void __user *argp = (void __user *) arg;
+
+	if (data->abort) {
+		pr_err("Aborting qseecom driver\n");
+		return -ENODEV;
+	}
+
+	switch (cmd) {
+	case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
+		pr_debug("ioctl register_listener_req()\n");
+		atomic_inc(&data->ioctl_count);
+		ret = qseecom_register_listener(data, argp);
+		atomic_dec(&data->ioctl_count);
+		wake_up_all(&data->abort_wq);
+		if (ret)
+			pr_err("failed qseecom_register_listener: %d\n", ret);
+		break;
+	}
+	case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
+		pr_debug("ioctl unregister_listener_req()\n");
+		atomic_inc(&data->ioctl_count);
+		ret = qseecom_unregister_listener(data);
+		atomic_dec(&data->ioctl_count);
+		wake_up_all(&data->abort_wq);
+		if (ret)
+			pr_err("failed qseecom_unregister_listener: %d\n", ret);
+		break;
+	}
+	case QSEECOM_IOCTL_SEND_CMD_REQ: {
+		/* Only one client allowed here at a time */
+		mutex_lock(&send_msg_lock);
+		atomic_inc(&data->ioctl_count);
+		ret = qseecom_send_cmd(data, argp);
+		atomic_dec(&data->ioctl_count);
+		wake_up_all(&data->abort_wq);
+		mutex_unlock(&send_msg_lock);
+		if (ret)
+			pr_err("failed qseecom_send_cmd: %d\n", ret);
+		break;
+	}
+	case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
+		/* Only one client allowed here at a time */
+		mutex_lock(&send_msg_lock);
+		atomic_inc(&data->ioctl_count);
+		ret = qseecom_send_modfd_cmd(data, argp);
+		atomic_dec(&data->ioctl_count);
+		wake_up_all(&data->abort_wq);
+		mutex_unlock(&send_msg_lock);
+		if (ret)
+			pr_err("failed qseecom_send_cmd: %d\n", ret);
+		break;
+	}
+	case QSEECOM_IOCTL_RECEIVE_REQ: {
+		atomic_inc(&data->ioctl_count);
+		ret = qseecom_receive_req(data);
+		atomic_dec(&data->ioctl_count);
+		wake_up_all(&data->abort_wq);
+		if (ret)
+			pr_err("failed qseecom_receive_req: %d\n", ret);
+		break;
+	}
+	case QSEECOM_IOCTL_SEND_RESP_REQ: {
+		atomic_inc(&data->ioctl_count);
+		ret = qseecom_send_resp();
+		atomic_dec(&data->ioctl_count);
+		wake_up_all(&data->abort_wq);
+		if (ret)
+			pr_err("failed qseecom_send_resp: %d\n", ret);
+		break;
+	}
+	case QSEECOM_IOCTL_SET_MEM_PARAM_REQ: {
+		ret = qseecom_set_client_mem_param(data, argp);
+		if (ret)
+			pr_err("failed Qqseecom_set_mem_param request: %d\n",
+								ret);
+		break;
+	}
+	case QSEECOM_IOCTL_LOAD_APP_REQ: {
+		mutex_lock(&app_access_lock);
+		atomic_inc(&data->ioctl_count);
+		ret = qseecom_load_app(data, argp);
+		atomic_dec(&data->ioctl_count);
+		mutex_unlock(&app_access_lock);
+		if (ret)
+			pr_err("failed load_app request: %d\n", ret);
+		break;
+	}
+	case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
+		mutex_lock(&app_access_lock);
+		atomic_inc(&data->ioctl_count);
+		ret = qseecom_unload_app(data);
+		atomic_dec(&data->ioctl_count);
+		mutex_unlock(&app_access_lock);
+		if (ret)
+			pr_err("failed unload_app request: %d\n", ret);
+		break;
+	}
+	case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: {
+		atomic_inc(&data->ioctl_count);
+		ret = qseecom_get_qseos_version(data, argp);
+		if (ret)
+			pr_err("qseecom_get_qseos_version: %d\n", ret);
+		atomic_dec(&data->ioctl_count);
+		break;
+	}
+	case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
+		atomic_inc(&data->ioctl_count);
+		ret = qsee_vote_for_clock();
+		if (ret)
+			pr_err("Failed to vote for clock%d\n", ret);
+		atomic_dec(&data->ioctl_count);
+		break;
+	}
+	case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
+		atomic_inc(&data->ioctl_count);
+		qsee_disable_clock_vote();
+		atomic_dec(&data->ioctl_count);
+		break;
+	}
+	default:
+		return -EINVAL;
+	}
+	return ret;
+}
+
+static int qseecom_open(struct inode *inode, struct file *file)
+{
+	int ret = 0;
+	struct qseecom_dev_handle *data;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		pr_err("kmalloc failed\n");
+		return -ENOMEM;
+	}
+	file->private_data = data;
+	data->abort = 0;
+	data->service = false;
+	data->released = false;
+	init_waitqueue_head(&data->abort_wq);
+	atomic_set(&data->ioctl_count, 0);
+	return ret;
+}
+
+static int qseecom_release(struct inode *inode, struct file *file)
+{
+	struct qseecom_dev_handle *data = file->private_data;
+	int ret = 0;
+
+	if (data->released == false) {
+		pr_warn("data->released == false\n");
+		if (data->service)
+			ret = qseecom_unregister_listener(data);
+		else
+			ret = qseecom_unload_app(data);
+		if (ret) {
+			pr_err("Close failed\n");
+			return ret;
+		}
+	}
+	kfree(data);
+	return ret;
+}
+
+/* qseecom bus scaling */
+static struct msm_bus_paths qsee_bw_table[] = {
+	{
+		.vectors = (struct msm_bus_vectors[]){
+			{
+				.src = MSM_BUS_MASTER_SPS,
+				.dst = MSM_BUS_SLAVE_EBI_CH0,
+			},
+		},
+		.num_paths = 1,
+	},
+	{
+		.vectors = (struct msm_bus_vectors[]){
+			{
+				.src = MSM_BUS_MASTER_SPS,
+				.dst = MSM_BUS_SLAVE_EBI_CH0,
+				.ib = (492 * 8) * 1000000UL,
+				.ab = (492 * 8) *  100000UL,
+			},
+		},
+		.num_paths = 1,
+	},
+};
+
+static struct msm_bus_scale_pdata qsee_bus_pdata = {
+	.usecase = qsee_bw_table,
+	.num_usecases = ARRAY_SIZE(qsee_bw_table),
+	.name = "qsee",
+};
+
+static const struct file_operations qseecom_fops = {
+		.owner = THIS_MODULE,
+		.unlocked_ioctl = qseecom_ioctl,
+		.open = qseecom_open,
+		.release = qseecom_release
+};
+
+static int __init qseecom_init(void)
+{
+	int rc;
+	int ret = 0;
+	struct device *class_dev;
+	char qsee_not_legacy = 0;
+	uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
+
+	rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
+	if (rc < 0) {
+		pr_err("alloc_chrdev_region failed %d\n", rc);
+		return rc;
+	}
+
+	driver_class = class_create(THIS_MODULE, QSEECOM_DEV);
+	if (IS_ERR(driver_class)) {
+		rc = -ENOMEM;
+		pr_err("class_create failed %d\n", rc);
+		goto unregister_chrdev_region;
+	}
+
+	class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL,
+			QSEECOM_DEV);
+	if (!class_dev) {
+		pr_err("class_device_create failed %d\n", rc);
+		rc = -ENOMEM;
+		goto class_destroy;
+	}
+
+	cdev_init(&qseecom_cdev, &qseecom_fops);
+	qseecom_cdev.owner = THIS_MODULE;
+
+	rc = cdev_add(&qseecom_cdev, MKDEV(MAJOR(qseecom_device_no), 0), 1);
+	if (rc < 0) {
+		pr_err("cdev_add failed %d\n", rc);
+		goto err;
+	}
+
+	INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
+	spin_lock_init(&qseecom.registered_listener_list_lock);
+	INIT_LIST_HEAD(&qseecom.registered_app_list_head);
+	spin_lock_init(&qseecom.registered_app_list_lock);
+	init_waitqueue_head(&qseecom.send_resp_wq);
+	qseecom.send_resp_flag = 0;
+
+	rc = scm_call(6, 1, &system_call_id, sizeof(system_call_id),
+				&qsee_not_legacy, sizeof(qsee_not_legacy));
+	if (rc) {
+		pr_err("Failed to retrieve QSEE version information %d\n", rc);
+		goto err;
+	}
+	if (qsee_not_legacy)
+		qseecom.qseos_version = QSEOS_VERSION_14;
+	else {
+		qseecom.qseos_version = QSEOS_VERSION_13;
+		pil = NULL;
+		pil_ref_cnt = 0;
+	}
+	/* Create ION msm client */
+	qseecom.ion_clnt = msm_ion_client_create(0x03, "qseecom-kernel");
+	if (qseecom.ion_clnt == NULL) {
+		pr_err("Ion client cannot be created\n");
+		rc = -ENOMEM;
+		goto err;
+	}
+
+	/* register client for bus scaling */
+	qsee_perf_client = msm_bus_scale_register_client(&qsee_bus_pdata);
+	if (!qsee_perf_client)
+		pr_err("Unable to register bus client\n");
+
+	qseecom_bus_clk = clk_get_sys("scm", "bus_clk");
+	if (!IS_ERR(qseecom_bus_clk)) {
+		ret = clk_set_rate(qseecom_bus_clk, 64000000);
+		if (ret) {
+			qseecom_bus_clk = NULL;
+			pr_err("Unable to set clock rate\n");
+		}
+	} else {
+		qseecom_bus_clk = NULL;
+		pr_warn("Unable to get bus clk\n");
+	}
+	return 0;
+err:
+	device_destroy(driver_class, qseecom_device_no);
+class_destroy:
+	class_destroy(driver_class);
+unregister_chrdev_region:
+	unregister_chrdev_region(qseecom_device_no, 1);
+	return rc;
+}
+
+static void __exit qseecom_exit(void)
+{
+	device_destroy(driver_class, qseecom_device_no);
+	class_destroy(driver_class);
+	unregister_chrdev_region(qseecom_device_no, 1);
+	ion_client_destroy(qseecom.ion_clnt);
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator");
+
+module_init(qseecom_init);
+module_exit(qseecom_exit);
diff --git a/drivers/misc/qseecom_legacy.h b/drivers/misc/qseecom_legacy.h
new file mode 100644
index 0000000..66f87e9
--- /dev/null
+++ b/drivers/misc/qseecom_legacy.h
@@ -0,0 +1,79 @@
+/* Qualcomm Secure Execution Environment Communicator (QSEECOM) driver
+ *
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#ifndef __QSEECOM_LEGACY_H_
+#define __QSEECOM_LEGACY_H_
+
+#include <linux/types.h>
+
+#define TZ_SCHED_CMD_ID_REGISTER_LISTENER    0x04
+
+enum tz_sched_cmd_type {
+	TZ_SCHED_CMD_INVALID = 0,
+	TZ_SCHED_CMD_NEW,      /* New TZ Scheduler Command */
+	TZ_SCHED_CMD_PENDING,  /* Pending cmd...sched will restore stack */
+	TZ_SCHED_CMD_COMPLETE, /* TZ sched command is complete */
+	TZ_SCHED_CMD_MAX     = 0x7FFFFFFF
+};
+
+enum tz_sched_cmd_status {
+	TZ_SCHED_STATUS_INCOMPLETE = 0,
+	TZ_SCHED_STATUS_COMPLETE,
+	TZ_SCHED_STATUS_MAX  = 0x7FFFFFFF
+};
+/* Command structure for initializing shared buffers */
+__packed struct qse_pr_init_sb_req_s {
+	/* First 4 bytes should always be command id */
+	uint32_t                  pr_cmd;
+	/* Pointer to the physical location of sb buffer */
+	uint32_t                  sb_ptr;
+	/* length of shared buffer */
+	uint32_t                  sb_len;
+	uint32_t                  listener_id;
+};
+
+__packed struct qse_pr_init_sb_rsp_s {
+	/* First 4 bytes should always be command id */
+	uint32_t                  pr_cmd;
+	/* Return code, 0 for success, Approp error code otherwise */
+	int32_t                   ret;
+};
+
+/*
+ * struct QSEECom_command - QSECom command buffer
+ * @cmd_type: value from enum tz_sched_cmd_type
+ * @sb_in_cmd_addr: points to physical location of command
+ *                buffer
+ * @sb_in_cmd_len: length of command buffer
+ */
+__packed struct qseecom_command {
+	uint32_t               cmd_type;
+	uint8_t                *sb_in_cmd_addr;
+	uint32_t               sb_in_cmd_len;
+};
+
+/*
+ * struct QSEECom_response - QSECom response buffer
+ * @cmd_status: value from enum tz_sched_cmd_status
+ * @sb_in_rsp_addr: points to physical location of response
+ *                buffer
+ * @sb_in_rsp_len: length of command response
+ */
+__packed struct qseecom_response {
+	uint32_t                 cmd_status;
+	uint8_t                  *sb_in_rsp_addr;
+	uint32_t                 sb_in_rsp_len;
+};
+
+#endif /* __QSEECOM_LEGACY_H_ */
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 48f3f2d..4634e75 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -94,6 +94,11 @@
 	unsigned int	read_only;
 	unsigned int	part_type;
 	unsigned int	name_idx;
+	unsigned int	reset_done;
+#define MMC_BLK_READ		BIT(0)
+#define MMC_BLK_WRITE		BIT(1)
+#define MMC_BLK_DISCARD		BIT(2)
+#define MMC_BLK_SECDISCARD	BIT(3)
 
 	/*
 	 * Only set in main mmc_blk_data associated
@@ -106,6 +111,16 @@
 
 static DEFINE_MUTEX(open_lock);
 
+enum mmc_blk_status {
+	MMC_BLK_SUCCESS = 0,
+	MMC_BLK_PARTIAL,
+	MMC_BLK_CMD_ERR,
+	MMC_BLK_RETRY,
+	MMC_BLK_ABORT,
+	MMC_BLK_DATA_ERR,
+	MMC_BLK_ECC_ERR,
+};
+
 module_param(perdev_minors, int, 0444);
 MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
 
@@ -277,7 +292,7 @@
 	struct mmc_card *card;
 	struct mmc_command cmd = {0};
 	struct mmc_data data = {0};
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 	struct scatterlist sg;
 	int err;
 
@@ -423,32 +438,29 @@
 #endif
 };
 
-struct mmc_blk_request {
-	struct mmc_request	mrq;
-	struct mmc_command	sbc;
-	struct mmc_command	cmd;
-	struct mmc_command	stop;
-	struct mmc_data		data;
-};
-
 static inline int mmc_blk_part_switch(struct mmc_card *card,
 				      struct mmc_blk_data *md)
 {
 	int ret;
 	struct mmc_blk_data *main_md = mmc_get_drvdata(card);
+
 	if (main_md->part_curr == md->part_type)
 		return 0;
 
 	if (mmc_card_mmc(card)) {
-		card->ext_csd.part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
-		card->ext_csd.part_config |= md->part_type;
+		u8 part_config = card->ext_csd.part_config;
+
+		part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
+		part_config |= md->part_type;
 
 		ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				 EXT_CSD_PART_CONFIG, card->ext_csd.part_config,
+				 EXT_CSD_PART_CONFIG, part_config,
 				 card->ext_csd.part_time);
 		if (ret)
 			return ret;
-}
+
+		card->ext_csd.part_config = part_config;
+	}
 
 	main_md->part_curr = md->part_type;
 	return 0;
@@ -460,7 +472,7 @@
 	u32 result;
 	__be32 *blocks;
 
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 	struct mmc_command cmd = {0};
 	struct mmc_data data = {0};
 	unsigned int timeout_us;
@@ -615,7 +627,7 @@
  * Otherwise we don't understand what happened, so abort.
  */
 static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
-	struct mmc_blk_request *brq)
+	struct mmc_blk_request *brq, int *ecc_err)
 {
 	bool prev_cmd_status_valid = true;
 	u32 status, stop_status = 0;
@@ -647,6 +659,12 @@
 		return ERR_ABORT;
 	}
 
+	/* Flag ECC errors */
+	if ((status & R1_CARD_ECC_FAILED) ||
+	    (brq->stop.resp[0] & R1_CARD_ECC_FAILED) ||
+	    (brq->cmd.resp[0] & R1_CARD_ECC_FAILED))
+		*ecc_err = 1;
+
 	/*
 	 * Check the current card state.  If it is in some data transfer
 	 * mode, tell it to stop (and hopefully transition back to TRAN.)
@@ -664,6 +682,8 @@
 		 */
 		if (err)
 			return ERR_ABORT;
+		if (stop_status & R1_CARD_ECC_FAILED)
+			*ecc_err = 1;
 	}
 
 	/* Check for set block count errors */
@@ -676,6 +696,10 @@
 		return mmc_blk_cmd_error(req, "r/w cmd", brq->cmd.error,
 				prev_cmd_status_valid, status);
 
+	/* Data errors */
+	if (!brq->stop.error)
+		return ERR_CONTINUE;
+
 	/* Now for stop errors.  These aren't fatal to the transfer. */
 	pr_err("%s: error %d sending stop command, original cmd response %#x, card status %#x\n",
 	       req->rq_disk->disk_name, brq->stop.error,
@@ -692,12 +716,45 @@
 	return ERR_CONTINUE;
 }
 
+static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host,
+			 int type)
+{
+	int err;
+
+	if (md->reset_done & type)
+		return -EEXIST;
+
+	md->reset_done |= type;
+	err = mmc_hw_reset(host);
+	/* Ensure we switch back to the correct partition */
+	if (err != -EOPNOTSUPP) {
+		struct mmc_blk_data *main_md = mmc_get_drvdata(host->card);
+		int part_err;
+
+		main_md->part_curr = main_md->part_type;
+		part_err = mmc_blk_part_switch(host->card, md);
+		if (part_err) {
+			/*
+			 * We have failed to get back into the correct
+			 * partition, so we need to abort the whole request.
+			 */
+			return -ENODEV;
+		}
+	}
+	return err;
+}
+
+static inline void mmc_blk_reset_success(struct mmc_blk_data *md, int type)
+{
+	md->reset_done &= ~type;
+}
+
 static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
 {
 	struct mmc_blk_data *md = mq->data;
 	struct mmc_card *card = md->queue.card;
 	unsigned int from, nr, arg;
-	int err = 0;
+	int err = 0, type = MMC_BLK_DISCARD;
 
 	if (!mmc_can_erase(card)) {
 		err = -EOPNOTSUPP;
@@ -707,11 +764,13 @@
 	from = blk_rq_pos(req);
 	nr = blk_rq_sectors(req);
 
-	if (mmc_can_trim(card))
+	if (mmc_can_discard(card))
+		arg = MMC_DISCARD_ARG;
+	else if (mmc_can_trim(card))
 		arg = MMC_TRIM_ARG;
 	else
 		arg = MMC_ERASE_ARG;
-
+retry:
 	if (card->quirks & MMC_QUIRK_INAND_CMD38) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 				 INAND_CMD38_ARG_EXT_CSD,
@@ -724,6 +783,10 @@
 	}
 	err = mmc_erase(card, from, nr, arg);
 out:
+	if (err == -EIO && !mmc_blk_reset(md, card->host, type))
+		goto retry;
+	if (!err)
+		mmc_blk_reset_success(md, type);
 	spin_lock_irq(&md->lock);
 	__blk_end_request(req, err, blk_rq_bytes(req));
 	spin_unlock_irq(&md->lock);
@@ -737,13 +800,20 @@
 	struct mmc_blk_data *md = mq->data;
 	struct mmc_card *card = md->queue.card;
 	unsigned int from, nr, arg;
-	int err = 0;
+	int err = 0, type = MMC_BLK_SECDISCARD;
 
-	if (!mmc_can_secure_erase_trim(card)) {
+	if (!(mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))) {
 		err = -EOPNOTSUPP;
 		goto out;
 	}
 
+	/* The sanitize operation is supported at v4.5 only */
+	if (mmc_can_sanitize(card)) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				EXT_CSD_SANITIZE_START, 1, 0);
+		goto out;
+	}
+
 	from = blk_rq_pos(req);
 	nr = blk_rq_sectors(req);
 
@@ -751,7 +821,7 @@
 		arg = MMC_SECURE_TRIM1_ARG;
 	else
 		arg = MMC_SECURE_ERASE_ARG;
-
+retry:
 	if (card->quirks & MMC_QUIRK_INAND_CMD38) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 				 INAND_CMD38_ARG_EXT_CSD,
@@ -775,6 +845,10 @@
 		err = mmc_erase(card, from, nr, MMC_SECURE_TRIM2_ARG);
 	}
 out:
+	if (err == -EIO && !mmc_blk_reset(md, card->host, type))
+		goto retry;
+	if (!err)
+		mmc_blk_reset_success(md, type);
 	spin_lock_irq(&md->lock);
 	__blk_end_request(req, err, blk_rq_bytes(req));
 	spin_unlock_irq(&md->lock);
@@ -785,16 +859,18 @@
 static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
 {
 	struct mmc_blk_data *md = mq->data;
+	struct mmc_card *card = md->queue.card;
+	int ret = 0;
 
-	/*
-	 * No-op, only service this because we need REQ_FUA for reliable
-	 * writes.
-	 */
+	ret = mmc_flush_cache(card);
+	if (ret)
+		ret = -EIO;
+
 	spin_lock_irq(&md->lock);
-	__blk_end_request_all(req, 0);
+	__blk_end_request_all(req, ret);
 	spin_unlock_irq(&md->lock);
 
-	return 1;
+	return ret ? 0 : 1;
 }
 
 /*
@@ -828,12 +904,106 @@
 	 R1_CC_ERROR |		/* Card controller error */		\
 	 R1_ERROR)		/* General/unknown error */
 
-static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
+static int mmc_blk_err_check(struct mmc_card *card,
+			     struct mmc_async_req *areq)
 {
+	struct mmc_queue_req *mq_mrq = container_of(areq, struct mmc_queue_req,
+						    mmc_active);
+	struct mmc_blk_request *brq = &mq_mrq->brq;
+	struct request *req = mq_mrq->req;
+	int ecc_err = 0;
+
+	/*
+	 * sbc.error indicates a problem with the set block count
+	 * command.  No data will have been transferred.
+	 *
+	 * cmd.error indicates a problem with the r/w command.  No
+	 * data will have been transferred.
+	 *
+	 * stop.error indicates a problem with the stop command.  Data
+	 * may have been transferred, or may still be transferring.
+	 */
+	if (brq->sbc.error || brq->cmd.error || brq->stop.error ||
+	    brq->data.error) {
+		switch (mmc_blk_cmd_recovery(card, req, brq, &ecc_err)) {
+		case ERR_RETRY:
+			return MMC_BLK_RETRY;
+		case ERR_ABORT:
+		case ERR_NOMEDIUM:
+			return MMC_BLK_ABORT;
+		case ERR_CONTINUE:
+			break;
+		}
+	}
+
+	/*
+	 * Check for errors relating to the execution of the
+	 * initial command - such as address errors.  No data
+	 * has been transferred.
+	 */
+	if (brq->cmd.resp[0] & CMD_ERRORS) {
+		pr_err("%s: r/w command failed, status = %#x\n",
+		       req->rq_disk->disk_name, brq->cmd.resp[0]);
+		return MMC_BLK_ABORT;
+	}
+
+	/*
+	 * Everything else is either success, or a data error of some
+	 * kind.  If it was a write, we may have transitioned to
+	 * program mode, which we have to wait for it to complete.
+	 */
+	if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
+		u32 status;
+		do {
+			int err = get_card_status(card, &status, 5);
+			if (err) {
+				printk(KERN_ERR "%s: error %d requesting status\n",
+				       req->rq_disk->disk_name, err);
+				return MMC_BLK_CMD_ERR;
+			}
+			/*
+			 * Some cards mishandle the status bits,
+			 * so make sure to check both the busy
+			 * indication and the card state.
+			 */
+		} while (!(status & R1_READY_FOR_DATA) ||
+			 (R1_CURRENT_STATE(status) == R1_STATE_PRG));
+	}
+
+	if (brq->data.error) {
+		pr_err("%s: error %d transferring data, sector %u, nr %u, cmd response %#x, card status %#x\n",
+		       req->rq_disk->disk_name, brq->data.error,
+		       (unsigned)blk_rq_pos(req),
+		       (unsigned)blk_rq_sectors(req),
+		       brq->cmd.resp[0], brq->stop.resp[0]);
+
+		if (rq_data_dir(req) == READ) {
+			if (ecc_err)
+				return MMC_BLK_ECC_ERR;
+			return MMC_BLK_DATA_ERR;
+		} else {
+			return MMC_BLK_CMD_ERR;
+		}
+	}
+
+	if (!brq->data.bytes_xfered)
+		return MMC_BLK_RETRY;
+
+	if (blk_rq_bytes(req) != brq->data.bytes_xfered)
+		return MMC_BLK_PARTIAL;
+
+	return MMC_BLK_SUCCESS;
+}
+
+static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
+			       struct mmc_card *card,
+			       int disable_multi,
+			       struct mmc_queue *mq)
+{
+	u32 readcmd, writecmd;
+	struct mmc_blk_request *brq = &mqrq->brq;
+	struct request *req = mqrq->req;
 	struct mmc_blk_data *md = mq->data;
-	struct mmc_card *card = md->queue.card;
-	struct mmc_blk_request brq;
-	int ret = 1, disable_multi = 0, retry = 0;
 
 	/*
 	 * Reliable writes are used to implement Forced Unit Access and
@@ -844,225 +1014,135 @@
 		(rq_data_dir(req) == WRITE) &&
 		(md->flags & MMC_BLK_REL_WR);
 
-	do {
-		u32 readcmd, writecmd;
+	memset(brq, 0, sizeof(struct mmc_blk_request));
+	brq->mrq.cmd = &brq->cmd;
+	brq->mrq.data = &brq->data;
 
-		memset(&brq, 0, sizeof(struct mmc_blk_request));
-		brq.mrq.cmd = &brq.cmd;
-		brq.mrq.data = &brq.data;
+	brq->cmd.arg = blk_rq_pos(req);
+	if (!mmc_card_blockaddr(card))
+		brq->cmd.arg <<= 9;
+	brq->cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+	brq->data.blksz = 512;
+	brq->stop.opcode = MMC_STOP_TRANSMISSION;
+	brq->stop.arg = 0;
+	brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+	brq->data.blocks = blk_rq_sectors(req);
 
-		brq.cmd.arg = blk_rq_pos(req);
-		if (!mmc_card_blockaddr(card))
-			brq.cmd.arg <<= 9;
-		brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
-		brq.data.blksz = 512;
-		brq.stop.opcode = MMC_STOP_TRANSMISSION;
-		brq.stop.arg = 0;
-		brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
-		brq.data.blocks = blk_rq_sectors(req);
+	/*
+	 * The block layer doesn't support all sector count
+	 * restrictions, so we need to be prepared for too big
+	 * requests.
+	 */
+	if (brq->data.blocks > card->host->max_blk_count)
+		brq->data.blocks = card->host->max_blk_count;
 
+	if (brq->data.blocks > 1) {
 		/*
-		 * The block layer doesn't support all sector count
-		 * restrictions, so we need to be prepared for too big
-		 * requests.
+		 * After a read error, we redo the request one sector
+		 * at a time in order to accurately determine which
+		 * sectors can be read successfully.
 		 */
-		if (brq.data.blocks > card->host->max_blk_count)
-			brq.data.blocks = card->host->max_blk_count;
+		if (disable_multi)
+			brq->data.blocks = 1;
 
-		/*
-		 * After a read error, we redo the request one sector at a time
-		 * in order to accurately determine which sectors can be read
-		 * successfully.
+		/* Some controllers can't do multiblock reads due to hw bugs */
+		if (card->host->caps2 & MMC_CAP2_NO_MULTI_READ &&
+		    rq_data_dir(req) == READ)
+			brq->data.blocks = 1;
+	}
+
+	if (brq->data.blocks > 1 || do_rel_wr) {
+		/* SPI multiblock writes terminate using a special
+		 * token, not a STOP_TRANSMISSION request.
 		 */
-		if (disable_multi && brq.data.blocks > 1)
-			brq.data.blocks = 1;
+		if (!mmc_host_is_spi(card->host) ||
+		    rq_data_dir(req) == READ)
+			brq->mrq.stop = &brq->stop;
+		readcmd = MMC_READ_MULTIPLE_BLOCK;
+		writecmd = MMC_WRITE_MULTIPLE_BLOCK;
+	} else {
+		brq->mrq.stop = NULL;
+		readcmd = MMC_READ_SINGLE_BLOCK;
+		writecmd = MMC_WRITE_BLOCK;
+	}
+	if (rq_data_dir(req) == READ) {
+		brq->cmd.opcode = readcmd;
+		brq->data.flags |= MMC_DATA_READ;
+	} else {
+		brq->cmd.opcode = writecmd;
+		brq->data.flags |= MMC_DATA_WRITE;
+	}
 
-		if (brq.data.blocks > 1 || do_rel_wr) {
-			/* SPI multiblock writes terminate using a special
-			 * token, not a STOP_TRANSMISSION request.
-			 */
-			if (!mmc_host_is_spi(card->host) ||
-			    rq_data_dir(req) == READ)
-				brq.mrq.stop = &brq.stop;
-			readcmd = MMC_READ_MULTIPLE_BLOCK;
-			writecmd = MMC_WRITE_MULTIPLE_BLOCK;
-		} else {
-			brq.mrq.stop = NULL;
-			readcmd = MMC_READ_SINGLE_BLOCK;
-			writecmd = MMC_WRITE_BLOCK;
-		}
-		if (rq_data_dir(req) == READ) {
-			brq.cmd.opcode = readcmd;
-			brq.data.flags |= MMC_DATA_READ;
-		} else {
-			brq.cmd.opcode = writecmd;
-			brq.data.flags |= MMC_DATA_WRITE;
-		}
+	if (do_rel_wr)
+		mmc_apply_rel_rw(brq, card, req);
 
-		if (do_rel_wr)
-			mmc_apply_rel_rw(&brq, card, req);
+	/*
+	 * Pre-defined multi-block transfers are preferable to
+	 * open ended-ones (and necessary for reliable writes).
+	 * However, it is not sufficient to just send CMD23,
+	 * and avoid the final CMD12, as on an error condition
+	 * CMD12 (stop) needs to be sent anyway. This, coupled
+	 * with Auto-CMD23 enhancements provided by some
+	 * hosts, means that the complexity of dealing
+	 * with this is best left to the host. If CMD23 is
+	 * supported by card and host, we'll fill sbc in and let
+	 * the host deal with handling it correctly. This means
+	 * that for hosts that don't expose MMC_CAP_CMD23, no
+	 * change of behavior will be observed.
+	 *
+	 * N.B: Some MMC cards experience perf degradation.
+	 * We'll avoid using CMD23-bounded multiblock writes for
+	 * these, while retaining features like reliable writes.
+	 */
 
-		/*
-		 * Pre-defined multi-block transfers are preferable to
-		 * open ended-ones (and necessary for reliable writes).
-		 * However, it is not sufficient to just send CMD23,
-		 * and avoid the final CMD12, as on an error condition
-		 * CMD12 (stop) needs to be sent anyway. This, coupled
-		 * with Auto-CMD23 enhancements provided by some
-		 * hosts, means that the complexity of dealing
-		 * with this is best left to the host. If CMD23 is
-		 * supported by card and host, we'll fill sbc in and let
-		 * the host deal with handling it correctly. This means
-		 * that for hosts that don't expose MMC_CAP_CMD23, no
-		 * change of behavior will be observed.
-		 *
-		 * N.B: Some MMC cards experience perf degradation.
-		 * We'll avoid using CMD23-bounded multiblock writes for
-		 * these, while retaining features like reliable writes.
-		 */
+	if ((md->flags & MMC_BLK_CMD23) &&
+	    mmc_op_multi(brq->cmd.opcode) &&
+	    (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23))) {
+		brq->sbc.opcode = MMC_SET_BLOCK_COUNT;
+		brq->sbc.arg = brq->data.blocks |
+			(do_rel_wr ? (1 << 31) : 0);
+		brq->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
+		brq->mrq.sbc = &brq->sbc;
+	}
 
-		if ((md->flags & MMC_BLK_CMD23) &&
-		    mmc_op_multi(brq.cmd.opcode) &&
-		    (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23))) {
-			brq.sbc.opcode = MMC_SET_BLOCK_COUNT;
-			brq.sbc.arg = brq.data.blocks |
-				(do_rel_wr ? (1 << 31) : 0);
-			brq.sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
-			brq.mrq.sbc = &brq.sbc;
-		}
+	mmc_set_data_timeout(&brq->data, card);
 
-		mmc_set_data_timeout(&brq.data, card);
+	brq->data.sg = mqrq->sg;
+	brq->data.sg_len = mmc_queue_map_sg(mq, mqrq);
 
-		brq.data.sg = mq->sg;
-		brq.data.sg_len = mmc_queue_map_sg(mq);
+	/*
+	 * Adjust the sg list so it is the same size as the
+	 * request.
+	 */
+	if (brq->data.blocks != blk_rq_sectors(req)) {
+		int i, data_size = brq->data.blocks << 9;
+		struct scatterlist *sg;
 
-		/*
-		 * Adjust the sg list so it is the same size as the
-		 * request.
-		 */
-		if (brq.data.blocks != blk_rq_sectors(req)) {
-			int i, data_size = brq.data.blocks << 9;
-			struct scatterlist *sg;
-
-			for_each_sg(brq.data.sg, sg, brq.data.sg_len, i) {
-				data_size -= sg->length;
-				if (data_size <= 0) {
-					sg->length += data_size;
-					i++;
-					break;
-				}
-			}
-			brq.data.sg_len = i;
-		}
-
-		mmc_queue_bounce_pre(mq);
-
-		mmc_wait_for_req(card->host, &brq.mrq);
-
-		mmc_queue_bounce_post(mq);
-
-		/*
-		 * sbc.error indicates a problem with the set block count
-		 * command.  No data will have been transferred.
-		 *
-		 * cmd.error indicates a problem with the r/w command.  No
-		 * data will have been transferred.
-		 *
-		 * stop.error indicates a problem with the stop command.  Data
-		 * may have been transferred, or may still be transferring.
-		 */
-		if (brq.sbc.error || brq.cmd.error || brq.stop.error) {
-			switch (mmc_blk_cmd_recovery(card, req, &brq)) {
-			case ERR_RETRY:
-				if (retry++ < 5)
-					continue;
-			case ERR_ABORT:
-			case ERR_NOMEDIUM:
-				goto cmd_abort;
-			case ERR_CONTINUE:
+		for_each_sg(brq->data.sg, sg, brq->data.sg_len, i) {
+			data_size -= sg->length;
+			if (data_size <= 0) {
+				sg->length += data_size;
+				i++;
 				break;
 			}
 		}
+		brq->data.sg_len = i;
+	}
 
-		/*
-		 * Check for errors relating to the execution of the
-		 * initial command - such as address errors.  No data
-		 * has been transferred.
-		 */
-		if (brq.cmd.resp[0] & CMD_ERRORS) {
-			pr_err("%s: r/w command failed, status = %#x\n",
-				req->rq_disk->disk_name, brq.cmd.resp[0]);
-			goto cmd_abort;
-		}
+	mqrq->mmc_active.mrq = &brq->mrq;
+	mqrq->mmc_active.err_check = mmc_blk_err_check;
 
-		/*
-		 * Everything else is either success, or a data error of some
-		 * kind.  If it was a write, we may have transitioned to
-		 * program mode, which we have to wait for it to complete.
-		 */
-		if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
-			u32 status;
-			do {
-				int err = get_card_status(card, &status, 5);
-				if (err) {
-					printk(KERN_ERR "%s: error %d requesting status\n",
-					       req->rq_disk->disk_name, err);
-					goto cmd_err;
-				}
-				/*
-				 * Some cards mishandle the status bits,
-				 * so make sure to check both the busy
-				 * indication and the card state.
-				 */
-			} while (!(status & R1_READY_FOR_DATA) ||
-				 (R1_CURRENT_STATE(status) == R1_STATE_PRG));
-		}
+	mmc_queue_bounce_pre(mqrq);
+}
 
-		if (brq.data.error) {
-			pr_err("%s: error %d transferring data, sector %u, nr %u, cmd response %#x, card status %#x\n",
-				req->rq_disk->disk_name, brq.data.error,
-				(unsigned)blk_rq_pos(req),
-				(unsigned)blk_rq_sectors(req),
-				brq.cmd.resp[0], brq.stop.resp[0]);
-
-			if (rq_data_dir(req) == READ) {
-				if (brq.data.blocks > 1) {
-					/* Redo read one sector at a time */
-					pr_warning("%s: retrying using single block read\n",
-						req->rq_disk->disk_name);
-					disable_multi = 1;
-					continue;
-				}
-
-				/*
-				 * After an error, we redo I/O one sector at a
-				 * time, so we only reach here after trying to
-				 * read a single sector.
-				 */
-				spin_lock_irq(&md->lock);
-				ret = __blk_end_request(req, -EIO, brq.data.blksz);
-				spin_unlock_irq(&md->lock);
-				continue;
-			} else {
-				goto cmd_err;
-			}
-		}
-
-		/*
-		 * A block was successfully transferred.
-		 */
-		spin_lock_irq(&md->lock);
-		ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
-		spin_unlock_irq(&md->lock);
-	} while (ret);
-
-	return 1;
-
- cmd_err:
- 	/*
- 	 * If this is an SD card and we're writing, we can first
- 	 * mark the known good sectors as ok.
- 	 *
+static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card,
+			   struct mmc_blk_request *brq, struct request *req,
+			   int ret)
+{
+	/*
+	 * If this is an SD card and we're writing, we can first
+	 * mark the known good sectors as ok.
+	 *
 	 * If the card is not SD, we can still ok written sectors
 	 * as reported by the controller (which might be less than
 	 * the real number of written sectors, but never more).
@@ -1078,9 +1158,122 @@
 		}
 	} else {
 		spin_lock_irq(&md->lock);
-		ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
+		ret = __blk_end_request(req, 0, brq->data.bytes_xfered);
 		spin_unlock_irq(&md->lock);
 	}
+	return ret;
+}
+
+static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
+{
+	struct mmc_blk_data *md = mq->data;
+	struct mmc_card *card = md->queue.card;
+	struct mmc_blk_request *brq = &mq->mqrq_cur->brq;
+	int ret = 1, disable_multi = 0, retry = 0, type;
+	enum mmc_blk_status status;
+	struct mmc_queue_req *mq_rq;
+	struct request *req;
+	struct mmc_async_req *areq;
+
+	if (!rqc && !mq->mqrq_prev->req)
+		return 0;
+
+	do {
+		if (rqc) {
+			mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
+			areq = &mq->mqrq_cur->mmc_active;
+		} else
+			areq = NULL;
+		areq = mmc_start_req(card->host, areq, (int *) &status);
+		if (!areq)
+			return 0;
+
+		mq_rq = container_of(areq, struct mmc_queue_req, mmc_active);
+		brq = &mq_rq->brq;
+		req = mq_rq->req;
+		type = rq_data_dir(req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE;
+		mmc_queue_bounce_post(mq_rq);
+
+		switch (status) {
+		case MMC_BLK_SUCCESS:
+		case MMC_BLK_PARTIAL:
+			/*
+			 * A block was successfully transferred.
+			 */
+			mmc_blk_reset_success(md, type);
+			spin_lock_irq(&md->lock);
+			ret = __blk_end_request(req, 0,
+						brq->data.bytes_xfered);
+			spin_unlock_irq(&md->lock);
+			/*
+			 * If the blk_end_request function returns non-zero even
+			 * though all data has been transferred and no errors
+			 * were returned by the host controller, it's a bug.
+			 */
+			if (status == MMC_BLK_SUCCESS && ret) {
+				printk(KERN_ERR "%s BUG rq_tot %d d_xfer %d\n",
+				       __func__, blk_rq_bytes(req),
+				       brq->data.bytes_xfered);
+				rqc = NULL;
+				goto cmd_abort;
+			}
+			break;
+		case MMC_BLK_CMD_ERR:
+			ret = mmc_blk_cmd_err(md, card, brq, req, ret);
+			if (!mmc_blk_reset(md, card->host, type))
+				break;
+			goto cmd_abort;
+		case MMC_BLK_RETRY:
+			if (retry++ < 5)
+				break;
+			/* Fall through */
+		case MMC_BLK_ABORT:
+			if (!mmc_blk_reset(md, card->host, type))
+				break;
+			goto cmd_abort;
+		case MMC_BLK_DATA_ERR: {
+			int err;
+
+			err = mmc_blk_reset(md, card->host, type);
+			if (!err)
+				break;
+			if (err == -ENODEV)
+				goto cmd_abort;
+			/* Fall through */
+		}
+		case MMC_BLK_ECC_ERR:
+			if (brq->data.blocks > 1) {
+				/* Redo read one sector at a time */
+				pr_warning("%s: retrying using single block read\n",
+					   req->rq_disk->disk_name);
+				disable_multi = 1;
+				break;
+			}
+			/*
+			 * After an error, we redo I/O one sector at a
+			 * time, so we only reach here after trying to
+			 * read a single sector.
+			 */
+			spin_lock_irq(&md->lock);
+			ret = __blk_end_request(req, -EIO,
+						brq->data.blksz);
+			spin_unlock_irq(&md->lock);
+			if (!ret)
+				goto start_new_req;
+			break;
+		}
+
+		if (ret) {
+			/*
+			 * In case of a incomplete request
+			 * prepare it again and resend.
+			 */
+			mmc_blk_rw_rq_prep(mq_rq, card, disable_multi, mq);
+			mmc_start_req(card->host, &mq_rq->mmc_active, NULL);
+		}
+	} while (ret);
+
+	return 1;
 
  cmd_abort:
 	spin_lock_irq(&md->lock);
@@ -1090,6 +1283,12 @@
 		ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
 	spin_unlock_irq(&md->lock);
 
+ start_new_req:
+	if (rqc) {
+		mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
+		mmc_start_req(card->host, &mq->mqrq_cur->mmc_active, NULL);
+	}
+
 	return 0;
 }
 
@@ -1109,26 +1308,42 @@
 	}
 #endif
 
-	mmc_claim_host(card->host);
+	if (req && !mq->mqrq_prev->req)
+		/* claim host only for the first request */
+		mmc_claim_host(card->host);
+
 	ret = mmc_blk_part_switch(card, md);
 	if (ret) {
+		if (req) {
+			spin_lock_irq(&md->lock);
+			__blk_end_request_all(req, -EIO);
+			spin_unlock_irq(&md->lock);
+		}
 		ret = 0;
 		goto out;
 	}
 
-	if (req->cmd_flags & REQ_DISCARD) {
+	if (req && req->cmd_flags & REQ_DISCARD) {
+		/* complete ongoing async transfer before issuing discard */
+		if (card->host->areq)
+			mmc_blk_issue_rw_rq(mq, NULL);
 		if (req->cmd_flags & REQ_SECURE)
 			ret = mmc_blk_issue_secdiscard_rq(mq, req);
 		else
 			ret = mmc_blk_issue_discard_rq(mq, req);
-	} else if (req->cmd_flags & REQ_FLUSH) {
+	} else if (req && req->cmd_flags & REQ_FLUSH) {
+		/* complete ongoing async transfer before issuing flush */
+		if (card->host->areq)
+			mmc_blk_issue_rw_rq(mq, NULL);
 		ret = mmc_blk_issue_flush(mq, req);
 	} else {
 		ret = mmc_blk_issue_rw_rq(mq, req);
 	}
 
 out:
-	mmc_release_host(card->host);
+	if (!req)
+		/* release host only when there are no more requests */
+		mmc_release_host(card->host);
 	return ret;
 }
 
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index 233cdfa..a2b005e 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -22,6 +22,7 @@
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
 #include <linux/seq_file.h>
+#include <linux/module.h>
 
 #define RESULT_OK		0
 #define RESULT_FAIL		1
@@ -148,6 +149,27 @@
 	struct mmc_test_general_result	*gr;
 };
 
+enum mmc_test_prep_media {
+	MMC_TEST_PREP_NONE = 0,
+	MMC_TEST_PREP_WRITE_FULL = 1 << 0,
+	MMC_TEST_PREP_ERASE = 1 << 1,
+};
+
+struct mmc_test_multiple_rw {
+	unsigned int *sg_len;
+	unsigned int *bs;
+	unsigned int len;
+	unsigned int size;
+	bool do_write;
+	bool do_nonblock_req;
+	enum mmc_test_prep_media prepare;
+};
+
+struct mmc_test_async_req {
+	struct mmc_async_req areq;
+	struct mmc_test_card *test;
+};
+
 /*******************************************************************/
 /*  General helper functions                                       */
 /*******************************************************************/
@@ -203,7 +225,7 @@
 static int mmc_test_busy(struct mmc_command *cmd)
 {
 	return !(cmd->resp[0] & R1_READY_FOR_DATA) ||
-		(R1_CURRENT_STATE(cmd->resp[0]) == 7);
+		(R1_CURRENT_STATE(cmd->resp[0]) == R1_STATE_PRG);
 }
 
 /*
@@ -367,21 +389,26 @@
  * Map memory into a scatterlist.  Optionally allow the same memory to be
  * mapped more than once.
  */
-static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long sz,
+static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long size,
 			   struct scatterlist *sglist, int repeat,
 			   unsigned int max_segs, unsigned int max_seg_sz,
-			   unsigned int *sg_len)
+			   unsigned int *sg_len, int min_sg_len)
 {
 	struct scatterlist *sg = NULL;
 	unsigned int i;
+	unsigned long sz = size;
 
 	sg_init_table(sglist, max_segs);
+	if (min_sg_len > max_segs)
+		min_sg_len = max_segs;
 
 	*sg_len = 0;
 	do {
 		for (i = 0; i < mem->cnt; i++) {
 			unsigned long len = PAGE_SIZE << mem->arr[i].order;
 
+			if (min_sg_len && (size / min_sg_len < len))
+				len = ALIGN(size / min_sg_len, 512);
 			if (len > sz)
 				len = sz;
 			if (len > max_seg_sz)
@@ -554,11 +581,12 @@
 
 	printk(KERN_INFO "%s: Transfer of %u x %u sectors (%u x %u%s KiB) took "
 			 "%lu.%09lu seconds (%u kB/s, %u KiB/s, "
-			 "%u.%02u IOPS)\n",
+			 "%u.%02u IOPS, sg_len %d)\n",
 			 mmc_hostname(test->card->host), count, sectors, count,
 			 sectors >> 1, (sectors & 1 ? ".5" : ""),
 			 (unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec,
-			 rate / 1000, rate / 1024, iops / 100, iops % 100);
+			 rate / 1000, rate / 1024, iops / 100, iops % 100,
+			 test->area.sg_len);
 
 	mmc_test_save_transfer_result(test, count, sectors, ts, rate, iops);
 }
@@ -661,7 +689,7 @@
  * Checks that a normal transfer didn't have any errors
  */
 static int mmc_test_check_result(struct mmc_test_card *test,
-	struct mmc_request *mrq)
+				 struct mmc_request *mrq)
 {
 	int ret;
 
@@ -685,6 +713,17 @@
 	return ret;
 }
 
+static int mmc_test_check_result_async(struct mmc_card *card,
+				       struct mmc_async_req *areq)
+{
+	struct mmc_test_async_req *test_async =
+		container_of(areq, struct mmc_test_async_req, areq);
+
+	mmc_test_wait_busy(test_async->test);
+
+	return mmc_test_check_result(test_async->test, areq->mrq);
+}
+
 /*
  * Checks that a "short transfer" behaved as expected
  */
@@ -720,6 +759,85 @@
 }
 
 /*
+ * Tests nonblock transfer with certain parameters
+ */
+static void mmc_test_nonblock_reset(struct mmc_request *mrq,
+				    struct mmc_command *cmd,
+				    struct mmc_command *stop,
+				    struct mmc_data *data)
+{
+	memset(mrq, 0, sizeof(struct mmc_request));
+	memset(cmd, 0, sizeof(struct mmc_command));
+	memset(data, 0, sizeof(struct mmc_data));
+	memset(stop, 0, sizeof(struct mmc_command));
+
+	mrq->cmd = cmd;
+	mrq->data = data;
+	mrq->stop = stop;
+}
+static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
+				      struct scatterlist *sg, unsigned sg_len,
+				      unsigned dev_addr, unsigned blocks,
+				      unsigned blksz, int write, int count)
+{
+	struct mmc_request mrq1;
+	struct mmc_command cmd1;
+	struct mmc_command stop1;
+	struct mmc_data data1;
+
+	struct mmc_request mrq2;
+	struct mmc_command cmd2;
+	struct mmc_command stop2;
+	struct mmc_data data2;
+
+	struct mmc_test_async_req test_areq[2];
+	struct mmc_async_req *done_areq;
+	struct mmc_async_req *cur_areq = &test_areq[0].areq;
+	struct mmc_async_req *other_areq = &test_areq[1].areq;
+	int i;
+	int ret;
+
+	test_areq[0].test = test;
+	test_areq[1].test = test;
+
+	mmc_test_nonblock_reset(&mrq1, &cmd1, &stop1, &data1);
+	mmc_test_nonblock_reset(&mrq2, &cmd2, &stop2, &data2);
+
+	cur_areq->mrq = &mrq1;
+	cur_areq->err_check = mmc_test_check_result_async;
+	other_areq->mrq = &mrq2;
+	other_areq->err_check = mmc_test_check_result_async;
+
+	for (i = 0; i < count; i++) {
+		mmc_test_prepare_mrq(test, cur_areq->mrq, sg, sg_len, dev_addr,
+				     blocks, blksz, write);
+		done_areq = mmc_start_req(test->card->host, cur_areq, &ret);
+
+		if (ret || (!done_areq && i > 0))
+			goto err;
+
+		if (done_areq) {
+			if (done_areq->mrq == &mrq2)
+				mmc_test_nonblock_reset(&mrq2, &cmd2,
+							&stop2, &data2);
+			else
+				mmc_test_nonblock_reset(&mrq1, &cmd1,
+							&stop1, &data1);
+		}
+		done_areq = cur_areq;
+		cur_areq = other_areq;
+		other_areq = done_areq;
+		dev_addr += blocks;
+	}
+
+	done_areq = mmc_start_req(test->card->host, NULL, &ret);
+
+	return ret;
+err:
+	return ret;
+}
+
+/*
  * Tests a basic transfer with certain parameters
  */
 static int mmc_test_simple_transfer(struct mmc_test_card *test,
@@ -1302,7 +1420,7 @@
  * Map sz bytes so that it can be transferred.
  */
 static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz,
-			     int max_scatter)
+			     int max_scatter, int min_sg_len)
 {
 	struct mmc_test_area *t = &test->area;
 	int err;
@@ -1315,7 +1433,7 @@
 				       &t->sg_len);
 	} else {
 		err = mmc_test_map_sg(t->mem, sz, t->sg, 1, t->max_segs,
-				      t->max_seg_sz, &t->sg_len);
+				      t->max_seg_sz, &t->sg_len, min_sg_len);
 	}
 	if (err)
 		printk(KERN_INFO "%s: Failed to map sg list\n",
@@ -1336,14 +1454,17 @@
 }
 
 /*
- * Map and transfer bytes.
+ * Map and transfer bytes for multiple transfers.
  */
-static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
-			    unsigned int dev_addr, int write, int max_scatter,
-			    int timed)
+static int mmc_test_area_io_seq(struct mmc_test_card *test, unsigned long sz,
+				unsigned int dev_addr, int write,
+				int max_scatter, int timed, int count,
+				bool nonblock, int min_sg_len)
 {
 	struct timespec ts1, ts2;
-	int ret;
+	int ret = 0;
+	int i;
+	struct mmc_test_area *t = &test->area;
 
 	/*
 	 * In the case of a maximally scattered transfer, the maximum transfer
@@ -1361,14 +1482,21 @@
 			sz = max_tfr;
 	}
 
-	ret = mmc_test_area_map(test, sz, max_scatter);
+	ret = mmc_test_area_map(test, sz, max_scatter, min_sg_len);
 	if (ret)
 		return ret;
 
 	if (timed)
 		getnstimeofday(&ts1);
+	if (nonblock)
+		ret = mmc_test_nonblock_transfer(test, t->sg, t->sg_len,
+				 dev_addr, t->blocks, 512, write, count);
+	else
+		for (i = 0; i < count && ret == 0; i++) {
+			ret = mmc_test_area_transfer(test, dev_addr, write);
+			dev_addr += sz >> 9;
+		}
 
-	ret = mmc_test_area_transfer(test, dev_addr, write);
 	if (ret)
 		return ret;
 
@@ -1376,11 +1504,19 @@
 		getnstimeofday(&ts2);
 
 	if (timed)
-		mmc_test_print_rate(test, sz, &ts1, &ts2);
+		mmc_test_print_avg_rate(test, sz, count, &ts1, &ts2);
 
 	return 0;
 }
 
+static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
+			    unsigned int dev_addr, int write, int max_scatter,
+			    int timed)
+{
+	return mmc_test_area_io_seq(test, sz, dev_addr, write, max_scatter,
+				    timed, 1, false, 0);
+}
+
 /*
  * Write the test area entirely.
  */
@@ -1954,6 +2090,270 @@
 	return mmc_test_large_seq_perf(test, 1);
 }
 
+static int mmc_test_rw_multiple(struct mmc_test_card *test,
+				struct mmc_test_multiple_rw *tdata,
+				unsigned int reqsize, unsigned int size,
+				int min_sg_len)
+{
+	unsigned int dev_addr;
+	struct mmc_test_area *t = &test->area;
+	int ret = 0;
+
+	/* Set up test area */
+	if (size > mmc_test_capacity(test->card) / 2 * 512)
+		size = mmc_test_capacity(test->card) / 2 * 512;
+	if (reqsize > t->max_tfr)
+		reqsize = t->max_tfr;
+	dev_addr = mmc_test_capacity(test->card) / 4;
+	if ((dev_addr & 0xffff0000))
+		dev_addr &= 0xffff0000; /* Round to 64MiB boundary */
+	else
+		dev_addr &= 0xfffff800; /* Round to 1MiB boundary */
+	if (!dev_addr)
+		goto err;
+
+	if (reqsize > size)
+		return 0;
+
+	/* prepare test area */
+	if (mmc_can_erase(test->card) &&
+	    tdata->prepare & MMC_TEST_PREP_ERASE) {
+		ret = mmc_erase(test->card, dev_addr,
+				size / 512, MMC_SECURE_ERASE_ARG);
+		if (ret)
+			ret = mmc_erase(test->card, dev_addr,
+					size / 512, MMC_ERASE_ARG);
+		if (ret)
+			goto err;
+	}
+
+	/* Run test */
+	ret = mmc_test_area_io_seq(test, reqsize, dev_addr,
+				   tdata->do_write, 0, 1, size / reqsize,
+				   tdata->do_nonblock_req, min_sg_len);
+	if (ret)
+		goto err;
+
+	return ret;
+ err:
+	printk(KERN_INFO "[%s] error\n", __func__);
+	return ret;
+}
+
+static int mmc_test_rw_multiple_size(struct mmc_test_card *test,
+				     struct mmc_test_multiple_rw *rw)
+{
+	int ret = 0;
+	int i;
+	void *pre_req = test->card->host->ops->pre_req;
+	void *post_req = test->card->host->ops->post_req;
+
+	if (rw->do_nonblock_req &&
+	    ((!pre_req && post_req) || (pre_req && !post_req))) {
+		printk(KERN_INFO "error: only one of pre/post is defined\n");
+		return -EINVAL;
+	}
+
+	for (i = 0 ; i < rw->len && ret == 0; i++) {
+		ret = mmc_test_rw_multiple(test, rw, rw->bs[i], rw->size, 0);
+		if (ret)
+			break;
+	}
+	return ret;
+}
+
+static int mmc_test_rw_multiple_sg_len(struct mmc_test_card *test,
+				       struct mmc_test_multiple_rw *rw)
+{
+	int ret = 0;
+	int i;
+
+	for (i = 0 ; i < rw->len && ret == 0; i++) {
+		ret = mmc_test_rw_multiple(test, rw, 512*1024, rw->size,
+					   rw->sg_len[i]);
+		if (ret)
+			break;
+	}
+	return ret;
+}
+
+/*
+ * Multiple blocking write 4k to 4 MB chunks
+ */
+static int mmc_test_profile_mult_write_blocking_perf(struct mmc_test_card *test)
+{
+	unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
+			     1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
+	struct mmc_test_multiple_rw test_data = {
+		.bs = bs,
+		.size = TEST_AREA_MAX_SIZE,
+		.len = ARRAY_SIZE(bs),
+		.do_write = true,
+		.do_nonblock_req = false,
+		.prepare = MMC_TEST_PREP_ERASE,
+	};
+
+	return mmc_test_rw_multiple_size(test, &test_data);
+};
+
+/*
+ * Multiple non-blocking write 4k to 4 MB chunks
+ */
+static int mmc_test_profile_mult_write_nonblock_perf(struct mmc_test_card *test)
+{
+	unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
+			     1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
+	struct mmc_test_multiple_rw test_data = {
+		.bs = bs,
+		.size = TEST_AREA_MAX_SIZE,
+		.len = ARRAY_SIZE(bs),
+		.do_write = true,
+		.do_nonblock_req = true,
+		.prepare = MMC_TEST_PREP_ERASE,
+	};
+
+	return mmc_test_rw_multiple_size(test, &test_data);
+}
+
+/*
+ * Multiple blocking read 4k to 4 MB chunks
+ */
+static int mmc_test_profile_mult_read_blocking_perf(struct mmc_test_card *test)
+{
+	unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
+			     1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
+	struct mmc_test_multiple_rw test_data = {
+		.bs = bs,
+		.size = TEST_AREA_MAX_SIZE,
+		.len = ARRAY_SIZE(bs),
+		.do_write = false,
+		.do_nonblock_req = false,
+		.prepare = MMC_TEST_PREP_NONE,
+	};
+
+	return mmc_test_rw_multiple_size(test, &test_data);
+}
+
+/*
+ * Multiple non-blocking read 4k to 4 MB chunks
+ */
+static int mmc_test_profile_mult_read_nonblock_perf(struct mmc_test_card *test)
+{
+	unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
+			     1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
+	struct mmc_test_multiple_rw test_data = {
+		.bs = bs,
+		.size = TEST_AREA_MAX_SIZE,
+		.len = ARRAY_SIZE(bs),
+		.do_write = false,
+		.do_nonblock_req = true,
+		.prepare = MMC_TEST_PREP_NONE,
+	};
+
+	return mmc_test_rw_multiple_size(test, &test_data);
+}
+
+/*
+ * Multiple blocking write 1 to 512 sg elements
+ */
+static int mmc_test_profile_sglen_wr_blocking_perf(struct mmc_test_card *test)
+{
+	unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
+				 1 << 7, 1 << 8, 1 << 9};
+	struct mmc_test_multiple_rw test_data = {
+		.sg_len = sg_len,
+		.size = TEST_AREA_MAX_SIZE,
+		.len = ARRAY_SIZE(sg_len),
+		.do_write = true,
+		.do_nonblock_req = false,
+		.prepare = MMC_TEST_PREP_ERASE,
+	};
+
+	return mmc_test_rw_multiple_sg_len(test, &test_data);
+};
+
+/*
+ * Multiple non-blocking write 1 to 512 sg elements
+ */
+static int mmc_test_profile_sglen_wr_nonblock_perf(struct mmc_test_card *test)
+{
+	unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
+				 1 << 7, 1 << 8, 1 << 9};
+	struct mmc_test_multiple_rw test_data = {
+		.sg_len = sg_len,
+		.size = TEST_AREA_MAX_SIZE,
+		.len = ARRAY_SIZE(sg_len),
+		.do_write = true,
+		.do_nonblock_req = true,
+		.prepare = MMC_TEST_PREP_ERASE,
+	};
+
+	return mmc_test_rw_multiple_sg_len(test, &test_data);
+}
+
+/*
+ * Multiple blocking read 1 to 512 sg elements
+ */
+static int mmc_test_profile_sglen_r_blocking_perf(struct mmc_test_card *test)
+{
+	unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
+				 1 << 7, 1 << 8, 1 << 9};
+	struct mmc_test_multiple_rw test_data = {
+		.sg_len = sg_len,
+		.size = TEST_AREA_MAX_SIZE,
+		.len = ARRAY_SIZE(sg_len),
+		.do_write = false,
+		.do_nonblock_req = false,
+		.prepare = MMC_TEST_PREP_NONE,
+	};
+
+	return mmc_test_rw_multiple_sg_len(test, &test_data);
+}
+
+/*
+ * Multiple non-blocking read 1 to 512 sg elements
+ */
+static int mmc_test_profile_sglen_r_nonblock_perf(struct mmc_test_card *test)
+{
+	unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
+				 1 << 7, 1 << 8, 1 << 9};
+	struct mmc_test_multiple_rw test_data = {
+		.sg_len = sg_len,
+		.size = TEST_AREA_MAX_SIZE,
+		.len = ARRAY_SIZE(sg_len),
+		.do_write = false,
+		.do_nonblock_req = true,
+		.prepare = MMC_TEST_PREP_NONE,
+	};
+
+	return mmc_test_rw_multiple_sg_len(test, &test_data);
+}
+
+/*
+ * eMMC hardware reset.
+ */
+static int mmc_test_hw_reset(struct mmc_test_card *test)
+{
+	struct mmc_card *card = test->card;
+	struct mmc_host *host = card->host;
+	int err;
+
+	err = mmc_hw_reset_check(host);
+	if (!err)
+		return RESULT_OK;
+
+	if (err == -ENOSYS)
+		return RESULT_FAIL;
+
+	if (err != -EOPNOTSUPP)
+		return err;
+
+	if (!mmc_can_reset(card))
+		return RESULT_UNSUP_CARD;
+
+	return RESULT_UNSUP_HOST;
+}
+
 static const struct mmc_test_case mmc_test_cases[] = {
 	{
 		.name = "Basic write (no data verification)",
@@ -2221,6 +2621,66 @@
 		.cleanup = mmc_test_area_cleanup,
 	},
 
+	{
+		.name = "Write performance with blocking req 4k to 4MB",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_mult_write_blocking_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Write performance with non-blocking req 4k to 4MB",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_mult_write_nonblock_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Read performance with blocking req 4k to 4MB",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_mult_read_blocking_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Read performance with non-blocking req 4k to 4MB",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_mult_read_nonblock_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Write performance blocking req 1 to 512 sg elems",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_sglen_wr_blocking_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Write performance non-blocking req 1 to 512 sg elems",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_sglen_wr_nonblock_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Read performance blocking req 1 to 512 sg elems",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_sglen_r_blocking_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Read performance non-blocking req 1 to 512 sg elems",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_sglen_r_nonblock_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "eMMC hardware reset",
+		.run = mmc_test_hw_reset,
+	},
 };
 
 static DEFINE_MUTEX(mmc_test_lock);
@@ -2445,6 +2905,32 @@
 	.release	= single_release,
 };
 
+static int mtf_testlist_show(struct seq_file *sf, void *data)
+{
+	int i;
+
+	mutex_lock(&mmc_test_lock);
+
+	for (i = 0; i < ARRAY_SIZE(mmc_test_cases); i++)
+		seq_printf(sf, "%d:\t%s\n", i+1, mmc_test_cases[i].name);
+
+	mutex_unlock(&mmc_test_lock);
+
+	return 0;
+}
+
+static int mtf_testlist_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, mtf_testlist_show, inode->i_private);
+}
+
+static const struct file_operations mmc_test_fops_testlist = {
+	.open		= mtf_testlist_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
 static void mmc_test_free_file_test(struct mmc_card *card)
 {
 	struct mmc_test_dbgfs_file *df, *dfs;
@@ -2476,7 +2962,18 @@
 
 	if (IS_ERR_OR_NULL(file)) {
 		dev_err(&card->dev,
-			"Can't create file. Perhaps debugfs is disabled.\n");
+			"Can't create test. Perhaps debugfs is disabled.\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	if (card->debugfs_root)
+		file = debugfs_create_file("testlist", S_IRUGO,
+			card->debugfs_root, card, &mmc_test_fops_testlist);
+
+	if (IS_ERR_OR_NULL(file)) {
+		dev_err(&card->dev,
+			"Can't create testlist. Perhaps debugfs is disabled.\n");
 		ret = -ENODEV;
 		goto err;
 	}
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index b2fb161..73f63c9 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -53,26 +53,23 @@
 	struct request_queue *q = mq->queue;
 	struct request *req;
 
-#ifdef CONFIG_MMC_PERF_PROFILING
-	ktime_t start, diff;
-	struct mmc_host *host = mq->card->host;
-	unsigned long bytes_xfer;
-#endif
-
-
 	current->flags |= PF_MEMALLOC;
 
 	down(&mq->thread_sem);
 	do {
+		struct mmc_queue_req *tmp;
 		req = NULL;	/* Must be set to NULL at each iteration */
 
 		spin_lock_irq(q->queue_lock);
 		set_current_state(TASK_INTERRUPTIBLE);
 		req = blk_fetch_request(q);
-		mq->req = req;
+		mq->mqrq_cur->req = req;
 		spin_unlock_irq(q->queue_lock);
 
-		if (!req) {
+		if (req || mq->mqrq_prev->req) {
+			set_current_state(TASK_RUNNING);
+			mq->issue_fn(mq, req);
+		} else {
 			if (kthread_should_stop()) {
 				set_current_state(TASK_RUNNING);
 				break;
@@ -80,30 +77,14 @@
 			up(&mq->thread_sem);
 			schedule();
 			down(&mq->thread_sem);
-			continue;
 		}
-		set_current_state(TASK_RUNNING);
 
-#ifdef CONFIG_MMC_PERF_PROFILING
-		bytes_xfer = blk_rq_bytes(req);
-		if (rq_data_dir(req) == READ) {
-			start = ktime_get();
-			mq->issue_fn(mq, req);
-			diff = ktime_sub(ktime_get(), start);
-			host->perf.rbytes_mmcq += bytes_xfer;
-			host->perf.rtime_mmcq =
-				ktime_add(host->perf.rtime_mmcq, diff);
-		} else {
-			start = ktime_get();
-			mq->issue_fn(mq, req);
-			diff = ktime_sub(ktime_get(), start);
-			host->perf.wbytes_mmcq += bytes_xfer;
-			host->perf.wtime_mmcq =
-				ktime_add(host->perf.wtime_mmcq, diff);
-		}
-#else
-			mq->issue_fn(mq, req);
-#endif
+		/* Current request becomes previous request and vice versa. */
+		mq->mqrq_prev->brq.mrq.data = NULL;
+		mq->mqrq_prev->req = NULL;
+		tmp = mq->mqrq_prev;
+		mq->mqrq_prev = mq->mqrq_cur;
+		mq->mqrq_cur = tmp;
 	} while (1);
 	up(&mq->thread_sem);
 
@@ -129,10 +110,46 @@
 		return;
 	}
 
-	if (!mq->req)
+	if (!mq->mqrq_cur->req && !mq->mqrq_prev->req)
 		wake_up_process(mq->thread);
 }
 
+struct scatterlist *mmc_alloc_sg(int sg_len, int *err)
+{
+	struct scatterlist *sg;
+
+	sg = kmalloc(sizeof(struct scatterlist)*sg_len, GFP_KERNEL);
+	if (!sg)
+		*err = -ENOMEM;
+	else {
+		*err = 0;
+		sg_init_table(sg, sg_len);
+	}
+
+	return sg;
+}
+
+static void mmc_queue_setup_discard(struct request_queue *q,
+				    struct mmc_card *card)
+{
+	unsigned max_discard;
+
+	max_discard = mmc_calc_max_discard(card);
+	if (!max_discard)
+		return;
+
+	queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
+	q->limits.max_discard_sectors = max_discard;
+	if (card->erased_byte == 0)
+		q->limits.discard_zeroes_data = 1;
+	q->limits.discard_granularity = card->pref_erase << 9;
+	/* granularity must not be greater than max. discard */
+	if (card->pref_erase > max_discard)
+		q->limits.discard_granularity = 0;
+	if (mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))
+		queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q);
+}
+
 /**
  * mmc_init_queue - initialise a queue structure.
  * @mq: mmc queue
@@ -148,6 +165,8 @@
 	struct mmc_host *host = card->host;
 	u64 limit = BLK_BOUNCE_HIGH;
 	int ret;
+	struct mmc_queue_req *mqrq_cur = &mq->mqrq[0];
+	struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
 
 	if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
 		limit = *mmc_dev(host)->dma_mask;
@@ -157,21 +176,16 @@
 	if (!mq->queue)
 		return -ENOMEM;
 
+	memset(&mq->mqrq_cur, 0, sizeof(mq->mqrq_cur));
+	memset(&mq->mqrq_prev, 0, sizeof(mq->mqrq_prev));
+	mq->mqrq_cur = mqrq_cur;
+	mq->mqrq_prev = mqrq_prev;
 	mq->queue->queuedata = mq;
-	mq->req = NULL;
 
 	blk_queue_prep_rq(mq->queue, mmc_prep_request);
 	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
-	if (mmc_can_erase(card)) {
-		queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mq->queue);
-		mq->queue->limits.max_discard_sectors = UINT_MAX;
-		if (card->erased_byte == 0)
-			mq->queue->limits.discard_zeroes_data = 1;
-		mq->queue->limits.discard_granularity = card->pref_erase << 9;
-		if (mmc_can_secure_erase_trim(card))
-			queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD,
-						mq->queue);
-	}
+	if (mmc_can_erase(card))
+		mmc_queue_setup_discard(mq->queue, card);
 
 #ifdef CONFIG_MMC_BLOCK_BOUNCE
 	if (host->max_segs == 1) {
@@ -187,53 +201,64 @@
 			bouncesz = host->max_blk_count * 512;
 
 		if (bouncesz > 512) {
-			mq->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
-			if (!mq->bounce_buf) {
+			mqrq_cur->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
+			if (!mqrq_cur->bounce_buf) {
 				printk(KERN_WARNING "%s: unable to "
-					"allocate bounce buffer\n",
+					"allocate bounce cur buffer\n",
 					mmc_card_name(card));
 			}
+			mqrq_prev->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
+			if (!mqrq_prev->bounce_buf) {
+				printk(KERN_WARNING "%s: unable to "
+					"allocate bounce prev buffer\n",
+					mmc_card_name(card));
+				kfree(mqrq_cur->bounce_buf);
+				mqrq_cur->bounce_buf = NULL;
+			}
 		}
 
-		if (mq->bounce_buf) {
+		if (mqrq_cur->bounce_buf && mqrq_prev->bounce_buf) {
 			blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY);
 			blk_queue_max_hw_sectors(mq->queue, bouncesz / 512);
 			blk_queue_max_segments(mq->queue, bouncesz / 512);
 			blk_queue_max_segment_size(mq->queue, bouncesz);
 
-			mq->sg = kmalloc(sizeof(struct scatterlist),
-				GFP_KERNEL);
-			if (!mq->sg) {
-				ret = -ENOMEM;
+			mqrq_cur->sg = mmc_alloc_sg(1, &ret);
+			if (ret)
 				goto cleanup_queue;
-			}
-			sg_init_table(mq->sg, 1);
 
-			mq->bounce_sg = kmalloc(sizeof(struct scatterlist) *
-				bouncesz / 512, GFP_KERNEL);
-			if (!mq->bounce_sg) {
-				ret = -ENOMEM;
+			mqrq_cur->bounce_sg =
+				mmc_alloc_sg(bouncesz / 512, &ret);
+			if (ret)
 				goto cleanup_queue;
-			}
-			sg_init_table(mq->bounce_sg, bouncesz / 512);
+
+			mqrq_prev->sg = mmc_alloc_sg(1, &ret);
+			if (ret)
+				goto cleanup_queue;
+
+			mqrq_prev->bounce_sg =
+				mmc_alloc_sg(bouncesz / 512, &ret);
+			if (ret)
+				goto cleanup_queue;
 		}
 	}
 #endif
 
-	if (!mq->bounce_buf) {
+	if (!mqrq_cur->bounce_buf && !mqrq_prev->bounce_buf) {
 		blk_queue_bounce_limit(mq->queue, limit);
 		blk_queue_max_hw_sectors(mq->queue,
 			min(host->max_blk_count, host->max_req_size / 512));
 		blk_queue_max_segments(mq->queue, host->max_segs);
 		blk_queue_max_segment_size(mq->queue, host->max_seg_size);
 
-		mq->sg = kmalloc(sizeof(struct scatterlist) *
-			host->max_segs, GFP_KERNEL);
-		if (!mq->sg) {
-			ret = -ENOMEM;
+		mqrq_cur->sg = mmc_alloc_sg(host->max_segs, &ret);
+		if (ret)
 			goto cleanup_queue;
-		}
-		sg_init_table(mq->sg, host->max_segs);
+
+
+		mqrq_prev->sg = mmc_alloc_sg(host->max_segs, &ret);
+		if (ret)
+			goto cleanup_queue;
 	}
 
 	sema_init(&mq->thread_sem, 1);
@@ -248,16 +273,22 @@
 
 	return 0;
  free_bounce_sg:
- 	if (mq->bounce_sg)
- 		kfree(mq->bounce_sg);
- 	mq->bounce_sg = NULL;
+	kfree(mqrq_cur->bounce_sg);
+	mqrq_cur->bounce_sg = NULL;
+	kfree(mqrq_prev->bounce_sg);
+	mqrq_prev->bounce_sg = NULL;
+
  cleanup_queue:
- 	if (mq->sg)
-		kfree(mq->sg);
-	mq->sg = NULL;
-	if (mq->bounce_buf)
-		kfree(mq->bounce_buf);
-	mq->bounce_buf = NULL;
+	kfree(mqrq_cur->sg);
+	mqrq_cur->sg = NULL;
+	kfree(mqrq_cur->bounce_buf);
+	mqrq_cur->bounce_buf = NULL;
+
+	kfree(mqrq_prev->sg);
+	mqrq_prev->sg = NULL;
+	kfree(mqrq_prev->bounce_buf);
+	mqrq_prev->bounce_buf = NULL;
+
 	blk_cleanup_queue(mq->queue);
 	return ret;
 }
@@ -266,6 +297,8 @@
 {
 	struct request_queue *q = mq->queue;
 	unsigned long flags;
+	struct mmc_queue_req *mqrq_cur = mq->mqrq_cur;
+	struct mmc_queue_req *mqrq_prev = mq->mqrq_prev;
 
 	/* Make sure the queue isn't suspended, as that will deadlock */
 	mmc_queue_resume(mq);
@@ -279,16 +312,23 @@
 	blk_start_queue(q);
 	spin_unlock_irqrestore(q->queue_lock, flags);
 
- 	if (mq->bounce_sg)
- 		kfree(mq->bounce_sg);
- 	mq->bounce_sg = NULL;
+	kfree(mqrq_cur->bounce_sg);
+	mqrq_cur->bounce_sg = NULL;
 
-	kfree(mq->sg);
-	mq->sg = NULL;
+	kfree(mqrq_cur->sg);
+	mqrq_cur->sg = NULL;
 
-	if (mq->bounce_buf)
-		kfree(mq->bounce_buf);
-	mq->bounce_buf = NULL;
+	kfree(mqrq_cur->bounce_buf);
+	mqrq_cur->bounce_buf = NULL;
+
+	kfree(mqrq_prev->bounce_sg);
+	mqrq_prev->bounce_sg = NULL;
+
+	kfree(mqrq_prev->sg);
+	mqrq_prev->sg = NULL;
+
+	kfree(mqrq_prev->bounce_buf);
+	mqrq_prev->bounce_buf = NULL;
 
 	mq->card = NULL;
 }
@@ -341,27 +381,27 @@
 /*
  * Prepare the sg list(s) to be handed of to the host driver
  */
-unsigned int mmc_queue_map_sg(struct mmc_queue *mq)
+unsigned int mmc_queue_map_sg(struct mmc_queue *mq, struct mmc_queue_req *mqrq)
 {
 	unsigned int sg_len;
 	size_t buflen;
 	struct scatterlist *sg;
 	int i;
 
-	if (!mq->bounce_buf)
-		return blk_rq_map_sg(mq->queue, mq->req, mq->sg);
+	if (!mqrq->bounce_buf)
+		return blk_rq_map_sg(mq->queue, mqrq->req, mqrq->sg);
 
-	BUG_ON(!mq->bounce_sg);
+	BUG_ON(!mqrq->bounce_sg);
 
-	sg_len = blk_rq_map_sg(mq->queue, mq->req, mq->bounce_sg);
+	sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg);
 
-	mq->bounce_sg_len = sg_len;
+	mqrq->bounce_sg_len = sg_len;
 
 	buflen = 0;
-	for_each_sg(mq->bounce_sg, sg, sg_len, i)
+	for_each_sg(mqrq->bounce_sg, sg, sg_len, i)
 		buflen += sg->length;
 
-	sg_init_one(mq->sg, mq->bounce_buf, buflen);
+	sg_init_one(mqrq->sg, mqrq->bounce_buf, buflen);
 
 	return 1;
 }
@@ -370,31 +410,30 @@
  * If writing, bounce the data to the buffer before the request
  * is sent to the host driver
  */
-void mmc_queue_bounce_pre(struct mmc_queue *mq)
+void mmc_queue_bounce_pre(struct mmc_queue_req *mqrq)
 {
-	if (!mq->bounce_buf)
+	if (!mqrq->bounce_buf)
 		return;
 
-	if (rq_data_dir(mq->req) != WRITE)
+	if (rq_data_dir(mqrq->req) != WRITE)
 		return;
 
-	sg_copy_to_buffer(mq->bounce_sg, mq->bounce_sg_len,
-		mq->bounce_buf, mq->sg[0].length);
+	sg_copy_to_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len,
+		mqrq->bounce_buf, mqrq->sg[0].length);
 }
 
 /*
  * If reading, bounce the data from the buffer after the request
  * has been handled by the host driver
  */
-void mmc_queue_bounce_post(struct mmc_queue *mq)
+void mmc_queue_bounce_post(struct mmc_queue_req *mqrq)
 {
-	if (!mq->bounce_buf)
+	if (!mqrq->bounce_buf)
 		return;
 
-	if (rq_data_dir(mq->req) != READ)
+	if (rq_data_dir(mqrq->req) != READ)
 		return;
 
-	sg_copy_from_buffer(mq->bounce_sg, mq->bounce_sg_len,
-		mq->bounce_buf, mq->sg[0].length);
+	sg_copy_from_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len,
+		mqrq->bounce_buf, mqrq->sg[0].length);
 }
-
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index 6223ef8..d2a1eb4 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -4,19 +4,35 @@
 struct request;
 struct task_struct;
 
+struct mmc_blk_request {
+	struct mmc_request	mrq;
+	struct mmc_command	sbc;
+	struct mmc_command	cmd;
+	struct mmc_command	stop;
+	struct mmc_data		data;
+};
+
+struct mmc_queue_req {
+	struct request		*req;
+	struct mmc_blk_request	brq;
+	struct scatterlist	*sg;
+	char			*bounce_buf;
+	struct scatterlist	*bounce_sg;
+	unsigned int		bounce_sg_len;
+	struct mmc_async_req	mmc_active;
+};
+
 struct mmc_queue {
 	struct mmc_card		*card;
 	struct task_struct	*thread;
 	struct semaphore	thread_sem;
 	unsigned int		flags;
-	struct request		*req;
 	int			(*issue_fn)(struct mmc_queue *, struct request *);
 	void			*data;
 	struct request_queue	*queue;
-	struct scatterlist	*sg;
-	char			*bounce_buf;
-	struct scatterlist	*bounce_sg;
-	unsigned int		bounce_sg_len;
+	struct mmc_queue_req	mqrq[2];
+	struct mmc_queue_req	*mqrq_cur;
+	struct mmc_queue_req	*mqrq_prev;
 };
 
 extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
@@ -25,8 +41,9 @@
 extern void mmc_queue_suspend(struct mmc_queue *);
 extern void mmc_queue_resume(struct mmc_queue *);
 
-extern unsigned int mmc_queue_map_sg(struct mmc_queue *);
-extern void mmc_queue_bounce_pre(struct mmc_queue *);
-extern void mmc_queue_bounce_post(struct mmc_queue *);
+extern unsigned int mmc_queue_map_sg(struct mmc_queue *,
+				     struct mmc_queue_req *);
+extern void mmc_queue_bounce_pre(struct mmc_queue_req *);
+extern void mmc_queue_bounce_post(struct mmc_queue_req *);
 
 #endif
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 51434b6..1eb9d5f 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -106,12 +106,12 @@
 	}
 
 	if (err && cmd->retries && !mmc_card_removed(host->card)) {
-		pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
-			mmc_hostname(host), cmd->opcode, err);
-
-		cmd->retries--;
-		cmd->error = 0;
-		host->ops->request(host, mrq);
+		/*
+		 * Request starter must handle retries - see
+		 * mmc_wait_for_req_done().
+		 */
+		if (mrq->done)
+			mrq->done(mrq);
 	} else {
 		led_trigger_event(host->led, LED_OFF);
 
@@ -220,9 +220,123 @@
 
 static void mmc_wait_done(struct mmc_request *mrq)
 {
-	complete(mrq->done_data);
+	complete(&mrq->completion);
 }
 
+static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
+{
+	init_completion(&mrq->completion);
+	mrq->done = mmc_wait_done;
+	mmc_start_request(host, mrq);
+}
+
+static void mmc_wait_for_req_done(struct mmc_host *host,
+				  struct mmc_request *mrq)
+{
+	struct mmc_command *cmd;
+
+	while (1) {
+		wait_for_completion(&mrq->completion);
+
+		cmd = mrq->cmd;
+		if (!cmd->error || !cmd->retries)
+			break;
+
+		pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
+			 mmc_hostname(host), cmd->opcode, cmd->error);
+		cmd->retries--;
+		cmd->error = 0;
+		host->ops->request(host, mrq);
+	}
+}
+
+/**
+ *	mmc_pre_req - Prepare for a new request
+ *	@host: MMC host to prepare command
+ *	@mrq: MMC request to prepare for
+ *	@is_first_req: true if there is no previous started request
+ *                     that may run in parellel to this call, otherwise false
+ *
+ *	mmc_pre_req() is called in prior to mmc_start_req() to let
+ *	host prepare for the new request. Preparation of a request may be
+ *	performed while another request is running on the host.
+ */
+static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
+		 bool is_first_req)
+{
+	if (host->ops->pre_req)
+		host->ops->pre_req(host, mrq, is_first_req);
+}
+
+/**
+ *	mmc_post_req - Post process a completed request
+ *	@host: MMC host to post process command
+ *	@mrq: MMC request to post process for
+ *	@err: Error, if non zero, clean up any resources made in pre_req
+ *
+ *	Let the host post process a completed request. Post processing of
+ *	a request may be performed while another reuqest is running.
+ */
+static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
+			 int err)
+{
+	if (host->ops->post_req)
+		host->ops->post_req(host, mrq, err);
+}
+
+/**
+ *	mmc_start_req - start a non-blocking request
+ *	@host: MMC host to start command
+ *	@areq: async request to start
+ *	@error: out parameter returns 0 for success, otherwise non zero
+ *
+ *	Start a new MMC custom command request for a host.
+ *	If there is on ongoing async request wait for completion
+ *	of that request and start the new one and return.
+ *	Does not wait for the new request to complete.
+ *
+ *      Returns the completed request, NULL in case of none completed.
+ *	Wait for the an ongoing request (previoulsy started) to complete and
+ *	return the completed request. If there is no ongoing request, NULL
+ *	is returned without waiting. NULL is not an error condition.
+ */
+struct mmc_async_req *mmc_start_req(struct mmc_host *host,
+				    struct mmc_async_req *areq, int *error)
+{
+	int err = 0;
+	struct mmc_async_req *data = host->areq;
+
+	/* Prepare a new request */
+	if (areq)
+		mmc_pre_req(host, areq->mrq, !host->areq);
+
+	if (host->areq) {
+		mmc_wait_for_req_done(host, host->areq->mrq);
+		err = host->areq->err_check(host->card, host->areq);
+		if (err) {
+			mmc_post_req(host, host->areq->mrq, 0);
+			if (areq)
+				mmc_post_req(host, areq->mrq, -EINVAL);
+
+			host->areq = NULL;
+			goto out;
+		}
+	}
+
+	if (areq)
+		__mmc_start_req(host, areq->mrq);
+
+	if (host->areq)
+		mmc_post_req(host, host->areq->mrq, 0);
+
+	host->areq = areq;
+ out:
+	if (error)
+		*error = err;
+	return data;
+}
+EXPORT_SYMBOL(mmc_start_req);
+
 /**
  *	mmc_wait_for_req - start a request and wait for completion
  *	@host: MMC host to start command
@@ -234,21 +348,67 @@
  */
 void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
 {
-	DECLARE_COMPLETION_ONSTACK(complete);
+	__mmc_start_req(host, mrq);
+	mmc_wait_for_req_done(host, mrq);
+}
+EXPORT_SYMBOL(mmc_wait_for_req);
 
-	mrq->done_data = &complete;
-	mrq->done = mmc_wait_done;
-	if (mmc_card_removed(host->card)) {
-		mrq->cmd->error = -ENOMEDIUM;
-		return;
+/**
+ *	mmc_interrupt_hpi - Issue for High priority Interrupt
+ *	@card: the MMC card associated with the HPI transfer
+ *
+ *	Issued High Priority Interrupt, and check for card status
+ *	util out-of prg-state.
+ */
+int mmc_interrupt_hpi(struct mmc_card *card)
+{
+	int err;
+	u32 status;
+
+	BUG_ON(!card);
+
+	if (!card->ext_csd.hpi_en) {
+		pr_info("%s: HPI enable bit unset\n", mmc_hostname(card->host));
+		return 1;
 	}
 
-	mmc_start_request(host, mrq);
+	mmc_claim_host(card->host);
+	err = mmc_send_status(card, &status);
+	if (err) {
+		pr_err("%s: Get card status fail\n", mmc_hostname(card->host));
+		goto out;
+	}
 
-	wait_for_completion_io(&complete);
+	/*
+	 * If the card status is in PRG-state, we can send the HPI command.
+	 */
+	if (R1_CURRENT_STATE(status) == R1_STATE_PRG) {
+		do {
+			/*
+			 * We don't know when the HPI command will finish
+			 * processing, so we need to resend HPI until out
+			 * of prg-state, and keep checking the card status
+			 * with SEND_STATUS.  If a timeout error occurs when
+			 * sending the HPI command, we are already out of
+			 * prg-state.
+			 */
+			err = mmc_send_hpi_cmd(card, &status);
+			if (err)
+				pr_debug("%s: abort HPI (%d error)\n",
+					 mmc_hostname(card->host), err);
+
+			err = mmc_send_status(card, &status);
+			if (err)
+				break;
+		} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
+	} else
+		pr_debug("%s: Left prg-state\n", mmc_hostname(card->host));
+
+out:
+	mmc_release_host(card->host);
+	return err;
 }
-
-EXPORT_SYMBOL(mmc_wait_for_req);
+EXPORT_SYMBOL(mmc_interrupt_hpi);
 
 /**
  *	mmc_wait_for_cmd - start a command and wait for completion
@@ -262,7 +422,7 @@
  */
 int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
 {
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 
 	WARN_ON(!host->claimed);
 
@@ -1035,6 +1195,46 @@
 	mmc_host_clk_release(host);
 }
 
+static void mmc_poweroff_notify(struct mmc_host *host)
+{
+	struct mmc_card *card;
+	unsigned int timeout;
+	unsigned int notify_type = EXT_CSD_NO_POWER_NOTIFICATION;
+	int err = 0;
+
+	card = host->card;
+
+	/*
+	 * Send power notify command only if card
+	 * is mmc and notify state is powered ON
+	 */
+	if (card && mmc_card_mmc(card) &&
+	    (card->poweroff_notify_state == MMC_POWERED_ON)) {
+
+		if (host->power_notify_type == MMC_HOST_PW_NOTIFY_SHORT) {
+			notify_type = EXT_CSD_POWER_OFF_SHORT;
+			timeout = card->ext_csd.generic_cmd6_time;
+			card->poweroff_notify_state = MMC_POWEROFF_SHORT;
+		} else {
+			notify_type = EXT_CSD_POWER_OFF_LONG;
+			timeout = card->ext_csd.power_off_longtime;
+			card->poweroff_notify_state = MMC_POWEROFF_LONG;
+		}
+
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_POWER_OFF_NOTIFICATION,
+				 notify_type, timeout);
+
+		if (err && err != -EBADMSG)
+			pr_err("Device failed to respond within %d poweroff "
+			       "time. Forcefully powering down the device\n",
+			       timeout);
+
+		/* Set the card state to no notification after the poweroff */
+		card->poweroff_notify_state = MMC_NO_POWER_NOTIFICATION;
+	}
+}
+
 /*
  * Apply power to the MMC stack.  This is a two-stage process.
  * First, we enable power to the card without the clock running.
@@ -1091,13 +1291,15 @@
 	mmc_host_clk_release(host);
 }
 
-static void mmc_power_off(struct mmc_host *host)
+void mmc_power_off(struct mmc_host *host)
 {
 	mmc_host_clk_hold(host);
 
 	host->ios.clock = 0;
 	host->ios.vdd = 0;
 
+	mmc_poweroff_notify(host);
+
 	/*
 	 * Reset ocr mask to be the highest possible voltage supported for
 	 * this mmc host. This value will be used at next power up.
@@ -1452,7 +1654,7 @@
 	if (err) {
 		printk(KERN_ERR "mmc_erase: group start error %d, "
 		       "status %#x\n", err, cmd.resp[0]);
-		err = -EINVAL;
+		err = -EIO;
 		goto out;
 	}
 
@@ -1467,7 +1669,7 @@
 	if (err) {
 		printk(KERN_ERR "mmc_erase: group end error %d, status %#x\n",
 		       err, cmd.resp[0]);
-		err = -EINVAL;
+		err = -EIO;
 		goto out;
 	}
 
@@ -1501,7 +1703,7 @@
 			goto out;
 		}
 	} while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
-		 R1_CURRENT_STATE(cmd.resp[0]) == 7);
+		 R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG);
 out:
 	return err;
 }
@@ -1586,10 +1788,32 @@
 {
 	if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN)
 		return 1;
+	if (mmc_can_discard(card))
+		return 1;
 	return 0;
 }
 EXPORT_SYMBOL(mmc_can_trim);
 
+int mmc_can_discard(struct mmc_card *card)
+{
+	/*
+	 * As there's no way to detect the discard support bit at v4.5
+	 * use the s/w feature support filed.
+	 */
+	if (card->ext_csd.feature_support & MMC_DISCARD_FEATURE)
+		return 1;
+	return 0;
+}
+EXPORT_SYMBOL(mmc_can_discard);
+
+int mmc_can_sanitize(struct mmc_card *card)
+{
+	if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_SANITIZE)
+		return 1;
+	return 0;
+}
+EXPORT_SYMBOL(mmc_can_sanitize);
+
 int mmc_can_secure_erase_trim(struct mmc_card *card)
 {
 	if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN)
@@ -1609,6 +1833,82 @@
 }
 EXPORT_SYMBOL(mmc_erase_group_aligned);
 
+static unsigned int mmc_do_calc_max_discard(struct mmc_card *card,
+					    unsigned int arg)
+{
+	struct mmc_host *host = card->host;
+	unsigned int max_discard, x, y, qty = 0, max_qty, timeout;
+	unsigned int last_timeout = 0;
+
+	if (card->erase_shift)
+		max_qty = UINT_MAX >> card->erase_shift;
+	else if (mmc_card_sd(card))
+		max_qty = UINT_MAX;
+	else
+		max_qty = UINT_MAX / card->erase_size;
+
+	/* Find the largest qty with an OK timeout */
+	do {
+		y = 0;
+		for (x = 1; x && x <= max_qty && max_qty - x >= qty; x <<= 1) {
+			timeout = mmc_erase_timeout(card, arg, qty + x);
+			if (timeout > host->max_discard_to)
+				break;
+			if (timeout < last_timeout)
+				break;
+			last_timeout = timeout;
+			y = x;
+		}
+		qty += y;
+	} while (y);
+
+	if (!qty)
+		return 0;
+
+	if (qty == 1)
+		return 1;
+
+	/* Convert qty to sectors */
+	if (card->erase_shift)
+		max_discard = --qty << card->erase_shift;
+	else if (mmc_card_sd(card))
+		max_discard = qty;
+	else
+		max_discard = --qty * card->erase_size;
+
+	return max_discard;
+}
+
+unsigned int mmc_calc_max_discard(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	unsigned int max_discard, max_trim;
+
+	if (!host->max_discard_to)
+		return UINT_MAX;
+
+	/*
+	 * Without erase_group_def set, MMC erase timeout depends on clock
+	 * frequence which can change.  In that case, the best choice is
+	 * just the preferred erase size.
+	 */
+	if (mmc_card_mmc(card) && !(card->ext_csd.erase_group_def & 1))
+		return card->pref_erase;
+
+	max_discard = mmc_do_calc_max_discard(card, MMC_ERASE_ARG);
+	if (mmc_can_trim(card)) {
+		max_trim = mmc_do_calc_max_discard(card, MMC_TRIM_ARG);
+		if (max_trim < max_discard)
+			max_discard = max_trim;
+	} else if (max_discard < card->erase_size) {
+		max_discard = 0;
+	}
+	pr_debug("%s: calculated max. discard sectors %u for timeout %u ms\n",
+		 mmc_hostname(host), max_discard, host->max_discard_to);
+	return max_discard;
+}
+EXPORT_SYMBOL(mmc_calc_max_discard);
+
 int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
 {
 	struct mmc_command cmd = {0};
@@ -1623,6 +1923,94 @@
 }
 EXPORT_SYMBOL(mmc_set_blocklen);
 
+static void mmc_hw_reset_for_init(struct mmc_host *host)
+{
+	if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
+		return;
+	mmc_host_clk_hold(host);
+	host->ops->hw_reset(host);
+	mmc_host_clk_release(host);
+}
+
+int mmc_can_reset(struct mmc_card *card)
+{
+	u8 rst_n_function;
+
+	if (!mmc_card_mmc(card))
+		return 0;
+	rst_n_function = card->ext_csd.rst_n_function;
+	if ((rst_n_function & EXT_CSD_RST_N_EN_MASK) != EXT_CSD_RST_N_ENABLED)
+		return 0;
+	return 1;
+}
+EXPORT_SYMBOL(mmc_can_reset);
+
+static int mmc_do_hw_reset(struct mmc_host *host, int check)
+{
+	struct mmc_card *card = host->card;
+
+	if (!host->bus_ops->power_restore)
+		return -EOPNOTSUPP;
+
+	if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
+		return -EOPNOTSUPP;
+
+	if (!card)
+		return -EINVAL;
+
+	if (!mmc_can_reset(card))
+		return -EOPNOTSUPP;
+
+	mmc_host_clk_hold(host);
+	mmc_set_clock(host, host->f_init);
+
+	host->ops->hw_reset(host);
+
+	/* If the reset has happened, then a status command will fail */
+	if (check) {
+		struct mmc_command cmd = {0};
+		int err;
+
+		cmd.opcode = MMC_SEND_STATUS;
+		if (!mmc_host_is_spi(card->host))
+			cmd.arg = card->rca << 16;
+		cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
+		err = mmc_wait_for_cmd(card->host, &cmd, 0);
+		if (!err) {
+			mmc_host_clk_release(host);
+			return -ENOSYS;
+		}
+	}
+
+	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR);
+	if (mmc_host_is_spi(host)) {
+		host->ios.chip_select = MMC_CS_HIGH;
+		host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
+	} else {
+		host->ios.chip_select = MMC_CS_DONTCARE;
+		host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+	}
+	host->ios.bus_width = MMC_BUS_WIDTH_1;
+	host->ios.timing = MMC_TIMING_LEGACY;
+	mmc_set_ios(host);
+
+	mmc_host_clk_release(host);
+
+	return host->bus_ops->power_restore(host);
+}
+
+int mmc_hw_reset(struct mmc_host *host)
+{
+	return mmc_do_hw_reset(host, 0);
+}
+EXPORT_SYMBOL(mmc_hw_reset);
+
+int mmc_hw_reset_check(struct mmc_host *host)
+{
+	return mmc_do_hw_reset(host, 1);
+}
+EXPORT_SYMBOL(mmc_hw_reset_check);
+
 static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
 {
 	host->f_init = freq;
@@ -1634,6 +2022,12 @@
 	mmc_power_up(host);
 
 	/*
+	 * Some eMMCs (with VCCQ always on) may not be reset after power up, so
+	 * do a hardware reset if possible.
+	 */
+	mmc_hw_reset_for_init(host);
+
+	/*
 	 * sdio_reset sends CMD52 to reset card.  Since we do not know
 	 * if the card is being re-initialized, just send it.  CMD52
 	 * should be ignored by SD/eMMC cards.
@@ -1870,7 +2264,7 @@
 
 	mmc_bus_get(host);
 
-	if (host->bus_ops && !host->bus_dead && host->bus_ops->awake)
+	if (host->bus_ops && !host->bus_dead && host->bus_ops->sleep)
 		err = host->bus_ops->sleep(host);
 
 	mmc_bus_put(host);
@@ -1889,6 +2283,65 @@
 }
 EXPORT_SYMBOL(mmc_card_can_sleep);
 
+/*
+ * Flush the cache to the non-volatile storage.
+ */
+int mmc_flush_cache(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = 0;
+
+	if (!(host->caps2 & MMC_CAP2_CACHE_CTRL))
+		return err;
+
+	if (mmc_card_mmc(card) &&
+			(card->ext_csd.cache_size > 0) &&
+			(card->ext_csd.cache_ctrl & 1)) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				EXT_CSD_FLUSH_CACHE, 1, 0);
+		if (err)
+			pr_err("%s: cache flush error %d\n",
+					mmc_hostname(card->host), err);
+	}
+
+	return err;
+}
+EXPORT_SYMBOL(mmc_flush_cache);
+
+/*
+ * Turn the cache ON/OFF.
+ * Turning the cache OFF shall trigger flushing of the data
+ * to the non-volatile storage.
+ */
+int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
+{
+	struct mmc_card *card = host->card;
+	int err = 0;
+
+	if (!(host->caps2 & MMC_CAP2_CACHE_CTRL) ||
+			mmc_card_is_removable(host))
+		return err;
+
+	if (card && mmc_card_mmc(card) &&
+			(card->ext_csd.cache_size > 0)) {
+		enable = !!enable;
+
+		if (card->ext_csd.cache_ctrl ^ enable)
+			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+					EXT_CSD_CACHE_CTRL, enable, 0);
+		if (err)
+			pr_err("%s: cache %s error %d\n",
+					mmc_hostname(card->host),
+					enable ? "on" : "off",
+					err);
+		else
+			card->ext_csd.cache_ctrl = enable;
+	}
+
+	return err;
+}
+EXPORT_SYMBOL(mmc_cache_ctrl);
+
 #ifdef CONFIG_PM
 
 /**
@@ -1907,6 +2360,9 @@
 	if (cancel_delayed_work(&host->detect))
 		wake_unlock(&host->detect_wake_lock);
 	mmc_flush_scheduled_work();
+	err = mmc_cache_ctrl(host, 0);
+	if (err)
+		goto out;
 
 	mmc_bus_get(host);
 	if (host->bus_ops && !host->bus_dead) {
@@ -1928,8 +2384,15 @@
 				err = -EBUSY;
 
 		if (!err) {
-			if (host->bus_ops->suspend)
+			if (host->bus_ops->suspend) {
+				/*
+				 * For eMMC 4.5 device send notify command
+				 * before sleep, because in sleep state eMMC 4.5
+				 * devices respond to only RESET and AWAKE cmd
+				 */
+				mmc_poweroff_notify(host);
 				err = host->bus_ops->suspend(host);
+			}
 			if (!(host->card && mmc_card_sdio(host->card)))
 				mmc_do_release_host(host);
 
@@ -1954,6 +2417,7 @@
 	if (!err && !mmc_card_keep_power(host))
 		mmc_power_off(host);
 
+out:
 	return err;
 }
 
@@ -2029,6 +2493,7 @@
 			break;
 		}
 		host->rescan_disable = 1;
+		host->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT;
 		spin_unlock_irqrestore(&host->lock, flags);
 		if (cancel_delayed_work_sync(&host->detect))
 			wake_unlock(&host->detect_wake_lock);
@@ -2056,6 +2521,7 @@
 			break;
 		}
 		host->rescan_disable = 0;
+		host->power_notify_type = MMC_HOST_PW_NOTIFY_LONG;
 		spin_unlock_irqrestore(&host->lock, flags);
 		mmc_detect_change(host, 0);
 
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 79d6e97..0c70d4a 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -259,7 +259,7 @@
 	}
 
 	card->ext_csd.rev = ext_csd[EXT_CSD_REV];
-	if (card->ext_csd.rev > 5) {
+	if (card->ext_csd.rev > 6) {
 		printk(KERN_ERR "%s: unrecognised EXT_CSD revision %d\n",
 			mmc_hostname(card->host), card->ext_csd.rev);
 		err = -EINVAL;
@@ -359,6 +359,7 @@
 		 * card has the Enhanced area enabled.  If so, export enhanced
 		 * area offset and size to user by adding sysfs interface.
 		 */
+		card->ext_csd.raw_partition_support = ext_csd[EXT_CSD_PARTITION_SUPPORT];
 		if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) &&
 		    (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) {
 			u8 hc_erase_grp_sz =
@@ -402,14 +403,48 @@
 			ext_csd[EXT_CSD_TRIM_MULT];
 	}
 
-	if (card->ext_csd.rev >= 5)
-		card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
+	if (card->ext_csd.rev >= 5) {
+		/* check whether the eMMC card supports HPI */
+		if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) {
+			card->ext_csd.hpi = 1;
+			if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2)
+				card->ext_csd.hpi_cmd =	MMC_STOP_TRANSMISSION;
+			else
+				card->ext_csd.hpi_cmd = MMC_SEND_STATUS;
+			/*
+			 * Indicate the maximum timeout to close
+			 * a command interrupted by HPI
+			 */
+			card->ext_csd.out_of_int_time =
+				ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] * 10;
+		}
 
+		card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
+		card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION];
+	}
+
+	card->ext_csd.raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT];
 	if (ext_csd[EXT_CSD_ERASED_MEM_CONT])
 		card->erased_byte = 0xFF;
 	else
 		card->erased_byte = 0x0;
 
+	/* eMMC v4.5 or later */
+	if (card->ext_csd.rev >= 6) {
+		card->ext_csd.feature_support |= MMC_DISCARD_FEATURE;
+
+		card->ext_csd.generic_cmd6_time = 10 *
+			ext_csd[EXT_CSD_GENERIC_CMD6_TIME];
+		card->ext_csd.power_off_longtime = 10 *
+			ext_csd[EXT_CSD_POWER_OFF_LONG_TIME];
+
+		card->ext_csd.cache_size =
+			ext_csd[EXT_CSD_CACHE_SIZE + 0] << 0 |
+			ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 |
+			ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 |
+			ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24;
+	}
+
 out:
 	return err;
 }
@@ -530,6 +565,86 @@
 };
 
 /*
+ * Select the PowerClass for the current bus width
+ * If power class is defined for 4/8 bit bus in the
+ * extended CSD register, select it by executing the
+ * mmc_switch command.
+ */
+static int mmc_select_powerclass(struct mmc_card *card,
+		unsigned int bus_width, u8 *ext_csd)
+{
+	int err = 0;
+	unsigned int pwrclass_val;
+	unsigned int index = 0;
+	struct mmc_host *host;
+
+	BUG_ON(!card);
+
+	host = card->host;
+	BUG_ON(!host);
+
+	if (ext_csd == NULL)
+		return 0;
+
+	/* Power class selection is supported for versions >= 4.0 */
+	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+		return 0;
+
+	/* Power class values are defined only for 4/8 bit bus */
+	if (bus_width == EXT_CSD_BUS_WIDTH_1)
+		return 0;
+
+	switch (1 << host->ios.vdd) {
+	case MMC_VDD_165_195:
+		if (host->ios.clock <= 26000000)
+			index = EXT_CSD_PWR_CL_26_195;
+		else if	(host->ios.clock <= 52000000)
+			index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
+				EXT_CSD_PWR_CL_52_195 :
+				EXT_CSD_PWR_CL_DDR_52_195;
+		else if (host->ios.clock <= 200000000)
+			index = EXT_CSD_PWR_CL_200_195;
+		break;
+	case MMC_VDD_32_33:
+	case MMC_VDD_33_34:
+	case MMC_VDD_34_35:
+	case MMC_VDD_35_36:
+		if (host->ios.clock <= 26000000)
+			index = EXT_CSD_PWR_CL_26_360;
+		else if	(host->ios.clock <= 52000000)
+			index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
+				EXT_CSD_PWR_CL_52_360 :
+				EXT_CSD_PWR_CL_DDR_52_360;
+		else if (host->ios.clock <= 200000000)
+			index = EXT_CSD_PWR_CL_200_360;
+		break;
+	default:
+		pr_warning("%s: Voltage range not supported "
+			   "for power class.\n", mmc_hostname(host));
+		return -EINVAL;
+	}
+
+	pwrclass_val = ext_csd[index];
+
+	if (bus_width & (EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_BUS_WIDTH_8))
+		pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_8BIT_MASK) >>
+				EXT_CSD_PWR_CL_8BIT_SHIFT;
+	else
+		pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_4BIT_MASK) >>
+				EXT_CSD_PWR_CL_4BIT_SHIFT;
+
+	/* If the power class is different from the default value */
+	if (pwrclass_val > 0) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_POWER_CLASS,
+				 pwrclass_val,
+				 card->ext_csd.generic_cmd6_time);
+	}
+
+	return err;
+}
+
+/*
  * Handle the detection and initialisation of a card.
  *
  * In the case of a resume, "oldcard" will contain the card
@@ -671,7 +786,8 @@
 	 */
 	if (card->ext_csd.enhanced_area_en) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				 EXT_CSD_ERASE_GROUP_DEF, 1, 0);
+				 EXT_CSD_ERASE_GROUP_DEF, 1,
+				 card->ext_csd.generic_cmd6_time);
 
 		if (err && err != -EBADMSG)
 			goto free_card;
@@ -709,12 +825,34 @@
 	}
 
 	/*
+	 * If the host supports the power_off_notify capability then
+	 * set the notification byte in the ext_csd register of device
+	 */
+	if ((host->caps2 & MMC_CAP2_POWEROFF_NOTIFY) &&
+	    (card->ext_csd.rev >= 6)) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_POWER_OFF_NOTIFICATION,
+				 EXT_CSD_POWER_ON,
+				 card->ext_csd.generic_cmd6_time);
+		if (err && err != -EBADMSG)
+			goto free_card;
+
+		/*
+		 * The err can be -EBADMSG or 0,
+		 * so check for success and update the flag
+		 */
+		if (!err)
+			card->poweroff_notify_state = MMC_POWERED_ON;
+	}
+
+	/*
 	 * Activate high speed (if supported)
 	 */
 	if ((card->ext_csd.hs_max_dtr != 0) &&
 		(host->caps & MMC_CAP_MMC_HIGHSPEED)) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				 EXT_CSD_HS_TIMING, 1, 0);
+				 EXT_CSD_HS_TIMING, 1,
+				 card->ext_csd.generic_cmd6_time);
 		if (err && err != -EBADMSG)
 			goto free_card;
 
@@ -729,6 +867,22 @@
 	}
 
 	/*
+	 * Enable HPI feature (if supported)
+	 */
+	if (card->ext_csd.hpi) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			EXT_CSD_HPI_MGMT, 1, 0);
+		if (err && err != -EBADMSG)
+			goto free_card;
+		if (err) {
+			pr_warning("%s: Enabling HPI failed\n",
+				   mmc_hostname(card->host));
+			err = 0;
+		} else
+			card->ext_csd.hpi_en = 1;
+	}
+
+	/*
 	 * Compute bus speed.
 	 */
 	max_dtr = (unsigned int)-1;
@@ -783,10 +937,18 @@
 			bus_width = bus_widths[idx];
 			if (bus_width == MMC_BUS_WIDTH_1)
 				ddr = 0; /* no DDR for 1-bit width */
+			err = mmc_select_powerclass(card, ext_csd_bits[idx][0],
+						    ext_csd);
+			if (err)
+				pr_err("%s: power class selection to "
+				       "bus width %d failed\n",
+				       mmc_hostname(card->host),
+				       1 << bus_width);
+
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_BUS_WIDTH,
 					 ext_csd_bits[idx][0],
-					 0);
+					 card->ext_csd.generic_cmd6_time);
 			if (!err) {
 				mmc_set_bus_width(card->host, bus_width);
 
@@ -806,10 +968,18 @@
 		}
 
 		if (!err && ddr) {
+			err = mmc_select_powerclass(card, ext_csd_bits[idx][1],
+						    ext_csd);
+			if (err)
+				pr_err("%s: power class selection to "
+				       "bus width %d ddr %d failed\n",
+				       mmc_hostname(card->host),
+				       1 << bus_width, ddr);
+
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_BUS_WIDTH,
 					 ext_csd_bits[idx][1],
-					 0);
+					 card->ext_csd.generic_cmd6_time);
 		}
 		if (err) {
 			printk(KERN_WARNING "%s: switch to bus width %d ddr %d "
@@ -843,6 +1013,23 @@
 		}
 	}
 
+	/*
+	 * If cache size is higher than 0, this indicates
+	 * the existence of cache and it can be turned on.
+	 */
+	if ((host->caps2 & MMC_CAP2_CACHE_CTRL) &&
+			card->ext_csd.cache_size > 0) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				EXT_CSD_CACHE_CTRL, 1, 0);
+		if (err && err != -EBADMSG)
+			goto free_card;
+
+		/*
+		 * Only if no error, cache is turned on successfully.
+		 */
+		card->ext_csd.cache_ctrl = err ? 0 : 1;
+	}
+
 	if (!oldcard)
 		host->card = card;
 
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 2e39d2c..2438176 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -233,7 +233,7 @@
 mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
 		u32 opcode, void *buf, unsigned len)
 {
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 	struct mmc_command cmd = {0};
 	struct mmc_data data = {0};
 	struct scatterlist sg;
@@ -408,7 +408,7 @@
 			break;
 		if (mmc_host_is_spi(card->host))
 			break;
-	} while (R1_CURRENT_STATE(status) == 7);
+	} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
 
 	if (mmc_host_is_spi(card->host)) {
 		if (status & R1_SPI_ILLEGAL_COMMAND)
@@ -455,7 +455,7 @@
 mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
 		  u8 len)
 {
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 	struct mmc_command cmd = {0};
 	struct mmc_data data = {0};
 	struct scatterlist sg;
@@ -551,3 +551,34 @@
 	err = mmc_send_bus_test(card, card->host, MMC_BUS_TEST_R, width);
 	return err;
 }
+
+int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
+{
+	struct mmc_command cmd = {0};
+	unsigned int opcode;
+	unsigned int flags;
+	int err;
+
+	opcode = card->ext_csd.hpi_cmd;
+	if (opcode == MMC_STOP_TRANSMISSION)
+		flags = MMC_RSP_R1 | MMC_CMD_AC;
+	else if (opcode == MMC_SEND_STATUS)
+		flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+	cmd.opcode = opcode;
+	cmd.arg = card->rca << 16 | 1;
+	cmd.flags = flags;
+	cmd.cmd_timeout_ms = card->ext_csd.out_of_int_time;
+
+	err = mmc_wait_for_cmd(card->host, &cmd, 0);
+	if (err) {
+		pr_warn("%s: error %d interrupting operation. "
+			"HPI command response %#x\n", mmc_hostname(card->host),
+			err, cmd.resp[0]);
+		return err;
+	}
+	if (status)
+		*status = cmd.resp[0];
+
+	return 0;
+}
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 9276946..3dd8941 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -26,6 +26,7 @@
 int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
 int mmc_card_sleepawake(struct mmc_host *host, int sleep);
 int mmc_bus_test(struct mmc_card *card, u8 bus_width);
+int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status);
 
 #endif
 
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index 021fed1..46a7854 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -67,7 +67,7 @@
 int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
 	struct mmc_command *cmd, int retries)
 {
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 
 	int i, err;
 
@@ -244,7 +244,7 @@
 int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
 {
 	int err;
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 	struct mmc_command cmd = {0};
 	struct mmc_data data = {0};
 	struct scatterlist sg;
@@ -303,7 +303,7 @@
 int mmc_sd_switch(struct mmc_card *card, int mode, int group,
 	u8 value, u8 *resp)
 {
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 	struct mmc_command cmd = {0};
 	struct mmc_data data = {0};
 	struct scatterlist sg;
@@ -348,7 +348,7 @@
 int mmc_app_sd_status(struct mmc_card *card, void *ssr)
 {
 	int err;
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 	struct mmc_command cmd = {0};
 	struct mmc_data data = {0};
 	struct scatterlist sg;
diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c
index f087d87..4addbe9 100644
--- a/drivers/mmc/core/sdio_ops.c
+++ b/drivers/mmc/core/sdio_ops.c
@@ -121,7 +121,7 @@
 int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
 	unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz)
 {
-	struct mmc_request mrq = {0};
+	struct mmc_request mrq = {NULL};
 	struct mmc_command cmd = {0};
 	struct mmc_data data = {0};
 	struct scatterlist sg;
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
index 7c1e16a..92946b8 100644
--- a/drivers/mmc/host/mmc_spi.c
+++ b/drivers/mmc/host/mmc_spi.c
@@ -27,6 +27,7 @@
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/module.h>
 #include <linux/bio.h>
 #include <linux/dma-mapping.h>
 #include <linux/crc7.h>
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
index d513d47..99b449d 100644
--- a/drivers/mmc/host/mxs-mmc.c
+++ b/drivers/mmc/host/mxs-mmc.c
@@ -37,6 +37,7 @@
 #include <linux/mmc/sdio.h>
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
+#include <linux/module.h>
 
 #include <mach/mxs.h>
 #include <mach/common.h>
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index ba40d6d..6be0a24 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -15,6 +15,7 @@
 
 #include <linux/io.h>
 #include <linux/delay.h>
+#include <linux/module.h>
 #include <linux/mmc/host.h>
 #include "sdhci-of.h"
 #include "sdhci.h"
diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c
index 68ddb75..aaea044 100644
--- a/drivers/mmc/host/sdhci-of-hlwd.c
+++ b/drivers/mmc/host/sdhci-of-hlwd.c
@@ -20,6 +20,7 @@
  */
 
 #include <linux/delay.h>
+#include <linux/module.h>
 #include <linux/mmc/host.h>
 #include "sdhci-of.h"
 #include "sdhci.h"
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index 936bbca..67c8709 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -14,6 +14,7 @@
 
 #include <linux/delay.h>
 #include <linux/highmem.h>
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c
index 60a4c97..a152b5c 100644
--- a/drivers/mmc/host/sdhci-spear.c
+++ b/drivers/mmc/host/sdhci-spear.c
@@ -17,6 +17,7 @@
 #include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/highmem.h>
+#include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/platform_device.h>
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 343c97e..bb1ae46 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -20,6 +20,7 @@
 #include <linux/gpio.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
+#include <linux/module.h>
 
 #include <mach/gpio.h>
 #include <mach/sdhci.h>
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index aad27c8..9cf813e 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -16,6 +16,7 @@
 #include <linux/delay.h>
 #include <linux/highmem.h>
 #include <linux/io.h>
+#include <linux/module.h>
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
 #include <linux/scatterlist.h>
@@ -2558,6 +2559,15 @@
 	if (caps[1] & SDHCI_DRIVER_TYPE_D)
 		mmc->caps |= MMC_CAP_DRIVER_TYPE_D;
 
+	/*
+	 * If Power Off Notify capability is enabled by the host,
+	 * set notify to short power off notify timeout value.
+	 */
+	if (mmc->caps2 & MMC_CAP2_POWEROFF_NOTIFY)
+		mmc->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT;
+	else
+		mmc->power_notify_type = MMC_HOST_PW_NOTIFY_NONE;
+
 	/* Initial value for re-tuning timer count */
 	host->tuning_count = (caps[1] & SDHCI_RETUNING_TIMER_COUNT_MASK) >>
 			      SDHCI_RETUNING_TIMER_COUNT_SHIFT;
diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c
index 496b7ef..7009f17 100644
--- a/drivers/mmc/host/sdricoh_cs.c
+++ b/drivers/mmc/host/sdricoh_cs.c
@@ -26,6 +26,7 @@
 */
 #include <linux/delay.h>
 #include <linux/highmem.h>
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/ioport.h>
 #include <linux/scatterlist.h>
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index 14f8edb..51b68cc 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -31,6 +31,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/spinlock.h>
+#include <linux/module.h>
 
 #define DRIVER_NAME	"sh_mmcif"
 #define DRIVER_VERSION	"2010-04-28"
diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index ce500f0..f5ce77b 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -21,6 +21,7 @@
 #include <linux/kernel.h>
 #include <linux/clk.h>
 #include <linux/slab.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/sh_mobile_sdhi.h>
diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c
index 457c26e..90c6b1b 100644
--- a/drivers/mmc/host/tifm_sd.c
+++ b/drivers/mmc/host/tifm_sd.c
@@ -16,6 +16,7 @@
 #include <linux/mmc/host.h>
 #include <linux/highmem.h>
 #include <linux/scatterlist.h>
+#include <linux/module.h>
 #include <asm/io.h>
 
 #define DRIVER_NAME "tifm_sd"
diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c
index 4dfe2c0..faf3594 100644
--- a/drivers/mmc/host/via-sdmmc.c
+++ b/drivers/mmc/host/via-sdmmc.c
@@ -9,6 +9,7 @@
  */
 
 #include <linux/pci.h>
+#include <linux/module.h>
 #include <linux/dma-mapping.h>
 #include <linux/highmem.h>
 #include <linux/delay.h>
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 93de829..709583a 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -29,6 +29,7 @@
 #define BMS_CONTROL		0x224
 #define BMS_OUTPUT0		0x230
 #define BMS_OUTPUT1		0x231
+#define BMS_TOLERANCES		0x232
 #define BMS_TEST1		0x237
 
 #define ADC_ARB_SECP_CNTRL	0x190
@@ -102,7 +103,7 @@
 	unsigned int		charging_began;
 	unsigned int		start_percent;
 	unsigned int		end_percent;
-
+	enum battery_type	batt_type;
 	uint16_t		ocv_reading_at_100;
 	int			cc_reading_at_100;
 	int			max_voltage_uv;
@@ -1268,6 +1269,10 @@
 }
 EXPORT_SYMBOL_GPL(pm8921_bms_get_fcc);
 
+#define IBAT_TOL_MASK		0x0F
+#define OCV_TOL_MASK			0xF0
+#define IBAT_TOL_DEFAULT	0x03
+#define IBAT_TOL_NOCHG		0x0F
 void pm8921_bms_charging_began(void)
 {
 	int batt_temp, rc;
@@ -1291,7 +1296,8 @@
 	bms_start_percent = the_chip->start_percent;
 	bms_start_ocv_uv = raw.last_good_ocv_uv;
 	calculate_cc_uah(the_chip, raw.cc, &bms_start_cc_uah);
-
+	pm_bms_masked_write(the_chip, BMS_TOLERANCES,
+			IBAT_TOL_MASK, IBAT_TOL_DEFAULT);
 	pr_debug("start_percent = %u%%\n", the_chip->start_percent);
 }
 EXPORT_SYMBOL_GPL(pm8921_bms_charging_began);
@@ -1373,6 +1379,8 @@
 			last_chargecycles);
 	the_chip->start_percent = -EINVAL;
 	the_chip->end_percent = -EINVAL;
+	pm_bms_masked_write(the_chip, BMS_TOLERANCES,
+				IBAT_TOL_MASK, IBAT_TOL_NOCHG);
 }
 EXPORT_SYMBOL_GPL(pm8921_bms_charging_end);
 
@@ -1514,6 +1522,9 @@
 				BMS_CONTROL, rc);
 	}
 
+	/* The charger will call start charge later if usb is present */
+	pm_bms_masked_write(chip, BMS_TOLERANCES,
+				IBAT_TOL_MASK, IBAT_TOL_NOCHG);
 	return 0;
 }
 
@@ -1554,38 +1565,60 @@
 	}
 	pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
 						result.measurement);
-	return result.physical;
+	return result.adc_code;
 }
 
-#define PALLADIUM_ID_MIN  2500
-#define PALLADIUM_ID_MAX  4000
+#define PALLADIUM_ID_MIN	0x7F40
+#define PALLADIUM_ID_MAX	0x7F5A
+#define DESAY_5200_ID_MIN	0x7F7F
+#define DESAY_5200_ID_MAX	0x802F
 static int set_battery_data(struct pm8921_bms_chip *chip)
 {
 	int64_t battery_id;
 
-	battery_id = read_battery_id(chip);
+	if (chip->batt_type == BATT_DESAY)
+		goto desay;
+	else if (chip->batt_type == BATT_PALLADIUM)
+		goto palladium;
 
+	battery_id = read_battery_id(chip);
 	if (battery_id < 0) {
 		pr_err("cannot read battery id err = %lld\n", battery_id);
 		return battery_id;
 	}
 
 	if (is_between(PALLADIUM_ID_MIN, PALLADIUM_ID_MAX, battery_id)) {
-		chip->fcc = palladium_1500_data.fcc;
-		chip->fcc_temp_lut = palladium_1500_data.fcc_temp_lut;
-		chip->fcc_sf_lut = palladium_1500_data.fcc_sf_lut;
-		chip->pc_temp_ocv_lut = palladium_1500_data.pc_temp_ocv_lut;
-		chip->pc_sf_lut = palladium_1500_data.pc_sf_lut;
-		return 0;
+		goto palladium;
+	} else if (is_between(DESAY_5200_ID_MIN, DESAY_5200_ID_MAX,
+				battery_id)) {
+		goto desay;
 	} else {
-		pr_warn("invalid battery id, palladium 1500 assumed\n");
+		goto unknown;
+	}
+
+palladium:
 		chip->fcc = palladium_1500_data.fcc;
 		chip->fcc_temp_lut = palladium_1500_data.fcc_temp_lut;
 		chip->fcc_sf_lut = palladium_1500_data.fcc_sf_lut;
 		chip->pc_temp_ocv_lut = palladium_1500_data.pc_temp_ocv_lut;
 		chip->pc_sf_lut = palladium_1500_data.pc_sf_lut;
 		return 0;
-	}
+desay:
+		chip->fcc = desay_5200_data.fcc;
+		chip->fcc_temp_lut = desay_5200_data.fcc_temp_lut;
+		chip->fcc_sf_lut = desay_5200_data.fcc_sf_lut;
+		chip->pc_temp_ocv_lut = desay_5200_data.pc_temp_ocv_lut;
+		chip->pc_sf_lut = desay_5200_data.pc_sf_lut;
+		return 0;
+unknown:
+		pr_warn("invalid battery id, palladium 1500 assumed batt_id %llx\n",
+				battery_id);
+		chip->fcc = palladium_1500_data.fcc;
+		chip->fcc_temp_lut = palladium_1500_data.fcc_temp_lut;
+		chip->fcc_sf_lut = palladium_1500_data.fcc_sf_lut;
+		chip->pc_temp_ocv_lut = palladium_1500_data.pc_temp_ocv_lut;
+		chip->pc_sf_lut = palladium_1500_data.pc_sf_lut;
+		return 0;
 }
 
 enum {
@@ -1856,6 +1889,7 @@
 	chip->v_failure = pdata->v_failure;
 	chip->calib_delay_ms = pdata->calib_delay_ms;
 	chip->max_voltage_uv = pdata->max_voltage_uv;
+	chip->batt_type = pdata->battery_type;
 	chip->start_percent = -EINVAL;
 	chip->end_percent = -EINVAL;
 	rc = set_battery_data(chip);
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index d053cd6..22297be 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -1171,6 +1171,27 @@
 			}
 			slim_assign_laddr(&dev->ctrl, e_addr, 6, &laddr);
 			sat->satcl.laddr = laddr;
+			/*
+			 * Since capability message is already sent, present
+			 * message will indicate subsystem hosting this
+			 * satellite has restarted.
+			 * Remove all active channels of this satellite
+			 * when this is detected
+			 */
+			if (sat->sent_capability) {
+				for (i = 0; i < sat->nsatch; i++) {
+					enum slim_ch_state chs =
+						slim_get_ch_state(&sat->satcl,
+							sat->satch[i].chanh);
+					pr_err("Slim-SSR, sat:%d, rm chan:%d",
+							laddr,
+							sat->satch[i].chan);
+					if (chs == SLIM_CH_ACTIVE)
+						slim_control_ch(&sat->satcl,
+							sat->satch[i].chanh,
+							SLIM_CH_REMOVE, true);
+				}
+			}
 		} else if (mt != SLIM_MSG_MT_CORE &&
 				mc != SLIM_MSG_MC_REPORT_PRESENT) {
 			satv = msm_slim_get_ctrl(dev);
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index 6733396..cc008ab 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -2730,15 +2730,19 @@
  * -EXFULL is returned if there is no space in TDM to reserve the bandwidth.
  * -EISCONN/-ENOTCONN is returned if the channel is already connected or not
  * yet defined.
+ * -EINVAL is returned if individual control of a grouped-channel is attempted.
  */
 int slim_control_ch(struct slim_device *sb, u16 chanh,
 			enum slim_ch_control chctrl, bool commit)
 {
 	struct slim_controller *ctrl = sb->ctrl;
-	struct slim_ich *slc;
 	int ret = 0;
 	/* Get rid of the group flag in MSB if any */
 	u8 chan = SLIM_HDL_TO_CHIDX(chanh);
+	struct slim_ich *slc = &ctrl->chans[chan];
+	if (!(slc->nextgrp & SLIM_START_GRP))
+		return -EINVAL;
+
 	mutex_lock(&sb->sldev_reconf);
 	mutex_lock(&ctrl->m_ctrl);
 	do {
diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig
index 648d2e9..7768eed 100644
--- a/drivers/spmi/Kconfig
+++ b/drivers/spmi/Kconfig
@@ -19,4 +19,11 @@
 	  This is required for communicating with Qualcomm PMICs and
 	  other devices that have the SPMI interface.
 
+config MSM_QPNP
+	depends on ARCH_MSMCOPPER
+	depends on OF_SPMI
+	bool "MSM QPNP"
+	help
+	  Say 'y' here to include support for the Qualcomm QPNP
+	  support. QPNP is a SPMI based PMIC implementation.
 endif
diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile
index 8406134..659e886 100644
--- a/drivers/spmi/Makefile
+++ b/drivers/spmi/Makefile
@@ -3,3 +3,4 @@
 #
 obj-$(CONFIG_SPMI)			+= spmi.o
 obj-$(CONFIG_SPMI_MSM_PMIC_ARB)		+= spmi-pmic-arb.o
+obj-$(CONFIG_MSM_QPNP)                  += qpnp.o
diff --git a/drivers/spmi/qpnp.c b/drivers/spmi/qpnp.c
new file mode 100644
index 0000000..ddf9000
--- /dev/null
+++ b/drivers/spmi/qpnp.c
@@ -0,0 +1,55 @@
+/* Copyright (c) 2002-3 Patrick Mochel
+ * Copyright (c) 2002-3 Open Source Development Labs
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ *
+ * Resource handling based on platform.c.
+ */
+
+#include <mach/qpnp.h>
+
+/**
+ * qpnp_get_resource - get a resource for a device
+ * @dev: qpnp device
+ * @type: resource type
+ * @num: resource index
+ */
+struct resource *qpnp_get_resource(struct spmi_device *dev,
+				   unsigned int node_idx, unsigned int type,
+				   unsigned int res_num)
+{
+	int i;
+
+	for (i = 0; i < dev->dev_node[node_idx].num_resources; i++) {
+		struct resource *r = &dev->dev_node[node_idx].resource[i];
+
+		if (type == resource_type(r) && res_num-- == 0)
+			return r;
+	}
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(qpnp_get_resource);
+
+/**
+ * qpnp_get_irq - get an IRQ for a device
+ * @dev: qpnp device
+ * @num: IRQ number index
+ */
+int qpnp_get_irq(struct spmi_device *dev, unsigned int node_idx,
+					  unsigned int res_num)
+{
+	struct resource *r = qpnp_get_resource(dev, node_idx,
+						IORESOURCE_IRQ, res_num);
+
+	return r ? r->start : -ENXIO;
+}
+EXPORT_SYMBOL_GPL(qpnp_get_irq);
+
diff --git a/drivers/thermal/msm8960_tsens.c b/drivers/thermal/msm8960_tsens.c
index 0e279b8..c38b279 100644
--- a/drivers/thermal/msm8960_tsens.c
+++ b/drivers/thermal/msm8960_tsens.c
@@ -920,7 +920,7 @@
 	}
 
 	for (i = 0; i < tmdev->tsens_num_sensor; i++) {
-		char name[17];
+		char name[18];
 		snprintf(name, sizeof(name), "tsens_tz_sensor%d", i);
 		tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
 		tmdev->sensor[i].sensor_num = i;
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index c893889..8ea4632 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -47,7 +47,6 @@
 	.flags			= CI13XXX_REGS_SHARED |
 				  CI13XXX_REQUIRE_TRANSCEIVER |
 				  CI13XXX_PULLUP_ON_VBUS |
-				  CI13XXX_DISABLE_STREAMING |
 				  CI13XXX_ZERO_ITC,
 
 	.notify_event		= ci13xxx_msm_notify_event,
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index dc11eaf..97b0a2e 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1274,6 +1274,7 @@
 
 #ifdef CONFIG_USB_EHCI_MSM
 #include "ehci-msm.c"
+#include "ehci-msm2.c"
 #define PLATFORM_DRIVER_PRESENT
 #endif
 
@@ -1391,7 +1392,11 @@
 #endif
 
 #ifdef CONFIG_USB_EHCI_MSM_HSIC
-	&ehci_msm_hsic_driver
+	&ehci_msm_hsic_driver,
+#endif
+
+#ifdef CONFIG_USB_EHCI_MSM
+	&ehci_msm2_driver,
 #endif
 
 };
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index d64f223..dd3ec34 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -712,10 +712,12 @@
 	return 0;
 
 put_clocks:
-	clk_disable_unprepare(mehci->core_clk);
-	clk_disable_unprepare(mehci->phy_clk);
-	clk_disable_unprepare(mehci->cal_clk);
-	clk_disable_unprepare(mehci->ahb_clk);
+	if (!atomic_read(&mehci->in_lpm)) {
+		clk_disable_unprepare(mehci->core_clk);
+		clk_disable_unprepare(mehci->phy_clk);
+		clk_disable_unprepare(mehci->cal_clk);
+		clk_disable_unprepare(mehci->ahb_clk);
+	}
 	clk_put(mehci->ahb_clk);
 put_cal_clk:
 	clk_put(mehci->cal_clk);
@@ -893,7 +895,6 @@
 		free_irq(mehci->peripheral_status_irq, mehci);
 
 	device_init_wakeup(&pdev->dev, 0);
-	pm_runtime_disable(&pdev->dev);
 	pm_runtime_set_suspended(&pdev->dev);
 
 	usb_remove_hcd(hcd);
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
new file mode 100644
index 0000000..4f6fe3e
--- /dev/null
+++ b/drivers/usb/host/ehci-msm2.c
@@ -0,0 +1,1003 @@
+/* ehci-msm2.c - HSUSB Host Controller Driver Implementation
+ *
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+ *
+ * Partly derived from ehci-fsl.c and ehci-hcd.c
+ * Copyright (c) 2000-2004 by David Brownell
+ * Copyright (c) 2005 MontaVista Software
+ *
+ * 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/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/wakelock.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/usb/ulpi.h>
+#include <linux/usb/msm_hsusb_hw.h>
+#include <linux/usb/msm_hsusb.h>
+#include <mach/clk.h>
+#include <mach/msm_iomap.h>
+
+#define MSM_USB_BASE (hcd->regs)
+
+struct msm_hcd {
+	struct ehci_hcd				ehci;
+	struct device				*dev;
+	struct clk				*iface_clk;
+	struct clk				*core_clk;
+	struct clk				*alt_core_clk;
+	struct regulator			*hsusb_vddcx;
+	struct regulator			*hsusb_3p3;
+	struct regulator			*hsusb_1p8;
+	struct regulator			*vbus;
+	bool					async_int;
+	atomic_t				in_lpm;
+	struct wake_lock			wlock;
+};
+
+static inline struct msm_hcd *hcd_to_mhcd(struct usb_hcd *hcd)
+{
+	return (struct msm_hcd *) (hcd->hcd_priv);
+}
+
+static inline struct usb_hcd *mhcd_to_hcd(struct msm_hcd *mhcd)
+{
+	return container_of((void *) mhcd, struct usb_hcd, hcd_priv);
+}
+
+#define HSUSB_PHY_3P3_VOL_MIN		3050000 /* uV */
+#define HSUSB_PHY_3P3_VOL_MAX		3300000 /* uV */
+#define HSUSB_PHY_3P3_HPM_LOAD		50000	/* uA */
+
+#define HSUSB_PHY_1P8_VOL_MIN		1800000 /* uV */
+#define HSUSB_PHY_1P8_VOL_MAX		1800000 /* uV */
+#define HSUSB_PHY_1P8_HPM_LOAD		50000	/* uA */
+
+#define HSUSB_PHY_VDD_DIG_VOL_MIN	1045000	/* uV */
+#define HSUSB_PHY_VDD_DIG_VOL_MAX	1320000	/* uV */
+#define HSUSB_PHY_VDD_DIG_LOAD		49360	/* uA */
+
+static int msm_ehci_init_vddcx(struct msm_hcd *mhcd, int init)
+{
+	int ret = 0;
+
+	if (!init)
+		goto disable_reg;
+
+	mhcd->hsusb_vddcx = regulator_get(mhcd->dev, "HSUSB_VDDCX");
+	if (IS_ERR(mhcd->hsusb_vddcx)) {
+		dev_err(mhcd->dev, "unable to get ehci vddcx\n");
+		return PTR_ERR(mhcd->hsusb_vddcx);
+	}
+
+	ret = regulator_set_voltage(mhcd->hsusb_vddcx,
+			HSUSB_PHY_VDD_DIG_VOL_MIN,
+			HSUSB_PHY_VDD_DIG_VOL_MAX);
+	if (ret) {
+		dev_err(mhcd->dev, "unable to set the voltage"
+				"for ehci vddcx\n");
+		goto reg_set_voltage_err;
+	}
+
+	ret = regulator_set_optimum_mode(mhcd->hsusb_vddcx,
+				HSUSB_PHY_VDD_DIG_LOAD);
+	if (ret < 0) {
+		dev_err(mhcd->dev, "%s: Unable to set optimum mode of the"
+				" regulator: VDDCX\n", __func__);
+		goto reg_optimum_mode_err;
+	}
+
+	ret = regulator_enable(mhcd->hsusb_vddcx);
+	if (ret) {
+		dev_err(mhcd->dev, "unable to enable ehci vddcx\n");
+		goto reg_enable_err;
+	}
+
+	return 0;
+
+disable_reg:
+	regulator_disable(mhcd->hsusb_vddcx);
+reg_enable_err:
+	regulator_set_optimum_mode(mhcd->hsusb_vddcx, 0);
+reg_optimum_mode_err:
+	regulator_set_voltage(mhcd->hsusb_vddcx, 0,
+				HSUSB_PHY_VDD_DIG_VOL_MIN);
+reg_set_voltage_err:
+	regulator_put(mhcd->hsusb_vddcx);
+
+	return ret;
+
+}
+
+static int msm_ehci_ldo_init(struct msm_hcd *mhcd, int init)
+{
+	int rc = 0;
+
+	if (!init)
+		goto put_1p8;
+
+	mhcd->hsusb_3p3 = regulator_get(mhcd->dev, "HSUSB_3p3");
+	if (IS_ERR(mhcd->hsusb_3p3)) {
+		dev_err(mhcd->dev, "unable to get hsusb 3p3\n");
+		return PTR_ERR(mhcd->hsusb_3p3);
+	}
+
+	rc = regulator_set_voltage(mhcd->hsusb_3p3,
+			HSUSB_PHY_3P3_VOL_MIN, HSUSB_PHY_3P3_VOL_MAX);
+	if (rc) {
+		dev_err(mhcd->dev, "unable to set voltage level for"
+				"hsusb 3p3\n");
+		goto put_3p3;
+	}
+	mhcd->hsusb_1p8 = regulator_get(mhcd->dev, "HSUSB_1p8");
+	if (IS_ERR(mhcd->hsusb_1p8)) {
+		dev_err(mhcd->dev, "unable to get hsusb 1p8\n");
+		rc = PTR_ERR(mhcd->hsusb_1p8);
+		goto put_3p3_lpm;
+	}
+	rc = regulator_set_voltage(mhcd->hsusb_1p8,
+			HSUSB_PHY_1P8_VOL_MIN, HSUSB_PHY_1P8_VOL_MAX);
+	if (rc) {
+		dev_err(mhcd->dev, "unable to set voltage level for"
+				"hsusb 1p8\n");
+		goto put_1p8;
+	}
+
+	return 0;
+
+put_1p8:
+	regulator_set_voltage(mhcd->hsusb_1p8, 0, HSUSB_PHY_1P8_VOL_MAX);
+	regulator_put(mhcd->hsusb_1p8);
+put_3p3_lpm:
+	regulator_set_voltage(mhcd->hsusb_3p3, 0, HSUSB_PHY_3P3_VOL_MAX);
+put_3p3:
+	regulator_put(mhcd->hsusb_3p3);
+
+	return rc;
+}
+
+#ifdef CONFIG_PM_SLEEP
+#define HSUSB_PHY_SUSP_DIG_VOL  500000
+static int msm_ehci_config_vddcx(struct msm_hcd *mhcd, int high)
+{
+	int max_vol = HSUSB_PHY_VDD_DIG_VOL_MAX;
+	int min_vol;
+	int ret;
+
+	if (high)
+		min_vol = HSUSB_PHY_VDD_DIG_VOL_MIN;
+	else
+		min_vol = HSUSB_PHY_SUSP_DIG_VOL;
+
+	ret = regulator_set_voltage(mhcd->hsusb_vddcx, min_vol, max_vol);
+	if (ret) {
+		dev_err(mhcd->dev, "%s: unable to set the voltage of regulator"
+			" HSUSB_VDDCX\n", __func__);
+		return ret;
+	}
+
+	dev_dbg(mhcd->dev, "%s: min_vol:%d max_vol:%d\n", __func__, min_vol,
+								max_vol);
+
+	return ret;
+}
+#else
+static int msm_ehci_config_vddcx(struct msm_hcd *mhcd, int high)
+{
+	return 0;
+}
+#endif
+
+static int msm_ehci_init_vbus(struct msm_hcd *mhcd, int init)
+{
+	struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+	struct msm_usb_host_platform_data *pdata;
+
+	if (!init) {
+		regulator_put(mhcd->vbus);
+		return 0;
+	}
+
+	mhcd->vbus = regulator_get(mhcd->dev, "vbus");
+	if (IS_ERR(mhcd->vbus)) {
+		pr_err("Unable to get vbus\n");
+		return -ENODEV;
+	}
+
+	pdata = mhcd->dev->platform_data;
+	if (pdata)
+		hcd->power_budget = pdata->power_budget;
+
+	return 0;
+}
+
+static void msm_ehci_vbus_power(struct msm_hcd *mhcd, bool on)
+{
+	int ret;
+
+	if (!mhcd->vbus) {
+		pr_err("vbus is NULL.");
+		return;
+	}
+	if (on) {
+		ret = regulator_enable(mhcd->vbus);
+		if (ret) {
+			pr_err("unable to enable vbus\n");
+			return;
+		}
+	} else {
+		ret = regulator_disable(mhcd->vbus);
+		if (ret) {
+			pr_err("unable to disable vbus\n");
+			return;
+		}
+	}
+}
+
+static int msm_ehci_ldo_enable(struct msm_hcd *mhcd, int on)
+{
+	int ret = 0;
+
+	if (IS_ERR(mhcd->hsusb_1p8)) {
+		dev_err(mhcd->dev, "%s: HSUSB_1p8 is not initialized\n",
+								__func__);
+		return -ENODEV;
+	}
+
+	if (IS_ERR(mhcd->hsusb_3p3)) {
+		dev_err(mhcd->dev, "%s: HSUSB_3p3 is not initialized\n",
+								__func__);
+		return -ENODEV;
+	}
+
+	if (on) {
+		ret = regulator_set_optimum_mode(mhcd->hsusb_1p8,
+						HSUSB_PHY_1P8_HPM_LOAD);
+		if (ret < 0) {
+			dev_err(mhcd->dev, "%s: Unable to set HPM of the"
+				" regulator: HSUSB_1p8\n", __func__);
+			return ret;
+		}
+
+		ret = regulator_enable(mhcd->hsusb_1p8);
+		if (ret) {
+			dev_err(mhcd->dev, "%s: unable to enable the hsusb"
+						" 1p8\n", __func__);
+			regulator_set_optimum_mode(mhcd->hsusb_1p8, 0);
+			return ret;
+		}
+
+		ret = regulator_set_optimum_mode(mhcd->hsusb_3p3,
+						HSUSB_PHY_3P3_HPM_LOAD);
+		if (ret < 0) {
+			dev_err(mhcd->dev, "%s: Unable to set HPM of the "
+				"regulator: HSUSB_3p3\n", __func__);
+			regulator_set_optimum_mode(mhcd->hsusb_1p8, 0);
+			regulator_disable(mhcd->hsusb_1p8);
+			return ret;
+		}
+
+		ret = regulator_enable(mhcd->hsusb_3p3);
+		if (ret) {
+			dev_err(mhcd->dev, "%s: unable to enable the "
+					"hsusb 3p3\n", __func__);
+			regulator_set_optimum_mode(mhcd->hsusb_3p3, 0);
+			regulator_set_optimum_mode(mhcd->hsusb_1p8, 0);
+			regulator_disable(mhcd->hsusb_1p8);
+			return ret;
+		}
+
+	} else {
+		ret = regulator_disable(mhcd->hsusb_1p8);
+		if (ret) {
+			dev_err(mhcd->dev, "%s: unable to disable the "
+					"hsusb 1p8\n", __func__);
+			return ret;
+		}
+
+		ret = regulator_set_optimum_mode(mhcd->hsusb_1p8, 0);
+		if (ret < 0)
+			dev_err(mhcd->dev, "%s: Unable to set LPM of the "
+				"regulator: HSUSB_1p8\n", __func__);
+
+		ret = regulator_disable(mhcd->hsusb_3p3);
+		if (ret) {
+			dev_err(mhcd->dev, "%s: unable to disable the "
+					"hsusb 3p3\n", __func__);
+			return ret;
+		}
+		ret = regulator_set_optimum_mode(mhcd->hsusb_3p3, 0);
+		if (ret < 0)
+			dev_err(mhcd->dev, "%s: Unable to set LPM of the "
+					"regulator: HSUSB_3p3\n", __func__);
+	}
+
+	dev_dbg(mhcd->dev, "reg (%s)\n", on ? "HPM" : "LPM");
+
+	return ret < 0 ? ret : 0;
+}
+
+
+#define ULPI_IO_TIMEOUT_USECS	(10 * 1000)
+static int msm_ulpi_read(struct msm_hcd *mhcd, u32 reg)
+{
+	struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+	unsigned long timeout;
+
+	/* initiate read operation */
+	writel_relaxed(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
+	       USB_ULPI_VIEWPORT);
+
+	/* wait for completion */
+	timeout = jiffies + usecs_to_jiffies(ULPI_IO_TIMEOUT_USECS);
+	while (readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN) {
+		if (time_after(jiffies, timeout)) {
+			dev_err(mhcd->dev, "msm_ulpi_read: timeout %08x\n",
+				readl_relaxed(USB_ULPI_VIEWPORT));
+			return -ETIMEDOUT;
+		}
+		udelay(1);
+	}
+
+	return ULPI_DATA_READ(readl_relaxed(USB_ULPI_VIEWPORT));
+}
+
+
+static int msm_ulpi_write(struct msm_hcd *mhcd, u32 val, u32 reg)
+{
+	struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+	unsigned long timeout;
+
+	/* initiate write operation */
+	writel_relaxed(ULPI_RUN | ULPI_WRITE |
+	       ULPI_ADDR(reg) | ULPI_DATA(val),
+	       USB_ULPI_VIEWPORT);
+
+	/* wait for completion */
+	timeout = jiffies + usecs_to_jiffies(ULPI_IO_TIMEOUT_USECS);
+	while (readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN) {
+		if (time_after(jiffies, timeout)) {
+			dev_err(mhcd->dev, "msm_ulpi_write: timeout\n");
+			return -ETIMEDOUT;
+		}
+		udelay(1);
+	}
+
+	return 0;
+}
+
+static int msm_ehci_link_clk_reset(struct msm_hcd *mhcd, bool assert)
+{
+	int ret;
+
+	if (assert) {
+		ret = clk_reset(mhcd->alt_core_clk, CLK_RESET_ASSERT);
+		if (ret)
+			dev_err(mhcd->dev, "usb alt_core_clk assert failed\n");
+	} else {
+		ret = clk_reset(mhcd->alt_core_clk, CLK_RESET_DEASSERT);
+		if (ret)
+			dev_err(mhcd->dev, "usb alt_core_clk deassert failed\n");
+	}
+
+	return ret;
+}
+
+static int msm_ehci_phy_reset(struct msm_hcd *mhcd)
+{
+	struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+	u32 val;
+	int ret;
+	int retries;
+
+	ret = msm_ehci_link_clk_reset(mhcd, 1);
+	if (ret)
+		return ret;
+
+	udelay(1);
+
+	ret = msm_ehci_link_clk_reset(mhcd, 0);
+	if (ret)
+		return ret;
+
+	val = readl_relaxed(USB_PORTSC) & ~PORTSC_PTS_MASK;
+	writel_relaxed(val | PORTSC_PTS_ULPI, USB_PORTSC);
+
+	for (retries = 3; retries > 0; retries--) {
+		ret = msm_ulpi_write(mhcd, ULPI_FUNC_CTRL_SUSPENDM,
+				ULPI_CLR(ULPI_FUNC_CTRL));
+		if (!ret)
+			break;
+	}
+	if (!retries)
+		return -ETIMEDOUT;
+
+	/* Wakeup the PHY with a reg-access for calibration */
+	for (retries = 3; retries > 0; retries--) {
+		ret = msm_ulpi_read(mhcd, ULPI_DEBUG);
+		if (ret != -ETIMEDOUT)
+			break;
+	}
+	if (!retries)
+		return -ETIMEDOUT;
+
+	dev_info(mhcd->dev, "phy_reset: success\n");
+
+	return 0;
+}
+
+#define LINK_RESET_TIMEOUT_USEC		(250 * 1000)
+static int msm_hsusb_reset(struct msm_hcd *mhcd)
+{
+	struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+	unsigned long timeout;
+	int ret;
+
+	clk_prepare_enable(mhcd->alt_core_clk);
+	ret = msm_ehci_phy_reset(mhcd);
+	if (ret) {
+		dev_err(mhcd->dev, "phy_reset failed\n");
+		return ret;
+	}
+
+	writel_relaxed(USBCMD_RESET, USB_USBCMD);
+
+	timeout = jiffies + usecs_to_jiffies(LINK_RESET_TIMEOUT_USEC);
+	while (readl_relaxed(USB_USBCMD) & USBCMD_RESET) {
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+		udelay(1);
+	}
+
+	/* select ULPI phy */
+	writel_relaxed(0x80000000, USB_PORTSC);
+
+	msleep(100);
+
+	writel_relaxed(0x0, USB_AHBBURST);
+	writel_relaxed(0x00, USB_AHBMODE);
+
+	/* Ensure that RESET operation is completed before turning off clock */
+	mb();
+	clk_disable_unprepare(mhcd->alt_core_clk);
+
+	/*rising edge interrupts with Dp rise and fall enabled*/
+	msm_ulpi_write(mhcd, ULPI_INT_DP, ULPI_USB_INT_EN_RISE);
+	msm_ulpi_write(mhcd, ULPI_INT_DP, ULPI_USB_INT_EN_FALL);
+
+	/*Clear the PHY interrupts by reading the PHY interrupt latch register*/
+	msm_ulpi_read(mhcd, ULPI_USB_INT_LATCH);
+
+	return 0;
+}
+
+#define PHY_SUSPEND_TIMEOUT_USEC	(500 * 1000)
+#define PHY_RESUME_TIMEOUT_USEC		(100 * 1000)
+
+#ifdef CONFIG_PM_SLEEP
+static int msm_ehci_suspend(struct msm_hcd *mhcd)
+{
+	struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+	unsigned long timeout;
+	u32 portsc;
+
+	if (atomic_read(&mhcd->in_lpm)) {
+		dev_dbg(mhcd->dev, "%s called in lpm\n", __func__);
+		return 0;
+	}
+
+	disable_irq(hcd->irq);
+
+	/* Set the PHCD bit, only if it is not set by the controller.
+	 * PHY may take some time or even fail to enter into low power
+	 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
+	 * in failure case.
+	 */
+	portsc = readl_relaxed(USB_PORTSC);
+	if (!(portsc & PORTSC_PHCD)) {
+		writel_relaxed(portsc | PORTSC_PHCD,
+				USB_PORTSC);
+
+		timeout = jiffies + usecs_to_jiffies(PHY_SUSPEND_TIMEOUT_USEC);
+		while (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD)) {
+			if (time_after(jiffies, timeout)) {
+				dev_err(mhcd->dev, "Unable to suspend PHY\n");
+				msm_hsusb_reset(mhcd);
+				break;
+			}
+			udelay(1);
+		}
+	}
+
+	/*
+	 * PHY has capability to generate interrupt asynchronously in low
+	 * power mode (LPM). This interrupt is level triggered. So USB IRQ
+	 * line must be disabled till async interrupt enable bit is cleared
+	 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
+	 * block data communication from PHY.
+	 */
+	writel_relaxed(readl_relaxed(USB_USBCMD) | ASYNC_INTR_CTRL |
+				ULPI_STP_CTRL, USB_USBCMD);
+
+	/*
+	 * Ensure that hardware is put in low power mode before
+	 * clocks are turned OFF and VDD is allowed to minimize.
+	 */
+	mb();
+
+	clk_disable_unprepare(mhcd->iface_clk);
+	clk_disable_unprepare(mhcd->core_clk);
+
+	msm_ehci_config_vddcx(mhcd, 0);
+
+	atomic_set(&mhcd->in_lpm, 1);
+	enable_irq(hcd->irq);
+	wake_unlock(&mhcd->wlock);
+
+	dev_info(mhcd->dev, "EHCI USB in low power mode\n");
+
+	return 0;
+}
+
+static int msm_ehci_resume(struct msm_hcd *mhcd)
+{
+	struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+	unsigned long timeout;
+	unsigned temp;
+
+	if (!atomic_read(&mhcd->in_lpm)) {
+		dev_dbg(mhcd->dev, "%s called in !in_lpm\n", __func__);
+		return 0;
+	}
+
+	wake_lock(&mhcd->wlock);
+
+	clk_prepare_enable(mhcd->core_clk);
+	clk_prepare_enable(mhcd->iface_clk);
+
+	msm_ehci_config_vddcx(mhcd, 1);
+
+	temp = readl_relaxed(USB_USBCMD);
+	temp &= ~ASYNC_INTR_CTRL;
+	temp &= ~ULPI_STP_CTRL;
+	writel_relaxed(temp, USB_USBCMD);
+
+	if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD))
+		goto skip_phy_resume;
+
+	temp = readl_relaxed(USB_PORTSC) & ~PORTSC_PHCD;
+	writel_relaxed(temp, USB_PORTSC);
+
+	timeout = jiffies + usecs_to_jiffies(PHY_RESUME_TIMEOUT_USEC);
+	while ((readl_relaxed(USB_PORTSC) & PORTSC_PHCD) ||
+			!(readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_SYNC_STATE)) {
+		if (time_after(jiffies, timeout)) {
+			/*This is a fatal error. Reset the link and PHY*/
+			dev_err(mhcd->dev, "Unable to resume USB. Resetting the h/w\n");
+			msm_hsusb_reset(mhcd);
+			break;
+		}
+		udelay(1);
+	}
+
+skip_phy_resume:
+
+	atomic_set(&mhcd->in_lpm, 0);
+
+	if (mhcd->async_int) {
+		mhcd->async_int = false;
+		pm_runtime_put_noidle(mhcd->dev);
+		enable_irq(hcd->irq);
+	}
+
+	dev_info(mhcd->dev, "EHCI USB exited from low power mode\n");
+
+	return 0;
+}
+#endif
+
+static irqreturn_t msm_ehci_irq(struct usb_hcd *hcd)
+{
+	struct msm_hcd *mhcd = hcd_to_mhcd(hcd);
+
+	if (atomic_read(&mhcd->in_lpm)) {
+		disable_irq_nosync(hcd->irq);
+		mhcd->async_int = true;
+		pm_runtime_get(mhcd->dev);
+		return IRQ_HANDLED;
+	}
+
+	return ehci_irq(hcd);
+}
+
+static int msm_ehci_reset(struct usb_hcd *hcd)
+{
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	int retval;
+
+	ehci->caps = USB_CAPLENGTH;
+	ehci->regs = USB_CAPLENGTH +
+		HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
+	dbg_hcs_params(ehci, "reset");
+	dbg_hcc_params(ehci, "reset");
+
+	/* cache the data to minimize the chip reads*/
+	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+	hcd->has_tt = 1;
+	ehci->sbrn = HCD_USB2;
+
+	retval = ehci_halt(ehci);
+	if (retval)
+		return retval;
+
+	/* data structure init */
+	retval = ehci_init(hcd);
+	if (retval)
+		return retval;
+
+	retval = ehci_reset(ehci);
+	if (retval)
+		return retval;
+
+	/* bursts of unspecified length. */
+	writel_relaxed(0, USB_AHBBURST);
+	/* Use the AHB transactor */
+	writel_relaxed(0, USB_AHBMODE);
+	/* Disable streaming mode and select host mode */
+	writel_relaxed(0x13, USB_USBMODE);
+
+	ehci_port_power(ehci, 1);
+	return 0;
+}
+
+static struct hc_driver msm_hc2_driver = {
+	.description		= hcd_name,
+	.product_desc		= "Qualcomm EHCI Host Controller",
+	.hcd_priv_size		= sizeof(struct msm_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq			= msm_ehci_irq,
+	.flags			= HCD_USB2 | HCD_MEMORY,
+
+	.reset			= msm_ehci_reset,
+	.start			= ehci_run,
+
+	.stop			= ehci_stop,
+	.shutdown		= ehci_shutdown,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue		= ehci_urb_enqueue,
+	.urb_dequeue		= ehci_urb_dequeue,
+	.endpoint_disable	= ehci_endpoint_disable,
+	.endpoint_reset		= ehci_endpoint_reset,
+	.clear_tt_buffer_complete	 = ehci_clear_tt_buffer_complete,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number	= ehci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data	= ehci_hub_status_data,
+	.hub_control		= ehci_hub_control,
+	.relinquish_port	= ehci_relinquish_port,
+	.port_handed_over	= ehci_port_handed_over,
+
+	/*
+	 * PM support
+	 */
+	.bus_suspend		= ehci_bus_suspend,
+	.bus_resume		= ehci_bus_resume,
+};
+
+static int msm_ehci_init_clocks(struct msm_hcd *mhcd, u32 init)
+{
+	int ret = 0;
+
+	if (!init)
+		goto put_clocks;
+
+	/* 60MHz alt_core_clk is for LINK to be used during PHY RESET  */
+	mhcd->alt_core_clk = clk_get(mhcd->dev, "alt_core_clk");
+	if (IS_ERR(mhcd->alt_core_clk)) {
+		dev_err(mhcd->dev, "failed to get alt_core_clk\n");
+		ret = PTR_ERR(mhcd->alt_core_clk);
+		return ret;
+	}
+	clk_set_rate(mhcd->alt_core_clk, 60000000);
+
+	/* iface_clk is required for data transfers */
+	mhcd->iface_clk = clk_get(mhcd->dev, "iface_clk");
+	if (IS_ERR(mhcd->iface_clk)) {
+		dev_err(mhcd->dev, "failed to get iface_clk\n");
+		ret = PTR_ERR(mhcd->iface_clk);
+		goto put_alt_core_clk;
+	}
+
+	/* Link's protocol engine is based on pclk which must
+	 * be running >55Mhz and frequency should also not change.
+	 * Hence, vote for maximum clk frequency on its source
+	 */
+	mhcd->core_clk = clk_get(mhcd->dev, "core_clk");
+	if (IS_ERR(mhcd->core_clk)) {
+		dev_err(mhcd->dev, "failed to get core_clk\n");
+		ret = PTR_ERR(mhcd->core_clk);
+		goto put_iface_clk;
+	}
+	clk_set_rate(mhcd->core_clk, INT_MAX);
+
+	clk_prepare_enable(mhcd->core_clk);
+	clk_prepare_enable(mhcd->iface_clk);
+
+	return 0;
+
+put_clocks:
+	clk_disable_unprepare(mhcd->iface_clk);
+	clk_disable_unprepare(mhcd->core_clk);
+	clk_put(mhcd->core_clk);
+put_iface_clk:
+	clk_put(mhcd->iface_clk);
+put_alt_core_clk:
+	clk_put(mhcd->alt_core_clk);
+
+	return ret;
+}
+
+static int __devinit ehci_msm2_probe(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd;
+	struct resource *res;
+	struct msm_hcd *mhcd;
+	int ret;
+
+	dev_dbg(&pdev->dev, "ehci_msm2 probe\n");
+
+	hcd = usb_create_hcd(&msm_hc2_driver, &pdev->dev,
+				dev_name(&pdev->dev));
+	if (!hcd) {
+		dev_err(&pdev->dev, "Unable to create HCD\n");
+		return  -ENOMEM;
+	}
+
+	hcd->irq = platform_get_irq(pdev, 0);
+	if (hcd->irq < 0) {
+		dev_err(&pdev->dev, "Unable to get IRQ resource\n");
+		ret = hcd->irq;
+		goto put_hcd;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "Unable to get memory resource\n");
+		ret = -ENODEV;
+		goto put_hcd;
+	}
+
+	hcd->rsrc_start = res->start;
+	hcd->rsrc_len = resource_size(res);
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		ret = -ENOMEM;
+		goto put_hcd;
+	}
+
+	mhcd = hcd_to_mhcd(hcd);
+	mhcd->dev = &pdev->dev;
+
+	ret = msm_ehci_init_clocks(mhcd, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to initialize clocks\n");
+		ret = -ENODEV;
+		goto unmap;
+	}
+
+	ret = msm_ehci_init_vddcx(mhcd, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to initialize VDDCX\n");
+		ret = -ENODEV;
+		goto deinit_clocks;
+	}
+
+	ret = msm_ehci_config_vddcx(mhcd, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
+		goto deinit_vddcx;
+	}
+
+	ret = msm_ehci_ldo_init(mhcd, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
+		goto deinit_vddcx;
+	}
+
+	ret = msm_ehci_ldo_enable(mhcd, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "hsusb vreg enable failed\n");
+		goto deinit_ldo;
+	}
+
+	ret = msm_ehci_init_vbus(mhcd, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to get vbus\n");
+		goto disable_ldo;
+	}
+
+	ret = msm_hsusb_reset(mhcd);
+	if (ret) {
+		dev_err(&pdev->dev, "hsusb PHY initialization failed\n");
+		goto vbus_deinit;
+	}
+
+	ret = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to register HCD\n");
+		goto vbus_deinit;
+	}
+
+	/*TBD:for now enable vbus here*/
+	msm_ehci_vbus_power(mhcd, 1);
+
+	device_init_wakeup(&pdev->dev, 1);
+	wake_lock_init(&mhcd->wlock, WAKE_LOCK_SUSPEND, dev_name(&pdev->dev));
+	wake_lock(&mhcd->wlock);
+	/*
+	 * This pdev->dev is assigned parent of root-hub by USB core,
+	 * hence, runtime framework automatically calls this driver's
+	 * runtime APIs based on root-hub's state.
+	 */
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
+	return 0;
+
+vbus_deinit:
+	msm_ehci_init_vbus(mhcd, 0);
+disable_ldo:
+	msm_ehci_ldo_enable(mhcd, 0);
+deinit_ldo:
+	msm_ehci_ldo_init(mhcd, 0);
+deinit_vddcx:
+	msm_ehci_init_vddcx(mhcd, 0);
+deinit_clocks:
+	msm_ehci_init_clocks(mhcd, 0);
+unmap:
+	iounmap(hcd->regs);
+put_hcd:
+	usb_put_hcd(hcd);
+
+	return ret;
+}
+
+static int __devexit ehci_msm2_remove(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd = platform_get_drvdata(pdev);
+	struct msm_hcd *mhcd = hcd_to_mhcd(hcd);
+
+	device_init_wakeup(&pdev->dev, 0);
+	pm_runtime_disable(&pdev->dev);
+	pm_runtime_set_suspended(&pdev->dev);
+
+	usb_remove_hcd(hcd);
+	msm_ehci_vbus_power(mhcd, 0);
+	msm_ehci_init_vbus(mhcd, 0);
+	msm_ehci_ldo_enable(mhcd, 0);
+	msm_ehci_ldo_init(mhcd, 0);
+	msm_ehci_init_vddcx(mhcd, 0);
+
+	msm_ehci_init_clocks(mhcd, 0);
+	wake_lock_destroy(&mhcd->wlock);
+	iounmap(hcd->regs);
+	usb_put_hcd(hcd);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ehci_msm2_pm_suspend(struct device *dev)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct msm_hcd *mhcd = hcd_to_mhcd(hcd);
+
+	dev_dbg(dev, "ehci-msm2 PM suspend\n");
+
+	if (device_may_wakeup(dev))
+		enable_irq_wake(hcd->irq);
+
+	return msm_ehci_suspend(mhcd);
+
+}
+
+static int ehci_msm2_pm_resume(struct device *dev)
+{
+	int ret;
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct msm_hcd *mhcd = hcd_to_mhcd(hcd);
+
+	dev_dbg(dev, "ehci-msm2 PM resume\n");
+
+	if (device_may_wakeup(dev))
+		disable_irq_wake(hcd->irq);
+
+	ret = msm_ehci_resume(mhcd);
+	if (ret)
+		return ret;
+
+	/* Bring the device to full powered state upon system resume */
+	pm_runtime_disable(dev);
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_PM_RUNTIME
+static int ehci_msm2_runtime_idle(struct device *dev)
+{
+	dev_dbg(dev, "EHCI runtime idle\n");
+
+	return 0;
+}
+
+static int ehci_msm2_runtime_suspend(struct device *dev)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct msm_hcd *mhcd = hcd_to_mhcd(hcd);
+
+	dev_dbg(dev, "EHCI runtime suspend\n");
+	return msm_ehci_suspend(mhcd);
+}
+
+static int ehci_msm2_runtime_resume(struct device *dev)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct msm_hcd *mhcd = hcd_to_mhcd(hcd);
+
+	dev_dbg(dev, "EHCI runtime resume\n");
+	return msm_ehci_resume(mhcd);
+}
+#endif
+
+#ifdef CONFIG_PM
+static const struct dev_pm_ops ehci_msm2_dev_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(ehci_msm2_pm_suspend, ehci_msm2_pm_resume)
+	SET_RUNTIME_PM_OPS(ehci_msm2_runtime_suspend, ehci_msm2_runtime_resume,
+				ehci_msm2_runtime_idle)
+};
+#endif
+
+static struct platform_driver ehci_msm2_driver = {
+	.probe	= ehci_msm2_probe,
+	.remove	= __devexit_p(ehci_msm2_remove),
+	.driver = {
+		.name = "msm_ehci_host",
+#ifdef CONFIG_PM
+		.pm = &ehci_msm2_dev_pm_ops,
+#endif
+	},
+};
diff --git a/drivers/video/msm/adv7520.c b/drivers/video/msm/adv7520.c
index b3b34bb..7386983 100644
--- a/drivers/video/msm/adv7520.c
+++ b/drivers/video/msm/adv7520.c
@@ -874,7 +874,11 @@
 	} else
 		DEV_ERR("adv7520_probe: failed to add fb device\n");
 
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+	external_common_state->sdev.name = "hdmi_as_primary";
+#else
 	external_common_state->sdev.name = "hdmi";
+#endif
 	if (switch_dev_register(&external_common_state->sdev) < 0)
 		DEV_ERR("Hdmi switch registration failed\n");
 
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index a0665ac..ef357db 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -4062,6 +4062,11 @@
 
 static void hdmi_msm_hpd_off(void)
 {
+	if (!hdmi_msm_state->hpd_initialized) {
+		DEV_DBG("%s: HPD is already OFF, returning\n", __func__);
+		return;
+	}
+
 	DEV_DBG("%s: (timer, clk, 5V, core, IRQ off)\n", __func__);
 	del_timer(&hdmi_msm_state->hpd_state_timer);
 	disable_irq(hdmi_msm_state->irq);
@@ -4087,6 +4092,12 @@
 static int hdmi_msm_hpd_on(bool trigger_handler)
 {
 	static int phy_reset_done;
+	uint32 hpd_ctrl;
+
+	if (hdmi_msm_state->hpd_initialized) {
+		DEV_DBG("%s: HPD is already ON, returning\n", __func__);
+		return 0;
+	}
 
 	hdmi_msm_clk(1);
 	hdmi_msm_state->pd->core_power(1, 1);
@@ -4104,36 +4115,34 @@
 	HDMI_OUTP(0x0208, 0x0001001B);
 
 	/* Check HPD State */
-	if (!hdmi_msm_state->hpd_initialized) {
-		uint32 hpd_ctrl;
-		enable_irq(hdmi_msm_state->irq);
+	enable_irq(hdmi_msm_state->irq);
 
-		/* set timeout to 4.1ms (max) for hardware debounce */
-		hpd_ctrl = (HDMI_INP(0x0258) & ~0xFFF) | 0xFFF;
+	/* set timeout to 4.1ms (max) for hardware debounce */
+	hpd_ctrl = (HDMI_INP(0x0258) & ~0xFFF) | 0xFFF;
 
-		/* Toggle HPD circuit to trigger HPD sense */
-		HDMI_OUTP(0x0258, ~(1 << 28) & hpd_ctrl);
-		HDMI_OUTP(0x0258, (1 << 28) | hpd_ctrl);
+	/* Toggle HPD circuit to trigger HPD sense */
+	HDMI_OUTP(0x0258, ~(1 << 28) & hpd_ctrl);
+	HDMI_OUTP(0x0258, (1 << 28) | hpd_ctrl);
 
-		DEV_DBG("%s: (clk, 5V, core, IRQ on) <trigger:%s>\n", __func__,
-			trigger_handler ? "true" : "false");
+	DEV_DBG("%s: (clk, 5V, core, IRQ on) <trigger:%s>\n", __func__,
+		trigger_handler ? "true" : "false");
 
-		if (trigger_handler) {
-			/* Set HPD state machine: ensure at least 2 readouts */
-			mutex_lock(&hdmi_msm_state_mutex);
-			hdmi_msm_state->hpd_stable = 0;
-			hdmi_msm_state->hpd_prev_state = TRUE;
-			mutex_lock(&external_common_state_hpd_mutex);
-			external_common_state->hpd_state = FALSE;
-			mutex_unlock(&external_common_state_hpd_mutex);
-			hdmi_msm_state->hpd_cable_chg_detected = TRUE;
-			mutex_unlock(&hdmi_msm_state_mutex);
-			mod_timer(&hdmi_msm_state->hpd_state_timer,
-				jiffies + HZ/2);
-		}
-
-		hdmi_msm_state->hpd_initialized = TRUE;
+	if (trigger_handler) {
+		/* Set HPD state machine: ensure at least 2 readouts */
+		mutex_lock(&hdmi_msm_state_mutex);
+		hdmi_msm_state->hpd_stable = 0;
+		hdmi_msm_state->hpd_prev_state = TRUE;
+		mutex_lock(&external_common_state_hpd_mutex);
+		external_common_state->hpd_state = FALSE;
+		mutex_unlock(&external_common_state_hpd_mutex);
+		hdmi_msm_state->hpd_cable_chg_detected = TRUE;
+		mutex_unlock(&hdmi_msm_state_mutex);
+		mod_timer(&hdmi_msm_state->hpd_state_timer,
+			jiffies + HZ/2);
 	}
+
+	hdmi_msm_state->hpd_initialized = TRUE;
+
 	hdmi_msm_set_mode(TRUE);
 
 	return 0;
@@ -4398,7 +4407,11 @@
 	queue_work(hdmi_work_queue, &hdmi_msm_state->hpd_read_work);
 
 	/* Initialize hdmi node and register with switch driver */
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+	external_common_state->sdev.name = "hdmi_as_primary";
+#else
 	external_common_state->sdev.name = "hdmi";
+#endif
 	if (switch_dev_register(&external_common_state->sdev) < 0)
 		DEV_ERR("Hdmi switch registration failed\n");
 
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index e43f729..de91ade 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -86,6 +86,9 @@
 struct workqueue_struct *mdp_dma_wq;	/*mdp dma wq */
 struct workqueue_struct *mdp_vsync_wq;	/*mdp vsync wq */
 
+struct workqueue_struct *mdp_hist_wq;	/*mdp histogram wq */
+struct work_struct mdp_histogram_worker;
+
 static struct workqueue_struct *mdp_pipe_ctrl_wq; /* mdp mdp pipe ctrl wq */
 static struct delayed_work mdp_pipe_ctrl_worker;
 
@@ -142,6 +145,315 @@
 
 static uint32 mdp_prim_panel_type = NO_PANEL;
 #ifndef CONFIG_FB_MSM_MDP22
+
+struct list_head mdp_hist_lut_list;
+DEFINE_MUTEX(mdp_hist_lut_list_mutex);
+
+uint32_t mdp_block2base(uint32_t block)
+{
+	uint32_t base = 0x0;
+	switch (block) {
+	case MDP_BLOCK_DMA_P:
+		base = 0x90000;
+		break;
+	case MDP_BLOCK_DMA_S:
+		base = 0xA0000;
+		break;
+	case MDP_BLOCK_VG_1:
+		base = 0x20000;
+		break;
+	case MDP_BLOCK_VG_2:
+		base = 0x30000;
+		break;
+	case MDP_BLOCK_RGB_1:
+		base = 0x40000;
+		break;
+	case MDP_BLOCK_RGB_2:
+		base = 0x50000;
+		break;
+	default:
+		break;
+	}
+	return base;
+}
+
+static uint32_t mdp_pp_block2hist_lut(uint32_t block)
+{
+	uint32_t valid = 0;
+	switch (block) {
+	case MDP_BLOCK_DMA_P:
+		valid = (mdp_rev >= MDP_REV_40) ? 1 : 0;
+		break;
+	case MDP_BLOCK_DMA_S:
+		valid = (mdp_rev >= MDP_REV_40) ? 1 : 0;
+		break;
+	case MDP_BLOCK_VG_1:
+		valid = (mdp_rev >= MDP_REV_40) ? 1 : 0;
+		break;
+	case MDP_BLOCK_VG_2:
+		valid = (mdp_rev >= MDP_REV_40) ? 1 : 0;
+		break;
+	default:
+		break;
+	}
+	return valid;
+}
+
+static void mdp_hist_lut_init_mgmt(struct mdp_hist_lut_mgmt *mgmt,
+		uint32_t block)
+{
+	mutex_init(&mgmt->lock);
+	mgmt->block = block;
+
+	mutex_lock(&mdp_hist_lut_list_mutex);
+	list_add(&mgmt->list, &mdp_hist_lut_list);
+	mutex_unlock(&mdp_hist_lut_list_mutex);
+}
+
+static int mdp_hist_lut_init(void)
+{
+	struct mdp_hist_lut_mgmt *temp;
+	struct list_head *pos, *q;
+	INIT_LIST_HEAD(&mdp_hist_lut_list);
+
+	if (mdp_rev >= MDP_REV_30) {
+		temp = kmalloc(sizeof(struct mdp_hist_lut_mgmt), GFP_KERNEL);
+		if (!temp)
+			goto exit;
+		mdp_hist_lut_init_mgmt(temp, MDP_BLOCK_DMA_P);
+	}
+
+	if (mdp_rev >= MDP_REV_40) {
+		temp = kmalloc(sizeof(struct mdp_hist_lut_mgmt), GFP_KERNEL);
+		if (!temp)
+			goto exit_list;
+		mdp_hist_lut_init_mgmt(temp, MDP_BLOCK_VG_1);
+
+		temp = kmalloc(sizeof(struct mdp_hist_lut_mgmt), GFP_KERNEL);
+		if (!temp)
+			goto exit_list;
+		mdp_hist_lut_init_mgmt(temp, MDP_BLOCK_VG_2);
+	}
+
+	if (mdp_rev > MDP_REV_42) {
+		temp = kmalloc(sizeof(struct mdp_hist_lut_mgmt), GFP_KERNEL);
+		if (!temp)
+			goto exit_list;
+		mdp_hist_lut_init_mgmt(temp, MDP_BLOCK_DMA_S);
+	}
+	return 0;
+
+exit_list:
+	mutex_lock(&mdp_hist_lut_list_mutex);
+	list_for_each_safe(pos, q, &mdp_hist_lut_list) {
+		temp = list_entry(pos, struct mdp_hist_lut_mgmt, list);
+		list_del(pos);
+		kfree(temp);
+	}
+	mutex_unlock(&mdp_hist_lut_list_mutex);
+exit:
+	pr_err("Failed initializing histogram LUT memory\n");
+	return -ENOMEM;
+}
+
+static int mdp_hist_lut_block2mgmt(uint32_t block,
+		struct mdp_hist_lut_mgmt **mgmt)
+{
+	struct mdp_hist_lut_mgmt *temp, *output;
+	int ret = 0;
+
+	output = NULL;
+
+	mutex_lock(&mdp_hist_lut_list_mutex);
+	list_for_each_entry(temp, &mdp_hist_lut_list, list) {
+		if (temp->block == block)
+			output = temp;
+	}
+	mutex_unlock(&mdp_hist_lut_list_mutex);
+
+	if (output == NULL)
+		ret = -EINVAL;
+	else
+		*mgmt = output;
+
+	return ret;
+}
+
+#define MDP_HIST_LUT_SIZE (256)
+static int mdp_hist_lut_write_off(struct mdp_hist_lut_data *data,
+		struct mdp_hist_lut_info *info, uint32_t offset)
+{
+	int i;
+	uint32_t element[MDP_HIST_LUT_SIZE];
+	uint32_t base = mdp_block2base(info->block);
+	uint32_t sel = info->bank_sel;
+
+
+	if (data->len != MDP_HIST_LUT_SIZE) {
+		pr_err("%s: data->len != %d", __func__, MDP_HIST_LUT_SIZE);
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&element, data->data,
+				MDP_HIST_LUT_SIZE * sizeof(uint32_t))) {
+		pr_err("%s: Error copying histogram data", __func__);
+		return -ENOMEM;
+	}
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	for (i = 0; i < MDP_HIST_LUT_SIZE; i++)
+		MDP_OUTP(MDP_BASE + base + offset + (0x400*(sel)) + (4*i),
+				element[i]);
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+	return 0;
+}
+
+static int mdp_hist_lut_write(struct mdp_hist_lut_data *data,
+						struct mdp_hist_lut_info *info)
+{
+	int ret = 0;
+
+	if (data->block != info->block) {
+		ret = -1;
+		pr_err("%s, data/info mdp_block mismatch! %d != %d\n",
+				__func__, data->block, info->block);
+		goto error;
+	}
+
+	switch (data->block) {
+	case MDP_BLOCK_VG_1:
+	case MDP_BLOCK_VG_2:
+		ret = mdp_hist_lut_write_off(data, info, 0x3400);
+		break;
+	case MDP_BLOCK_DMA_P:
+	case MDP_BLOCK_DMA_S:
+		ret = mdp_hist_lut_write_off(data, info, 0x4800);
+		break;
+	default:
+		ret = -EINVAL;
+		goto error;
+	}
+
+error:
+	return ret;
+}
+
+#define MDP_HIST_LUT_VG_EN_MASK (0x20000)
+#define MDP_HIST_LUT_VG_EN_SHIFT (17)
+#define MDP_HIST_LUT_VG_EN_OFFSET (0x0058)
+#define MDP_HIST_LUT_VG_SEL_OFFSET (0x0064)
+static void mdp_hist_lut_commit_vg(struct mdp_hist_lut_info *info)
+{
+	uint32_t out_en, temp_en;
+	uint32_t base = mdp_block2base(info->block);
+	temp_en = (info->is_enabled) ? (1 << MDP_HIST_LUT_VG_EN_SHIFT) : 0x0;
+
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	out_en = inpdw(MDP_BASE + base + MDP_HIST_LUT_VG_EN_OFFSET) &
+						~MDP_HIST_LUT_VG_EN_MASK;
+	MDP_OUTP(MDP_BASE + base + MDP_HIST_LUT_VG_EN_OFFSET, out_en | temp_en);
+
+	if (info->has_sel_update)
+		MDP_OUTP(MDP_BASE + base + MDP_HIST_LUT_VG_SEL_OFFSET,
+								info->bank_sel);
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+}
+
+#define MDP_HIST_LUT_DMA_EN_MASK (0x7)
+#define MDP_HIST_LUT_DMA_SEL_MASK (0x400)
+#define MDP_HIST_LUT_DMA_SEL_SHIFT (10)
+#define MDP_HIST_LUT_DMA_P_OFFSET (0x0070)
+#define MDP_HIST_LUT_DMA_S_OFFSET (0x0028)
+static void mdp_hist_lut_commit_dma(struct mdp_hist_lut_info *info)
+{
+	uint32_t out, temp, mask;
+	uint32_t base = mdp_block2base(info->block);
+	uint32_t offset = (info->block == MDP_BLOCK_DMA_P) ?
+		MDP_HIST_LUT_DMA_P_OFFSET : MDP_HIST_LUT_DMA_S_OFFSET;
+
+	mask = MDP_HIST_LUT_DMA_EN_MASK;
+	temp = (info->is_enabled) ? 0x7 : 0x0;
+
+	if (info->has_sel_update) {
+		mask |= MDP_HIST_LUT_DMA_SEL_MASK;
+		temp |=  ((info->bank_sel & 0x1) << MDP_HIST_LUT_DMA_SEL_SHIFT);
+	}
+
+	out = inpdw(MDP_BASE + base + offset) & ~mask;
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	MDP_OUTP(MDP_BASE + base + offset, out | temp);
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+}
+
+static void mdp_hist_lut_commit_info(struct mdp_hist_lut_info *info)
+{
+	switch (info->block) {
+	case MDP_BLOCK_VG_1:
+	case MDP_BLOCK_VG_2:
+		mdp_hist_lut_commit_vg(info);
+		break;
+	case MDP_BLOCK_DMA_P:
+	case MDP_BLOCK_DMA_S:
+		mdp_hist_lut_commit_dma(info);
+		break;
+	default:
+		goto error;
+	}
+
+error:
+	return;
+}
+
+static void mdp_hist_lut_update_info(struct mdp_hist_lut_info *info, int ops)
+{
+	info->bank_sel = (ops & 0x8) >> 3;
+	info->is_enabled = (ops & 0x1) ? TRUE : FALSE;
+	info->has_sel_update = (ops & 0x10) ? TRUE : FALSE;
+}
+
+int mdp_hist_lut_config(struct mdp_hist_lut_data *data)
+{
+	struct mdp_hist_lut_mgmt *mgmt = NULL;
+	struct mdp_hist_lut_info info;
+	int ret = 0;
+
+	if (!mdp_pp_block2hist_lut(data->block)) {
+		ret = -ENOTTY;
+		goto error;
+	}
+
+	ret = mdp_hist_lut_block2mgmt(data->block, &mgmt);
+	if (ret)
+		goto error;
+
+	mutex_lock(&mgmt->lock);
+
+	info.block = mgmt->block;
+
+	mdp_hist_lut_update_info(&info, data->ops);
+
+	switch ((data->ops & 0x6) >> 1) {
+	case 0x1:
+		pr_info("%s: histogram LUT read not supported\n", __func__);
+		break;
+	case 0x2:
+		ret = mdp_hist_lut_write(data, &info);
+		if (ret)
+			goto error_lock;
+		break;
+	default:
+		break;
+	}
+
+	mdp_hist_lut_commit_info(&info);
+
+error_lock:
+	mutex_unlock(&mgmt->lock);
+error:
+	return ret;
+}
+
+
 DEFINE_MUTEX(mdp_lut_push_sem);
 static int mdp_lut_i;
 static int mdp_lut_hw_update(struct fb_cmap *cmap)
@@ -211,8 +523,8 @@
 	}
 
 	/*mask off non LUT select bits*/
-	out = inpdw(MDP_BASE + 0x90070) & ~(0x1 << 10);
-	MDP_OUTP(MDP_BASE + 0x90070, (mdp_lut_i << 10) | out);
+	out = inpdw(MDP_BASE + 0x90070) & ~((0x1 << 10) | 0x7);
+	MDP_OUTP(MDP_BASE + 0x90070, (mdp_lut_i << 10) | 0x7 | out);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 	mdp_lut_i = (mdp_lut_i + 1)%2;
 
@@ -225,9 +537,9 @@
 	if (mdp_lut_push) {
 		mutex_lock(&mdp_lut_push_sem);
 		mdp_lut_push = 0;
-		out = inpdw(MDP_BASE + 0x90070) & ~(0x1 << 10);
+		out = inpdw(MDP_BASE + 0x90070) & ~((0x1 << 10) | 0x7);
 		MDP_OUTP(MDP_BASE + 0x90070,
-				(mdp_lut_push_i << 10) | out);
+				(mdp_lut_push_i << 10) | 0x7 | out);
 		mutex_unlock(&mdp_lut_push_sem);
 	}
 }
@@ -237,20 +549,112 @@
 
 #ifdef CONFIG_FB_MSM_MDP40
 unsigned int mdp_hist_frame_cnt;
-struct completion mdp_hist_comp;
-boolean mdp_is_hist_start = FALSE;
 #else
 static unsigned int mdp_hist_frame_cnt;
-static struct completion mdp_hist_comp;
-static boolean mdp_is_hist_start = FALSE;
 #endif
+struct completion mdp_hist_comp;
 static DEFINE_MUTEX(mdp_hist_mutex);
 static boolean mdp_is_hist_data = FALSE;
+static boolean mdp_is_hist_start = FALSE;
+boolean mdp_is_hist_valid = FALSE;
+static boolean mdp_is_hist_init = FALSE;
+static uint32 mdp_hist_r[128];
+static uint32 mdp_hist_g[128];
+static uint32 mdp_hist_b[128];
+
+void __mdp_histogram_kickoff()
+{
+	char *mdp_hist_base;
+
+	if (mdp_rev >= MDP_REV_40)
+		mdp_hist_base = MDP_BASE + 0x95000;
+	else if (mdp_rev >= MDP_REV_30 && mdp_rev <= MDP_REV_31)
+		mdp_hist_base = MDP_BASE + 0x94000;
+	else {
+		pr_err("%s(): Unsupported MDP rev. %u\n", __func__, mdp_rev);
+		return ;
+	}
+
+	if (mdp_is_hist_data == TRUE) {
+		MDP_OUTP(mdp_hist_base + 0x004,	mdp_hist_frame_cnt);
+		MDP_OUTP(mdp_hist_base, 1);
+	}
+}
+
+void __mdp_histogram_reset()
+{
+	char *mdp_hist_base;
+
+	if (mdp_rev >= MDP_REV_40)
+		mdp_hist_base = MDP_BASE + 0x95000;
+	else if (mdp_rev >= MDP_REV_30 && mdp_rev <= MDP_REV_31)
+		mdp_hist_base = MDP_BASE + 0x94000;
+	else {
+		pr_err("%s(): Unsupported MDP rev %u\n", __func__, mdp_rev);
+		return ;
+	}
+
+	MDP_OUTP(mdp_hist_base + 0x00C, 1);
+}
+
+static void mdp_hist_read_work(struct work_struct *data)
+{
+	char *mdp_hist_base;
+	uint32 r_data_offset = 0x100, g_data_offset = 0x200;
+	uint32 b_data_offset = 0x300;
+	int num_bins, i = 0;
+
+	if (mdp_rev >= MDP_REV_42) {
+		mdp_hist_base = MDP_BASE + 0x95000;
+		r_data_offset = 0x400;
+		g_data_offset = 0x800;
+		b_data_offset = 0xc00;
+		num_bins = 128;
+	} else if (mdp_rev >= MDP_REV_40 && mdp_rev <= MDP_REV_41) {
+		mdp_hist_base = MDP_BASE + 0x95000;
+		num_bins = 32;
+	} else if (mdp_rev >= MDP_REV_30 && mdp_rev <= MDP_REV_31) {
+		mdp_hist_base = MDP_BASE + 0x94000;
+		num_bins = 32;
+	} else {
+		pr_err("%s(): Unsupported MDP rev %u\n", __func__, mdp_rev);
+		return ;
+	}
+
+	mutex_lock(&mdp_hist_mutex);
+	if (mdp_is_hist_data == FALSE) {
+		pr_debug("%s, Histogram disabled before read.\n", __func__);
+		goto error;
+	}
+
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	for (i = 0; i < num_bins; i++) {
+		mdp_hist_r[i] = inpdw(mdp_hist_base + r_data_offset + (4*i));
+		mdp_hist_g[i] = inpdw(mdp_hist_base + g_data_offset + (4*i));
+		mdp_hist_b[i] = inpdw(mdp_hist_base + b_data_offset + (4*i));
+	}
+
+	__mdp_histogram_kickoff();
+
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+	/* if read was triggered by an underrun, don't wake up readers*/
+	if (mdp_is_hist_valid && mdp_is_hist_init) {
+		complete(&mdp_hist_comp);
+	} else {
+		if (mdp_is_hist_valid == FALSE)
+			mdp_is_hist_valid = TRUE;
+
+		if (mdp_is_hist_init == FALSE)
+			mdp_is_hist_init = TRUE;
+	}
+error:
+	mutex_unlock(&mdp_hist_mutex);
+}
 
 /*should hold mdp_hist_mutex before calling this function*/
 int _mdp_histogram_ctrl(boolean en)
 {
-	unsigned long flag;
 	unsigned long hist_base;
 	uint32_t status;
 
@@ -266,34 +670,40 @@
 		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 		mdp_hist_frame_cnt = 1;
 		mdp_enable_irq(MDP_HISTOGRAM_TERM);
-		spin_lock_irqsave(&mdp_spin_lock, flag);
-		if (mdp_rev >= MDP_REV_40) {
-			MDP_OUTP(MDP_BASE + hist_base + 0x10, 1);
-			MDP_OUTP(MDP_BASE + hist_base + 0x1c, INTR_HIST_DONE);
-		}
-		spin_unlock_irqrestore(&mdp_spin_lock, flag);
-		MDP_OUTP(MDP_BASE + hist_base + 0x4, mdp_hist_frame_cnt);
-		MDP_OUTP(MDP_BASE + hist_base, 1);
-		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+		INIT_COMPLETION(mdp_hist_comp);
+
+		/*Clear the interrupts before enabling them*/
+		MDP_OUTP(MDP_BASE + hist_base + 0x18, INTR_HIST_DONE |
+						INTR_HIST_RESET_SEQ_DONE);
+		MDP_OUTP(MDP_BASE + hist_base + 0x10, 1);
+		MDP_OUTP(MDP_BASE + hist_base + 0x1c, INTR_HIST_DONE |
+						INTR_HIST_RESET_SEQ_DONE);
+
 		mdp_is_hist_data = TRUE;
+		mdp_is_hist_valid = TRUE;
+		mdp_is_hist_init = FALSE;
+
+		__mdp_histogram_reset();
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
 	} else {
 		if (!mdp_is_hist_data)
 			return -EINVAL;
 
 		mdp_is_hist_data = FALSE;
+		mdp_is_hist_valid = FALSE;
+		mdp_is_hist_init = FALSE;
+
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+		status = inpdw(MDP_BASE + hist_base + 0x1C);
+		status &= ~(INTR_HIST_DONE | INTR_HIST_RESET_SEQ_DONE);
+		MDP_OUTP(MDP_BASE + hist_base + 0x1C, status);
+		MDP_OUTP(MDP_BASE + hist_base + 0x18, INTR_HIST_DONE |
+						INTR_HIST_RESET_SEQ_DONE);
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
 		complete(&mdp_hist_comp);
 
-		if (mdp_rev >= MDP_REV_40) {
-			mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-			status = inpdw(MDP_BASE + hist_base + 0x1C);
-			status &= ~INTR_HIST_DONE;
-			MDP_OUTP(MDP_BASE + hist_base + 0x1C, status);
-
-			MDP_OUTP(MDP_BASE + hist_base + 0x18, INTR_HIST_DONE);
-			mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF,
-									FALSE);
-		}
-
 		mdp_disable_irq(MDP_HISTOGRAM_TERM);
 	}
 
@@ -307,6 +717,10 @@
 	if (mdp_is_hist_start)
 		ret = _mdp_histogram_ctrl(en);
 	mutex_unlock(&mdp_hist_mutex);
+
+	if (en == false)
+		flush_workqueue(mdp_hist_wq);
+
 	return ret;
 }
 
@@ -361,6 +775,10 @@
 
 	ret = _mdp_histogram_ctrl(FALSE);
 
+	mutex_unlock(&mdp_hist_mutex);
+	flush_workqueue(mdp_hist_wq);
+	return ret;
+
 mdp_hist_stop_err:
 	mutex_unlock(&mdp_hist_mutex);
 	return ret;
@@ -369,55 +787,26 @@
 /*call from within mdp_hist_mutex*/
 static int _mdp_copy_hist_data(struct mdp_histogram *hist)
 {
-	char *mdp_hist_base;
-	uint32 r_data_offset = 0x100, g_data_offset = 0x200;
-	uint32 b_data_offset = 0x300;
 	int ret = 0;
 
-	if (mdp_rev >= MDP_REV_42) {
-		mdp_hist_base = MDP_BASE + 0x95000;
-		r_data_offset = 0x400;
-		g_data_offset = 0x800;
-		b_data_offset = 0xc00;
-	} else if (mdp_rev >= MDP_REV_40 && mdp_rev <= MDP_REV_41) {
-		mdp_hist_base = MDP_BASE + 0x95000;
-	} else if (mdp_rev >= MDP_REV_30 && mdp_rev <= MDP_REV_31) {
-		mdp_hist_base = MDP_BASE + 0x94000;
-	} else {
-		pr_err("%s(): Unsupported MDP rev %u\n", __func__, mdp_rev);
-		return -EPERM;
-	}
-
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 	if (hist->r) {
-		ret = copy_to_user(hist->r, mdp_hist_base + r_data_offset,
-			hist->bin_cnt * 4);
+		ret = copy_to_user(hist->r, mdp_hist_r, hist->bin_cnt * 4);
 		if (ret)
 			goto hist_err;
 	}
 	if (hist->g) {
-		ret = copy_to_user(hist->g, mdp_hist_base + g_data_offset,
-			hist->bin_cnt * 4);
+		ret = copy_to_user(hist->g, mdp_hist_g, hist->bin_cnt * 4);
 		if (ret)
 			goto hist_err;
 	}
 	if (hist->b) {
-		ret = copy_to_user(hist->b, mdp_hist_base + b_data_offset,
-			hist->bin_cnt * 4);
+		ret = copy_to_user(hist->b, mdp_hist_b, hist->bin_cnt * 4);
 		if (ret)
 			goto hist_err;
 	}
-
-	if (mdp_is_hist_start == TRUE) {
-		MDP_OUTP(mdp_hist_base + 0x004,
-				mdp_hist_frame_cnt);
-		MDP_OUTP(mdp_hist_base, 1);
-	}
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 	return 0;
-
 hist_err:
-	printk(KERN_ERR "%s: invalid hist buffer\n", __func__);
+	pr_err("%s: invalid hist buffer\n", __func__);
 	return ret;
 }
 
@@ -435,17 +824,17 @@
 
 	mutex_lock(&mdp_hist_mutex);
 	if (!mdp_is_hist_data) {
-		ret = -EINVAL;
-		goto error;
-	}
-
-	if (!mdp_is_hist_start) {
-		printk(KERN_ERR "%s histogram not started\n", __func__);
+		pr_err("%s - histogram not ready\n", __func__);
 		ret = -EPERM;
 		goto error;
 	}
 
-	INIT_COMPLETION(mdp_hist_comp);
+	if (!mdp_is_hist_start) {
+		pr_err("%s histogram not started\n", __func__);
+		ret = -EPERM;
+		goto error;
+	}
+
 	mdp_hist_frame_cnt = hist->frame_cnt;
 	mutex_unlock(&mdp_hist_mutex);
 
@@ -455,8 +844,9 @@
 	}
 
 	mutex_lock(&mdp_hist_mutex);
-	if (mdp_is_hist_data)
+	if (mdp_is_hist_data && mdp_is_hist_init)
 		ret =  _mdp_copy_hist_data(hist);
+
 error:
 	mutex_unlock(&mdp_hist_mutex);
 	return ret;
@@ -818,7 +1208,7 @@
 #ifndef CONFIG_FB_MSM_MDP40
 irqreturn_t mdp_isr(int irq, void *ptr)
 {
-	uint32 mdp_interrupt = 0;
+	uint32 hist_interrupt, mdp_interrupt = 0;
 	struct mdp_dma_data *dma;
 	unsigned long flag;
 
@@ -853,24 +1243,34 @@
 	}
 #ifndef CONFIG_FB_MSM_MDP22
 	if (mdp_interrupt & MDP_HIST_DONE) {
+		hist_interrupt = inp32(MDP_DMA_P_HIST_INTR_STATUS);
 		outp32(MDP_BASE + 0x94018, 0x3);
 		outp32(MDP_INTR_CLEAR, MDP_HIST_DONE);
-		complete(&mdp_hist_comp);
+		if (hist_interrupt & INTR_HIST_RESET_SEQ_DONE)
+			__mdp_histogram_kickoff();
+
+		if (hist_interrupt & INTR_HIST_DONE) {
+			if (waitqueue_active(&mdp_hist_comp.wait)) {
+				if (!queue_work(mdp_hist_wq,
+						&mdp_histogram_worker)) {
+					pr_err("%s: can't queue hist_read\n",
+								__func__);
+				}
+			} else
+				__mdp_histogram_reset();
+		}
 	}
 
 	/* LCDC UnderFlow */
 	if (mdp_interrupt & LCDC_UNDERFLOW) {
 		mdp_lcdc_underflow_cnt++;
 		/*when underflow happens HW resets all the histogram
-		 registers that were set before so restore them back
-		 to normal.*/
+		  registers that were set before so restore them back
+		  to normal.*/
 		MDP_OUTP(MDP_BASE + 0x94010, 1);
-		MDP_OUTP(MDP_BASE + 0x9401c, 2);
-		if (mdp_is_hist_start == TRUE) {
-			MDP_OUTP(MDP_BASE + 0x94004,
-					 mdp_hist_frame_cnt);
-			MDP_OUTP(MDP_BASE + 0x94000, 1);
-		}
+		MDP_OUTP(MDP_BASE + 0x9401c, INTR_HIST_DONE);
+		mdp_is_hist_valid = FALSE;
+		__mdp_histogram_reset();
 	}
 
 	/* LCDC Frame Start */
@@ -969,6 +1369,8 @@
 	spin_lock_init(&mdp_spin_lock);
 	mdp_dma_wq = create_singlethread_workqueue("mdp_dma_wq");
 	mdp_vsync_wq = create_singlethread_workqueue("mdp_vsync_wq");
+	mdp_hist_wq = create_singlethread_workqueue("mdp_hist_wq");
+	INIT_WORK(&mdp_histogram_worker, mdp_hist_read_work);
 	mdp_pipe_ctrl_wq = create_singlethread_workqueue("mdp_pipe_ctrl_wq");
 	INIT_DELAYED_WORK(&mdp_pipe_ctrl_worker,
 			  mdp_pipe_ctrl_workqueue_handler);
@@ -1009,8 +1411,6 @@
 	mutex_init(&dma_wb_data.ov_mutex);
 #endif
 
-
-
 #ifndef CONFIG_FB_MSM_MDP22
 	init_completion(&mdp_hist_comp);
 #endif
@@ -1128,7 +1528,6 @@
 	}
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 #endif
-	mdp_histogram_ctrl(TRUE);
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 	ret = panel_next_on(pdev);
@@ -1141,6 +1540,7 @@
 		mdp4_mddi_overlay_restore();
 #endif
 
+	mdp_histogram_ctrl(TRUE);
 	return ret;
 }
 
@@ -1444,6 +1844,9 @@
 	mfd->ov0_blt_state  = 0;
 	mfd->use_ov0_blt = 0 ;
 
+    /* initialize Post Processing data*/
+	mdp_hist_lut_init();
+
 	/* add panel data */
 	if (platform_device_add_data
 	    (msm_fb_dev, pdev->dev.platform_data,
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 35a1453..6c5a9f9 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -44,6 +44,10 @@
 extern int mdp_rev;
 extern struct mdp_csc_cfg mdp_csc_convert[4];
 
+extern struct workqueue_struct *mdp_hist_wq;
+extern struct work_struct mdp_histogram_worker;
+extern boolean mdp_is_hist_valid;
+
 #define MDP4_REVISION_V1		0
 #define MDP4_REVISION_V2		1
 #define MDP4_REVISION_V2_1	2
@@ -221,6 +225,20 @@
 	struct completion dmap_comp;
 };
 
+extern struct list_head mdp_hist_lut_list;
+extern struct mutex mdp_hist_lut_list_mutex;
+struct mdp_hist_lut_mgmt {
+	uint32_t block;
+	struct mutex lock;
+	struct list_head list;
+};
+
+struct mdp_hist_lut_info {
+	uint32_t block;
+	boolean is_enabled, has_sel_update;
+	int bank_sel;
+};
+
 #define MDP_CMD_DEBUG_ACCESS_BASE   (MDP_BASE+0x10000)
 
 #define MDP_DMA2_TERM 0x1
@@ -606,6 +624,10 @@
 #define MDP_EBI2_LCD0		(msm_mdp_base + 0x003c)
 #define MDP_EBI2_LCD1		(msm_mdp_base + 0x0040)
 #define MDP_EBI2_PORTMAP_MODE	(msm_mdp_base + 0x005c)
+
+#define MDP_DMA_P_HIST_INTR_STATUS	(msm_mdp_base + 0x94014)
+#define MDP_DMA_P_HIST_INTR_CLEAR	(msm_mdp_base + 0x94018)
+#define MDP_DMA_P_HIST_INTR_ENABLE	(msm_mdp_base + 0x9401C)
 #endif
 
 #define MDP_FULL_BYPASS_WORD43  (msm_mdp_base + 0x101ac)
@@ -733,6 +755,8 @@
 int mdp_start_histogram(struct fb_info *info);
 int mdp_stop_histogram(struct fb_info *info);
 int mdp_histogram_ctrl(boolean en);
+void __mdp_histogram_kickoff(void);
+void __mdp_histogram_reset(void);
 void mdp_footswitch_ctrl(boolean on);
 
 #ifdef CONFIG_FB_MSM_MDP303
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index b72350d..f7f48e4 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -20,7 +20,6 @@
 extern struct mdp_dma_data dma_wb_data;
 extern unsigned int mdp_hist_frame_cnt;
 extern struct completion mdp_hist_comp;
-extern boolean mdp_is_hist_start;
 extern boolean mdp_is_in_isr;
 extern uint32 mdp_intr_mask;
 extern spinlock_t mdp_spin_lock;
@@ -708,6 +707,9 @@
 int mdp4_writeback_init(struct fb_info *info);
 int mdp4_writeback_terminate(struct fb_info *info);
 
+uint32_t mdp_block2base(uint32_t block);
+int mdp_hist_lut_config(struct mdp_hist_lut_data *data);
+
 void mdp4_hsic_set(struct mdp4_overlay_pipe *pipe, struct dpp_ctrl *ctrl);
 void mdp4_hsic_update(struct mdp4_overlay_pipe *pipe);
 int mdp4_csc_config(struct mdp_csc_cfg_data *config);
@@ -720,4 +722,5 @@
 void mdp4_init_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num);
 void mdp4_free_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num);
 
+int mdp4_igc_lut_config(struct mdp_igc_lut_data *cfg);
 #endif /* MDP_H */
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index aa383e0..3ca8c9c 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -277,6 +277,7 @@
 void mdp4_overlay_dmap_cfg(struct msm_fb_data_type *mfd, int lcdc)
 {
 	uint32	dma2_cfg_reg;
+	uint32 mask, curr;
 
 	dma2_cfg_reg = DMA_DITHER_EN;
 #ifdef BLT_RGB565
@@ -309,6 +310,9 @@
 #endif
 
 	/* dma2 config register */
+	curr = inpdw(MDP_BASE + 0x90000);
+	mask = 0xBFFFFFFF;
+	dma2_cfg_reg = (dma2_cfg_reg & mask) | (curr & ~mask);
 	MDP_OUTP(MDP_BASE + 0x90000, dma2_cfg_reg);
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
@@ -442,6 +446,7 @@
 	char *rgb_base;
 	uint32 src_size, src_xy, dst_size, dst_xy;
 	uint32 format, pattern;
+	uint32 curr, mask;
 	uint32 offset = 0;
 	int pnum;
 
@@ -473,6 +478,12 @@
 
 	mdp4_scale_setup(pipe);
 
+	/* Ensure proper covert matrix loaded when color space swaps */
+	curr = inpdw(rgb_base + 0x0058);
+	/* Don't touch bits you don't want to configure*/
+	mask = 0xFFFEFFFF;
+	pipe->op_mode = (pipe->op_mode & mask) | (curr & ~mask);
+
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 
 	outpdw(rgb_base + 0x0000, src_size);	/* MDP_RGB_SRC_SIZE */
@@ -558,7 +569,7 @@
 	char *vg_base;
 	uint32 frame_size, src_size, src_xy, dst_size, dst_xy;
 	uint32 format, pattern, luma_offset, chroma_offset;
-	uint32 mask, curr;
+	uint32 mask, curr, addr;
 	int pnum, ptype;
 
 	pnum = pipe->pipe_num - OVERLAY_PIPE_VG1; /* start from 0 */
@@ -625,13 +636,20 @@
 	/* Ensure proper covert matrix loaded when color space swaps */
 	curr = inpdw(vg_base + 0x0058);
 	mask = 0x600;
+
 	if ((curr & mask) != (pipe->op_mode & mask)) {
-		curr = ((uint32_t)vg_base) + 0x4000;
+		addr = ((uint32_t)vg_base) + 0x4000;
 		if (ptype != OVERLAY_TYPE_RGB)
-			mdp4_csc_write(&(mdp_csc_convert[1]), curr);
+			mdp4_csc_write(&(mdp_csc_convert[1]), addr);
 		else
-			mdp4_csc_write(&(mdp_csc_convert[0]), curr);
+			mdp4_csc_write(&(mdp_csc_convert[0]), addr);
+
+		mask = 0xFFFCFFFF;
+	} else {
+		/* Don't touch bits you don't want to configure*/
+		mask = 0xFFFCF1FF;
 	}
+	pipe->op_mode = (pipe->op_mode & mask) | (curr & ~mask);
 
 	/* luma component plane */
 	outpdw(vg_base + 0x0010, pipe->srcp0_addr + luma_offset);
@@ -2037,7 +2055,8 @@
 	}
 }
 
-static uint32 mdp4_overlay_get_perf_level(struct mdp_overlay *req)
+static uint32 mdp4_overlay_get_perf_level(struct mdp_overlay *req,
+					  struct msm_fb_data_type *mfd)
 {
 	int is_fg;
 
@@ -2061,9 +2080,18 @@
 		return OVERLAY_PERF_LEVEL1;
 
 	if (req->src.width*req->src.height <= OVERLAY_VGA_SIZE)
-		return OVERLAY_PERF_LEVEL3;
-	else if (req->src.width*req->src.height <= OVERLAY_720P_TILE_SIZE)
-		return OVERLAY_PERF_LEVEL2;
+		return OVERLAY_PERF_LEVEL4;
+	else if (req->src.width*req->src.height <= OVERLAY_720P_TILE_SIZE) {
+		u32 max, min;
+		max = (req->dst_rect.h > req->dst_rect.w) ?
+			req->dst_rect.h : req->dst_rect.w;
+		min = (mfd->panel_info.yres > mfd->panel_info.xres) ?
+			mfd->panel_info.xres : mfd->panel_info.yres;
+		if (max > min)	/* landscape mode */
+			return OVERLAY_PERF_LEVEL3;
+		else		/* potrait mode */
+			return OVERLAY_PERF_LEVEL2;
+	}
 	else
 		return OVERLAY_PERF_LEVEL1;
 }
@@ -2169,7 +2197,7 @@
 		return -EINTR;
 	}
 
-	perf_level = mdp4_overlay_get_perf_level(req);
+	perf_level = mdp4_overlay_get_perf_level(req, mfd);
 
 	mixer = mfd->panel_info.pdest;	/* DISPLAY_1 or DISPLAY_2 */
 
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index 2876d9f..b69a2fc 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -296,12 +296,6 @@
 	bits =  mdp_intr_mask;
 	outpdw(MDP_BASE + 0x0050, bits);/* enable specififed interrupts */
 
-	/* histogram */
-	MDP_OUTP(MDP_BASE + 0x95010, 1);	/* auto clear HIST */
-
-	/* enable histogram interrupts */
-	outpdw(MDP_BASE + 0x9501c, INTR_HIST_DONE);
-
 	/* For the max read pending cmd config below, if the MDP clock     */
 	/* is less than the AXI clock, then we must use 3 pending          */
 	/* pending requests.  Otherwise, we should use 8 pending requests. */
@@ -386,11 +380,8 @@
 		that histogram works.*/
 		MDP_OUTP(MDP_BASE + 0x95010, 1);
 		outpdw(MDP_BASE + 0x9501c, INTR_HIST_DONE);
-		if (mdp_is_hist_start == TRUE) {
-			MDP_OUTP(MDP_BASE + 0x95004,
-					mdp_hist_frame_cnt);
-			MDP_OUTP(MDP_BASE + 0x95000, 1);
-		}
+		mdp_is_hist_valid = FALSE;
+		__mdp_histogram_reset();
 	}
 
 	if (isr & INTR_EXTERNAL_INTF_UDERRUN)
@@ -569,16 +560,18 @@
 		outpdw(MDP_DMA_P_HIST_INTR_CLEAR, isr);
 		mb();
 		isr &= mask;
+		if (isr & INTR_HIST_RESET_SEQ_DONE)
+			__mdp_histogram_kickoff();
+
 		if (isr & INTR_HIST_DONE) {
-			if (waitqueue_active(&(mdp_hist_comp.wait))) {
-				complete(&mdp_hist_comp);
-			} else {
-				if (mdp_is_hist_start == TRUE) {
-					MDP_OUTP(MDP_BASE + 0x95004,
-							mdp_hist_frame_cnt);
-					MDP_OUTP(MDP_BASE + 0x95000, 1);
+			if (waitqueue_active(&mdp_hist_comp.wait)) {
+				if (!queue_work(mdp_hist_wq,
+						&mdp_histogram_worker)) {
+					pr_err("%s - can't queue hist_read\n",
+							__func__);
 				}
-			}
+			} else
+				__mdp_histogram_reset();
 		}
 	}
 
@@ -2996,3 +2989,144 @@
 	return ret;
 }
 
+static uint32_t mdp4_pp_block2igc(uint32_t block)
+{
+	uint32_t valid = 0;
+	switch (block) {
+	case MDP_BLOCK_VG_1:
+		valid = 0x1;
+		break;
+	case MDP_BLOCK_VG_2:
+		valid = 0x1;
+		break;
+	case MDP_BLOCK_RGB_1:
+		valid = 0x1;
+		break;
+	case MDP_BLOCK_RGB_2:
+		valid = 0x1;
+		break;
+	case MDP_BLOCK_DMA_P:
+		valid = (mdp_rev >= MDP_REV_40) ? 1 : 0;
+		break;
+	case MDP_BLOCK_DMA_S:
+		valid = (mdp_rev >= MDP_REV_40) ? 1 : 0;
+		break;
+	default:
+		break;
+	}
+	return valid;
+}
+
+static int mdp4_igc_lut_write(struct mdp_igc_lut_data *cfg, uint32_t en_off,
+		uint32_t lut_off)
+{
+	int i;
+	uint32_t base, *off_low, *off_high;
+	uint32_t low[cfg->len];
+	uint32_t high[cfg->len];
+
+	base = mdp_block2base(cfg->block);
+
+	if (cfg->len != 256)
+		return -EINVAL;
+
+	off_low = (uint32_t *)(MDP_BASE + base + lut_off);
+	off_high = (uint32_t *)(MDP_BASE + base + lut_off + 0x800);
+	if (copy_from_user(&low, cfg->c0_c1_data, cfg->len * sizeof(uint32_t)))
+		return -EFAULT;
+	if (copy_from_user(&high, cfg->c2_data, cfg->len * sizeof(uint32_t)))
+		return -EFAULT;
+
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	for (i = 0; i < cfg->len; i++) {
+		MDP_OUTP(off_low++, low[i]);
+		/*low address write should occur before high address write*/
+		wmb();
+		MDP_OUTP(off_high++, high[i]);
+	}
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+	return 0;
+}
+
+static int mdp4_igc_lut_ctrl(struct mdp_igc_lut_data *cfg)
+{
+	uint32_t mask, out;
+	uint32_t base = mdp_block2base(cfg->block);
+	int8_t shift = 0;
+
+	switch (cfg->block) {
+	case MDP_BLOCK_DMA_P:
+	case MDP_BLOCK_DMA_S:
+		base = base;
+		shift = 30;
+		break;
+	case MDP_BLOCK_VG_1:
+	case MDP_BLOCK_VG_2:
+	case MDP_BLOCK_RGB_1:
+	case MDP_BLOCK_RGB_2:
+		base += 0x58;
+		shift = 16;
+		break;
+	default:
+		return -EINVAL;
+
+	}
+	out = 1<<shift;
+	mask = ~out;
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	out = inpdw(MDP_BASE + base) & mask;
+	MDP_OUTP(MDP_BASE + base, out | ((cfg->ops & 0x1)<<shift));
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+	return 0;
+}
+
+static int mdp4_igc_lut_write_cfg(struct mdp_igc_lut_data *cfg)
+{
+	int ret = 0;
+
+	switch (cfg->block) {
+	case MDP_BLOCK_DMA_P:
+	case MDP_BLOCK_DMA_S:
+		ret = mdp4_igc_lut_write(cfg, 0x00, 0x9000);
+		break;
+	case MDP_BLOCK_VG_1:
+	case MDP_BLOCK_VG_2:
+	case MDP_BLOCK_RGB_1:
+	case MDP_BLOCK_RGB_2:
+		ret = mdp4_igc_lut_write(cfg, 0x58, 0x5000);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+int mdp4_igc_lut_config(struct mdp_igc_lut_data *cfg)
+{
+	int ret = 0;
+
+	if (!mdp4_pp_block2igc(cfg->block)) {
+		ret = -ENOTTY;
+		goto error;
+	}
+
+	switch ((cfg->ops & 0x6) >> 1) {
+	case 0x1:
+		pr_info("%s: IGC LUT read not supported\n", __func__);
+		break;
+	case 0x2:
+		ret = mdp4_igc_lut_write_cfg(cfg);
+		if (ret)
+			goto error;
+		break;
+	default:
+		break;
+	}
+
+	ret = mdp4_igc_lut_ctrl(cfg);
+
+error:
+	return ret;
+}
diff --git a/drivers/video/msm/mdp_dma_dsi_video.c b/drivers/video/msm/mdp_dma_dsi_video.c
index 0e76a07..3c89d8b 100644
--- a/drivers/video/msm/mdp_dma_dsi_video.c
+++ b/drivers/video/msm/mdp_dma_dsi_video.c
@@ -75,6 +75,7 @@
 	struct msm_fb_data_type *mfd;
 	struct msm_panel_info *panel_info;
 	int ret;
+	uint32 mask, curr;
 
 	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
 	panel_info = &mfd->panel_info;
@@ -163,6 +164,9 @@
 	MDP_OUTP(MDP_BASE + DMA_P_BASE + 0x10, 0);
 
 	/* dma config */
+	curr = inpdw(MDP_BASE + 0x90000);
+	mask = 0xBFFFFFFF;
+	dma2_cfg_reg = (dma2_cfg_reg & mask) | (curr & ~mask);
 	MDP_OUTP(MDP_BASE + DMA_P_BASE, dma2_cfg_reg);
 
 	/*
diff --git a/drivers/video/msm/mdp_hw_init.c b/drivers/video/msm/mdp_hw_init.c
index 8f8b4d3..ff3ad41 100644
--- a/drivers/video/msm/mdp_hw_init.c
+++ b/drivers/video/msm/mdp_hw_init.c
@@ -635,8 +635,6 @@
 	MDP_OUTP(MDP_BASE + 0xE0000, 0);
 	MDP_OUTP(MDP_BASE + 0x100, 0xffffffff);
 	MDP_OUTP(MDP_BASE + 0x90070, 0);
-	MDP_OUTP(MDP_BASE + 0x94010, 1);
-	MDP_OUTP(MDP_BASE + 0x9401c, 2);
 #endif
 
 	/*
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 69e0423..593f10b 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -2952,6 +2952,9 @@
 	case mdp_op_lut_cfg:
 		switch (pp_ptr->data.lut_cfg_data.lut_type) {
 		case mdp_lut_igc:
+			ret = mdp4_igc_lut_config(
+					(struct mdp_igc_lut_data *)
+					&pp_ptr->data.lut_cfg_data.data);
 			break;
 
 		case mdp_lut_pgc:
@@ -2960,6 +2963,9 @@
 			break;
 
 		case mdp_lut_hist:
+			ret = mdp_hist_lut_config(
+					(struct mdp_hist_lut_data *)
+					&pp_ptr->data.lut_cfg_data.data);
 			break;
 
 		default:
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_api.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_api.h
index 51a0d13..433dad4 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_api.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_api.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -14,8 +14,8 @@
 #ifndef _VCD_DDL_API_H_
 #define _VCD_DDL_API_H_
 
+#include <media/msm/vcd_api.h>
 #include "vidc.h"
-#include "vcd_api.h"
 
 #define VCD_EVT_RESP_DDL_BASE             0x3000
 #define VCD_EVT_RESP_DEVICE_INIT          (VCD_EVT_RESP_DDL_BASE + 0x1)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
index 42a991c..10b3404 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -15,7 +15,7 @@
 #define _VCD_DDL_UTILS_H_
 
 #include <linux/delay.h>
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 
 extern u32 vidc_msg_pmem;
 extern u32 vidc_msg_timing;
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
index c32ac81..8851b52 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
@@ -21,9 +21,9 @@
 #include <linux/interrupt.h>
 #include <linux/memory_alloc.h>
 #include <asm/sizes.h>
+#include <media/msm/vidc_init.h>
 #include "vidc.h"
 #include "vcd_res_tracker.h"
-#include "vidc_init.h"
 
 static unsigned int vidc_clk_table[3] = {
 	48000000, 133330000, 200000000
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c
index 7c68d63..02b2369 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd_ddl_utils.h"
 #include "vcd_ddl_metadata.h"
 #include "vcd_res_tracker_api.h"
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_errors.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_errors.c
index eb08b7e..ac5bce9 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_errors.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_errors.c
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd_ddl_utils.h"
 #include "vcd_ddl.h"
 
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_firmware.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_firmware.c
index 25aa6bc..965c3aa 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_firmware.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_firmware.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd_ddl_firmware.h"
 #include "vcd_ddl_utils.h"
 
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_firmware.h b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_firmware.h
index 7952dfb..a136de8 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_firmware.h
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_firmware.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,7 +12,7 @@
  */
 #ifndef _VCD_DDL_FIRMWARE_H_
 #define _VCD_DDL_FIRMWARE_H_
-#include "vcd_property.h"
+#include <media/msm/vcd_property.h>
 
 #define VCD_FW_BIG_ENDIAN     0x0
 #define VCD_FW_LITTLE_ENDIAN  0x1
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_hal.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_hal.c
index f09bd71..6a69955 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_hal.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_hal.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 
 #include "vcd_ddl_utils.h"
 #include "vcd_ddl_metadata.h"
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_helper.c
index 2ec8419..15adf21 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_helper.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd_ddl_utils.h"
 
 DDL_INLINE struct ddl_context *ddl_get_context(void)
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_internal_property.h b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_internal_property.h
index 00c00cd..9dc495b 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_internal_property.h
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_internal_property.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,7 +12,7 @@
  */
 #ifndef _VCD_DDL_INTERNAL_PROPERTY_H_
 #define _VCD_DDL_INTERNAL_PROPERTY_H_
-#include "vcd_api.h"
+#include <media/msm/vcd_api.h>
 
 #define VCD_EVT_RESP_DDL_BASE          0x3000
 #define VCD_EVT_RESP_DEVICE_INIT       (VCD_EVT_RESP_DDL_BASE + 0x1)
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_interrupt_handler.c
index ece4c30..fe71dc1 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_interrupt_handler.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vidc.h"
 #include "vcd_ddl_utils.h"
 #include "vcd_ddl_metadata.h"
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_metadata.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_metadata.c
index 376ea6d..2a74da8 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_metadata.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_metadata.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd_ddl_utils.h"
 #include "vcd_ddl_metadata.h"
 
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_properties.c
index 6d3c666..3aebdaf 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_properties.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd_ddl_utils.h"
 #include "vcd_ddl_metadata.h"
 
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c
index c8ea83f..17dedb8 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -11,7 +11,7 @@
  *
  */
 #include <linux/memory_alloc.h>
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd_ddl_utils.h"
 
 #if DEBUG
diff --git a/drivers/video/msm/vidc/720p/ddl/vidc.c b/drivers/video/msm/vidc/720p/ddl/vidc.c
index 0f5932a..de6cbbb 100644
--- a/drivers/video/msm/vidc/720p/ddl/vidc.c
+++ b/drivers/video/msm/vidc/720p/ddl/vidc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,8 +12,8 @@
  */
 
 #include <linux/unistd.h>
+#include <media/msm/vidc_type.h>
 #include "vidc.h"
-#include "vidc_type.h"
 
 #if DEBUG
 #define DBG(x...) printk(KERN_DEBUG x)
diff --git a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
index 522ff16..86bf397 100644
--- a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
@@ -16,9 +16,9 @@
 #include <linux/regulator/consumer.h>
 #include <mach/clk.h>
 #include <linux/interrupt.h>
-#include "vidc_type.h"
+#include <media/msm/vidc_init.h>
+#include <media/msm/vidc_type.h>
 #include "vcd_res_tracker.h"
-#include "vidc_init.h"
 
 #define MSM_AXI_QOS_NAME "msm_vidc_reg"
 #define AXI_CLK_SCALING
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
index dee4da7..bfaac82 100644
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -29,11 +29,11 @@
 #include <linux/clk.h>
 #include <linux/timer.h>
 #include <mach/msm_subsystem_map.h>
+#include <media/msm/vidc_type.h>
+#include <media/msm/vcd_api.h>
+#include <media/msm/vidc_init.h>
 #include "vcd_res_tracker_api.h"
-#include "vidc_type.h"
-#include "vcd_api.h"
 #include "vdec_internal.h"
-#include "vidc_init.h"
 
 
 
diff --git a/drivers/video/msm/vidc/common/dec/vdec_internal.h b/drivers/video/msm/vidc/common/dec/vdec_internal.h
index f310e25..89da9a2 100644
--- a/drivers/video/msm/vidc/common/dec/vdec_internal.h
+++ b/drivers/video/msm/vidc/common/dec/vdec_internal.h
@@ -16,7 +16,7 @@
 
 #include <linux/msm_vidc_dec.h>
 #include <linux/cdev.h>
-#include "vidc_init.h"
+#include <media/msm/vidc_init.h>
 
 #define NUM_OF_DRIVER_NODES 2
 
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
index cc6606c..6d6dcdc 100644
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -27,11 +27,11 @@
 #include <linux/workqueue.h>
 #include <linux/android_pmem.h>
 #include <linux/clk.h>
+#include <media/msm/vidc_type.h>
+#include <media/msm/vcd_api.h>
+#include <media/msm/vidc_init.h>
 
-#include "vidc_type.h"
-#include "vcd_api.h"
 #include "venc_internal.h"
-#include "vidc_init.h"
 #include "vcd_res_tracker_api.h"
 
 #define VID_ENC_NAME	"msm_vidc_enc"
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c
index e3bb9db..f362f7b 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.c
@@ -28,10 +28,10 @@
 #include <linux/android_pmem.h>
 #include <linux/clk.h>
 #include <mach/msm_subsystem_map.h>
-#include "vidc_type.h"
-#include "vcd_api.h"
+#include <media/msm/vidc_type.h>
+#include <media/msm/vcd_api.h>
+#include <media/msm/vidc_init.h>
 #include "venc_internal.h"
-#include "vidc_init.h"
 
 #if DEBUG
 #define DBG(x...) printk(KERN_DEBUG x)
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.h b/drivers/video/msm/vidc/common/enc/venc_internal.h
index 2b5a532..a07f7ab 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.h
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -16,8 +16,7 @@
 
 #include <linux/msm_vidc_enc.h>
 #include <linux/cdev.h>
-
-#include "vidc_init.h"
+#include <media/msm/vidc_init.h>
 
 #define VID_ENC_MAX_NUM_OF_BUFF 100
 
diff --git a/drivers/video/msm/vidc/common/init/vidc_init.c b/drivers/video/msm/vidc/common/init/vidc_init.c
index f799a6c..0ea64d4 100644
--- a/drivers/video/msm/vidc/common/init/vidc_init.c
+++ b/drivers/video/msm/vidc/common/init/vidc_init.c
@@ -31,9 +31,9 @@
 #include <mach/clk.h>
 #include <linux/pm_runtime.h>
 #include <mach/msm_subsystem_map.h>
-#include "vcd_api.h"
+#include <media/msm/vcd_api.h>
+#include <media/msm/vidc_init.h>
 #include "vidc_init_internal.h"
-#include "vidc_init.h"
 #include "vcd_res_tracker_api.h"
 
 #if DEBUG
diff --git a/drivers/video/msm/vidc/common/init/vidc_init.h b/drivers/video/msm/vidc/common/init/vidc_init.h
deleted file mode 100644
index a67329c..0000000
--- a/drivers/video/msm/vidc/common/init/vidc_init.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only 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.
- *
- */
-
-#ifndef VIDC_INIT_H
-#define VIDC_INIT_H
-#include <linux/ion.h>
-#include "vidc_type.h"
-
-#define VIDC_MAX_NUM_CLIENTS 4
-#define MAX_VIDEO_NUM_OF_BUFF 100
-
-enum buffer_dir {
-	BUFFER_TYPE_INPUT,
-	BUFFER_TYPE_OUTPUT
-};
-
-struct buf_addr_table {
-	unsigned long user_vaddr;
-	unsigned long kernel_vaddr;
-	unsigned long phy_addr;
-	unsigned long buff_ion_flag;
-	struct ion_handle *buff_ion_handle;
-	int pmem_fd;
-	struct file *file;
-	unsigned long dev_addr;
-	void *client_data;
-};
-
-struct video_client_ctx {
-	void *vcd_handle;
-	u32 num_of_input_buffers;
-	u32 num_of_output_buffers;
-	struct buf_addr_table input_buf_addr_table[MAX_VIDEO_NUM_OF_BUFF];
-	struct buf_addr_table output_buf_addr_table[MAX_VIDEO_NUM_OF_BUFF];
-	struct list_head msg_queue;
-	struct mutex msg_queue_lock;
-	struct mutex enrty_queue_lock;
-	wait_queue_head_t msg_wait;
-	struct completion event;
-	struct vcd_property_h264_mv_buffer vcd_h264_mv_buffer;
-	struct vcd_property_enc_recon_buffer recon_buffer[4];
-	u32 event_status;
-	u32 seq_header_set;
-	u32 stop_msg;
-	u32 stop_called;
-	u32 stop_sync_cb;
-	struct ion_client *user_ion_client;
-	struct ion_handle *seq_hdr_ion_handle;
-	struct ion_handle *h264_mv_ion_handle;
-	struct ion_handle *recon_buffer_ion_handle[4];
-	u32 dmx_disable;
-};
-
-void __iomem *vidc_get_ioaddr(void);
-int vidc_load_firmware(void);
-void vidc_release_firmware(void);
-u32 vidc_get_fd_info(struct video_client_ctx *client_ctx,
-		enum buffer_dir buffer, int pmem_fd,
-		unsigned long kvaddr, int index);
-u32 vidc_lookup_addr_table(struct video_client_ctx *client_ctx,
-	enum buffer_dir buffer, u32 search_with_user_vaddr,
-	unsigned long *user_vaddr, unsigned long *kernel_vaddr,
-	unsigned long *phy_addr, int *pmem_fd, struct file **file,
-	s32 *buffer_index);
-u32 vidc_insert_addr_table(struct video_client_ctx *client_ctx,
-	enum buffer_dir buffer, unsigned long user_vaddr,
-	unsigned long *kernel_vaddr, int pmem_fd,
-	unsigned long buffer_addr_offset,
-	unsigned int max_num_buffers, unsigned long length);
-u32 vidc_delete_addr_table(struct video_client_ctx *client_ctx,
-	enum buffer_dir buffer, unsigned long user_vaddr,
-	unsigned long *kernel_vaddr);
-void vidc_cleanup_addr_table(struct video_client_ctx *client_ctx,
-				enum buffer_dir buffer);
-
-u32 vidc_timer_create(void (*timer_handler)(void *),
-	void *user_data, void **timer_handle);
-void  vidc_timer_release(void *timer_handle);
-void  vidc_timer_start(void *timer_handle, u32 time_out);
-void  vidc_timer_stop(void *timer_handle);
-
-
-#endif
diff --git a/drivers/video/msm/vidc/common/vcd/vcd.h b/drivers/video/msm/vidc/common/vcd/vcd.h
index b557752..9fc76d8 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -13,10 +13,10 @@
 #ifndef _VCD_H_
 #define _VCD_H_
 
-#include "vcd_api.h"
+#include <media/msm/vcd_api.h>
+#include "vcd_util.h"
 #include "vcd_ddl_api.h"
 #include "vcd_res_tracker_api.h"
-#include "vcd_util.h"
 #include "vcd_client_sm.h"
 #include "vcd_core.h"
 #include "vcd_device_sm.h"
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_api.c b/drivers/video/msm/vidc/common/vcd/vcd_api.c
index 5e9fd55..e0ef3af 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_api.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_api.c
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd.h"
 
 u32 vcd_init(struct vcd_init_config *config, s32 *driver_handle)
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_api.h b/drivers/video/msm/vidc/common/vcd/vcd_api.h
deleted file mode 100644
index 9580ece..0000000
--- a/drivers/video/msm/vidc/common/vcd/vcd_api.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only 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.
- *
- */
-#ifndef _VCD_API_H_
-#define _VCD_API_H_
-#include "vcd_property.h"
-#include "vcd_status.h"
-
-#define VCD_FRAME_FLAG_EOS 0x00000001
-#define VCD_FRAME_FLAG_DECODEONLY   0x00000004
-#define VCD_FRAME_FLAG_DATACORRUPT 0x00000008
-#define VCD_FRAME_FLAG_ENDOFFRAME 0x00000010
-#define VCD_FRAME_FLAG_SYNCFRAME 0x00000020
-#define VCD_FRAME_FLAG_EXTRADATA 0x00000040
-#define VCD_FRAME_FLAG_CODECCONFIG  0x00000080
-#define VCD_FRAME_FLAG_BFRAME 0x00100000
-#define VCD_FRAME_FLAG_EOSEQ 0x00200000
-
-#define VCD_FLUSH_INPUT   0x0001
-#define VCD_FLUSH_OUTPUT  0x0002
-#define VCD_FLUSH_ALL     0x0003
-
-#define VCD_FRAMETAG_INVALID  0xffffffff
-
-struct vcd_handle_container {
-	void *handle;
-};
-struct vcd_flush_cmd {
-	u32 mode;
-};
-
-enum vcd_frame {
-	VCD_FRAME_YUV = 1,
-	VCD_FRAME_I,
-	VCD_FRAME_P,
-	VCD_FRAME_B,
-	VCD_FRAME_NOTCODED,
-	VCD_FRAME_IDR,
-	VCD_FRAME_32BIT = 0x7fffffff
-};
-
-enum vcd_power_state {
-	VCD_PWR_STATE_ON = 1,
-	VCD_PWR_STATE_SLEEP,
-};
-
-struct vcd_frame_data {
-	u8 *virtual;
-	u8 *physical;
-	u32 ion_flag;
-	u32 alloc_len;
-	u32 data_len;
-	u32 offset;
-	s64 time_stamp;
-	u32 flags;
-	u32 frm_clnt_data;
-	struct vcd_property_dec_output_buffer dec_op_prop;
-	u32 interlaced;
-	enum vcd_frame frame;
-	u32 ip_frm_tag;
-	u32 intrlcd_ip_frm_tag;
-	u8 *desc_buf;
-	u32 desc_size;
-};
-
-struct vcd_sequence_hdr {
-	u8 *sequence_header;
-	u32 sequence_header_len;
-
-};
-
-enum vcd_buffer_type {
-	VCD_BUFFER_INPUT = 0x1,
-	VCD_BUFFER_OUTPUT = 0x2,
-	VCD_BUFFER_INVALID = 0x3,
-	VCD_BUFFER_32BIT = 0x7FFFFFFF
-};
-
-struct vcd_buffer_requirement {
-	u32 min_count;
-	u32 actual_count;
-	u32 max_count;
-	size_t sz;
-	u32 align;
-	u32 buf_pool_id;
-};
-
-struct vcd_init_config {
-	void *device_name;
-	void *(*map_dev_base_addr) (void *device_name);
-	void (*un_map_dev_base_addr) (void);
-	void (*interrupt_clr) (void);
-	void (*register_isr) (void *device_name);
-	void (*deregister_isr) (void);
-	u32  (*timer_create) (void (*timer_handler)(void *),
-		void *user_data, void **timer_handle);
-	void (*timer_release) (void *timer_handle);
-	void (*timer_start) (void *timer_handle, u32 time_out);
-	void (*timer_stop) (void *timer_handle);
-};
-
-u32 vcd_init(struct vcd_init_config *config, s32 *driver_handle);
-u32 vcd_term(s32 driver_handle);
-u32 vcd_open(s32 driver_handle, u32 decoding,
-	void (*callback) (u32 event, u32 status, void *info, size_t sz,
-	void *handle, void *const client_data), void *client_data);
-u32 vcd_close(void *handle);
-u32 vcd_encode_start(void *handle);
-u32 vcd_encode_frame(void *handle, struct vcd_frame_data *input_frame);
-u32 vcd_decode_start(void *handle, struct vcd_sequence_hdr *seq_hdr);
-u32 vcd_decode_frame(void *handle, struct vcd_frame_data *input_frame);
-u32 vcd_pause(void *handle);
-u32 vcd_resume(void *handle);
-u32 vcd_flush(void *handle, u32 mode);
-u32 vcd_stop(void *handle);
-u32 vcd_set_property(void *handle, struct vcd_property_hdr *prop_hdr,
-					void *prop_val);
-u32 vcd_get_property(void *handle, struct vcd_property_hdr *prop_hdr,
-					 void *prop_val);
-u32 vcd_set_buffer_requirements(void *handle, enum vcd_buffer_type buffer,
-		struct vcd_buffer_requirement *buffer_req);
-u32 vcd_get_buffer_requirements(void *handle, enum vcd_buffer_type buffer,
-		struct vcd_buffer_requirement *buffer_req);
-u32 vcd_set_buffer(void *handle, enum vcd_buffer_type buffer_type,
-		u8 *buffer, u32 buf_size);
-u32 vcd_allocate_buffer(void *handle, enum vcd_buffer_type buffer,
-		u32 buf_size, u8 **vir_buf_addr, u8 **phy_buf_addr);
-
-u32 vcd_free_buffer(void *handle, enum vcd_buffer_type buffer_type, u8 *buffer);
-u32 vcd_fill_output_buffer(void *handle, struct vcd_frame_data *buffer);
-u32 vcd_set_device_power(s32 driver_handle,
-		enum vcd_power_state pwr_state);
-void vcd_read_and_clear_interrupt(void);
-void vcd_response_handler(void);
-u8 vcd_get_num_of_clients(void);
-u32 vcd_get_ion_status(void);
-struct ion_client *vcd_get_ion_client(void);
-#endif
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
index e00e85f..9376900 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd.h"
 
 static const struct vcd_clnt_state_table *vcd_clnt_state_table[];
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.h b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.h
index e9ab41c..9f2d63d 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,7 +12,7 @@
  */
 #ifndef _VCD_CLIENT_SM_H_
 #define _VCD_CLIENT_SM_H_
-#include "vcd_api.h"
+#include <media/msm/vcd_api.h>
 #include "vcd_ddl_api.h"
 
 struct vcd_clnt_state_table;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_core.h b/drivers/video/msm/vidc/common/vcd/vcd_core.h
index 64dec2d..1f844e8 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_core.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd_core.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -14,7 +14,7 @@
 #define _VCD_CORE_H_
 
 #include <linux/ion.h>
-#include "vcd_api.h"
+#include <media/msm/vcd_api.h>
 #include "vcd_ddl_api.h"
 
 #include "vcd_util.h"
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
index 4c477cb..9576387 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd.h"
 
 static const struct vcd_dev_state_table *vcd_dev_state_table[];
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.h b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.h
index 8245966..2443c33 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -13,7 +13,7 @@
 #ifndef _VCD_DEVICE_SM_H_
 #define _VCD_DEVICE_SM_H_
 
-#include "vcd_api.h"
+#include <media/msm/vcd_api.h>
 #include "vcd_ddl_api.h"
 #include "vcd_core.h"
 
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c
index 6a1cc80..01bd931 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd_power_sm.h"
 #include "vcd_core.h"
 #include "vcd.h"
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_property.h b/drivers/video/msm/vidc/common/vcd/vcd_property.h
deleted file mode 100644
index a3069e3..0000000
--- a/drivers/video/msm/vidc/common/vcd/vcd_property.h
+++ /dev/null
@@ -1,350 +0,0 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only 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.
- *
- */
-#ifndef _VCD_DRIVER_PROPERTY_H_
-#define _VCD_DRIVER_PROPERTY_H_
-
-#define VCD_START_BASE       0x0
-#define VCD_I_LIVE           (VCD_START_BASE + 0x1)
-#define VCD_I_CODEC          (VCD_START_BASE + 0x2)
-#define VCD_I_FRAME_SIZE     (VCD_START_BASE + 0x3)
-#define VCD_I_METADATA_ENABLE  (VCD_START_BASE + 0x4)
-#define VCD_I_METADATA_HEADER  (VCD_START_BASE + 0x5)
-#define VCD_I_PROFILE        (VCD_START_BASE + 0x6)
-#define VCD_I_LEVEL          (VCD_START_BASE + 0x7)
-#define VCD_I_BUFFER_FORMAT  (VCD_START_BASE + 0x8)
-#define VCD_I_FRAME_RATE  (VCD_START_BASE + 0x9)
-#define VCD_I_TARGET_BITRATE (VCD_START_BASE + 0xA)
-#define VCD_I_MULTI_SLICE    (VCD_START_BASE + 0xB)
-#define VCD_I_ENTROPY_CTRL   (VCD_START_BASE + 0xC)
-#define VCD_I_DEBLOCKING     (VCD_START_BASE + 0xD)
-#define VCD_I_RATE_CONTROL   (VCD_START_BASE + 0xE)
-#define VCD_I_QP_RANGE      (VCD_START_BASE + 0xF)
-#define VCD_I_SESSION_QP    (VCD_START_BASE + 0x10)
-#define VCD_I_INTRA_PERIOD   (VCD_START_BASE + 0x11)
-#define VCD_I_VOP_TIMING     (VCD_START_BASE + 0x12)
-#define VCD_I_SHORT_HEADER   (VCD_START_BASE + 0x13)
-#define VCD_I_SEQ_HEADER    (VCD_START_BASE + 0x14)
-#define VCD_I_HEADER_EXTENSION   (VCD_START_BASE + 0x15)
-#define VCD_I_INTRA_REFRESH  (VCD_START_BASE + 0x16)
-#define VCD_I_POST_FILTER    (VCD_START_BASE + 0x17)
-#define VCD_I_PROGRESSIVE_ONLY (VCD_START_BASE + 0x18)
-#define VCD_I_OUTPUT_ORDER (VCD_START_BASE + 0x19)
-#define VCD_I_RECON_BUFFERS   (VCD_START_BASE + 0x1A)
-#define VCD_I_FREE_RECON_BUFFERS   (VCD_START_BASE + 0x1B)
-#define VCD_I_GET_RECON_BUFFER_SIZE   (VCD_START_BASE + 0x1C)
-#define VCD_I_H264_MV_BUFFER   (VCD_START_BASE + 0x1D)
-#define VCD_I_FREE_H264_MV_BUFFER (VCD_START_BASE + 0x1E)
-#define VCD_I_GET_H264_MV_SIZE (VCD_START_BASE + 0x1F)
-#define VCD_I_DEC_PICTYPE (VCD_START_BASE + 0x20)
-#define VCD_I_CONT_ON_RECONFIG (VCD_START_BASE + 0x21)
-#define VCD_I_META_BUFFER_MODE (VCD_START_BASE + 0x22)
-#define VCD_I_DISABLE_DMX (VCD_START_BASE + 0x23)
-#define VCD_I_DISABLE_DMX_SUPPORT (VCD_START_BASE + 0x24)
-
-#define VCD_START_REQ      (VCD_START_BASE + 0x1000)
-#define VCD_I_REQ_IFRAME   (VCD_START_REQ + 0x1)
-
-#define VCD_I_RESERVED_BASE  (VCD_START_BASE + 0x10000)
-
-struct vcd_property_hdr {
-	u32    prop_id;
-	size_t sz;
-};
-
-struct vcd_property_live {
-	u32             live;
-};
-
-enum vcd_codec {
-	VCD_CODEC_H264      = 0x1,
-	VCD_CODEC_H263      = 0x2,
-	VCD_CODEC_MPEG1     = 0x3,
-	VCD_CODEC_MPEG2     = 0x4,
-	VCD_CODEC_MPEG4     = 0x5,
-	VCD_CODEC_DIVX_3    = 0x6,
-	VCD_CODEC_DIVX_4    = 0x7,
-	VCD_CODEC_DIVX_5    = 0x8,
-	VCD_CODEC_DIVX_6    = 0x9,
-	VCD_CODEC_XVID      = 0xA,
-	VCD_CODEC_VC1       = 0xB,
-	VCD_CODEC_VC1_RCV   = 0xC
-};
-
-struct vcd_property_codec {
-	enum vcd_codec       codec;
-};
-
-struct vcd_property_frame_size {
-	u32              width;
-	u32              height;
-	u32              stride;
-	u32              scan_lines;
-};
-
-
-#define VCD_METADATA_DATANONE       0x001
-#define VCD_METADATA_QCOMFILLER     0x002
-#define VCD_METADATA_QPARRAY        0x004
-#define VCD_METADATA_CONCEALMB      0x008
-#define VCD_METADATA_SEI            0x010
-#define VCD_METADATA_VUI            0x020
-#define VCD_METADATA_VC1            0x040
-#define VCD_METADATA_PASSTHROUGH    0x080
-#define VCD_METADATA_ENC_SLICE      0x100
-
-struct vcd_property_meta_data_enable {
-	u32 meta_data_enable_flag;
-};
-
-struct vcd_property_metadata_hdr {
-	u32 meta_data_id;
-	u32 version;
-	u32 port_index;
-	u32 type;
-};
-
-struct vcd_property_frame_rate {
-	u32              fps_denominator;
-	u32              fps_numerator;
-};
-
-struct vcd_property_target_bitrate {
-	u32             target_bitrate;
-};
-
-enum vcd_yuv_buffer_format {
-	VCD_BUFFER_FORMAT_NV12      = 0x1,
-	VCD_BUFFER_FORMAT_TILE_4x2    = 0x2,
-	VCD_BUFFER_FORMAT_NV12_16M2KA = 0x3,
-	VCD_BUFFER_FORMAT_TILE_1x1    = 0x4
-};
-
-struct vcd_property_buffer_format {
-	enum vcd_yuv_buffer_format  buffer_format;
-};
-
-struct vcd_property_post_filter {
-	u32           post_filter;
-};
-
-enum vcd_codec_profile {
-	VCD_PROFILE_UNKNOWN       = 0x0,
-	VCD_PROFILE_MPEG4_SP      = 0x1,
-	VCD_PROFILE_MPEG4_ASP     = 0x2,
-	VCD_PROFILE_H264_BASELINE = 0x3,
-	VCD_PROFILE_H264_MAIN     = 0x4,
-	VCD_PROFILE_H264_HIGH     = 0x5,
-	VCD_PROFILE_H263_BASELINE = 0x6,
-	VCD_PROFILE_VC1_SIMPLE    = 0x7,
-	VCD_PROFILE_VC1_MAIN      = 0x8,
-	VCD_PROFILE_VC1_ADVANCE   = 0x9,
-	VCD_PROFILE_MPEG2_MAIN    = 0xA,
-	VCD_PROFILE_MPEG2_SIMPLE  = 0xB
-};
-
-struct vcd_property_profile {
-	enum vcd_codec_profile       profile;
-};
-
-enum vcd_codec_level {
-   VCD_LEVEL_UNKNOWN       = 0x0,
-   VCD_LEVEL_MPEG4_0       = 0x1,
-   VCD_LEVEL_MPEG4_0b      = 0x2,
-   VCD_LEVEL_MPEG4_1       = 0x3,
-   VCD_LEVEL_MPEG4_2       = 0x4,
-   VCD_LEVEL_MPEG4_3       = 0x5,
-   VCD_LEVEL_MPEG4_3b      = 0x6,
-   VCD_LEVEL_MPEG4_4       = 0x7,
-   VCD_LEVEL_MPEG4_4a      = 0x8,
-   VCD_LEVEL_MPEG4_5       = 0x9,
-   VCD_LEVEL_MPEG4_6       = 0xA,
-   VCD_LEVEL_MPEG4_7       = 0xB,
-   VCD_LEVEL_MPEG4_X       = 0xC,
-   VCD_LEVEL_H264_1        = 0x10,
-   VCD_LEVEL_H264_1b       = 0x11,
-   VCD_LEVEL_H264_1p1      = 0x12,
-   VCD_LEVEL_H264_1p2      = 0x13,
-   VCD_LEVEL_H264_1p3      = 0x14,
-   VCD_LEVEL_H264_2        = 0x15,
-   VCD_LEVEL_H264_2p1      = 0x16,
-   VCD_LEVEL_H264_2p2      = 0x17,
-   VCD_LEVEL_H264_3        = 0x18,
-   VCD_LEVEL_H264_3p1      = 0x19,
-   VCD_LEVEL_H264_3p2      = 0x1A,
-   VCD_LEVEL_H264_4        = 0x1B,
-   VCD_LEVEL_H264_4p1      = 0x1C,
-   VCD_LEVEL_H264_4p2      = 0x1D,
-   VCD_LEVEL_H264_5        = 0x1E,
-   VCD_LEVEL_H264_5p1      = 0x1F,
-   VCD_LEVEL_H263_10       = 0x20,
-   VCD_LEVEL_H263_20       = 0x21,
-   VCD_LEVEL_H263_30       = 0x22,
-   VCD_LEVEL_H263_40       = 0x23,
-   VCD_LEVEL_H263_45       = 0x24,
-   VCD_LEVEL_H263_50       = 0x25,
-   VCD_LEVEL_H263_60       = 0x26,
-   VCD_LEVEL_H263_70       = 0x27,
-   VCD_LEVEL_H263_X        = 0x28,
-   VCD_LEVEL_MPEG2_LOW     = 0x30,
-   VCD_LEVEL_MPEG2_MAIN    = 0x31,
-   VCD_LEVEL_MPEG2_HIGH_14 = 0x32,
-   VCD_LEVEL_MPEG2_HIGH    = 0x33,
-   VCD_LEVEL_MPEG2_X       = 0x34,
-   VCD_LEVEL_VC1_S_LOW     = 0x40,
-   VCD_LEVEL_VC1_S_MEDIUM  = 0x41,
-   VCD_LEVEL_VC1_M_LOW     = 0x42,
-   VCD_LEVEL_VC1_M_MEDIUM  = 0x43,
-   VCD_LEVEL_VC1_M_HIGH    = 0x44,
-   VCD_LEVEL_VC1_A_0       = 0x45,
-   VCD_LEVEL_VC1_A_1       = 0x46,
-   VCD_LEVEL_VC1_A_2       = 0x47,
-   VCD_LEVEL_VC1_A_3       = 0x48,
-   VCD_LEVEL_VC1_A_4       = 0x49,
-   VCD_LEVEL_VC1_X         = 0x4A
-};
-
-struct vcd_property_level {
-	enum vcd_codec_level   level;
-};
-
-enum vcd_m_slice_sel {
-	VCD_MSLICE_OFF             = 0x1,
-	VCD_MSLICE_BY_MB_COUNT     = 0x2,
-	VCD_MSLICE_BY_BYTE_COUNT   = 0x3,
-	VCD_MSLICE_BY_GOB          = 0x4
-};
-
-struct vcd_property_multi_slice {
-	enum vcd_m_slice_sel   m_slice_sel;
-	u32             m_slice_size;
-};
-
-enum vcd_entropy_sel {
-	VCD_ENTROPY_SEL_CAVLC = 0x1,
-	VCD_ENTROPY_SEL_CABAC = 0x2
-};
-
-enum vcd_cabac_model {
-	VCD_CABAC_MODEL_NUMBER_0 = 0x1,
-	VCD_CABAC_MODEL_NUMBER_1 = 0x2,
-	VCD_CABAC_MODEL_NUMBER_2 = 0x3
-};
-
-struct vcd_property_entropy_control {
-	enum vcd_entropy_sel  entropy_sel;
-	enum vcd_cabac_model  cabac_model;
-};
-
-enum vcd_db_config {
-	VCD_DB_ALL_BLOCKING_BOUNDARY = 0x1,
-	VCD_DB_DISABLE               = 0x2,
-	VCD_DB_SKIP_SLICE_BOUNDARY   = 0x3
-};
-struct vcd_property_db_config {
-	enum vcd_db_config    db_config;
-	u32             slice_alpha_offset;
-	u32             slice_beta_offset;
-};
-
-enum vcd_rate_control {
-	VCD_RATE_CONTROL_OFF      = 0x1,
-	VCD_RATE_CONTROL_VBR_VFR  = 0x2,
-	VCD_RATE_CONTROL_VBR_CFR  = 0x3,
-	VCD_RATE_CONTROL_CBR_VFR  = 0x4,
-	VCD_RATE_CONTROL_CBR_CFR  = 0x5
-};
-
-struct vcd_property_rate_control {
-	enum vcd_rate_control     rate_control;
-};
-
-struct vcd_property_qp_range {
-	u32              max_qp;
-	u32              min_qp;
-};
-
-struct vcd_property_session_qp {
-	u32 i_frame_qp;
-	u32 p_frame_qp;
-	u32	b_frame_qp;
-};
-
-struct vcd_property_i_period {
-	u32 p_frames;
-	u32 b_frames;
-};
-
-struct vcd_property_vop_timing {
-	u32   vop_time_resolution;
-};
-
-struct vcd_property_short_header {
-	u32             short_header;
-};
-
-struct vcd_property_intra_refresh_mb_number {
-	u32            cir_mb_number;
-};
-
-struct vcd_property_req_i_frame {
-	u32        req_i_frame;
-};
-
-struct vcd_frame_rect{
-   u32   left;
-   u32   top;
-   u32   right;
-   u32   bottom;
-};
-
-struct vcd_property_dec_output_buffer {
-	struct vcd_frame_rect   disp_frm;
-	struct vcd_property_frame_size frm_size;
-};
-
-enum vcd_output_order {
-   VCD_DEC_ORDER_DISPLAY  = 0x0,
-   VCD_DEC_ORDER_DECODE   = 0x1
-};
-
-struct vcd_property_enc_recon_buffer{
-	u8 *user_virtual_addr;
-	u8 *kernel_virtual_addr;
-	u8 *physical_addr;
-	u8 *dev_addr;
-	u32 buffer_size;
-	u32 ysize;
-	int pmem_fd;
-	u32 offset;
-	void *client_data;
-};
-
-struct vcd_property_h264_mv_buffer{
-	u8 *kernel_virtual_addr;
-	u8 *physical_addr;
-	u32 size;
-	u32 count;
-	int pmem_fd;
-	u32 offset;
-	u8 *dev_addr;
-	void *client_data;
-};
-
-struct vcd_property_buffer_size{
-	int width;
-	int height;
-	int size;
-	int alignment;
-};
-
-#endif
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_scheduler.c b/drivers/video/msm/vidc/common/vcd/vcd_scheduler.c
index 34a3445..dec9b4e 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_scheduler.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_scheduler.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -11,7 +11,7 @@
  *
  */
 
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd.h"
 
 #define NORMALIZATION_FACTOR 3600
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_status.h b/drivers/video/msm/vidc/common/vcd/vcd_status.h
deleted file mode 100644
index 1a36167..0000000
--- a/drivers/video/msm/vidc/common/vcd/vcd_status.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only 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.
- *
- */
-
-#ifndef _VCD_ERR_STATUS_H_
-#define _VCD_ERR_STATUS_H_
-
-#define VCD_EVT_RESP_BASE                 0x1000
-#define VCD_EVT_RESP_OPEN                 (VCD_EVT_RESP_BASE + 0x1)
-#define VCD_EVT_RESP_START                (VCD_EVT_RESP_BASE + 0x2)
-#define VCD_EVT_RESP_STOP                 (VCD_EVT_RESP_BASE + 0x3)
-#define VCD_EVT_RESP_PAUSE                (VCD_EVT_RESP_BASE + 0x4)
-#define VCD_EVT_RESP_FLUSH_INPUT_DONE     (VCD_EVT_RESP_BASE + 0x5)
-#define VCD_EVT_RESP_FLUSH_OUTPUT_DONE    (VCD_EVT_RESP_BASE + 0x6)
-#define VCD_EVT_RESP_INPUT_FLUSHED        (VCD_EVT_RESP_BASE + 0x7)
-#define VCD_EVT_RESP_OUTPUT_FLUSHED       (VCD_EVT_RESP_BASE + 0x8)
-#define VCD_EVT_RESP_INPUT_DONE           (VCD_EVT_RESP_BASE + 0x9)
-#define VCD_EVT_RESP_OUTPUT_DONE          (VCD_EVT_RESP_BASE + 0xa)
-
-#define VCD_EVT_IND_BASE                  0x2000
-#define VCD_EVT_IND_INPUT_RECONFIG        (VCD_EVT_IND_BASE + 0x1)
-#define VCD_EVT_IND_OUTPUT_RECONFIG       (VCD_EVT_IND_BASE + 0x2)
-#define VCD_EVT_IND_HWERRFATAL            (VCD_EVT_IND_BASE + 0x3)
-#define VCD_EVT_IND_RESOURCES_LOST        (VCD_EVT_IND_BASE + 0x4)
-#define VCD_EVT_IND_INFO_OUTPUT_RECONFIG  (VCD_EVT_IND_BASE + 0x5)
-#define VCD_EVT_IND_INFO_FIELD_DROPPED    (VCD_EVT_IND_BASE + 0x6)
-
-#define VCD_S_SUCCESS           0x0
-
-#define VCD_S_ERR_BASE                    0x80000000
-#define VCD_ERR_FAIL                      (VCD_S_ERR_BASE + 0x01)
-#define VCD_ERR_ALLOC_FAIL                (VCD_S_ERR_BASE + 0x02)
-#define VCD_ERR_ILLEGAL_OP                (VCD_S_ERR_BASE + 0x03)
-#define VCD_ERR_ILLEGAL_PARM              (VCD_S_ERR_BASE + 0x04)
-#define VCD_ERR_BAD_POINTER               (VCD_S_ERR_BASE + 0x05)
-#define VCD_ERR_BAD_HANDLE                (VCD_S_ERR_BASE + 0x06)
-#define VCD_ERR_NOT_SUPPORTED             (VCD_S_ERR_BASE + 0x07)
-#define VCD_ERR_BAD_STATE                 (VCD_S_ERR_BASE + 0x08)
-#define VCD_ERR_BUSY                      (VCD_S_ERR_BASE + 0x09)
-#define VCD_ERR_MAX_CLIENT                (VCD_S_ERR_BASE + 0x0a)
-#define VCD_ERR_IFRAME_EXPECTED           (VCD_S_ERR_BASE + 0x0b)
-#define VCD_ERR_INTRLCD_FIELD_DROP        (VCD_S_ERR_BASE + 0x0c)
-#define VCD_ERR_HW_FATAL                  (VCD_S_ERR_BASE + 0x0d)
-#define VCD_ERR_BITSTREAM_ERR             (VCD_S_ERR_BASE + 0x0e)
-#define VCD_ERR_QEMPTY                    (VCD_S_ERR_BASE + 0x0f)
-#define VCD_ERR_SEQHDR_PARSE_FAIL         (VCD_S_ERR_BASE + 0x10)
-#define VCD_ERR_INPUT_NOT_PROCESSED       (VCD_S_ERR_BASE + 0x11)
-#define VCD_ERR_INDEX_NOMORE              (VCD_S_ERR_BASE + 0x12)
-
-#define VCD_FAILED(rc)   ((rc > VCD_S_ERR_BASE) ? true : false)
-
-#endif
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index 509b897..ebc30fd 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -13,7 +13,7 @@
 #include <linux/memory_alloc.h>
 #include <mach/msm_subsystem_map.h>
 #include <asm/div64.h>
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
 #include "vcd.h"
 #include "vdec_internal.h"
 
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_util.h b/drivers/video/msm/vidc/common/vcd/vcd_util.h
index 07ad651..7164029 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_util.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd_util.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,8 +12,8 @@
  */
 #ifndef _VCD_UTIL_H_
 #define _VCD_UTIL_H_
-#include "vidc_type.h"
-#include "vcd_api.h"
+#include <media/msm/vidc_type.h>
+#include <media/msm/vcd_api.h>
 
 #if DEBUG
 
diff --git a/drivers/video/msm/vidc/common/vcd/vidc_type.h b/drivers/video/msm/vidc/common/vcd/vidc_type.h
deleted file mode 100644
index bd87c0d..0000000
--- a/drivers/video/msm/vidc/common/vcd/vidc_type.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only 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.
- *
- */
-#ifndef VIDC_TYPE_H
-#define VIDC_TYPE_H
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/list.h>
-#include <linux/time.h>
-#include <linux/dma-mapping.h>
-#include <linux/android_pmem.h>
-
-#define DEBUG   0
-#define VIDC_ENABLE_DBGFS
-
-#define USE_RES_TRACKER
-#endif
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 9c43f56..79f7874 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -428,6 +428,7 @@
 header-y += msm_ipc.h
 header-y += msm_charm.h
 header-y += tzcom.h
+header-y += qseecom.h
 header-y += qcedev.h
 header-y += idle_stats_device.h
 header-y += genlock.h
diff --git a/include/linux/ion.h b/include/linux/ion.h
index 3256fba..caed2a2 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -570,6 +570,7 @@
 			struct ion_handle *handle, int domain_num,
 			int partition_num, unsigned long align,
 			unsigned long iova_length, unsigned long *iova,
+			unsigned long *buffer_size,
 			unsigned long flags)
 {
 	return -ENODEV;
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index 82db9a4..e2d4d93 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -95,8 +95,15 @@
 	unsigned int	batt_id_channel;
 };
 
+enum battery_type {
+	BATT_UNKNOWN = 0,
+	BATT_PALLADIUM,
+	BATT_DESAY,
+};
+
 /**
  * struct pm8921_bms_platform_data -
+ * @batt_type:		allows to force chose battery calibration data
  * @r_sense:		sense resistor value in (mOhms)
  * @i_test:		current at which the unusable charger cutoff is to be
  *			calculated or the peak system current (mA)
@@ -105,6 +112,7 @@
  */
 struct pm8921_bms_platform_data {
 	struct pm8xxx_bms_core_data	bms_cdata;
+	enum battery_type		battery_type;
 	unsigned int			r_sense;
 	unsigned int			i_test;
 	unsigned int			v_failure;
@@ -114,6 +122,7 @@
 
 #if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)
 extern struct pm8921_bms_battery_data  palladium_1500_data;
+extern struct pm8921_bms_battery_data  desay_5200_data;
 /**
  * pm8921_bms_get_vsense_avg - return the voltage across the sense
  *				resitor in microvolts
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 9e82abf8..ff53742 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -50,8 +50,12 @@
 	u8			rel_sectors;
 	u8			rel_param;
 	u8			part_config;
+	u8			cache_ctrl;
+	u8			rst_n_function;
 	unsigned int		part_time;		/* Units: ms */
 	unsigned int		sa_timeout;		/* Units: 100ns */
+	unsigned int		generic_cmd6_time;	/* Units: 10ms */
+	unsigned int            power_off_longtime;     /* Units: ms */
 	unsigned int		hs_max_dtr;
 	unsigned int		sectors;
 	unsigned int		card_type;
@@ -64,10 +68,15 @@
 	unsigned long long	enhanced_area_offset;	/* Units: Byte */
 	unsigned int		enhanced_area_size;	/* Units: KB */
 	unsigned int		boot_size;		/* in bytes */
+	unsigned int		cache_size;		/* Units: KB */
+	bool			hpi_en;			/* HPI enablebit */
+	bool			hpi;			/* HPI support bit */
+	unsigned int		hpi_cmd;		/* cmd used as HPI */
 	u8			raw_partition_support;	/* 160 */
 	u8			raw_erased_mem_count;	/* 181 */
 	u8			raw_ext_csd_structure;	/* 194 */
 	u8			raw_card_type;		/* 196 */
+	u8			out_of_int_time;	/* 198 */
 	u8			raw_s_a_timeout;		/* 217 */
 	u8			raw_hc_erase_gap_size;	/* 221 */
 	u8			raw_erase_timeout_mult;	/* 223 */
@@ -77,6 +86,9 @@
 	u8			raw_sec_feature_support;/* 231 */
 	u8			raw_trim_mult;		/* 232 */
 	u8			raw_sectors[4];		/* 212 - 4 bytes */
+
+	unsigned int            feature_support;
+#define MMC_DISCARD_FEATURE	BIT(0)                  /* CMD38 feature */
 };
 
 struct sd_scr {
@@ -189,6 +201,11 @@
 #define MMC_QUIRK_DISABLE_CD	(1<<5)		/* disconnect CD/DAT[3] resistor */
 #define MMC_QUIRK_INAND_CMD38	(1<<6)		/* iNAND devices have broken CMD38 */
 #define MMC_QUIRK_BLK_NO_CMD23	(1<<7)		/* Avoid CMD23 for regular multiblock */
+	unsigned int    poweroff_notify_state;	/* eMMC4.5 notify feature */
+#define MMC_NO_POWER_NOTIFICATION	0
+#define MMC_POWERED_ON			1
+#define MMC_POWEROFF_SHORT		2
+#define MMC_POWEROFF_LONG		3
 
 	unsigned int		erase_size;	/* erase size in sectors */
  	unsigned int		erase_shift;	/* if erase unit is power 2 */
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 279c023..05c126c 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -117,6 +117,7 @@
 
 	unsigned int		sg_len;		/* size of scatter list */
 	struct scatterlist	*sg;		/* I/O scatter list */
+	s32			host_cookie;	/* host private data */
 };
 
 struct mmc_request {
@@ -125,13 +126,17 @@
 	struct mmc_data		*data;
 	struct mmc_command	*stop;
 
-	void			*done_data;	/* completion data */
+	struct completion	completion;
 	void			(*done)(struct mmc_request *);/* completion function */
 };
 
 struct mmc_host;
 struct mmc_card;
+struct mmc_async_req;
 
+extern struct mmc_async_req *mmc_start_req(struct mmc_host *,
+					   struct mmc_async_req *, int *);
+extern int mmc_interrupt_hpi(struct mmc_card *);
 extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
 extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
 extern int mmc_app_cmd(struct mmc_host *, struct mmc_card *);
@@ -142,6 +147,7 @@
 #define MMC_ERASE_ARG		0x00000000
 #define MMC_SECURE_ERASE_ARG	0x80000000
 #define MMC_TRIM_ARG		0x00000001
+#define MMC_DISCARD_ARG		0x00000003
 #define MMC_SECURE_TRIM1_ARG	0x80000001
 #define MMC_SECURE_TRIM2_ARG	0x80008000
 
@@ -152,11 +158,17 @@
 		     unsigned int arg);
 extern int mmc_can_erase(struct mmc_card *card);
 extern int mmc_can_trim(struct mmc_card *card);
+extern int mmc_can_discard(struct mmc_card *card);
+extern int mmc_can_sanitize(struct mmc_card *card);
 extern int mmc_can_secure_erase_trim(struct mmc_card *card);
 extern int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
 				   unsigned int nr);
+extern unsigned int mmc_calc_max_discard(struct mmc_card *card);
 
 extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
+extern int mmc_hw_reset(struct mmc_host *host);
+extern int mmc_hw_reset_check(struct mmc_host *host);
+extern int mmc_can_reset(struct mmc_card *card);
 
 extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *);
 extern unsigned int mmc_align_data_size(struct mmc_card *, unsigned int);
@@ -167,6 +179,7 @@
 extern int mmc_try_claim_host(struct mmc_host *host);
 
 extern int mmc_detect_card_removed(struct mmc_host *host);
+extern int mmc_flush_cache(struct mmc_card *);
 
 /**
  *	mmc_claim_host - exclusively claim a host
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index d90c779..35137d6 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -107,6 +107,15 @@
 	 */
 	int (*enable)(struct mmc_host *host);
 	int (*disable)(struct mmc_host *host, int lazy);
+	/*
+	 * It is optional for the host to implement pre_req and post_req in
+	 * order to support double buffering of requests (prepare one
+	 * request while another request is active).
+	 */
+	void	(*post_req)(struct mmc_host *host, struct mmc_request *req,
+			    int err);
+	void	(*pre_req)(struct mmc_host *host, struct mmc_request *req,
+			   bool is_first_req);
 	void	(*request)(struct mmc_host *host, struct mmc_request *req);
 	/*
 	 * Avoid calling these three functions too often or in a "fast path",
@@ -140,11 +149,22 @@
 	int	(*start_signal_voltage_switch)(struct mmc_host *host, struct mmc_ios *ios);
 	int	(*execute_tuning)(struct mmc_host *host);
 	void	(*enable_preset_value)(struct mmc_host *host, bool enable);
+	void	(*hw_reset)(struct mmc_host *host);
 };
 
 struct mmc_card;
 struct device;
 
+struct mmc_async_req {
+	/* active mmc request */
+	struct mmc_request	*mrq;
+	/*
+	 * Check error status of completed mmc request.
+	 * Returns 0 if success otherwise non zero.
+	 */
+	int (*err_check) (struct mmc_card *, struct mmc_async_req *);
+};
+
 struct mmc_host {
 	struct device		*parent;
 	struct device		class_dev;
@@ -212,8 +232,19 @@
 #define MMC_CAP_MAX_CURRENT_600	(1 << 28)	/* Host max current limit is 600mA */
 #define MMC_CAP_MAX_CURRENT_800	(1 << 29)	/* Host max current limit is 800mA */
 #define MMC_CAP_CMD23		(1 << 30)	/* CMD23 supported. */
+#define MMC_CAP_HW_RESET	(1 << 31)	/* Hardware reset */
+
+	unsigned int		caps2;		/* More host capabilities */
+
+#define MMC_CAP2_CACHE_CTRL	(1 << 1)	/* Allow cache control */
+#define MMC_CAP2_POWEROFF_NOTIFY (1 << 2)	/* Notify poweroff supported */
+#define MMC_CAP2_NO_MULTI_READ	(1 << 3)	/* Multiblock reads don't work */
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
+	unsigned int        power_notify_type;
+#define MMC_HOST_PW_NOTIFY_NONE		0
+#define MMC_HOST_PW_NOTIFY_SHORT	1
+#define MMC_HOST_PW_NOTIFY_LONG		2
 
 #ifdef CONFIG_MMC_CLKGATE
 	int			clk_requests;	/* internal reference counter */
@@ -234,6 +265,7 @@
 	unsigned int		max_req_size;	/* maximum number of bytes in one req */
 	unsigned int		max_blk_size;	/* maximum size of one mmc block */
 	unsigned int		max_blk_count;	/* maximum number of blocks in one req */
+	unsigned int		max_discard_to;	/* max. discard timeout in ms */
 
 	/* private data */
 	spinlock_t		lock;		/* lock for claim and bus ops */
@@ -314,6 +346,9 @@
 		ktime_t start;
 	} perf;
 #endif
+
+	struct mmc_async_req	*areq;		/* active async req */
+
 	unsigned long		private[0] ____cacheline_aligned;
 };
 
@@ -362,6 +397,8 @@
 extern void mmc_detect_change(struct mmc_host *, unsigned long delay);
 extern void mmc_request_done(struct mmc_host *, struct mmc_request *);
 
+extern int mmc_cache_ctrl(struct mmc_host *, u8);
+
 static inline void mmc_signal_sdio_irq(struct mmc_host *host)
 {
 	host->ops->enable_sdio_irq(host, 0);
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 53013f9..0a72bf8 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -271,18 +271,30 @@
  * EXT_CSD fields
  */
 
+#define EXT_CSD_FLUSH_CACHE		32      /* W */
+#define EXT_CSD_CACHE_CTRL		33      /* R/W */
+#define EXT_CSD_POWER_OFF_NOTIFICATION	34	/* R/W */
 #define EXT_CSD_PARTITION_ATTRIBUTE	156	/* R/W */
 #define EXT_CSD_PARTITION_SUPPORT	160	/* RO */
+#define EXT_CSD_HPI_MGMT		161	/* R/W */
+#define EXT_CSD_RST_N_FUNCTION		162	/* R/W */
+#define EXT_CSD_SANITIZE_START		165     /* W */
 #define EXT_CSD_WR_REL_PARAM		166	/* RO */
 #define EXT_CSD_ERASE_GROUP_DEF		175	/* R/W */
 #define EXT_CSD_PART_CONFIG		179	/* R/W */
 #define EXT_CSD_ERASED_MEM_CONT		181	/* RO */
 #define EXT_CSD_BUS_WIDTH		183	/* R/W */
 #define EXT_CSD_HS_TIMING		185	/* R/W */
+#define EXT_CSD_POWER_CLASS		187	/* R/W */
 #define EXT_CSD_REV			192	/* RO */
 #define EXT_CSD_STRUCTURE		194	/* RO */
 #define EXT_CSD_CARD_TYPE		196	/* RO */
+#define EXT_CSD_OUT_OF_INTERRUPT_TIME	198	/* RO */
 #define EXT_CSD_PART_SWITCH_TIME        199     /* RO */
+#define EXT_CSD_PWR_CL_52_195		200	/* RO */
+#define EXT_CSD_PWR_CL_26_195		201	/* RO */
+#define EXT_CSD_PWR_CL_52_360		202	/* RO */
+#define EXT_CSD_PWR_CL_26_360		203	/* RO */
 #define EXT_CSD_SEC_CNT			212	/* RO, 4 bytes */
 #define EXT_CSD_S_A_TIMEOUT		217	/* RO */
 #define EXT_CSD_REL_WR_SEC_C		222	/* RO */
@@ -294,6 +306,14 @@
 #define EXT_CSD_SEC_ERASE_MULT		230	/* RO */
 #define EXT_CSD_SEC_FEATURE_SUPPORT	231	/* RO */
 #define EXT_CSD_TRIM_MULT		232	/* RO */
+#define EXT_CSD_PWR_CL_200_195		236	/* RO */
+#define EXT_CSD_PWR_CL_200_360		237	/* RO */
+#define EXT_CSD_PWR_CL_DDR_52_195	238	/* RO */
+#define EXT_CSD_PWR_CL_DDR_52_360	239	/* RO */
+#define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
+#define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
+#define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
+#define EXT_CSD_HPI_FEATURES		503	/* RO */
 
 /*
  * EXT_CSD field definitions
@@ -328,7 +348,20 @@
 #define EXT_CSD_SEC_ER_EN	BIT(0)
 #define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
 #define EXT_CSD_SEC_GB_CL_EN	BIT(4)
+#define EXT_CSD_SEC_SANITIZE	BIT(6)  /* v4.5 only */
 
+#define EXT_CSD_RST_N_EN_MASK	0x3
+#define EXT_CSD_RST_N_ENABLED	1	/* RST_n is enabled on card */
+
+#define EXT_CSD_NO_POWER_NOTIFICATION	0
+#define EXT_CSD_POWER_ON		1
+#define EXT_CSD_POWER_OFF_SHORT		2
+#define EXT_CSD_POWER_OFF_LONG		3
+
+#define EXT_CSD_PWR_CL_8BIT_MASK	0xF0	/* 8 bit PWR CLS */
+#define EXT_CSD_PWR_CL_4BIT_MASK	0x0F	/* 8 bit PWR CLS */
+#define EXT_CSD_PWR_CL_8BIT_SHIFT	4
+#define EXT_CSD_PWR_CL_4BIT_SHIFT	0
 /*
  * MMC_SWITCH access modes
  */
diff --git a/include/linux/msm_audio_mvs.h b/include/linux/msm_audio_mvs.h
index 2813c8f..8ec9796 100644
--- a/include/linux/msm_audio_mvs.h
+++ b/include/linux/msm_audio_mvs.h
@@ -24,7 +24,7 @@
 #define MVS_MODE_G729A 0xE
 #define MVS_MODE_G711A 0xF
 #define MVS_MODE_G722 0x10
-#define MVS_MODE_PCM_WB 0x80000000
+#define MVS_MODE_PCM_WB 0x12
 
 enum msm_audio_amr_mode {
 	MVS_AMR_MODE_0475, /* AMR 4.75 kbps */
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index 37b9d35..5e39f89 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -140,6 +140,13 @@
 #define KGSL_2D1_REG_MEMORY	"kgsl_2d1_reg_memory"
 #define KGSL_2D1_IRQ		"kgsl_2d1_irq"
 
+struct kgsl_device_iommu_data {
+	const char **iommu_ctx_names;
+	int iommu_ctx_count;
+	unsigned int physstart;
+	unsigned int physend;
+};
+
 struct kgsl_device_platform_data {
 	struct kgsl_pwrlevel pwrlevel[KGSL_MAX_PWRLEVELS];
 	int init_level;
@@ -150,8 +157,8 @@
 	unsigned int clk_map;
 	unsigned int idle_needed;
 	struct msm_bus_scale_pdata *bus_scale_table;
-	const char *iommu_user_ctx_name;
-	const char *iommu_priv_ctx_name;
+	struct kgsl_device_iommu_data *iommu_data;
+	int iommu_count;
 };
 
 #endif
diff --git a/include/linux/of.h b/include/linux/of.h
index 6a1272c..f904bf4 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -241,6 +241,16 @@
 	return false;
 }
 
+#define for_each_child_of_node(parent, child) \
+	while (0)
+
+static inline struct property *of_find_property(const struct device_node *np,
+						const char *name,
+						int *lenp)
+{
+	return NULL;
+}
+
 static inline int of_property_read_u32_array(const struct device_node *np,
 				char *propname, u32 *out_values, size_t sz)
 {
diff --git a/include/linux/of_address.h b/include/linux/of_address.h
index 3118623..01b925a 100644
--- a/include/linux/of_address.h
+++ b/include/linux/of_address.h
@@ -4,6 +4,7 @@
 #include <linux/errno.h>
 #include <linux/of.h>
 
+#ifdef CONFIG_OF_ADDRESS
 extern u64 of_translate_address(struct device_node *np, const __be32 *addr);
 extern int of_address_to_resource(struct device_node *dev, int index,
 				  struct resource *r);
@@ -25,12 +26,37 @@
 #define pci_address_to_pio pci_address_to_pio
 #endif
 
-#ifdef CONFIG_PCI
+#else /* CONFIG_OF_ADDRESS */
+static inline int of_address_to_resource(struct device_node *dev, int index,
+					 struct resource *r)
+{
+	return -EINVAL;
+}
+static inline struct device_node *of_find_matching_node_by_address(
+					struct device_node *from,
+					const struct of_device_id *matches,
+					u64 base_address)
+{
+	return NULL;
+}
+static inline void __iomem *of_iomap(struct device_node *device, int index)
+{
+	return NULL;
+}
+static inline const u32 *of_get_address(struct device_node *dev, int index,
+					u64 *size, unsigned int *flags)
+{
+	return NULL;
+}
+#endif /* CONFIG_OF_ADDRESS */
+
+
+#if defined(CONFIG_OF_ADDRESS) && defined(CONFIG_PCI)
 extern const __be32 *of_get_pci_address(struct device_node *dev, int bar_no,
 			       u64 *size, unsigned int *flags);
 extern int of_pci_address_to_resource(struct device_node *dev, int bar,
 				      struct resource *r);
-#else /* CONFIG_PCI */
+#else /* CONFIG_OF_ADDRESS && CONFIG_PCI */
 static inline int of_pci_address_to_resource(struct device_node *dev, int bar,
 				             struct resource *r)
 {
@@ -42,8 +68,7 @@
 {
 	return NULL;
 }
-#endif /* CONFIG_PCI */
-
+#endif /* CONFIG_OF_ADDRESS && CONFIG_PCI */
 
 #endif /* __OF_ADDRESS_H */
 
diff --git a/include/linux/qseecom.h b/include/linux/qseecom.h
new file mode 100644
index 0000000..6d39026
--- /dev/null
+++ b/include/linux/qseecom.h
@@ -0,0 +1,149 @@
+#ifndef __QSEECOM_H_
+#define __QSEECOM_H_
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define MAX_ION_FD  4
+#define MAX_APP_NAME_SIZE  32
+
+/*
+ * struct qseecom_register_listener_req -
+ *      for register listener ioctl request
+ * @listener_id - service id (shared between userspace and QSE)
+ * @ifd_data_fd - ion handle
+ * @virt_sb_base - shared buffer base in user space
+ * @sb_size - shared buffer size
+ */
+struct qseecom_register_listener_req {
+	uint32_t listener_id; /* in */
+	int32_t ifd_data_fd; /* in */
+	uint32_t virt_sb_base; /* in */
+	uint32_t sb_size; /* in */
+};
+
+/*
+ * struct qseecom_send_cmd_req - for send command ioctl request
+ * @cmd_req_len - command buffer length
+ * @cmd_req_buf - command buffer
+ * @resp_len - response buffer length
+ * @resp_buf - response buffer
+ */
+struct qseecom_send_cmd_req {
+	void *cmd_req_buf; /* in */
+	unsigned int cmd_req_len; /* in */
+	void *resp_buf; /* in/out */
+	unsigned int resp_len; /* in/out */
+};
+
+
+/*
+ * struct qseecom_ion_fd_info - ion fd handle data information
+ * @fd - ion handle to some memory allocated in user space
+ * @cmd_buf_offset - command buffer offset
+ */
+struct qseecom_ion_fd_info {
+	int32_t fd;
+	uint32_t cmd_buf_offset;
+};
+/*
+ * struct qseecom_send_modfd_cmd_req - for send command ioctl request
+ * @cmd_req_len - command buffer length
+ * @cmd_req_buf - command buffer
+ * @resp_len - response buffer length
+ * @resp_buf - response buffer
+ * @ifd_data_fd - ion handle to memory allocated in user space
+ * @cmd_buf_offset - command buffer offset
+ */
+struct qseecom_send_modfd_cmd_req {
+	void *cmd_req_buf; /* in */
+	unsigned int cmd_req_len; /* in */
+	void *resp_buf; /* in/out */
+	unsigned int resp_len; /* in/out */
+	struct qseecom_ion_fd_info ifd_data[MAX_ION_FD];
+};
+/*
+ * struct qseecom_listener_send_resp_req - signal to continue the send_cmd req.
+ * Used as a trigger from HLOS service to notify QSEECOM that it's done with its
+ * operation and provide the response for QSEECOM can continue the incomplete
+ * command execution
+ * @resp_len - Length of the response
+ * @resp_buf - Response buffer where the response of the cmd should go.
+ */
+struct qseecom_send_resp_req {
+	void *resp_buf; /* in */
+	unsigned int resp_len; /* in */
+};
+
+/*
+ * struct qseecom_load_img_data - for sending image length information and
+ * ion file descriptor to the qseecom driver. ion file descriptor is used
+ * for retrieving the ion file handle and in turn the physical address of
+ * the image location.
+ * @mdt_len - Length of the .mdt file in bytes.
+ * @img_len - Length of the .mdt + .b00 +..+.bxx images files in bytes
+ * @ion_fd - Ion file descriptor used when allocating memory.
+ * @img_name - Name of the image.
+*/
+struct qseecom_load_img_req {
+	uint32_t mdt_len; /* in */
+	uint32_t img_len; /* in */
+	int32_t  ifd_data_fd; /* in */
+	char	 img_name[MAX_APP_NAME_SIZE]; /* in */
+	int app_id; /* out*/
+};
+
+struct qseecom_set_sb_mem_param_req {
+	int32_t ifd_data_fd; /* in */
+	uint32_t virt_sb_base; /* in */
+	uint32_t sb_len; /* in */
+};
+
+/*
+ * struct qseecom_qseos_version_req - get qseos version
+ * @qseos_version - version number
+ */
+struct qseecom_qseos_version_req {
+	unsigned int qseos_version; /* in */
+};
+
+#define QSEECOM_IOC_MAGIC    0x97
+
+
+#define QSEECOM_IOCTL_REGISTER_LISTENER_REQ \
+	_IOWR(QSEECOM_IOC_MAGIC, 1, struct qseecom_register_listener_req)
+
+#define QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ \
+	_IO(QSEECOM_IOC_MAGIC, 2)
+
+#define QSEECOM_IOCTL_SEND_CMD_REQ \
+	_IOWR(QSEECOM_IOC_MAGIC, 3, struct qseecom_send_cmd_req)
+
+#define QSEECOM_IOCTL_SEND_MODFD_CMD_REQ \
+	_IOWR(QSEECOM_IOC_MAGIC, 4, struct qseecom_send_modfd_cmd_req)
+
+#define QSEECOM_IOCTL_RECEIVE_REQ \
+	_IO(QSEECOM_IOC_MAGIC, 5)
+
+#define QSEECOM_IOCTL_SEND_RESP_REQ \
+	_IO(QSEECOM_IOC_MAGIC, 6)
+
+#define QSEECOM_IOCTL_LOAD_APP_REQ \
+	_IOWR(QSEECOM_IOC_MAGIC, 7, struct qseecom_load_img_req)
+
+#define QSEECOM_IOCTL_SET_MEM_PARAM_REQ \
+	_IOWR(QSEECOM_IOC_MAGIC, 8, struct qseecom_set_sb_mem_param_req)
+
+#define QSEECOM_IOCTL_UNLOAD_APP_REQ \
+	_IO(QSEECOM_IOC_MAGIC, 9)
+
+#define QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ \
+	_IOWR(QSEECOM_IOC_MAGIC, 10, struct qseecom_qseos_version_req)
+
+#define QSEECOM_IOCTL_PERF_ENABLE_REQ \
+	_IO(QSEECOM_IOC_MAGIC, 11)
+
+#define QSEECOM_IOCTL_PERF_DISABLE_REQ \
+	_IO(QSEECOM_IOC_MAGIC, 12)
+
+#endif /* __QSEECOM_H_ */
diff --git a/include/linux/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h
index 448d9ab..75b132b 100644
--- a/include/linux/slimbus/slimbus.h
+++ b/include/linux/slimbus/slimbus.h
@@ -877,6 +877,7 @@
  * -EXFULL is returned if there is no space in TDM to reserve the bandwidth.
  * -EISCONN/-ENOTCONN is returned if the channel is already connected or not
  * yet defined.
+ * -EINVAL is returned if individual control of a grouped-channel is attempted.
  */
 extern int slim_control_ch(struct slim_device *sb, u16 grpchanh,
 				enum slim_ch_control chctrl, bool commit);
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 037cfe7..79fb177 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -277,6 +277,10 @@
 	unsigned hub_reset;
 };
 
+struct msm_usb_host_platform_data {
+	unsigned int power_budget;
+};
+
 struct usb_bam_pipe_connect {
 	u32 src_phy_addr;
 	int src_pipe_index;
diff --git a/include/linux/usb/ulpi.h b/include/linux/usb/ulpi.h
index 9595796..540a74c 100644
--- a/include/linux/usb/ulpi.h
+++ b/include/linux/usb/ulpi.h
@@ -145,6 +145,7 @@
 #define ULPI_INT_SESS_VALID			(1 << 2)
 #define ULPI_INT_SESS_END			(1 << 3)
 #define ULPI_INT_IDGRD				(1 << 4)
+#define ULPI_INT_DP				(1 << 7)
 
 /* Debug */
 #define ULPI_DEBUG_LINESTATE0			(1 << 0)
diff --git a/include/media/msm/vcd_api.h b/include/media/msm/vcd_api.h
index 1cd8448..8bb2558 100644
--- a/include/media/msm/vcd_api.h
+++ b/include/media/msm/vcd_api.h
@@ -56,6 +56,7 @@
 struct vcd_frame_data {
 	u8 *virtual;
 	u8 *physical;
+	u32 ion_flag;
 	u32 alloc_len;
 	u32 data_len;
 	u32 offset;
diff --git a/include/media/msm/vidc_init.h b/include/media/msm/vidc_init.h
index 60cc35f..4e28c74 100644
--- a/include/media/msm/vidc_init.h
+++ b/include/media/msm/vidc_init.h
@@ -14,7 +14,8 @@
 #ifndef VIDC_INIT_H
 #define VIDC_INIT_H
 #include <linux/ion.h>
-#include "vidc_type.h"
+#include <media/msm/vidc_type.h>
+#include <media/msm/vcd_property.h>
 
 #define VIDC_MAX_NUM_CLIENTS 4
 #define MAX_VIDEO_NUM_OF_BUFF 100
@@ -28,6 +29,7 @@
 	unsigned long user_vaddr;
 	unsigned long kernel_vaddr;
 	unsigned long phy_addr;
+	unsigned long buff_ion_flag;
 	struct ion_handle *buff_ion_handle;
 	int pmem_fd;
 	struct file *file;
@@ -63,6 +65,9 @@
 void __iomem *vidc_get_ioaddr(void);
 int vidc_load_firmware(void);
 void vidc_release_firmware(void);
+u32 vidc_get_fd_info(struct video_client_ctx *client_ctx,
+		enum buffer_dir buffer, int pmem_fd,
+		unsigned long kvaddr, int index);
 u32 vidc_lookup_addr_table(struct video_client_ctx *client_ctx,
 	enum buffer_dir buffer, u32 search_with_user_vaddr,
 	unsigned long *user_vaddr, unsigned long *kernel_vaddr,
@@ -76,6 +81,8 @@
 u32 vidc_delete_addr_table(struct video_client_ctx *client_ctx,
 	enum buffer_dir buffer, unsigned long user_vaddr,
 	unsigned long *kernel_vaddr);
+void vidc_cleanup_addr_table(struct video_client_ctx *client_ctx,
+		enum buffer_dir buffer);
 
 u32 vidc_timer_create(void (*timer_handler)(void *),
 	void *user_data, void **timer_handle);
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index e0a04dc..867bd8a 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -1137,6 +1137,10 @@
 	uint32_t f_pix_den;
 	uint32_t total_f_dist_num;
 	uint32_t total_f_dist_den;
+	uint32_t hor_view_angle_num;
+	uint32_t hor_view_angle_den;
+	uint32_t ver_view_angle_num;
+	uint32_t ver_view_angle_den;
 };
 
 struct msm_actuator_cfg_data {
diff --git a/include/media/radio-iris.h b/include/media/radio-iris.h
index 34a21bd..de2b356 100644
--- a/include/media/radio-iris.h
+++ b/include/media/radio-iris.h
@@ -675,7 +675,7 @@
 
 /* Band limits */
 #define REGION_US_EU_BAND_LOW              87500
-#define REGION_US_EU_BAND_HIGH             107900
+#define REGION_US_EU_BAND_HIGH             108000
 #define REGION_JAPAN_STANDARD_BAND_LOW     76000
 #define REGION_JAPAN_STANDARD_BAND_HIGH    90000
 #define REGION_JAPAN_WIDE_BAND_LOW         90000
diff --git a/include/media/tavarua.h b/include/media/tavarua.h
index bedfc7c..211d146 100644
--- a/include/media/tavarua.h
+++ b/include/media/tavarua.h
@@ -152,7 +152,7 @@
 	* Here we have IOCTl's that are specific to IRIS
 	* (V4L2_CID_PRIVATE_BASE + 0x1E to V4L2_CID_PRIVATE_BASE + 0x28)
 	*/
-	V4L2_CID_PRIVATE_SOFT_MUTE, /* 0x800001E*/
+	V4L2_CID_PRIVATE_SOFT_MUTE,/* 0x800001E*/
 	V4L2_CID_PRIVATE_RIVA_ACCS_ADDR,
 	V4L2_CID_PRIVATE_RIVA_ACCS_LEN,
 	V4L2_CID_PRIVATE_RIVA_PEEK,
@@ -162,16 +162,16 @@
 	V4L2_CID_PRIVATE_SSBI_POKE,
 	V4L2_CID_PRIVATE_TX_TONE,
 	V4L2_CID_PRIVATE_RDS_GRP_COUNTERS,
-	V4L2_CID_PRIVATE_SET_NOTCH_FILTER, /* 0x8000028 */
+	V4L2_CID_PRIVATE_SET_NOTCH_FILTER,/* 0x8000028 */
 
-	V4L2_CID_PRIVATE_TAVARUA_SET_AUDIO_PATH, /* 0x8000029 */
-	V4L2_CID_PRIVATE_TAVARUA_DO_CALIBRATION, /* 0x800002A : IRIS command */
-	V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM, /* 0x800002B */
-
-	V4L2_CID_PRIVATE_TAVARUA_ON_CHANNEL_THRESHOLD =
-		V4L2_CTRL_CLASS_USER + 0x92B,
-	V4L2_CID_PRIVATE_TAVARUA_OFF_CHANNEL_THRESHOLD =
-		V4L2_CTRL_CLASS_USER + 0x92C
+	V4L2_CID_PRIVATE_TAVARUA_SET_AUDIO_PATH,/* 0x8000029 */
+	V4L2_CID_PRIVATE_TAVARUA_DO_CALIBRATION,/* 0x800002A : IRIS */
+	V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM,/* 0x800002B */
+	V4L2_CID_PRIVATE_IRIS_GET_SINR, /* 0x800002C : IRIS */
+	V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD, /* 0x800002D */
+	V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD, /* 0x800002E */
+	V4L2_CID_PRIVATE_SINR_THRESHOLD,  /* 0x800002F : IRIS */
+	V4L2_CID_PRIVATE_SINR_SAMPLES,  /* 0x8000030 : IRIS */
 
 };
 
@@ -349,6 +349,7 @@
 	(reg = (reg & ~mask) | (((val) << offset) & mask))
 #define GET_REG_FIELD(reg, offset, mask) ((reg & mask) >> offset)
 #define RSH_DATA(val, offset)    ((val) >> (offset))
+#define LSH_DATA(val, offset)    ((val) << (offset))
 #define GET_ABS_VAL(val)        ((val) & (0xFF))
 
 enum radio_state_t {
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index f23a6a0..070dc7b 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -100,6 +100,7 @@
 			break;
 		}
 	}
+	dai_data->rate = params_rate(params);
 	/* Q6 only supports 16 as now */
 	dai_data->port_config.mi2s.bitwidth = 16;
 
diff --git a/sound/soc/msm/msm-pcm-lpa.c b/sound/soc/msm/msm-pcm-lpa.c
index 83fd691..0b7cc78 100644
--- a/sound/soc/msm/msm-pcm-lpa.c
+++ b/sound/soc/msm/msm-pcm-lpa.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -27,6 +27,9 @@
 #include <asm/dma.h>
 #include <linux/dma-mapping.h>
 #include <linux/android_pmem.h>
+#include <sound/snd_compress_params.h>
+#include <sound/compress_offload.h>
+#include <sound/compress_driver.h>
 
 #include "msm-pcm-q6.h"
 #include "msm-pcm-routing.h"
@@ -459,7 +462,8 @@
 		return -ENOMEM;
 	}
 	buf = prtd->audio_client->port[dir].buf;
-	if (!buf && !buf[0].data)
+
+	if (buf == NULL || buf[0].data == NULL)
 		return -ENOMEM;
 
 	pr_debug("%s:buf = %p\n", __func__, buf);
@@ -482,8 +486,37 @@
 	int rc = 0;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct msm_audio *prtd = runtime->private_data;
+	uint64_t timestamp;
+	uint64_t temp;
 
 	switch (cmd) {
+	case SNDRV_COMPRESS_TSTAMP: {
+		struct snd_compr_tstamp tstamp;
+		pr_debug("SNDRV_COMPRESS_TSTAMP\n");
+
+		memset(&tstamp, 0x0, sizeof(struct snd_compr_tstamp));
+		timestamp = q6asm_get_session_time(prtd->audio_client);
+		if (timestamp < 0) {
+			pr_err("%s: Get Session Time return value =%lld\n",
+				__func__, timestamp);
+			return -EAGAIN;
+		}
+		temp = (timestamp * 2 * runtime->channels);
+		temp = temp * (runtime->rate/1000);
+		temp = div_u64(temp, 1000);
+		tstamp.sampling_rate = runtime->rate;
+		tstamp.rendered = (size_t)(temp & 0xFFFFFFFF);
+		tstamp.decoded  = (size_t)((temp >> 32) & 0xFFFFFFFF);
+		tstamp.timestamp = timestamp;
+		pr_debug("%s: bytes_consumed:lsb = %d, msb = %d,"
+			"timestamp = %lld,\n",
+			__func__, tstamp.rendered, tstamp.decoded,
+			tstamp.timestamp);
+		if (copy_to_user((void *) arg, &tstamp,
+			sizeof(struct snd_compr_tstamp)))
+			return -EFAULT;
+		return 0;
+	}
 	case SNDRV_PCM_IOCTL1_RESET:
 		prtd->cmd_ack = 0;
 		rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
diff --git a/sound/soc/msm/msm-pcm-voice.c b/sound/soc/msm/msm-pcm-voice.c
index eafe0f9..471284b 100644
--- a/sound/soc/msm/msm-pcm-voice.c
+++ b/sound/soc/msm/msm-pcm-voice.c
@@ -129,7 +129,7 @@
 
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct msm_voice *prtd = runtime->private_data;
-	int ret;
+	int ret = 0;
 
 	mutex_lock(&prtd->lock);
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index dc49f12..d822af5 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -3211,7 +3211,7 @@
 {
 	pr_debug("%s\n", __func__);
 
-	if (session_id < 0) {
+	if (session_id < 0 || session_id > SESSION_MAX) {
 		pr_err("%s: invalid session_id = %d\n", __func__, session_id);
 		return -EINVAL;
 	}
diff --git a/tools/perf/builtin-periodic.c b/tools/perf/builtin-periodic.c
index 70a0e2b..060e909 100644
--- a/tools/perf/builtin-periodic.c
+++ b/tools/perf/builtin-periodic.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -194,6 +194,8 @@
 	if (p == NULL)
 		return PERF_PERIODIC_ERROR;
 	for (cpu = 0; cpu < cpus->nr; cpu++) {
+		if (((1 << cpu) & cpumask) == 0)
+			continue;
 		p->perf_fd[cpu] = sys_perf_event_open(p->attr, target_pid, cpu,
 					-1, 0);
 		if (p->perf_fd[cpu] < 0)