Merge "msm_serial_hs_lite: Increase TX path timeout" into msm-3.4
diff --git a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
index a33d833..d8784db 100644
--- a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
+++ b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
@@ -40,6 +40,7 @@
 - qcom,saw2-spm-cmd-ret: The Retention command sequence
 - qcom,saw2-spm-cmd-spc: The Standalone PC command sequence
 - qcom,saw2-spm-cmd-pc: The Power Collapse command sequence
+- qcom,saw2-spm-cmd-gdhs: L2 GDHS command sequence
 
 Example:
 	qcom,spm@f9089000 {
@@ -56,11 +57,11 @@
 		qcom,saw2-avs-dly= <0>;
 		qcom,saw2-spm-dly= <0x20000400>;
 		qcom,saw2-spm-ctl = <0x1>;
-		qcom,spm-cmd-wfi = [03 0b 0f];
-		qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
 				a0 b0 03 68 70 3b 92 a0 b0
 				82 2b 50 10 30 02 22 30 0f];
-		qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+		qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
 				a0 b0 82 10 30 02 22 30 0f];
 	};
 
diff --git a/arch/arm/boot/dts/msmcopper-regulator.dtsi b/arch/arm/boot/dts/msmcopper-regulator.dtsi
index 0d0c587..a926aa3 100644
--- a/arch/arm/boot/dts/msmcopper-regulator.dtsi
+++ b/arch/arm/boot/dts/msmcopper-regulator.dtsi
@@ -155,7 +155,7 @@
 			};
 
 			pm8941_l13: regulator@4c00 {
-				regulator-min-microvolt = <2950000>;
+				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <2950000>;
 				qcom,enable-time = <200>;
 				qcom,pull-down-enable = <1>;
diff --git a/arch/arm/boot/dts/msmcopper_pm.dtsi b/arch/arm/boot/dts/msmcopper_pm.dtsi
index 0da3200..79cb95c 100644
--- a/arch/arm/boot/dts/msmcopper_pm.dtsi
+++ b/arch/arm/boot/dts/msmcopper_pm.dtsi
@@ -27,11 +27,11 @@
 		qcom,saw2-avs-dly= <0>;
 		qcom,saw2-spm-dly= <0x20000400>;
 		qcom,saw2-spm-ctl = <0x1>;
-		qcom,spm-cmd-wfi = [03 0b 0f];
-		qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
 				a0 b0 03 68 70 3b 92 a0 b0
 				82 2b 50 10 30 02 22 30 0f];
-		qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+		qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
 				a0 b0 82 10 30 02 22 30 0f];
 	};
 
@@ -49,11 +49,11 @@
 		qcom,saw2-avs-dly= <0>;
 		qcom,saw2-spm-dly= <0x20000400>;
 		qcom,saw2-spm-ctl = <0x1>;
-		qcom,spm-cmd-wfi = [03 0b 0f];
-		qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
 				a0 b0 03 68 70 3b 92 a0 b0
 				82 2b 50 10 30 02 22 30 0f];
-		qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+		qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
 				a0 b0 82 10 30 02 22 30 0f];
 	};
 
@@ -71,11 +71,11 @@
 		qcom,saw2-avs-dly= <0>;
 		qcom,saw2-spm-dly= <0x20000400>;
 		qcom,saw2-spm-ctl = <0x1>;
-		qcom,spm-cmd-wfi = [03 0b 0f];
-		qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
 				a0 b0 03 68 70 3b 92 a0 b0
 				82 2b 50 10 30 02 22 30 0f];
-		qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+		qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
 				a0 b0 82 10 30 02 22 30 0f];
 	};
 
@@ -93,11 +93,11 @@
 		qcom,saw2-avs-dly= <0>;
 		qcom,saw2-spm-dly= <0x20000400>;
 		qcom,saw2-spm-ctl = <0x1>;
-		qcom,spm-cmd-wfi = [03 0b 0f];
-		qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
 				a0 b0 03 68 70 3b 92 a0 b0
 				82 2b 50 10 30 02 22 30 0f];
-		qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+		qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
 				a0 b0 82 10 30 02 22 30 0f];
 	};
 
@@ -123,12 +123,12 @@
 		qcom,vctl-timeout-us = <50>;
 		qcom,vctl-port = <0x0>; /* TODO: */
 		qcom,phase-port = <0x1>; /* TODO: */
-		qcom,spm-cmd-ret = [0b 00 20 03 22 00 0f];
-		qcom,spm-cmd-spc = [00 20 32 60 70 80 42 03
-				78 80 44 22 50 3b 60 02 32
-				50 0f];
-		qcom,spm-cmd-pc = [00 10 32 60 70 80 b0 11 42
-				07 01 b0 78 80 12 44 a0 50
+		qcom,saw2-spm-cmd-ret = [0b 00 20 03 22 00 0f];
+		qcom,saw2-spm-cmd-gdhs =  [00 20 32 60 70 80 0b 42 07
+				      78 80 44 22 50 3b 60 02 32
+				      50 0f];
+		qcom,saw2-spm-cmd-pc = [00 10 32 60 70 80 b0 11 0b
+				42 07 01 b0 78 80 12 44 a0 50
 				3b 60 02 32 a0 50 0f];
 	};
 
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 3043b78..eb9dc0a 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -331,6 +331,7 @@
 obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60-vcm.o
 endif
 obj-$(CONFIG_MSM_OCMEM) += ocmem.o ocmem_allocator.o ocmem_notifier.o
+obj-$(CONFIG_MSM_OCMEM) += ocmem_sched.o ocmem_api.o
 
 obj-$(CONFIG_ARCH_MSM7X27) += gpiomux-7x27.o gpiomux-v1.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM7X30) += gpiomux-7x30.o gpiomux-v1.o gpiomux.o
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator.c
index cb8903c..5bee8a2 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator.c
@@ -485,7 +485,7 @@
 	RPM_LDO(L15,	 0, 1, 0, 1800000, 2950000, NULL,      0, 0),
 	RPM_LDO(L17,	 0, 1, 0, 1800000, 2950000, NULL,      0, 0),
 	RPM_LDO(L18,	 0, 1, 0, 1800000, 1800000, NULL,      0, 0),
-	RPM_LDO(L20,	 1, 1, 0, 1200000, 1200000, "8038_s2", 10000, 10000),
+	RPM_LDO(L20,	 1, 1, 0, 1250000, 1250000, "8038_s2", 10000, 10000),
 	RPM_LDO(L21,	 0, 1, 0, 1900000, 1900000, "8038_s4", 0, 0),
 	RPM_LDO(L22,	 1, 1, 0, 1850000, 2950000, NULL,      10000, 10000),
 	RPM_LDO(L23,	 1, 1, 1, 1800000, 1800000, "8038_s4", 0, 0),
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 338cb84..8df37f7 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -786,13 +786,13 @@
 	{
 		.name = "VDDD_CDC_D",
 		.min_uV = 1200000,
-		.max_uV = 1200000,
+		.max_uV = 1250000,
 		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
 	},
 	{
 		.name = "CDC_VDDA_A_1P2V",
 		.min_uV = 1200000,
-		.max_uV = 1200000,
+		.max_uV = 1250000,
 		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
 	},
 	},
@@ -850,13 +850,13 @@
 	{
 		.name = "VDDD_CDC_D",
 		.min_uV = 1200000,
-		.max_uV = 1200000,
+		.max_uV = 1250000,
 		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
 	},
 	{
 		.name = "CDC_VDDA_A_1P2V",
 		.min_uV = 1200000,
-		.max_uV = 1200000,
+		.max_uV = 1250000,
 		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
 	},
 	},
diff --git a/arch/arm/mach-msm/board-msm7627a-display.c b/arch/arm/mach-msm/board-msm7627a-display.c
index 8740186..3da68ad 100644
--- a/arch/arm/mach-msm/board-msm7627a-display.c
+++ b/arch/arm/mach-msm/board-msm7627a-display.c
@@ -577,90 +577,98 @@
 };
 #endif
 
-static int evb_backlight_control(int level)
+static int evb_backlight_control(int level, int mode)
 {
 
 	int i = 0;
-	int remainder;
+	int remainder, ret = 0;
+
 	/* device address byte = 0x72 */
-	gpio_set_value(96, 0);
-	udelay(67);
-	gpio_set_value(96, 1);
-	udelay(33);
-	gpio_set_value(96, 0);
-	udelay(33);
-	gpio_set_value(96, 1);
-	udelay(67);
-	gpio_set_value(96, 0);
-	udelay(33);
-	gpio_set_value(96, 1);
-	udelay(67);
-	gpio_set_value(96, 0);
-	udelay(33);
-	gpio_set_value(96, 1);
-	udelay(67);
-	gpio_set_value(96, 0);
-	udelay(67);
-	gpio_set_value(96, 1);
-	udelay(33);
-	gpio_set_value(96, 0);
-	udelay(67);
-	gpio_set_value(96, 1);
-	udelay(33);
-	gpio_set_value(96, 0);
-	udelay(33);
-	gpio_set_value(96, 1);
-	udelay(67);
-	gpio_set_value(96, 0);
-	udelay(67);
-	gpio_set_value(96, 1);
-	udelay(33);
+	if (!mode) {
+		gpio_set_value(96, 0);
+		udelay(67);
+		gpio_set_value(96, 1);
+		udelay(33);
+		gpio_set_value(96, 0);
+		udelay(33);
+		gpio_set_value(96, 1);
+		udelay(67);
+		gpio_set_value(96, 0);
+		udelay(33);
+		gpio_set_value(96, 1);
+		udelay(67);
+		gpio_set_value(96, 0);
+		udelay(33);
+		gpio_set_value(96, 1);
+		udelay(67);
+		gpio_set_value(96, 0);
+		udelay(67);
+		gpio_set_value(96, 1);
+		udelay(33);
+		gpio_set_value(96, 0);
+		udelay(67);
+		gpio_set_value(96, 1);
+		udelay(33);
+		gpio_set_value(96, 0);
+		udelay(33);
+		gpio_set_value(96, 1);
+		udelay(67);
+		gpio_set_value(96, 0);
+		udelay(67);
+		gpio_set_value(96, 1);
+		udelay(33);
 
-	/* t-EOS and t-start */
-	gpio_set_value(96, 0);
-	ndelay(4200);
-	gpio_set_value(96, 1);
-	ndelay(9000);
+		/* t-EOS and t-start */
+		gpio_set_value(96, 0);
+		ndelay(4200);
+		gpio_set_value(96, 1);
+		ndelay(9000);
 
-	/* data byte */
-	/* RFA = 0 */
-	gpio_set_value(96, 0);
-	udelay(67);
-	gpio_set_value(96, 1);
-	udelay(33);
+		/* data byte */
+		/* RFA = 0 */
+		gpio_set_value(96, 0);
+		udelay(67);
+		gpio_set_value(96, 1);
+		udelay(33);
 
-	/* Address bits */
-	gpio_set_value(96, 0);
-	udelay(67);
-	gpio_set_value(96, 1);
-	udelay(33);
-	gpio_set_value(96, 0);
-	udelay(67);
-	gpio_set_value(96, 1);
-	udelay(33);
+		/* Address bits */
+		gpio_set_value(96, 0);
+		udelay(67);
+		gpio_set_value(96, 1);
+		udelay(33);
+		gpio_set_value(96, 0);
+		udelay(67);
+		gpio_set_value(96, 1);
+		udelay(33);
 
-	/* Data bits */
-	for (i = 0; i < 5; i++) {
-		remainder = (level) & (16);
-		if (remainder) {
-			gpio_set_value(96, 0);
-			udelay(33);
-			gpio_set_value(96, 1);
-			udelay(67);
-		} else {
-			gpio_set_value(96, 0);
-			udelay(67);
-			gpio_set_value(96, 1);
-			udelay(33);
+		/* Data bits */
+		for (i = 0; i < 5; i++) {
+			remainder = (level) & (16);
+			if (remainder) {
+				gpio_set_value(96, 0);
+				udelay(33);
+				gpio_set_value(96, 1);
+				udelay(67);
+			} else {
+				gpio_set_value(96, 0);
+				udelay(67);
+				gpio_set_value(96, 1);
+				udelay(33);
+			}
+			level = level << 1;
 		}
-		level = level << 1;
+
+		/* t-EOS */
+		gpio_set_value(96, 0);
+		ndelay(12000);
+		gpio_set_value(96, 1);
+	} else {
+		ret = pmapp_disp_backlight_set_brightness(level);
+		 if (ret)
+			pr_err("%s: can't set lcd backlight!\n", __func__);
 	}
 
-	/* t-EOS */
-	gpio_set_value(96, 0);
-	ndelay(12000);
-	gpio_set_value(96, 1);
-	return 0;
+	return ret;
 }
 
 static int mipi_NT35510_rotate_panel(void)
@@ -685,7 +693,7 @@
 };
 
 static struct msm_panel_common_pdata mipi_NT35510_pdata = {
-	.pmic_backlight = evb_backlight_control,
+	.backlight    = evb_backlight_control,
 	.rotate_panel = mipi_NT35510_rotate_panel,
 };
 
@@ -698,7 +706,7 @@
 };
 
 static struct msm_panel_common_pdata mipi_NT35516_pdata = {
-	.pmic_backlight = evb_backlight_control,
+	.backlight = evb_backlight_control,
 };
 
 static struct platform_device mipi_dsi_NT35516_panel_device = {
@@ -1141,6 +1149,7 @@
 	static struct regulator *gpio_reg_2p85v, *gpio_reg_1p8v;
 
 	if (!qrd3_dsi_gpio_initialized) {
+		pmapp_disp_backlight_init();
 		rc = gpio_request(GPIO_QRD3_LCD_BACKLIGHT_EN,
 			"qrd3_gpio_bkl_en");
 		if (rc < 0)
diff --git a/arch/arm/mach-msm/headsmp.S b/arch/arm/mach-msm/headsmp.S
index 50d2060..e5ad312 100644
--- a/arch/arm/mach-msm/headsmp.S
+++ b/arch/arm/mach-msm/headsmp.S
@@ -27,10 +27,6 @@
 	sub	r4, r4, r5		@ determine virtual/phys offsets
 	add	r6, r6, r4		@ apply
 pen:
-	wfe
-	dsb				@ ensure subsequent access is
-					@ after event
-
 	ldr	r7, [r6]		@ pen_rel has cpu to remove from reset
 	cmp	r7, r0			@ are we lucky?
 	bne	pen
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 8c1d5b7..243b488 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -389,6 +389,7 @@
 	int (*backlight_level)(int level, int max, int min);
 	int (*pmic_backlight)(int level);
 	int (*rotate_panel)(void);
+	int (*backlight) (int level, int mode);
 	int (*panel_num)(void);
 	void (*panel_config_gpio)(int);
 	int (*vga_switch)(int select_vga);
diff --git a/arch/arm/mach-msm/include/mach/ocmem.h b/arch/arm/mach-msm/include/mach/ocmem.h
index bf7c338..b0475ed 100644
--- a/arch/arm/mach-msm/include/mach/ocmem.h
+++ b/arch/arm/mach-msm/include/mach/ocmem.h
@@ -41,7 +41,7 @@
 };
 
 struct ocmem_map_list {
-	int num_chunks;
+	unsigned num_chunks;
 	struct ocmem_chunk chunks[OCMEM_MAX_CHUNKS];
 };
 
@@ -84,9 +84,14 @@
 
 int ocmem_notifier_unregister(void *notif_hndl, struct notifier_block *nb);
 
+/* Obtain the maximum quota for the client */
+unsigned long get_max_quota(int client_id);
+
 /* Allocation APIs */
 struct ocmem_buf *ocmem_allocate(int client_id, unsigned long size);
 
+struct ocmem_buf *ocmem_allocate_nowait(int client_id, unsigned long size);
+
 struct ocmem_buf *ocmem_allocate_nb(int client_id, unsigned long size);
 
 struct ocmem_buf *ocmem_allocate_range(int client_id, unsigned long min,
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index dd3a318..dd976ea 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -24,6 +24,9 @@
 #define OCMEM_PHYS_BASE 0xFEC00000
 #define OCMEM_PHYS_SIZE 0x180000
 
+#define TO_OCMEM 0x1
+#define TO_DDR 0x2
+
 struct ocmem_zone;
 
 struct ocmem_zone_ops {
@@ -45,6 +48,19 @@
 	struct ocmem_zone_ops *z_ops;
 };
 
+enum op_code {
+	SCHED_NOP = 0x0,
+	SCHED_ALLOCATE,
+	SCHED_FREE,
+	SCHED_GROW,
+	SCHED_SHRINK,
+	SCHED_MAP,
+	SCHED_UNMAP,
+	SCHED_EVICT,
+	SCHED_RESTORE,
+	SCHED_DUMP,
+};
+
 struct ocmem_req {
 	struct rw_semaphore rw_sem;
 	/* Chain in sched queue */
@@ -60,6 +76,8 @@
 	/* reverse pointers */
 	struct ocmem_zone *zone;
 	struct ocmem_buf *buffer;
+	struct ocmem_map_list *mlist;
+	enum op_code op;
 	unsigned long state;
 	/* Request assignments */
 	unsigned long req_start;
@@ -73,7 +91,41 @@
 	struct ocmem_req *req;
 };
 
+static inline struct ocmem_buf *handle_to_buffer(struct ocmem_handle *handle)
+{
+	if (handle)
+		return &handle->buffer;
+	else
+		return NULL;
+}
+
+static inline struct ocmem_handle *buffer_to_handle(struct ocmem_buf *buffer)
+{
+	if (buffer)
+		return container_of(buffer, struct ocmem_handle, buffer);
+	else
+		return NULL;
+}
+
+static inline struct ocmem_req *handle_to_req(struct ocmem_handle *handle)
+{
+	if (handle)
+		return handle->req;
+	else
+		return NULL;
+}
+
+static inline struct ocmem_handle *req_to_handle(struct ocmem_req *req)
+{
+	if (req && req->buffer)
+		return container_of(req->buffer, struct ocmem_handle, buffer);
+	else
+		return NULL;
+}
+
 struct ocmem_zone *get_zone(unsigned);
+unsigned long offset_to_phys(unsigned long);
+unsigned long phys_to_offset(unsigned long);
 unsigned long allocate_head(struct ocmem_zone *, unsigned long);
 int free_head(struct ocmem_zone *, unsigned long, unsigned long);
 unsigned long allocate_tail(struct ocmem_zone *, unsigned long);
@@ -82,4 +134,12 @@
 int ocmem_notifier_init(void);
 int check_notifier(int);
 int dispatch_notification(int, enum ocmem_notif_type, struct ocmem_buf *);
+
+int ocmem_sched_init(void);
+int process_allocate(int, struct ocmem_handle *, unsigned long, unsigned long,
+			unsigned long, bool, bool);
+int process_free(int, struct ocmem_handle *);
+int process_xfer(int, struct ocmem_handle *, struct ocmem_map_list *,
+			int direction);
+unsigned long process_quota(int);
 #endif
diff --git a/arch/arm/mach-msm/modem_notifier.c b/arch/arm/mach-msm/modem_notifier.c
index d92098b..2f4f6af 100644
--- a/arch/arm/mach-msm/modem_notifier.c
+++ b/arch/arm/mach-msm/modem_notifier.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-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
@@ -193,8 +193,15 @@
 }
 #endif
 
-static int __init init_modem_notifier_list(void)
+int __init msm_init_modem_notifier_list(void)
 {
+	static bool registered;
+
+	if (registered)
+		return 0;
+
+	registered = true;
+
 	srcu_init_notifier_head(&modem_notifier_list);
 	modem_notifier_debugfs_init();
 #if defined(DEBUG)
@@ -210,4 +217,4 @@
 
 	return 0;
 }
-module_init(init_modem_notifier_list);
+module_init(msm_init_modem_notifier_list);
diff --git a/arch/arm/mach-msm/modem_notifier.h b/arch/arm/mach-msm/modem_notifier.h
index 1bd2d6d..e39c163 100644
--- a/arch/arm/mach-msm/modem_notifier.h
+++ b/arch/arm/mach-msm/modem_notifier.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-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
@@ -30,5 +30,6 @@
 extern void modem_queue_start_reset_notify(void);
 extern void modem_queue_end_reset_notify(void);
 extern void modem_queue_smsm_init_notify(void);
+extern int __init msm_init_modem_notifier_list(void);
 
 #endif /* _MODEM_NOTIFIER_H */
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
index ddfc906..ae1d6f2 100644
--- a/arch/arm/mach-msm/ocmem.c
+++ b/arch/arm/mach-msm/ocmem.c
@@ -97,6 +97,25 @@
 	return -EINVAL;
 }
 
+inline unsigned long phys_to_offset(unsigned long addr)
+{
+	if (!ocmem_pdata)
+		return 0;
+	if (addr < ocmem_pdata->base ||
+		addr > (ocmem_pdata->base + ocmem_pdata->size))
+		return 0;
+	return addr - ocmem_pdata->base;
+}
+
+inline unsigned long offset_to_phys(unsigned long offset)
+{
+	if (!ocmem_pdata)
+		return 0;
+	if (offset > ocmem_pdata->size)
+		return 0;
+	return offset + ocmem_pdata->base;
+}
+
 static struct ocmem_plat_data *parse_static_config(struct platform_device *pdev)
 {
 	struct ocmem_plat_data *pdata = NULL;
@@ -276,6 +295,8 @@
 	if (ocmem_notifier_init())
 		return -EBUSY;
 
+	if (ocmem_sched_init())
+		return -EBUSY;
 	dev_info(dev, "initialized successfully\n");
 	return 0;
 }
diff --git a/arch/arm/mach-msm/ocmem_api.c b/arch/arm/mach-msm/ocmem_api.c
new file mode 100644
index 0000000..bed13de
--- /dev/null
+++ b/arch/arm/mach-msm/ocmem_api.c
@@ -0,0 +1,327 @@
+/* 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/slab.h>
+#include <mach/ocmem_priv.h>
+
+static inline int check_id(int id)
+{
+	return (id < OCMEM_CLIENT_MAX && id >= OCMEM_GRAPHICS);
+}
+
+static struct ocmem_handle *generate_handle(void)
+{
+	struct ocmem_handle *handle = NULL;
+
+	handle = kzalloc(sizeof(struct ocmem_handle), GFP_KERNEL);
+	if (!handle) {
+		pr_err("ocmem: Unable to generate buffer handle\n");
+		return NULL;
+	}
+	mutex_init(&handle->handle_mutex);
+	return handle;
+}
+
+static int free_handle(struct ocmem_handle *handle)
+{
+	if (!handle)
+		return -EINVAL;
+
+	mutex_destroy(&handle->handle_mutex);
+	kfree(handle);
+	handle = NULL;
+	return 0;
+}
+
+static int __ocmem_free(int id, struct ocmem_buf *buf)
+{
+	int ret = 0;
+	struct ocmem_handle *handle = buffer_to_handle(buf);
+
+	if (!handle)
+		return -EINVAL;
+
+	mutex_lock(&handle->handle_mutex);
+	ret = process_free(id, handle);
+	mutex_unlock(&handle->handle_mutex);
+
+	if (ret)
+		return -EINVAL;
+
+	free_handle(handle);
+	return 0;
+}
+
+static struct ocmem_buf *__ocmem_allocate_range(int id, unsigned long min,
+		unsigned long max, unsigned long step, bool block, bool wait)
+{
+	struct ocmem_handle *handle = NULL;
+	int ret = 0;
+
+	handle = generate_handle();
+	if (!handle) {
+		pr_err("ocmem: Unable to generate handle\n");
+		return NULL;
+	}
+
+	mutex_lock(&handle->handle_mutex);
+	ret = process_allocate(id, handle, min, max, step, block, wait);
+	mutex_unlock(&handle->handle_mutex);
+	if (ret) {
+		pr_err("ocmem allocation failed\n");
+		free_handle(handle);
+		return NULL;
+	} else
+		return handle_to_buffer(handle);
+}
+
+struct ocmem_buf *ocmem_allocate(int client_id, unsigned long size)
+{
+	bool can_block = false;
+	bool can_wait = true;
+
+	if (!check_id(client_id)) {
+		pr_err("ocmem: Invalid client id: %d\n", client_id);
+		return NULL;
+	}
+
+	if (size < OCMEM_MIN_ALLOC) {
+		pr_err("ocmem: requested size %lx must be at least %x\n",
+				size, OCMEM_MIN_ALLOC);
+		return NULL;
+	}
+
+	if (!IS_ALIGNED(size, OCMEM_MIN_ALIGN)) {
+		pr_err("ocmem: Invalid alignment, size must be %x aligned\n",
+				OCMEM_MIN_ALIGN);
+		return NULL;
+	}
+
+	return __ocmem_allocate_range(client_id, size, size,
+					size, can_block, can_wait);
+}
+
+struct ocmem_buf *ocmem_allocate_nowait(int client_id, unsigned long size)
+{
+	bool can_block = false;
+	bool can_wait = false;
+
+	if (!check_id(client_id)) {
+		pr_err("ocmem: Invalid client id: %d\n", client_id);
+		return NULL;
+	}
+
+	if (size < OCMEM_MIN_ALLOC) {
+		pr_err("ocmem: requested size %lx must be at least %x\n",
+				size, OCMEM_MIN_ALLOC);
+		return NULL;
+	}
+
+	if (!IS_ALIGNED(size, OCMEM_MIN_ALIGN)) {
+		pr_err("ocmem: Invalid alignment, size must be %x aligned\n",
+				OCMEM_MIN_ALIGN);
+		return NULL;
+	}
+	return __ocmem_allocate_range(client_id, size, size,
+					size, can_block, can_wait);
+}
+
+struct ocmem_buf *ocmem_allocate_range(int client_id, unsigned long min,
+		unsigned long goal, unsigned long step)
+{
+	bool can_block = true;
+	bool can_wait = false;
+
+	if (!check_id(client_id)) {
+		pr_err("ocmem: Invalid client id: %d\n", client_id);
+		return NULL;
+	}
+
+	/* Asynchronous API requires notifier registration */
+	if (!check_notifier(client_id)) {
+		pr_err("ocmem: No notifier registered for client %d\n",
+				client_id);
+		return NULL;
+	}
+
+	if (min < OCMEM_MIN_ALLOC) {
+		pr_err("ocmem: requested min size %lx must be at least %x\n",
+				min, OCMEM_MIN_ALLOC);
+		return NULL;
+	}
+
+	if (!IS_ALIGNED(min | goal | step, OCMEM_MIN_ALIGN)) {
+		pr_err("ocmem: Invalid alignment, args must be %x aligned\n",
+				OCMEM_MIN_ALIGN);
+		return NULL;
+	}
+
+	return __ocmem_allocate_range(client_id, min, goal,
+				step, can_block, can_wait);
+}
+
+struct ocmem_buf *ocmem_allocate_nb(int client_id, unsigned long size)
+{
+	bool can_block = true;
+	bool can_wait = false;
+
+	if (!check_id(client_id)) {
+		pr_err("ocmem: Invalid client id: %d\n", client_id);
+		return NULL;
+	}
+
+	/* Asynchronous API requires notifier registration */
+	if (!check_notifier(client_id)) {
+		pr_err("ocmem: No notifier registered for client %d\n",
+				client_id);
+		return NULL;
+	}
+
+	if (size < OCMEM_MIN_ALLOC) {
+		pr_err("ocmem: requested size %lx must be at least %x\n",
+				size, OCMEM_MIN_ALLOC);
+		return NULL;
+	}
+
+	if (!IS_ALIGNED(size, OCMEM_MIN_ALIGN)) {
+		pr_err("ocmem: Invalid alignment, args must be %x aligned\n",
+				OCMEM_MIN_ALIGN);
+		return NULL;
+	}
+
+	return __ocmem_allocate_range(client_id, 0, size, size,
+						can_block, can_wait);
+
+}
+
+int ocmem_free(int client_id, struct ocmem_buf *buffer)
+{
+	if (!check_id(client_id)) {
+		pr_err("ocmem: Invalid client id: %d\n", client_id);
+		return -EINVAL;
+	}
+
+	if (!buffer) {
+		pr_err("ocmem: Invalid buffer\n");
+		return -EINVAL;
+	}
+
+	return __ocmem_free(client_id, buffer);
+}
+
+int pre_validate_chunk_list(struct ocmem_map_list *list)
+{
+	int i = 0;
+	struct ocmem_chunk *chunks;
+
+	if (!list)
+		return -EINVAL;
+
+	if (list->num_chunks > OCMEM_MAX_CHUNKS || list->num_chunks == 0)
+		return -EINVAL;
+
+	chunks = list->chunks;
+
+	if (!chunks)
+		return -EINVAL;
+
+	for (i = 0; i < list->num_chunks; i++) {
+		if (!chunks[i].ddr_paddr ||
+			chunks[i].size < MIN_CHUNK_SIZE)
+			return -EINVAL;
+	}
+	return 0;
+}
+
+int ocmem_map(int client_id, struct ocmem_buf *buffer,
+			struct ocmem_map_list *list)
+{
+	int ret = 0;
+	struct ocmem_handle *handle = NULL;
+
+	if (!check_id(client_id)) {
+		pr_err("ocmem: Invalid client id: %d\n", client_id);
+		return -EINVAL;
+	}
+
+	/* Asynchronous API requires notifier registration */
+	if (!check_notifier(client_id)) {
+		pr_err("ocmem: No notifier registered for client %d\n",
+				client_id);
+		return -EINVAL;
+	}
+
+	if (!buffer) {
+		pr_err("ocmem: Invalid buffer\n");
+		return -EINVAL;
+	}
+
+	if (!pre_validate_chunk_list(list))
+		return -EINVAL;
+
+	handle = buffer_to_handle(buffer);
+
+	if (!handle)
+		return -EINVAL;
+
+	mutex_lock(&handle->handle_mutex);
+	ret = process_xfer(client_id, handle, list, TO_OCMEM);
+	mutex_unlock(&handle->handle_mutex);
+	return ret;
+}
+
+int ocmem_unmap(int client_id, struct ocmem_buf *buffer,
+			struct ocmem_map_list *list)
+{
+
+	int ret = 0;
+	struct ocmem_handle *handle = NULL;
+
+	if (!check_id(client_id)) {
+		pr_err("ocmem: Invalid client id: %d\n", client_id);
+		return -EINVAL;
+	}
+
+	/* Asynchronous API requires notifier registration */
+	if (!check_notifier(client_id)) {
+		pr_err("ocmem: No notifier registered for client %d\n",
+				client_id);
+		return -EINVAL;
+	}
+
+	if (!buffer) {
+		pr_err("ocmem: Invalid buffer\n");
+		return -EINVAL;
+	}
+
+	if (!pre_validate_chunk_list(list))
+		return -EINVAL;
+
+	handle = buffer_to_handle(buffer);
+
+	if (!handle)
+		return -EINVAL;
+
+	mutex_lock(&handle->handle_mutex);
+	ret = process_xfer(client_id, handle, list, TO_DDR);
+	mutex_unlock(&handle->handle_mutex);
+	return ret;
+}
+
+unsigned long get_max_quota(int client_id)
+{
+	if (!check_id(client_id)) {
+		pr_err("ocmem: Invalid client id: %d\n", client_id);
+		return 0x0;
+	}
+	return process_quota(client_id);
+}
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
new file mode 100644
index 0000000..10a267c
--- /dev/null
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -0,0 +1,1255 @@
+/* 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/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/rbtree.h>
+#include <linux/idr.h>
+#include <linux/genalloc.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <mach/ocmem_priv.h>
+
+enum request_states {
+	R_FREE = 0x0,	/* request is not allocated */
+	R_PENDING,	/* request has a pending operation */
+	R_ALLOCATED,	/* request has been allocated */
+	R_MUST_GROW,	/* request must grow as a part of pending operation */
+	R_MUST_SHRINK,	/* request must shrink as a part of pending operation */
+	R_MUST_MAP,	/* request must be mapped before being used */
+	R_MUST_UNMAP,	/* request must be unmapped when not being used */
+	R_MAPPED,	/* request is mapped and actively used by client */
+	R_UNMAPPED,	/* request is not mapped, so it's not in active use */
+	R_EVICTED,	/* request is evicted and must be restored */
+};
+
+#define SET_STATE(x, val) (set_bit((val), &(x)->state))
+#define CLEAR_STATE(x, val) (clear_bit((val), &(x)->state))
+#define TEST_STATE(x, val) (test_bit((val), &(x)->state))
+
+enum op_res {
+	OP_COMPLETE = 0x0,
+	OP_RESCHED,
+	OP_PARTIAL,
+	OP_FAIL = ~0x0,
+};
+
+/* Represents various client priorities */
+/* Note: More than one client can share a priority level */
+enum client_prio {
+	MIN_PRIO = 0x0,
+	NO_PRIO = MIN_PRIO,
+	PRIO_SENSORS = 0x1,
+	PRIO_BLAST = 0x1,
+	PRIO_LP_AUDIO = 0x1,
+	PRIO_HP_AUDIO = 0x2,
+	PRIO_VOICE = 0x3,
+	PRIO_GFX_GROWTH = 0x4,
+	PRIO_VIDEO = 0x5,
+	PRIO_GFX = 0x6,
+	PRIO_OCMEM = 0x7,
+	MAX_OCMEM_PRIO = PRIO_OCMEM + 1,
+};
+
+static struct list_head sched_queue[MAX_OCMEM_PRIO];
+static struct mutex sched_queue_mutex;
+
+/* The duration in msecs before a pending operation is scheduled
+ * This allows an idle window between use case boundaries where various
+ * hardware state changes can occur. The value will be tweaked on actual
+ * hardware.
+*/
+#define SCHED_DELAY 10
+
+/* OCMEM Operational modes */
+enum ocmem_client_modes {
+	OCMEM_PERFORMANCE = 1,
+	OCMEM_PASSIVE,
+	OCMEM_LOW_POWER,
+	OCMEM_MODE_MAX = OCMEM_LOW_POWER
+};
+
+/* OCMEM Addressing modes */
+enum ocmem_interconnects {
+	OCMEM_BLOCKED = 0,
+	OCMEM_PORT = 1,
+	OCMEM_OCMEMNOC = 2,
+	OCMEM_SYSNOC = 3,
+};
+
+/**
+ * Primary OCMEM Arbitration Table
+ **/
+struct ocmem_table {
+	int client_id;
+	int priority;
+	int mode;
+	int hw_interconnect;
+} ocmem_client_table[OCMEM_CLIENT_MAX] = {
+	{OCMEM_GRAPHICS, PRIO_GFX, OCMEM_PERFORMANCE, OCMEM_PORT},
+	{OCMEM_VIDEO, PRIO_VIDEO, OCMEM_PERFORMANCE, OCMEM_OCMEMNOC},
+	{OCMEM_CAMERA, NO_PRIO, OCMEM_PERFORMANCE, OCMEM_OCMEMNOC},
+	{OCMEM_HP_AUDIO, PRIO_HP_AUDIO, OCMEM_PASSIVE, OCMEM_BLOCKED},
+	{OCMEM_VOICE, PRIO_VOICE, OCMEM_PASSIVE, OCMEM_BLOCKED},
+	{OCMEM_LP_AUDIO, PRIO_LP_AUDIO, OCMEM_LOW_POWER, OCMEM_SYSNOC},
+	{OCMEM_SENSORS, PRIO_SENSORS, OCMEM_LOW_POWER, OCMEM_SYSNOC},
+	{OCMEM_BLAST, PRIO_BLAST, OCMEM_LOW_POWER, OCMEM_SYSNOC},
+};
+
+static struct rb_root sched_tree;
+static struct mutex sched_mutex;
+
+/* A region represents a continuous interval in OCMEM address space */
+struct ocmem_region {
+	/* Chain in Interval Tree */
+	struct rb_node region_rb;
+	/* Hash map of requests */
+	struct idr region_idr;
+	unsigned long r_start;
+	unsigned long r_end;
+	unsigned long r_sz;
+	/* Highest priority of all requests served by this region */
+	int max_prio;
+};
+
+/* Is OCMEM tightly coupled to the client ?*/
+static inline int is_tcm(int id)
+{
+	if (ocmem_client_table[id].hw_interconnect == OCMEM_PORT ||
+		ocmem_client_table[id].hw_interconnect == OCMEM_OCMEMNOC)
+		return 1;
+	else
+		return 0;
+}
+
+static inline int is_blocked(int id)
+{
+	return ocmem_client_table[id].hw_interconnect == OCMEM_BLOCKED ? 1 : 0;
+}
+
+/* Returns the address that can be used by a device core to access OCMEM */
+static unsigned long device_address(int id, unsigned long addr)
+{
+	int hw_interconnect = ocmem_client_table[id].hw_interconnect;
+	unsigned long ret_addr = 0x0;
+
+	switch (hw_interconnect) {
+	case OCMEM_PORT:
+		ret_addr = phys_to_offset(addr);
+		break;
+	case OCMEM_OCMEMNOC:
+	case OCMEM_SYSNOC:
+		ret_addr = addr;
+		break;
+	case OCMEM_BLOCKED:
+		ret_addr = 0x0;
+		break;
+	}
+	return ret_addr;
+}
+
+/* Returns the address as viewed by the core */
+static unsigned long core_address(int id, unsigned long addr)
+{
+	int hw_interconnect = ocmem_client_table[id].hw_interconnect;
+	unsigned long ret_addr = 0x0;
+
+	switch (hw_interconnect) {
+	case OCMEM_PORT:
+		ret_addr = offset_to_phys(addr);
+		break;
+	case OCMEM_OCMEMNOC:
+	case OCMEM_SYSNOC:
+		ret_addr = addr;
+		break;
+	case OCMEM_BLOCKED:
+		ret_addr = 0x0;
+		break;
+	}
+	return ret_addr;
+}
+
+static int insert_region(struct ocmem_region *region)
+{
+
+	struct rb_root *root = &sched_tree;
+	struct rb_node **p = &root->rb_node;
+	struct rb_node *parent = NULL;
+	struct ocmem_region *tmp = NULL;
+	unsigned long addr = region->r_start;
+
+	while (*p) {
+		parent = *p;
+		tmp = rb_entry(parent, struct ocmem_region, region_rb);
+
+		if (tmp->r_end > addr) {
+			if (tmp->r_start <= addr)
+				break;
+			p =  &(*p)->rb_left;
+		} else if (tmp->r_end <= addr)
+			p = &(*p)->rb_right;
+	}
+	rb_link_node(&region->region_rb, parent, p);
+	rb_insert_color(&region->region_rb, root);
+	return 0;
+}
+
+static int remove_region(struct ocmem_region *region)
+{
+	struct rb_root *root = &sched_tree;
+	rb_erase(&region->region_rb, root);
+	return 0;
+}
+
+static struct ocmem_req *ocmem_create_req(void)
+{
+	struct ocmem_req *p = NULL;
+
+	p =  kzalloc(sizeof(struct ocmem_req), GFP_KERNEL);
+	if (!p)
+		return NULL;
+
+	INIT_LIST_HEAD(&p->zone_list);
+	INIT_LIST_HEAD(&p->sched_list);
+	init_rwsem(&p->rw_sem);
+	SET_STATE(p, R_FREE);
+	return p;
+}
+
+static int ocmem_destroy_req(struct ocmem_req *req)
+{
+	kfree(req);
+	return 0;
+}
+
+static struct ocmem_region *create_region(void)
+{
+	struct ocmem_region *p = NULL;
+
+	p =  kzalloc(sizeof(struct ocmem_region), GFP_KERNEL);
+	if (!p)
+		return NULL;
+	idr_init(&p->region_idr);
+	p->r_start = p->r_end = p->r_sz = 0x0;
+	p->max_prio = NO_PRIO;
+	return p;
+}
+
+static int destroy_region(struct ocmem_region *region)
+{
+	kfree(region);
+	return 0;
+}
+
+static int attach_req(struct ocmem_region *region, struct ocmem_req *req)
+{
+	int ret, id;
+
+	while (1) {
+		if (idr_pre_get(&region->region_idr, GFP_KERNEL) == 0)
+			return -ENOMEM;
+
+		ret = idr_get_new_above(&region->region_idr, req, 1, &id);
+
+		if (ret != -EAGAIN)
+			break;
+	}
+
+	if (!ret) {
+		req->req_id = id;
+		pr_debug("ocmem: request %p(id:%d) attached to region %p\n",
+				req, id, region);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int detach_req(struct ocmem_region *region, struct ocmem_req *req)
+{
+	idr_remove(&region->region_idr, req->req_id);
+	return 0;
+}
+
+static int populate_region(struct ocmem_region *region, struct ocmem_req *req)
+{
+	region->r_start = req->req_start;
+	region->r_end = req->req_end;
+	region->r_sz =  req->req_end - req->req_start + 1;
+	return 0;
+}
+
+static int region_req_count(int id, void *ptr, void *data)
+{
+	int *count = data;
+	*count = *count + 1;
+	return 0;
+}
+
+static int req_count(struct ocmem_region *region)
+{
+	int count = 0;
+	idr_for_each(&region->region_idr, region_req_count, &count);
+	return count;
+}
+
+static int compute_max_prio(int id, void *ptr, void *data)
+{
+	int *max = data;
+	struct ocmem_req *req = ptr;
+
+	if (req->prio > *max)
+		*max = req->prio;
+	return 0;
+}
+
+static int update_region_prio(struct ocmem_region *region)
+{
+	int max_prio;
+	if (req_count(region) != 0) {
+		idr_for_each(&region->region_idr, compute_max_prio, &max_prio);
+		region->max_prio = max_prio;
+	} else {
+		region->max_prio = NO_PRIO;
+	}
+	pr_debug("ocmem: Updating prio of region %p as %d\n",
+			region, max_prio);
+
+	return 0;
+}
+
+static struct ocmem_region *find_region(unsigned long addr)
+{
+	struct ocmem_region *region = NULL;
+	struct rb_node *rb_node = NULL;
+
+	rb_node = sched_tree.rb_node;
+
+	while (rb_node) {
+		struct ocmem_region *tmp_region = NULL;
+		tmp_region = rb_entry(rb_node, struct ocmem_region, region_rb);
+
+		if (tmp_region->r_end > addr) {
+			region = tmp_region;
+			if (tmp_region->r_start <= addr)
+				break;
+			rb_node = rb_node->rb_left;
+		} else {
+			rb_node = rb_node->rb_right;
+		}
+	}
+	return region;
+}
+
+static struct ocmem_region *find_region_intersection(unsigned long start,
+					unsigned long end)
+{
+
+	struct ocmem_region *region = NULL;
+	region = find_region(start);
+	if (region && end <= region->r_start)
+		region = NULL;
+	return region;
+}
+
+static struct ocmem_region *find_region_match(unsigned long start,
+					unsigned long end)
+{
+
+	struct ocmem_region *region = NULL;
+	region = find_region(start);
+	if (region && start == region->r_start && end == region->r_end)
+		return region;
+	return NULL;
+}
+
+static struct ocmem_req *find_req_match(int owner, struct ocmem_region *region)
+{
+	struct ocmem_req *req = NULL;
+
+	if (!region)
+		return NULL;
+
+	req = idr_find(&region->region_idr, owner);
+
+	return req;
+}
+
+/* Must be called with req->sem held */
+static inline int is_mapped(struct ocmem_req *req)
+{
+	return TEST_STATE(req, R_MAPPED);
+}
+
+/* Must be called with sched_mutex held */
+static int __sched_unmap(struct ocmem_req *req)
+{
+	struct ocmem_req *matched_req = NULL;
+	struct ocmem_region *matched_region = NULL;
+
+	matched_region = find_region_match(req->req_start, req->req_end);
+	matched_req = find_req_match(req->req_id, matched_region);
+
+	if (!matched_region || !matched_req) {
+		pr_err("Could not find backing region for req");
+		goto invalid_op_error;
+	}
+
+	if (matched_req != req) {
+		pr_err("Request does not match backing req");
+		goto invalid_op_error;
+	}
+
+	if (!is_mapped(req)) {
+		pr_err("Request is not currently mapped");
+		goto invalid_op_error;
+	}
+
+	/* Update the request state */
+	CLEAR_STATE(req, R_MAPPED);
+	SET_STATE(req, R_MUST_MAP);
+
+	return OP_COMPLETE;
+
+invalid_op_error:
+	return OP_FAIL;
+}
+
+/* Must be called with sched_mutex held */
+static int __sched_map(struct ocmem_req *req)
+{
+	struct ocmem_req *matched_req = NULL;
+	struct ocmem_region *matched_region = NULL;
+
+	matched_region = find_region_match(req->req_start, req->req_end);
+	matched_req = find_req_match(req->req_id, matched_region);
+
+	if (!matched_region || !matched_req) {
+		pr_err("Could not find backing region for req");
+		goto invalid_op_error;
+	}
+
+	if (matched_req != req) {
+		pr_err("Request does not match backing req");
+		goto invalid_op_error;
+	}
+
+	/* Update the request state */
+	CLEAR_STATE(req, R_MUST_MAP);
+	SET_STATE(req, R_MAPPED);
+
+	return OP_COMPLETE;
+
+invalid_op_error:
+	return OP_FAIL;
+}
+
+static int do_map(struct ocmem_req *req)
+{
+	int rc = 0;
+
+	mutex_lock(&sched_mutex);
+	rc = __sched_map(req);
+	mutex_unlock(&sched_mutex);
+
+	if (rc == OP_FAIL)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int do_unmap(struct ocmem_req *req)
+{
+	int rc = 0;
+
+	mutex_lock(&sched_mutex);
+	rc = __sched_unmap(req);
+	mutex_unlock(&sched_mutex);
+
+	if (rc == OP_FAIL)
+		return -EINVAL;
+
+	return 0;
+}
+
+/* process map is a wrapper where power control will be added later */
+static int process_map(struct ocmem_req *req, unsigned long start,
+				unsigned long end)
+{
+	return do_map(req);
+}
+
+/* process unmap is a wrapper where power control will be added later */
+static int process_unmap(struct ocmem_req *req, unsigned long start,
+				unsigned long end)
+{
+	return do_unmap(req);
+}
+
+static int __sched_grow(struct ocmem_req *req, bool can_block)
+{
+	unsigned long min = req->req_min;
+	unsigned long max = req->req_max;
+	unsigned long step = req->req_step;
+	int owner = req->owner;
+	unsigned long curr_sz = 0;
+	unsigned long growth_sz = 0;
+	unsigned long curr_start = 0;
+	enum client_prio prio = req->prio;
+	unsigned long alloc_addr = 0x0;
+	bool retry;
+	struct ocmem_region *spanned_r = NULL;
+	struct ocmem_region *overlap_r = NULL;
+
+	struct ocmem_req *matched_req = NULL;
+	struct ocmem_region *matched_region = NULL;
+
+	struct ocmem_zone *zone = get_zone(owner);
+	struct ocmem_region *region = NULL;
+
+	matched_region = find_region_match(req->req_start, req->req_end);
+	matched_req = find_req_match(req->req_id, matched_region);
+
+	if (!matched_region || !matched_req) {
+		pr_err("Could not find backing region for req");
+		goto invalid_op_error;
+	}
+
+	if (matched_req != req) {
+		pr_err("Request does not match backing req");
+		goto invalid_op_error;
+	}
+
+	curr_sz = matched_req->req_sz;
+	curr_start = matched_req->req_start;
+	growth_sz = matched_req->req_max - matched_req->req_sz;
+
+	pr_debug("Attempting to grow req %p from %lx to %lx\n",
+			req, matched_req->req_sz, matched_req->req_max);
+
+	retry = false;
+
+	pr_debug("ocmem: GROW: growth size %lx\n", growth_sz);
+
+retry_next_step:
+
+	spanned_r = NULL;
+	overlap_r = NULL;
+
+	spanned_r = find_region(zone->z_head);
+	overlap_r = find_region_intersection(zone->z_head,
+				zone->z_head + growth_sz);
+
+	if (overlap_r == NULL) {
+		/* no conflicting regions, schedule this region */
+		zone->z_ops->free(zone, curr_start, curr_sz);
+		alloc_addr = zone->z_ops->allocate(zone, curr_sz + growth_sz);
+
+		if (alloc_addr < 0) {
+			pr_err("ocmem: zone allocation operation failed\n");
+			goto internal_error;
+		}
+
+		curr_sz += growth_sz;
+		/* Detach the region from the interval tree */
+		/* This is to guarantee that any change in size
+		 * causes the tree to be rebalanced if required */
+
+		detach_req(matched_region, req);
+		if (req_count(matched_region) == 0) {
+			remove_region(matched_region);
+			region = matched_region;
+		} else {
+			region = create_region();
+			if (!region) {
+				pr_err("ocmem: Unable to create region\n");
+				goto region_error;
+			}
+		}
+
+		/* update the request */
+		req->req_start = alloc_addr;
+		/* increment the size to reflect new length */
+		req->req_sz = curr_sz;
+		req->req_end = alloc_addr + req->req_sz - 1;
+
+		/* update request state */
+		CLEAR_STATE(req, R_MUST_GROW);
+		SET_STATE(req, R_ALLOCATED);
+		SET_STATE(req, R_MUST_MAP);
+		req->op = SCHED_MAP;
+
+		/* update the region with new req */
+		attach_req(region, req);
+		populate_region(region, req);
+		update_region_prio(region);
+
+		/* update the tree with new region */
+		if (insert_region(region)) {
+			pr_err("ocmem: Failed to insert the region\n");
+			goto region_error;
+		}
+
+		if (retry) {
+			SET_STATE(req, R_MUST_GROW);
+			SET_STATE(req, R_PENDING);
+			req->op = SCHED_GROW;
+			return OP_PARTIAL;
+		}
+	} else if (spanned_r != NULL && overlap_r != NULL) {
+		/* resolve conflicting regions based on priority */
+		if (overlap_r->max_prio < prio) {
+			/* Growth cannot be triggered unless a previous
+			 * client of lower priority was evicted */
+			pr_err("ocmem: Invalid growth scheduled\n");
+			/* This is serious enough to fail */
+			BUG();
+			return OP_FAIL;
+		} else if (overlap_r->max_prio > prio) {
+			if (min == max) {
+				/* Cannot grow at this time, try later */
+				SET_STATE(req, R_PENDING);
+				SET_STATE(req, R_MUST_GROW);
+				return OP_RESCHED;
+			} else {
+			/* Try to grow in steps */
+				growth_sz -= step;
+				/* We are OOM at this point so need to retry */
+				if (growth_sz <= curr_sz) {
+					SET_STATE(req, R_PENDING);
+					SET_STATE(req, R_MUST_GROW);
+					return OP_RESCHED;
+				}
+				retry = true;
+				pr_debug("ocmem: Attempting with reduced size %lx\n",
+						growth_sz);
+				goto retry_next_step;
+			}
+		} else {
+			pr_err("ocmem: grow: New Region %p Existing %p\n",
+				matched_region, overlap_r);
+			pr_err("ocmem: Undetermined behavior\n");
+			/* This is serious enough to fail */
+			BUG();
+		}
+	} else if (spanned_r == NULL && overlap_r != NULL) {
+		goto err_not_supported;
+	}
+
+	return OP_COMPLETE;
+
+err_not_supported:
+	pr_err("ocmem: Scheduled unsupported operation\n");
+	return OP_FAIL;
+region_error:
+	zone->z_ops->free(zone, alloc_addr, curr_sz);
+	detach_req(region, req);
+	update_region_prio(region);
+	/* req is going to be destroyed by the caller anyways */
+internal_error:
+	destroy_region(region);
+invalid_op_error:
+	return OP_FAIL;
+}
+
+/* Must be called with sched_mutex held */
+static int __sched_free(struct ocmem_req *req)
+{
+	int owner = req->owner;
+	int ret = 0;
+
+	struct ocmem_req *matched_req = NULL;
+	struct ocmem_region *matched_region = NULL;
+
+	struct ocmem_zone *zone = get_zone(owner);
+
+	BUG_ON(!zone);
+
+	matched_region = find_region_match(req->req_start, req->req_end);
+	matched_req = find_req_match(req->req_id, matched_region);
+
+	if (!matched_region || !matched_req)
+		goto invalid_op_error;
+	if (matched_req != req)
+		goto invalid_op_error;
+
+	ret = zone->z_ops->free(zone,
+		matched_req->req_start, matched_req->req_sz);
+
+	if (ret < 0)
+		goto err_op_fail;
+
+	detach_req(matched_region, matched_req);
+	update_region_prio(matched_region);
+	if (req_count(matched_region) == 0) {
+		remove_region(matched_region);
+		destroy_region(matched_region);
+	}
+
+	/* Update the request */
+	req->req_start = 0x0;
+	req->req_sz = 0x0;
+	req->req_end = 0x0;
+	SET_STATE(req, R_FREE);
+	return OP_COMPLETE;
+invalid_op_error:
+	pr_err("ocmem: free: Failed to find matching region\n");
+err_op_fail:
+	pr_err("ocmem: free: Failed\n");
+	return OP_FAIL;
+}
+
+/* Must be called with sched_mutex held */
+static int __sched_allocate(struct ocmem_req *req, bool can_block,
+				bool can_wait)
+{
+	unsigned long min = req->req_min;
+	unsigned long max = req->req_max;
+	unsigned long step = req->req_step;
+	int owner = req->owner;
+	unsigned long sz = max;
+	enum client_prio prio = req->prio;
+	unsigned long alloc_addr = 0x0;
+	bool retry;
+
+	struct ocmem_region *spanned_r = NULL;
+	struct ocmem_region *overlap_r = NULL;
+
+	struct ocmem_zone *zone = get_zone(owner);
+	struct ocmem_region *region = NULL;
+
+	BUG_ON(!zone);
+
+	if (min > (zone->z_end - zone->z_start)) {
+		pr_err("ocmem: requested minimum size exceeds quota\n");
+		goto invalid_op_error;
+	}
+
+	if (max > (zone->z_end - zone->z_start)) {
+		pr_err("ocmem: requested maximum size exceeds quota\n");
+		goto invalid_op_error;
+	}
+
+	if (min > zone->z_free) {
+			pr_err("ocmem: out of memory for zone %d\n", owner);
+			goto invalid_op_error;
+	}
+
+	region = create_region();
+
+	if (!region) {
+		pr_err("ocmem: Unable to create region\n");
+		goto invalid_op_error;
+	}
+
+	retry = false;
+
+	pr_debug("ocmem: ALLOCATE: request size %lx\n", sz);
+
+retry_next_step:
+
+	spanned_r = NULL;
+	overlap_r = NULL;
+
+	spanned_r = find_region(zone->z_head);
+	overlap_r = find_region_intersection(zone->z_head, zone->z_head + sz);
+
+	if (overlap_r == NULL) {
+		/* no conflicting regions, schedule this region */
+		alloc_addr = zone->z_ops->allocate(zone, sz);
+
+		if (alloc_addr < 0) {
+			pr_err("Zone Allocation operation failed\n");
+			goto internal_error;
+		}
+
+		/* update the request */
+		req->req_start = alloc_addr;
+		req->req_end = alloc_addr + sz - 1;
+		req->req_sz = sz;
+		req->zone = zone;
+
+		/* update request state */
+		CLEAR_STATE(req, R_FREE);
+		SET_STATE(req, R_ALLOCATED);
+		SET_STATE(req, R_MUST_MAP);
+		req->op = SCHED_NOP;
+
+		/* attach the request to the region */
+		attach_req(region, req);
+		populate_region(region, req);
+		update_region_prio(region);
+
+		/* update the tree with new region */
+		if (insert_region(region)) {
+			pr_err("ocmem: Failed to insert the region\n");
+			zone->z_ops->free(zone, alloc_addr, sz);
+			detach_req(region, req);
+			update_region_prio(region);
+			/* req will be destroyed by the caller */
+			goto internal_error;
+		}
+
+		if (retry) {
+			SET_STATE(req, R_MUST_GROW);
+			SET_STATE(req, R_PENDING);
+			req->op = SCHED_GROW;
+			return OP_PARTIAL;
+		}
+	} else if (spanned_r != NULL && overlap_r != NULL) {
+		/* resolve conflicting regions based on priority */
+		if (overlap_r->max_prio < prio) {
+			if (min == max) {
+				pr_err("ocmem: Requires eviction support\n");
+				goto err_not_supported;
+			} else {
+			/* Try to allocate atleast >= 'min' immediately */
+				sz -= step;
+				if (sz < min)
+					goto err_out_of_mem;
+				retry = true;
+				pr_debug("ocmem: Attempting with reduced size %lx\n",
+						sz);
+				goto retry_next_step;
+			}
+		} else if (overlap_r->max_prio > prio) {
+			if (can_block == true) {
+				SET_STATE(req, R_PENDING);
+				SET_STATE(req, R_MUST_GROW);
+				return OP_RESCHED;
+			} else {
+				if (min == max) {
+					pr_err("Cannot allocate %lx synchronously\n",
+							sz);
+					goto err_out_of_mem;
+				} else {
+					sz -= step;
+					if (sz < min)
+						goto err_out_of_mem;
+					retry = true;
+					pr_debug("ocmem: Attempting reduced size %lx\n",
+							sz);
+					goto retry_next_step;
+				}
+			}
+		} else {
+			pr_err("ocmem: Undetermined behavior\n");
+			pr_err("ocmem: New Region %p Existing %p\n", region,
+					overlap_r);
+			/* This is serious enough to fail */
+			BUG();
+		}
+	} else if (spanned_r == NULL && overlap_r != NULL)
+		goto err_not_supported;
+
+	return OP_COMPLETE;
+
+err_not_supported:
+	pr_err("ocmem: Scheduled unsupported operation\n");
+	return OP_FAIL;
+
+err_out_of_mem:
+	pr_err("ocmem: Out of memory during allocation\n");
+internal_error:
+	destroy_region(region);
+invalid_op_error:
+	return OP_FAIL;
+}
+
+static int sched_enqueue(struct ocmem_req *priv)
+{
+	struct ocmem_req *next = NULL;
+	mutex_lock(&sched_queue_mutex);
+	list_add_tail(&priv->sched_list, &sched_queue[priv->owner]);
+	pr_debug("enqueued req %p\n", priv);
+	list_for_each_entry(next, &sched_queue[priv->owner], sched_list) {
+		pr_debug("pending requests for client %p\n", next);
+	}
+	mutex_unlock(&sched_queue_mutex);
+	return 0;
+}
+
+static struct ocmem_req *ocmem_fetch_req(void)
+{
+	int i;
+	struct ocmem_req *req = NULL;
+	struct ocmem_req *next = NULL;
+
+	mutex_lock(&sched_queue_mutex);
+	for (i = MIN_PRIO; i < MAX_OCMEM_PRIO; i++) {
+		if (list_empty(&sched_queue[i]))
+			continue;
+		list_for_each_entry_safe(req, next, &sched_queue[i], sched_list)
+		{
+			if (req) {
+				pr_debug("ocmem: Fetched pending request %p\n",
+									req);
+				list_del(&req->sched_list);
+			break;
+			}
+		}
+	}
+	mutex_unlock(&sched_queue_mutex);
+	return req;
+}
+
+int process_xfer(int id, struct ocmem_handle *handle,
+		struct ocmem_map_list *list, int direction)
+{
+
+	return 0;
+}
+
+unsigned long process_quota(int id)
+{
+	struct ocmem_zone *zone = NULL;
+
+	if (is_blocked(id))
+		return 0;
+
+	zone = get_zone(id);
+
+	if (zone && zone->z_pool)
+		return zone->z_end - zone->z_start;
+	else
+		return 0;
+}
+
+static int do_grow(struct ocmem_req *req)
+{
+	struct ocmem_buf *buffer = NULL;
+	bool can_block = true;
+	int rc = 0;
+
+	down_write(&req->rw_sem);
+	buffer = req->buffer;
+
+	/* Take the scheduler mutex */
+	mutex_lock(&sched_mutex);
+	rc = __sched_grow(req, can_block);
+	mutex_unlock(&sched_mutex);
+
+	if (rc == OP_FAIL)
+		goto err_op_fail;
+
+	if (rc == OP_RESCHED) {
+		pr_debug("ocmem: Enqueue this allocation");
+		sched_enqueue(req);
+	}
+
+	else if (rc == OP_COMPLETE || rc == OP_PARTIAL) {
+		buffer->addr = device_address(req->owner, req->req_start);
+		buffer->len = req->req_sz;
+	}
+
+	up_write(&req->rw_sem);
+	return 0;
+err_op_fail:
+	up_write(&req->rw_sem);
+	return -EINVAL;
+}
+
+static int process_grow(struct ocmem_req *req)
+{
+	int rc = 0;
+
+	/* Attempt to grow the region */
+	rc = do_grow(req);
+
+	if (rc < 0)
+		return -EINVAL;
+
+	/* Map the newly grown region */
+	if (is_tcm(req->owner)) {
+		rc = process_map(req, req->req_start, req->req_end);
+		if (rc < 0)
+			return -EINVAL;
+	}
+
+	/* Notify the client about the buffer growth */
+	rc = dispatch_notification(req->owner, OCMEM_ALLOC_GROW, req->buffer);
+	if (rc < 0) {
+		pr_err("No notifier callback to cater for req %p event: %d\n",
+				req, OCMEM_ALLOC_GROW);
+		BUG();
+	}
+	return 0;
+}
+
+static void ocmem_sched_wk_func(struct work_struct *work);
+DECLARE_DELAYED_WORK(ocmem_sched_thread, ocmem_sched_wk_func);
+
+static int ocmem_schedule_pending(void)
+{
+	schedule_delayed_work(&ocmem_sched_thread,
+				msecs_to_jiffies(SCHED_DELAY));
+	return 0;
+}
+
+static int do_free(struct ocmem_req *req)
+{
+	int rc = 0;
+	struct ocmem_buf *buffer = req->buffer;
+
+	down_write(&req->rw_sem);
+
+	if (is_mapped(req)) {
+		pr_err("ocmem: Buffer needs to be unmapped before free\n");
+		goto err_free_fail;
+	}
+
+	/* Grab the sched mutex */
+	mutex_lock(&sched_mutex);
+	rc = __sched_free(req);
+	mutex_unlock(&sched_mutex);
+
+	switch (rc) {
+
+	case OP_COMPLETE:
+		buffer->addr = 0x0;
+		buffer->len = 0x0;
+		break;
+	case OP_FAIL:
+	default:
+		goto err_free_fail;
+		break;
+	}
+
+	up_write(&req->rw_sem);
+	return 0;
+err_free_fail:
+	up_write(&req->rw_sem);
+	pr_err("ocmem: freeing req %p failed\n", req);
+	return -EINVAL;
+}
+
+int process_free(int id, struct ocmem_handle *handle)
+{
+	struct ocmem_req *req = NULL;
+	struct ocmem_buf *buffer = NULL;
+	int rc = 0;
+
+	if (is_blocked(id)) {
+		pr_err("Client %d cannot request free\n", id);
+		return -EINVAL;
+	}
+
+	req = handle_to_req(handle);
+	buffer = handle_to_buffer(handle);
+
+	if (!req)
+		return -EINVAL;
+
+	if (req->req_start != core_address(id, buffer->addr)) {
+		pr_err("Invalid buffer handle passed for free\n");
+		return -EINVAL;
+	}
+
+	if (is_tcm(req->owner)) {
+		rc = process_unmap(req, req->req_start, req->req_end);
+		if (rc < 0)
+			return -EINVAL;
+	}
+
+	rc = do_free(req);
+
+	if (rc < 0)
+		return -EINVAL;
+
+	ocmem_destroy_req(req);
+	handle->req = NULL;
+
+	ocmem_schedule_pending();
+	return 0;
+}
+
+static int do_allocate(struct ocmem_req *req, bool can_block, bool can_wait)
+{
+	int rc = 0;
+	struct ocmem_buf *buffer = req->buffer;
+
+	down_write(&req->rw_sem);
+
+	/* Take the scheduler mutex */
+	mutex_lock(&sched_mutex);
+	rc = __sched_allocate(req, can_block, can_wait);
+	mutex_unlock(&sched_mutex);
+
+	if (rc == OP_FAIL)
+		goto err_allocate_fail;
+
+	if (rc == OP_RESCHED) {
+		buffer->addr = 0x0;
+		buffer->len = 0x0;
+		pr_debug("ocmem: Enqueuing req %p\n", req);
+		sched_enqueue(req);
+	} else if (rc == OP_PARTIAL) {
+		buffer->addr = device_address(req->owner, req->req_start);
+		buffer->len = req->req_sz;
+		pr_debug("ocmem: Enqueuing req %p\n", req);
+		sched_enqueue(req);
+	} else if (rc == OP_COMPLETE) {
+		buffer->addr = device_address(req->owner, req->req_start);
+		buffer->len = req->req_sz;
+	}
+
+	up_write(&req->rw_sem);
+	return 0;
+err_allocate_fail:
+	up_write(&req->rw_sem);
+	return -EINVAL;
+}
+
+
+int process_allocate(int id, struct ocmem_handle *handle,
+			unsigned long min, unsigned long max,
+			unsigned long step, bool can_block, bool can_wait)
+{
+
+	struct ocmem_req *req = NULL;
+	struct ocmem_buf *buffer = NULL;
+	int rc = 0;
+
+	/* sanity checks */
+	if (is_blocked(id)) {
+		pr_err("Client %d cannot request allocation\n", id);
+		return -EINVAL;
+	}
+
+	if (handle->req != NULL) {
+		pr_err("Invalid handle passed in\n");
+		return -EINVAL;
+	}
+
+	buffer = handle_to_buffer(handle);
+	BUG_ON(buffer == NULL);
+
+	/* prepare a request structure to represent this transaction */
+	req = ocmem_create_req();
+	if (!req)
+		return -ENOMEM;
+
+	req->owner = id;
+	req->req_min = min;
+	req->req_max = max;
+	req->req_step = step;
+	req->prio = ocmem_client_table[id].priority;
+	req->op = SCHED_ALLOCATE;
+	req->buffer = buffer;
+
+	rc = do_allocate(req, can_block, can_wait);
+
+	if (rc < 0)
+		goto do_allocate_error;
+
+	handle->req = req;
+
+	if (is_tcm(id)) {
+		rc = process_map(req, req->req_start, req->req_end);
+		if (rc < 0)
+			goto map_error;
+	}
+
+	return 0;
+
+map_error:
+	handle->req = NULL;
+	do_free(req);
+do_allocate_error:
+	ocmem_destroy_req(req);
+	return -EINVAL;
+}
+
+int process_delayed_allocate(struct ocmem_req *req)
+{
+
+	struct ocmem_handle *handle = NULL;
+	int rc = 0;
+	int id = req->owner;
+
+	handle = req_to_handle(req);
+	BUG_ON(handle == NULL);
+
+	rc = do_allocate(req, true, false);
+
+	if (rc < 0)
+		goto do_allocate_error;
+
+	if (is_tcm(id)) {
+		rc = process_map(req, req->req_start, req->req_end);
+		if (rc < 0)
+			goto map_error;
+	}
+
+	/* Notify the client about the buffer growth */
+	rc = dispatch_notification(id, OCMEM_ALLOC_GROW, req->buffer);
+	if (rc < 0) {
+		pr_err("No notifier callback to cater for req %p event: %d\n",
+				req, OCMEM_ALLOC_GROW);
+		BUG();
+	}
+	return 0;
+
+map_error:
+	handle->req = NULL;
+	do_free(req);
+do_allocate_error:
+	ocmem_destroy_req(req);
+	return -EINVAL;
+}
+
+static void ocmem_sched_wk_func(struct work_struct *work)
+{
+
+	struct ocmem_buf *buffer = NULL;
+	struct ocmem_handle *handle = NULL;
+	struct ocmem_req *req = ocmem_fetch_req();
+
+	if (!req) {
+		pr_debug("No Pending Requests found\n");
+		return;
+	}
+
+	pr_debug("ocmem: sched_wk pending req %p\n", req);
+	handle = req_to_handle(req);
+	buffer = handle_to_buffer(handle);
+	BUG_ON(req->op == SCHED_NOP);
+
+	switch (req->op) {
+	case SCHED_GROW:
+		process_grow(req);
+		break;
+	case SCHED_ALLOCATE:
+		process_delayed_allocate(req);
+		break;
+	default:
+		pr_err("ocmem: Unknown operation encountered\n");
+		break;
+	}
+	return;
+}
+
+int ocmem_sched_init(void)
+{
+	int i = 0;
+	sched_tree = RB_ROOT;
+	mutex_init(&sched_mutex);
+	mutex_init(&sched_queue_mutex);
+	for (i = MIN_PRIO; i < MAX_OCMEM_PRIO; i++)
+		INIT_LIST_HEAD(&sched_queue[i]);
+
+	return 0;
+}
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index b40c0c7..49e63aa 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -202,8 +202,6 @@
 	pen_release = cpu_logical_map(cpu);
 	__cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
 	outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
-	__asm__("sev");
-	mb();
 
 	/*
 	 * Send the secondary CPU a soft interrupt, thereby causing
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 2980811..6e81be6 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -282,14 +282,22 @@
 		uint32_t notify_rpm;
 	};
 
-	struct mode_of mode_of_data[] = {
-		{"qcom,spm-cmd-wfi", MSM_SPM_MODE_CLOCK_GATING, 0},
-		{"qcom,spm-cmd-ret", MSM_SPM_MODE_POWER_RETENTION, 0},
-		{"qcom,spm-cmd-spc", MSM_SPM_MODE_POWER_COLLAPSE, 0},
-		{"qcom,spm-cmd-pc", MSM_SPM_MODE_POWER_COLLAPSE, 1},
+	struct mode_of of_cpu_modes[] = {
+		{"qcom,saw2-spm-cmd-wfi", MSM_SPM_MODE_CLOCK_GATING, 0},
+		{"qcom,saw2-spm-cmd-ret", MSM_SPM_MODE_POWER_RETENTION, 0},
+		{"qcom,saw2-spm-cmd-spc", MSM_SPM_MODE_POWER_COLLAPSE, 0},
+		{"qcom,saw2-spm-cmd-pc", MSM_SPM_MODE_POWER_COLLAPSE, 1},
 	};
 
-	BUG_ON(ARRAY_SIZE(mode_of_data) > MSM_SPM_MODE_NR);
+	struct mode_of of_l2_modes[] = {
+		{"qcom,saw2-spm-cmd-ret", MSM_SPM_L2_MODE_RETENTION, 1},
+		{"qcom,saw2-spm-cmd-gdhs", MSM_SPM_L2_MODE_GDHS, 1},
+		{"qcom,saw2-spm-cmd-pc", MSM_SPM_L2_MODE_POWER_COLLAPSE, 1},
+	};
+
+	struct mode_of *mode_of_data;
+	int num_modes;
+
 	memset(&spm_data, 0, sizeof(struct msm_spm_platform_data));
 	memset(&modes, 0,
 		(MSM_SPM_MODE_NR - 2) * sizeof(struct msm_spm_seq_entry));
@@ -339,7 +347,22 @@
 		spm_data.reg_init_values[spm_of_data[i].id] = val;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(mode_of_data); i++) {
+	/*
+	 * Device with id 0..NR_CPUS are SPM for apps cores
+	 * Device with id 0xFFFF is for L2 SPM.
+	 */
+	if (cpu >= 0 && cpu < num_possible_cpus()) {
+		mode_of_data = of_cpu_modes;
+		num_modes = ARRAY_SIZE(of_cpu_modes);
+		dev = &per_cpu(msm_cpu_spm_device, cpu);
+
+	} else {
+		mode_of_data = of_l2_modes;
+		num_modes = ARRAY_SIZE(of_l2_modes);
+		dev = &msm_spm_l2_device;
+	}
+
+	for (i = 0; i < num_modes; i++) {
 		key = mode_of_data[i].key;
 		modes[mode_count].cmd =
 			(uint8_t *)of_get_property(node, key, &len);
@@ -353,16 +376,8 @@
 	spm_data.modes = modes;
 	spm_data.num_modes = mode_count;
 
-	/*
-	 * Device with id 0..NR_CPUS are SPM for apps cores
-	 * Device with id 0xFFFF is for L2 SPM.
-	 */
-	if (cpu >= 0 && cpu < num_possible_cpus())
-		dev = &per_cpu(msm_cpu_spm_device, cpu);
-	else
-		dev = &msm_spm_l2_device;
-
 	ret = msm_spm_dev_init(dev, &spm_data);
+
 	if (ret < 0)
 		pr_warn("%s():failed core-id:%u ret:%d\n", __func__, cpu, ret);
 
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 3de3af9..615c7ad 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1354,7 +1354,7 @@
 			* get an interrupt */
 			cmds[0] = cp_type3_packet(CP_NOP, 1);
 			cmds[1] = 0;
-			adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
+			adreno_ringbuffer_issuecmds_intr(device, context,
 				&cmds[0], 2);
 		}
 	}
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index feaa36f..df5f0f9 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -27,8 +27,8 @@
 /* Flags to control command packet settings */
 #define KGSL_CMD_FLAGS_NONE             0x00000000
 #define KGSL_CMD_FLAGS_PMODE		0x00000001
-#define KGSL_CMD_FLAGS_NO_TS_CMP	0x00000002
-#define KGSL_CMD_FLAGS_NOT_KERNEL_CMD	0x00000004
+#define KGSL_CMD_FLAGS_NOT_KERNEL_CMD	0x00000002
+#define KGSL_CMD_FLAGS_DUMMY_INTR_CMD	0x00000004
 
 /* Command identifiers */
 #define KGSL_CONTEXT_TO_MEM_IDENTIFIER	0x2EADBEEF
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 600e04f..e258072 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2409,30 +2409,29 @@
 
 static void a3xx_cp_callback(struct adreno_device *adreno_dev, int irq)
 {
-	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+	struct kgsl_device *device = &adreno_dev->dev;
 
 	if (irq == A3XX_INT_CP_RB_INT) {
 		unsigned int context_id;
-		kgsl_sharedmem_readl(&adreno_dev->dev.memstore,
-				&context_id,
+		kgsl_sharedmem_readl(&device->memstore, &context_id,
 				KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
 					current_context));
 		if (context_id < KGSL_MEMSTORE_MAX) {
-			kgsl_sharedmem_writel(&rb->device->memstore,
+			kgsl_sharedmem_writel(&device->memstore,
 					KGSL_MEMSTORE_OFFSET(context_id,
 						ts_cmp_enable), 0);
 			wmb();
 		}
-		KGSL_CMD_WARN(rb->device, "ringbuffer rb interrupt\n");
+		KGSL_CMD_WARN(device, "ringbuffer rb interrupt\n");
 	}
 
-	wake_up_interruptible_all(&rb->device->wait_queue);
+	wake_up_interruptible_all(&device->wait_queue);
 
 	/* Schedule work to free mem and issue ibs */
-	queue_work(rb->device->work_queue, &rb->device->ts_expired_ws);
+	queue_work(device->work_queue, &device->ts_expired_ws);
 
-	atomic_notifier_call_chain(&rb->device->ts_notifier_list,
-				   rb->device->id, NULL);
+	atomic_notifier_call_chain(&device->ts_notifier_list,
+				   device->id, NULL);
 }
 
 #define A3XX_IRQ_CALLBACK(_c) { .func = _c }
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 49d035f..76122ae 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -147,6 +147,7 @@
 {
 	struct adreno_context *drawctxt;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
 	int ret;
 
 	drawctxt = kzalloc(sizeof(struct adreno_context), GFP_KERNEL);
@@ -157,6 +158,7 @@
 	drawctxt->pagetable = pagetable;
 	drawctxt->bin_base_offset = 0;
 	drawctxt->id = context->id;
+	rb->timestamp[context->id] = 0;
 
 	if (flags & KGSL_CONTEXT_PREAMBLE)
 		drawctxt->flags |= CTXT_FLAGS_PREAMBLE;
@@ -174,6 +176,12 @@
 	kgsl_sharedmem_writel(&device->memstore,
 			KGSL_MEMSTORE_OFFSET(drawctxt->id, ref_wait_ts),
 			KGSL_INIT_REFTIMESTAMP);
+	kgsl_sharedmem_writel(&device->memstore,
+			KGSL_MEMSTORE_OFFSET(drawctxt->id, ts_cmp_enable), 0);
+	kgsl_sharedmem_writel(&device->memstore,
+			KGSL_MEMSTORE_OFFSET(drawctxt->id, soptimestamp), 0);
+	kgsl_sharedmem_writel(&device->memstore,
+			KGSL_MEMSTORE_OFFSET(drawctxt->id, eoptimestamp), 0);
 
 	context->devctxt = drawctxt;
 	return 0;
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 3d46221..8bc933a 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -453,7 +453,7 @@
 	*  error checking if needed
 	*/
 	total_sizedwords += flags & KGSL_CMD_FLAGS_PMODE ? 4 : 0;
-	total_sizedwords += !(flags & KGSL_CMD_FLAGS_NO_TS_CMP) ? 7 : 0;
+	total_sizedwords += context ? 7 : 0;
 	total_sizedwords += !(flags & KGSL_CMD_FLAGS_NOT_KERNEL_CMD) ? 2 : 0;
 
 	if (adreno_is_a3xx(adreno_dev))
@@ -498,9 +498,10 @@
 
 	/* always increment the global timestamp. once. */
 	rb->timestamp[KGSL_MEMSTORE_GLOBAL]++;
-	if (context) {
+
+	if (context && !(flags & KGSL_CMD_FLAGS_DUMMY_INTR_CMD)) {
 		if (context_id == KGSL_MEMSTORE_GLOBAL)
-			rb->timestamp[context_id] =
+			rb->timestamp[context->id] =
 				rb->timestamp[KGSL_MEMSTORE_GLOBAL];
 		else
 			rb->timestamp[context_id]++;
@@ -530,7 +531,7 @@
 		GSL_RB_WRITE(ringcmds, rcmd_gpu,
 			cp_type3_packet(CP_MEM_WRITE, 2));
 		GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
-			KGSL_MEMSTORE_OFFSET(context->id, soptimestamp)));
+			KGSL_MEMSTORE_OFFSET(context_id, soptimestamp)));
 		GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
 
 		/* end-of-pipeline timestamp */
@@ -538,14 +539,14 @@
 			cp_type3_packet(CP_EVENT_WRITE, 3));
 		GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
 		GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
-			KGSL_MEMSTORE_OFFSET(context->id, eoptimestamp)));
+			KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp)));
 		GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
 
 		GSL_RB_WRITE(ringcmds, rcmd_gpu,
 			cp_type3_packet(CP_MEM_WRITE, 2));
 		GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
-			      KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
-				      eoptimestamp)));
+			KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+				eoptimestamp)));
 		GSL_RB_WRITE(ringcmds, rcmd_gpu,
 			rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
 	} else {
@@ -553,13 +554,11 @@
 			cp_type3_packet(CP_EVENT_WRITE, 3));
 		GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
 		GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
-			      KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
-				      eoptimestamp)));
-		GSL_RB_WRITE(ringcmds, rcmd_gpu,
-			rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
+			KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp)));
+		GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp[context_id]);
 	}
 
-	if (!(flags & KGSL_CMD_FLAGS_NO_TS_CMP)) {
+	if (context) {
 		/* Conditional execution based on memory values */
 		GSL_RB_WRITE(ringcmds, rcmd_gpu,
 			cp_type3_packet(CP_COND_EXEC, 4));
@@ -592,6 +591,30 @@
 }
 
 void
+adreno_ringbuffer_issuecmds_intr(struct kgsl_device *device,
+						struct kgsl_context *k_ctxt,
+						unsigned int *cmds,
+						int sizedwords)
+{
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+	struct adreno_context *a_ctxt = NULL;
+
+	if (!k_ctxt)
+		return;
+
+	a_ctxt = k_ctxt->devctxt;
+
+	if (k_ctxt->id == KGSL_CONTEXT_INVALID ||
+		a_ctxt == NULL ||
+		device->state & KGSL_STATE_HUNG)
+		return;
+
+	adreno_ringbuffer_addcmds(rb, a_ctxt, KGSL_CMD_FLAGS_DUMMY_INTR_CMD,
+			cmds, sizedwords);
+}
+
+void
 adreno_ringbuffer_issuecmds(struct kgsl_device *device,
 						unsigned int flags,
 						unsigned int *cmds,
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index ae2e4c7..6ad85ad 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -108,6 +108,11 @@
 					unsigned int *cmdaddr,
 					int sizedwords);
 
+void adreno_ringbuffer_issuecmds_intr(struct kgsl_device *device,
+					struct kgsl_context *k_ctxt,
+					unsigned int *cmdaddr,
+					int sizedwords);
+
 void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb);
 
 void kgsl_cp_intrcallback(struct kgsl_device *device);
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index e789733..81de64f 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2523,7 +2523,7 @@
 	}
 
 	status = kgsl_allocate_contiguous(&device->memstore,
-		sizeof(struct kgsl_devmemstore));
+		KGSL_MEMSTORE_SIZE);
 
 	if (status != 0) {
 		KGSL_DRV_ERR(device, "kgsl_allocate_contiguous failed %d\n",
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 67da5ea..9ed6cca 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -7,7 +7,6 @@
 obj-$(CONFIG_MSM_CAMERA) += io/
 ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
   EXTRA_CFLAGS += -Idrivers/media/video/msm/csi
-  EXTRA_CFLAGS += -Idrivers/media/video/msm/io
   EXTRA_CFLAGS += -Idrivers/media/video/msm/eeprom
   EXTRA_CFLAGS += -Idrivers/media/video/msm/sensors
   EXTRA_CFLAGS += -Idrivers/media/video/msm/actuators
diff --git a/drivers/media/video/msm/flash.c b/drivers/media/video/msm/flash.c
index 7c4021d..54c59f8 100644
--- a/drivers/media/video/msm/flash.c
+++ b/drivers/media/video/msm/flash.c
@@ -17,15 +17,16 @@
 #include <linux/pwm.h>
 #include <linux/pmic8058-pwm.h>
 #include <linux/hrtimer.h>
-#include <linux/i2c.h>
 #include <linux/export.h>
 #include <mach/pmic.h>
 #include <mach/camera.h>
 #include <mach/gpio.h>
+#include "msm_camera_i2c.h"
 
 struct i2c_client *sx150x_client;
 struct timer_list timer_flash;
 static struct msm_camera_sensor_info *sensor_data;
+static struct msm_camera_i2c_client i2c_client;
 enum msm_cam_flash_stat{
 	MSM_CAM_FLASH_OFF,
 	MSM_CAM_FLASH_ON,
@@ -33,47 +34,6 @@
 
 static struct i2c_client *sc628a_client;
 
-static int32_t flash_i2c_txdata(struct i2c_client *client,
-		unsigned char *txdata, int length)
-{
-	struct i2c_msg msg[] = {
-		{
-			.addr = client->addr >> 1,
-			.flags = 0,
-			.len = length,
-			.buf = txdata,
-		},
-	};
-	if (i2c_transfer(client->adapter, msg, 1) < 0) {
-		CDBG("flash_i2c_txdata faild 0x%x\n", client->addr >> 1);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static int32_t flash_i2c_write_b(struct i2c_client *client,
-	uint8_t baddr, uint8_t bdata)
-{
-	int32_t rc = -EFAULT;
-	unsigned char buf[2];
-	if (!client)
-		return  -ENOTSUPP;
-
-	memset(buf, 0, sizeof(buf));
-	buf[0] = baddr;
-	buf[1] = bdata;
-
-	rc = flash_i2c_txdata(client, buf, 2);
-	if (rc < 0) {
-		CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
-				baddr, bdata);
-	}
-	usleep_range(4000, 5000);
-
-	return rc;
-}
-
 static const struct i2c_device_id sc628a_i2c_id[] = {
 	{"sc628a", 0},
 	{ }
@@ -128,8 +88,10 @@
 	}
 
 	tps61310_client = client;
-
-	rc = flash_i2c_write_b(tps61310_client, 0x01, 0x00);
+	i2c_client.client = tps61310_client;
+	i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+	rc = msm_camera_i2c_write(&i2c_client, 0x01, 0x00,
+		MSM_CAMERA_I2C_BYTE_DATA);
 	if (rc < 0) {
 		tps61310_client = NULL;
 		goto probe_failure;
@@ -431,10 +393,18 @@
 		break;
 
 	case MSM_CAMERA_LED_OFF:
-		if (sc628a_client)
-			rc = flash_i2c_write_b(sc628a_client, 0x02, 0x00);
-		if (tps61310_client)
-			rc = flash_i2c_write_b(tps61310_client, 0x01, 0x00);
+		if (sc628a_client) {
+			i2c_client.client = sc628a_client;
+			i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+			rc = msm_camera_i2c_write(&i2c_client, 0x02, 0x00,
+				MSM_CAMERA_I2C_BYTE_DATA);
+		}
+		if (tps61310_client) {
+			i2c_client.client = tps61310_client;
+			i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+			rc = msm_camera_i2c_write(&i2c_client, 0x01, 0x00,
+				MSM_CAMERA_I2C_BYTE_DATA);
+		}
 		gpio_set_value_cansleep(external->led_en, 0);
 		gpio_set_value_cansleep(external->led_flash_en, 0);
 		break;
@@ -443,20 +413,36 @@
 		gpio_set_value_cansleep(external->led_en, 1);
 		gpio_set_value_cansleep(external->led_flash_en, 1);
 		usleep_range(2000, 3000);
-		if (sc628a_client)
-			rc = flash_i2c_write_b(sc628a_client, 0x02, 0x06);
-		if (tps61310_client)
-			rc = flash_i2c_write_b(tps61310_client, 0x01, 0x86);
+		if (sc628a_client) {
+			i2c_client.client = sc628a_client;
+			i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+			rc = msm_camera_i2c_write(&i2c_client, 0x02, 0x06,
+				MSM_CAMERA_I2C_BYTE_DATA);
+		}
+		if (tps61310_client) {
+			i2c_client.client = tps61310_client;
+			i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+			rc = msm_camera_i2c_write(&i2c_client, 0x01, 0x86,
+				MSM_CAMERA_I2C_BYTE_DATA);
+		}
 		break;
 
 	case MSM_CAMERA_LED_HIGH:
 		gpio_set_value_cansleep(external->led_en, 1);
 		gpio_set_value_cansleep(external->led_flash_en, 1);
 		usleep_range(2000, 3000);
-		if (sc628a_client)
-			rc = flash_i2c_write_b(sc628a_client, 0x02, 0x49);
-		if (tps61310_client)
-			rc = flash_i2c_write_b(tps61310_client, 0x01, 0x8B);
+		if (sc628a_client) {
+			i2c_client.client = sc628a_client;
+			i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+			rc = msm_camera_i2c_write(&i2c_client, 0x02, 0x49,
+				MSM_CAMERA_I2C_BYTE_DATA);
+		}
+		if (tps61310_client) {
+			i2c_client.client = tps61310_client;
+			i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+			rc = msm_camera_i2c_write(&i2c_client, 0x01, 0x8B,
+				MSM_CAMERA_I2C_BYTE_DATA);
+		}
 		break;
 
 	default:
diff --git a/drivers/media/video/msm/io/Makefile b/drivers/media/video/msm/io/Makefile
index 64df7fb..611eecd 100644
--- a/drivers/media/video/msm/io/Makefile
+++ b/drivers/media/video/msm/io/Makefile
@@ -1,9 +1,9 @@
 GCC_VERSION      := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
 
-obj-$(CONFIG_MSM_CAMERA)   += msm_camera_io_util.o
 EXTRA_CFLAGS += -Idrivers/media/video/msm
+obj-$(CONFIG_MSM_CAMERA)   += msm_camera_io_util.o msm_camera_i2c.o
 ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
-  obj-$(CONFIG_MSM_CAMERA) += msm_camera_i2c.o msm_camera_i2c_mux.o
+  obj-$(CONFIG_MSM_CAMERA) += msm_camera_i2c_mux.o
   obj-$(CONFIG_ARCH_MSM7X27A) += msm_io_7x27a_v4l2.o
   obj-$(CONFIG_ARCH_MSM8X60) += msm_io_vfe31_v4l2.o
   obj-$(CONFIG_ARCH_MSM7X30) += msm_io_vfe31_v4l2.o
diff --git a/drivers/tty/n_smux.c b/drivers/tty/n_smux.c
index 65bcb08..b6a2ffb 100644
--- a/drivers/tty/n_smux.c
+++ b/drivers/tty/n_smux.c
@@ -78,6 +78,11 @@
 			pr_info(x);  \
 } while (0)
 
+#define SMUX_PWR(x...) do {                              \
+	if (smux_debug_mask & MSM_SMUX_POWER_INFO) \
+			pr_info(x);  \
+} while (0)
+
 #define SMUX_LOG_PKT_RX(pkt) do { \
 	if (smux_debug_mask & MSM_SMUX_PKT) \
 			smux_log_pkt(pkt, 1); \
@@ -1005,7 +1010,6 @@
 	pkt->hdr.cmd = SMUX_CMD_BYTE;
 	pkt->hdr.flags = ch;
 	pkt->hdr.lcid = SMUX_BROADCAST_LCID;
-	pkt->hdr.flags = ch;
 
 	list_add_tail(&pkt->list, &smux.power_queue);
 	queue_work(smux_tx_wq, &smux_tx_work);
@@ -1601,7 +1605,7 @@
 		/* local sleep request ack */
 		if (smux.power_state == SMUX_PWR_TURNING_OFF) {
 			/* Power-down complete, turn off UART */
-			SMUX_DBG("%s: Power %d->%d\n", __func__,
+			SMUX_PWR("%s: Power %d->%d\n", __func__,
 					smux.power_state, SMUX_PWR_OFF_FLUSH);
 			smux.power_state = SMUX_PWR_OFF_FLUSH;
 			queue_work(smux_tx_wq, &smux_inactivity_work);
@@ -1625,7 +1629,7 @@
 			|| smux.power_state == SMUX_PWR_TURNING_OFF) {
 			ack_pkt = smux_alloc_pkt();
 			if (ack_pkt) {
-				SMUX_DBG("%s: Power %d->%d\n", __func__,
+				SMUX_PWR("%s: Power %d->%d\n", __func__,
 						smux.power_state,
 						SMUX_PWR_TURNING_OFF_FLUSH);
 
@@ -1658,24 +1662,44 @@
  */
 static int smux_dispatch_rx_pkt(struct smux_pkt_t *pkt)
 {
-	int ret;
+	int ret = -ENXIO;
 
 	SMUX_LOG_PKT_RX(pkt);
 
 	switch (pkt->hdr.cmd) {
 	case SMUX_CMD_OPEN_LCH:
+		if (smux_assert_lch_id(pkt->hdr.lcid)) {
+			pr_err("%s: invalid channel id %d\n",
+					__func__, pkt->hdr.lcid);
+			break;
+		}
 		ret = smux_handle_rx_open_cmd(pkt);
 		break;
 
 	case SMUX_CMD_DATA:
+		if (smux_assert_lch_id(pkt->hdr.lcid)) {
+			pr_err("%s: invalid channel id %d\n",
+					__func__, pkt->hdr.lcid);
+			break;
+		}
 		ret = smux_handle_rx_data_cmd(pkt);
 		break;
 
 	case SMUX_CMD_CLOSE_LCH:
+		if (smux_assert_lch_id(pkt->hdr.lcid)) {
+			pr_err("%s: invalid channel id %d\n",
+					__func__, pkt->hdr.lcid);
+			break;
+		}
 		ret = smux_handle_rx_close_cmd(pkt);
 		break;
 
 	case SMUX_CMD_STATUS:
+		if (smux_assert_lch_id(pkt->hdr.lcid)) {
+			pr_err("%s: invalid channel id %d\n",
+					__func__, pkt->hdr.lcid);
+			break;
+		}
 		ret = smux_handle_rx_status_cmd(pkt);
 		break;
 
@@ -1705,7 +1729,6 @@
 static int smux_deserialize(unsigned char *data, int len)
 {
 	struct smux_pkt_t recv;
-	uint8_t lcid;
 
 	smux_init_pkt(&recv);
 
@@ -1720,12 +1743,6 @@
 		return -EINVAL;
 	}
 
-	lcid = recv.hdr.lcid;
-	if (smux_assert_lch_id(lcid)) {
-		pr_err("%s: invalid channel id %d\n", __func__, lcid);
-		return -ENXIO;
-	}
-
 	if (recv.hdr.payload_len)
 		recv.payload = data + sizeof(struct smux_hdr_t);
 
@@ -1743,7 +1760,7 @@
 	if (smux.power_state == SMUX_PWR_OFF
 		|| smux.power_state == SMUX_PWR_TURNING_ON) {
 		/* wakeup system */
-		SMUX_DBG("%s: Power %d->%d\n", __func__,
+		SMUX_PWR("%s: Power %d->%d\n", __func__,
 				smux.power_state, SMUX_PWR_ON);
 		smux.power_state = SMUX_PWR_ON;
 		queue_work(smux_tx_wq, &smux_wakeup_work);
@@ -1767,7 +1784,7 @@
 	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
 	if (smux.power_state == SMUX_PWR_TURNING_ON) {
 		/* received response to wakeup request */
-		SMUX_DBG("%s: Power %d->%d\n", __func__,
+		SMUX_PWR("%s: Power %d->%d\n", __func__,
 				smux.power_state, SMUX_PWR_ON);
 		smux.power_state = SMUX_PWR_ON;
 		queue_work(smux_tx_wq, &smux_tx_work);
@@ -2201,7 +2218,7 @@
 				/* start power-down sequence */
 				pkt = smux_alloc_pkt();
 				if (pkt) {
-					SMUX_DBG("%s: Power %d->%d\n", __func__,
+					SMUX_PWR("%s: Power %d->%d\n", __func__,
 						smux.power_state,
 						SMUX_PWR_TURNING_OFF);
 					smux.power_state = SMUX_PWR_TURNING_OFF;
@@ -2228,9 +2245,9 @@
 
 	if (smux.power_state == SMUX_PWR_OFF_FLUSH) {
 		/* ready to power-down the UART */
-		smux.power_state = SMUX_PWR_OFF;
-		SMUX_DBG("%s: Power %d->%d\n", __func__,
+		SMUX_PWR("%s: Power %d->%d\n", __func__,
 				smux.power_state, SMUX_PWR_OFF);
+		smux.power_state = SMUX_PWR_OFF;
 
 		/* if data is pending, schedule a new wakeup */
 		if (!list_empty(&smux.lch_tx_ready_list) ||
@@ -2455,7 +2472,7 @@
 			   !list_empty(&smux.power_queue)) {
 				/* data to transmit, do wakeup */
 				smux.pwr_wakeup_delay_us = 1;
-				SMUX_DBG("%s: Power %d->%d\n", __func__,
+				SMUX_PWR("%s: Power %d->%d\n", __func__,
 						smux.power_state,
 						SMUX_PWR_TURNING_ON);
 				smux.power_state = SMUX_PWR_TURNING_ON;
@@ -2492,7 +2509,7 @@
 			if (smux.power_state == SMUX_PWR_TURNING_OFF_FLUSH &&
 				pkt->hdr.cmd == SMUX_CMD_PWR_CTL &&
 				(pkt->hdr.flags & SMUX_CMD_PWR_CTL_ACK)) {
-				SMUX_DBG("%s: Power %d->%d\n", __func__,
+				SMUX_PWR("%s: Power %d->%d\n", __func__,
 						smux.power_state,
 						SMUX_PWR_OFF_FLUSH);
 				smux.power_state = SMUX_PWR_OFF_FLUSH;
@@ -3115,7 +3132,7 @@
 	/* Power-down UART */
 	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
 	if (smux.power_state != SMUX_PWR_OFF) {
-		SMUX_DBG("%s: SSR - turning off UART\n", __func__);
+		SMUX_PWR("%s: SSR - turning off UART\n", __func__);
 		smux.power_state = SMUX_PWR_OFF;
 		power_off_uart = 1;
 	}
@@ -3173,7 +3190,7 @@
 	/* power-down the UART if we are idle */
 	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
 	if (smux.power_state == SMUX_PWR_OFF) {
-		SMUX_DBG("%s: powering off uart\n", __func__);
+		SMUX_PWR("%s: powering off uart\n", __func__);
 		smux.power_state = SMUX_PWR_OFF_FLUSH;
 		spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
 		queue_work(smux_tx_wq, &smux_inactivity_work);
diff --git a/drivers/tty/smux_loopback.c b/drivers/tty/smux_loopback.c
index bf6d50b..c4374bb 100644
--- a/drivers/tty/smux_loopback.c
+++ b/drivers/tty/smux_loopback.c
@@ -174,13 +174,15 @@
 		}
 
 		lcid = pkt->hdr.lcid;
-		if (smux_assert_lch_id(lcid)) {
-			pr_err("%s: invalid channel id %d\n", __func__, lcid);
-			return;
-		}
 
 		switch (pkt->hdr.cmd) {
 		case SMUX_CMD_OPEN_LCH:
+			if (smux_assert_lch_id(lcid)) {
+				pr_err("%s: invalid channel id %d\n",
+						__func__, lcid);
+				break;
+			}
+
 			if (pkt->hdr.flags & SMUX_CMD_OPEN_ACK)
 				break;
 
@@ -207,6 +209,12 @@
 			break;
 
 		case SMUX_CMD_CLOSE_LCH:
+			if (smux_assert_lch_id(lcid)) {
+				pr_err("%s: invalid channel id %d\n",
+						__func__, lcid);
+				break;
+			}
+
 			if (pkt->hdr.flags == SMUX_CMD_CLOSE_ACK)
 				break;
 
@@ -232,6 +240,12 @@
 			break;
 
 		case SMUX_CMD_DATA:
+			if (smux_assert_lch_id(lcid)) {
+				pr_err("%s: invalid channel id %d\n",
+						__func__, lcid);
+				break;
+			}
+
 			/* Echo back received data */
 			smux_init_pkt(&reply_pkt);
 			reply_pkt.hdr.lcid = lcid;
@@ -245,6 +259,12 @@
 			break;
 
 		case SMUX_CMD_STATUS:
+			if (smux_assert_lch_id(lcid)) {
+				pr_err("%s: invalid channel id %d\n",
+						__func__, lcid);
+				break;
+			}
+
 			/* Echo back received status */
 			smux_init_pkt(&reply_pkt);
 			reply_pkt.hdr.lcid = lcid;
@@ -260,7 +280,7 @@
 		case SMUX_CMD_PWR_CTL:
 			/* reply with ack */
 			smux_init_pkt(&reply_pkt);
-			reply_pkt.hdr.lcid = lcid;
+			reply_pkt.hdr.lcid = SMUX_BROADCAST_LCID;
 			reply_pkt.hdr.cmd = SMUX_CMD_PWR_CTL;
 			reply_pkt.hdr.flags = SMUX_CMD_PWR_CTL_ACK;
 			reply_pkt.hdr.payload_len = 0;
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index d8f741f..742beef 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -3,7 +3,6 @@
 	depends on (USB && USB_GADGET)
 	select USB_OTG_UTILS
 	select USB_GADGET_DUALSPEED
-	select USB_GADGET_SUPERSPEED
 	select USB_XHCI_PLATFORM
 	help
 	  Say Y or M here if your system has a Dual Role SuperSpeed
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 81ce143..5a79cae 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -82,6 +82,12 @@
 
 #define DBM_MAX_EPS		4
 
+/* DBM TRB configurations */
+#define DBM_TRB_BIT		0x80000000
+#define DBM_TRB_DATA_SRC	0x40000000
+#define DBM_TRB_DMA		0x20000000
+#define DBM_TRB_EP_NUM(ep)	(ep<<24)
+
 struct dwc3_msm_req_complete {
 	struct list_head list_item;
 	struct usb_request *req;
@@ -507,19 +513,12 @@
 */
 static int __dwc3_msm_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 {
-	struct dwc3_trb_hw *trb_hw;
-	struct dwc3_trb_hw *trb_link_hw;
-	struct dwc3_trb trb;
+	struct dwc3_trb *trb;
+	struct dwc3_trb *trb_link;
 	struct dwc3_gadget_ep_cmd_params params;
 	u32 cmd;
 	int ret = 0;
 
-	if ((req->request.udc_priv & MSM_IS_FINITE_TRANSFER) &&
-	    (req->request.length > 0)) {
-		/* Map the request to a DMA. */
-		dwc3_map_buffer_to_dma(req);
-	}
-
 	/* We push the request to the dep->req_queued list to indicate that
 	 * this request is issued with start transfer. The request will be out
 	 * from this list in 2 cases. The first is that the transfer will be
@@ -531,31 +530,26 @@
 	list_add_tail(&req->list, &dep->req_queued);
 
 	/* First, prepare a normal TRB, point to the fake buffer */
-	trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
+	trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
 	dep->free_slot++;
-	memset(&trb, 0, sizeof(trb));
+	memset(trb, 0, sizeof(*trb));
 
-	req->trb = trb_hw;
-
-	trb.bplh = req->request.dma;
-	trb.lst = 0;
-	trb.trbctl = DWC3_TRBCTL_NORMAL;
-	trb.length = req->request.length;
-	trb.hwo = true;
-
-	dwc3_trb_to_hw(&trb, trb_hw);
-	req->trb_dma = dep->trb_pool_dma;
+	req->trb = trb;
+	req->trb_dma = dwc3_trb_dma_offset(dep, trb);
+	trb->bph = DBM_TRB_BIT | DBM_TRB_DATA_SRC |
+		   DBM_TRB_DMA | DBM_TRB_EP_NUM(dep->number);
+	trb->size = DWC3_TRB_SIZE_LENGTH(req->request.length);
+	trb->ctrl = DWC3_TRBCTL_NORMAL | DWC3_TRB_CTRL_HWO | DWC3_TRB_CTRL_CHN;
 
 	/* Second, prepare a Link TRB that points to the first TRB*/
-	trb_link_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
+	trb_link = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
 	dep->free_slot++;
-	memset(&trb, 0, sizeof(trb));
 
-	trb.bplh = dep->trb_pool_dma;
-	trb.trbctl = DWC3_TRBCTL_LINK_TRB;
-	trb.hwo = true;
-
-	dwc3_trb_to_hw(&trb, trb_link_hw);
+	trb_link->bpl = lower_32_bits(req->trb_dma);
+	trb_link->bph = DBM_TRB_BIT | DBM_TRB_DATA_SRC |
+			DBM_TRB_DMA | DBM_TRB_EP_NUM(dep->number);
+	trb_link->size = 0;
+	trb_link->ctrl = DWC3_TRBCTL_LINK_TRB | DWC3_TRB_CTRL_HWO;
 
 	/*
 	 * Now start the transfer
@@ -570,7 +564,6 @@
 			"%s: failed to send STARTTRANSFER command\n",
 			__func__);
 
-		dwc3_unmap_buffer_from_dma(req);
 		list_del(&req->list);
 		return ret;
 	}
@@ -1115,7 +1108,7 @@
 		goto disable_hs_ldo;
 	}
 
-	dwc3 = platform_device_alloc("dwc3-msm", -1);
+	dwc3 = platform_device_alloc("dwc3", -1);
 	if (!dwc3) {
 		dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
 		ret = -ENODEV;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 5255fe9..a988c43 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -313,7 +313,7 @@
 	} while (1);
 }
 
-static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
+dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
 		struct dwc3_trb *trb)
 {
 	u32		offset = (char *) trb - (char *) dep->trb_pool;
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index a860008..662682e 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -111,6 +111,8 @@
 int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
 int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
 		unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
+dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
+		struct dwc3_trb *trb);
 
 /**
  * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 14b07e5..95f11c1 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -506,6 +506,32 @@
 	  dynamically linked module called "ci13xxx_msm_hsic" and force all
 	  gadget drivers to also be dynamically linked.
 
+config USB_DWC3_MSM
+	tristate "DesignWare USB3.0 (DRD) Controller for MSM"
+	depends on ARCH_MSM
+	select USB_DWC3
+	select USB_GADGET_DUALSPEED
+	select USB_GADGET_SELECTED
+	help
+	  The DesignWare USB3.0 controller is a SuperSpeed USB3.0 Controller
+	  integrated into the Qualcomm MSM chipset series, supporting host,
+	  device and otg modes of operation. For more information please
+	  refer to http://www.qualcomm.com/chipsets.
+
+config USB_DWC3_OMAP
+	tristate "DesignWare USB3.0 (DRD) Controller for OMAP"
+	depends on ARCH_OMAP
+	select USB_DWC3
+	select USB_GADGET_DUALSPEED
+	select USB_GADGET_SUPERSPEED
+	select USB_GADGET_SELECTED
+	help
+	  DesignWare USB3.0 controller is a SuperSpeed USB3.0 Controller
+	  which can be configured for peripheral-only, host-only, hub-only
+	  and Dual-Role operation. This Controller was first integrated into
+	  the OMAP5 series of processors. More information about the OMAP5
+	  version of this controller, refer to http://www.ti.com/omap5.
+
 #
 # LAST -- dummy/emulated controller
 #
@@ -556,8 +582,15 @@
 
 # Selected by UDC drivers that support super-speed opperation
 config USB_GADGET_SUPERSPEED
-	bool
+	bool "Operate as superspeed"
+	depends on USB_GADGET
 	depends on USB_GADGET_DUALSPEED
+	default n
+	help
+	 When a superspeed peripheral controller is selected
+	 (for example DesignWare USB3.0 controller), use this flag to
+	 indicate if the device should operate in superspeed(=y)
+	 or not.
 
 #
 # USB Gadget Drivers
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index fb86874..8cdc2e9 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -1720,6 +1720,7 @@
 			if (!mReq->req.no_interrupt)
 				mReq->ptr->token |= MSM_ETD_IOC;
 		}
+		mReq->req.dma = 0;
 	}
 
 	mReq->ptr->page[0]  = mReq->req.dma;
diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c
index 37b4e53..8b762a2 100644
--- a/drivers/usb/misc/diag_bridge.c
+++ b/drivers/usb/misc/diag_bridge.c
@@ -428,7 +428,7 @@
 
 	dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
 
-	platform_device_del(dev->pdev);
+	platform_device_unregister(dev->pdev);
 	dev->ifc = NULL;
 	diag_bridge_debugfs_cleanup();
 	kref_put(&dev->kref, diag_bridge_delete);
diff --git a/drivers/usb/misc/mdm_ctrl_bridge.c b/drivers/usb/misc/mdm_ctrl_bridge.c
index 044af3a..e685233 100644
--- a/drivers/usb/misc/mdm_ctrl_bridge.c
+++ b/drivers/usb/misc/mdm_ctrl_bridge.c
@@ -703,7 +703,7 @@
 free_inturb:
 	usb_free_urb(dev->inturb);
 pdev_del:
-	platform_device_del(dev->pdev);
+	platform_device_unregister(dev->pdev);
 nomem:
 	kfree(dev);
 
@@ -716,7 +716,7 @@
 
 	dev_dbg(&dev->intf->dev, "%s:\n", __func__);
 
-	platform_device_del(dev->pdev);
+	platform_device_unregister(dev->pdev);
 
 	kfree(dev->in_ctlreq);
 	kfree(dev->readbuf);
diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c
index 26be973..db2f40a 100644
--- a/drivers/usb/misc/mdm_data_bridge.c
+++ b/drivers/usb/misc/mdm_data_bridge.c
@@ -918,12 +918,12 @@
 		return -EINVAL;
 	}
 
-	udev = interface_to_usbdev(iface);
-	usb_get_dev(udev);
-
 	if (!test_bit(iface_num, &id->driver_info))
 		return -ENODEV;
 
+	udev = interface_to_usbdev(iface);
+	usb_get_dev(udev);
+
 	numends = iface->cur_altsetting->desc.bNumEndpoints;
 	for (i = 0; i < numends; i++) {
 		endpoint = iface->cur_altsetting->endpoint + i;
@@ -965,7 +965,7 @@
 	return 0;
 
 free_data_bridge:
-	platform_device_del(__dev[ch_id]->pdev);
+	platform_device_unregister(__dev[ch_id]->pdev);
 	usb_set_intfdata(iface, NULL);
 	kfree(__dev[ch_id]);
 	__dev[ch_id] = NULL;
@@ -989,7 +989,7 @@
 
 	ch_id--;
 	ctrl_bridge_disconnect(ch_id);
-	platform_device_del(dev->pdev);
+	platform_device_unregister(dev->pdev);
 	usb_set_intfdata(intf, NULL);
 	__dev[ch_id] = NULL;
 
diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h
index de8d490..9811a82 100644
--- a/drivers/usb/serial/usb-wwan.h
+++ b/drivers/usb/serial/usb-wwan.h
@@ -53,6 +53,7 @@
 	u8 *out_buffer[N_OUT_URB];
 	unsigned long out_busy;	/* Bit vector of URBs in use */
 	int opened;
+	struct usb_anchor submitted;
 	struct usb_anchor delayed;
 
 	/* Settings for the port */
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 519af39..0c58554 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -252,10 +252,12 @@
 		} else {
 			intfdata->in_flight++;
 			spin_unlock_irqrestore(&intfdata->susp_lock, flags);
+			usb_anchor_urb(this_urb, &portdata->submitted);
 			err = usb_submit_urb(this_urb, GFP_ATOMIC);
 			if (err) {
 				dbg("usb_submit_urb %p (write bulk) failed "
 				    "(%d)", this_urb, err);
+				usb_unanchor_urb(this_urb);
 				clear_bit(i, &portdata->out_busy);
 				spin_lock_irqsave(&intfdata->susp_lock, flags);
 				intfdata->in_flight--;
@@ -281,6 +283,7 @@
 {
 	int err;
 	int endpoint;
+	struct usb_wwan_port_private *portdata;
 	struct usb_serial_port *port;
 	struct tty_struct *tty;
 	unsigned char *data = urb->transfer_buffer;
@@ -290,6 +293,7 @@
 
 	endpoint = usb_pipeendpoint(urb->pipe);
 	port = urb->context;
+	portdata = usb_get_serial_port_data(port);
 
 	if (status) {
 		dbg("%s: nonzero status: %d on endpoint %02x.",
@@ -308,8 +312,10 @@
 
 		/* Resubmit urb so we continue receiving */
 		if (status != -ESHUTDOWN) {
+			usb_anchor_urb(urb, &portdata->submitted);
 			err = usb_submit_urb(urb, GFP_ATOMIC);
 			if (err) {
+				usb_unanchor_urb(urb);
 				if (err != -EPERM) {
 					printk(KERN_ERR "%s: resubmit read urb failed. "
 						"(%d)", __func__, err);
@@ -418,8 +424,10 @@
 		urb = portdata->in_urbs[i];
 		if (!urb)
 			continue;
+		usb_anchor_urb(urb, &portdata->submitted);
 		err = usb_submit_urb(urb, GFP_KERNEL);
 		if (err) {
+			usb_unanchor_urb(urb);
 			dbg("%s: submit urb %d failed (%d) %d",
 			    __func__, i, err, urb->transfer_buffer_length);
 		}
@@ -551,6 +559,7 @@
 			return 1;
 		}
 		init_usb_anchor(&portdata->delayed);
+		init_usb_anchor(&portdata->submitted);
 
 		for (j = 0; j < N_IN_URB; j++) {
 			buffer = kmalloc(IN_BUFLEN, GFP_KERNEL);
@@ -590,7 +599,7 @@
 
 static void stop_read_write_urbs(struct usb_serial *serial)
 {
-	int i, j;
+	int i;
 	struct usb_serial_port *port;
 	struct usb_wwan_port_private *portdata;
 
@@ -598,10 +607,7 @@
 	for (i = 0; i < serial->num_ports; ++i) {
 		port = serial->port[i];
 		portdata = usb_get_serial_port_data(port);
-		for (j = 0; j < N_IN_URB; j++)
-			usb_kill_urb(portdata->in_urbs[j]);
-		for (j = 0; j < N_OUT_URB; j++)
-			usb_kill_urb(portdata->out_urbs[j]);
+		usb_kill_anchored_urbs(&portdata->submitted);
 	}
 }
 
@@ -694,10 +700,12 @@
 	portdata = usb_get_serial_port_data(port);
 	data = port->serial->private;
 	while ((urb = usb_get_from_anchor(&portdata->delayed))) {
+		usb_anchor_urb(urb, &portdata->submitted);
 		err = usb_submit_urb(urb, GFP_ATOMIC);
 		if (!err) {
 			data->in_flight++;
 		} else {
+			usb_unanchor_urb(urb);
 			/* we have to throw away the rest */
 			do {
 				unbusy_queued_urb(urb, portdata);
@@ -736,33 +744,32 @@
 
 	spin_lock_irq(&intfdata->susp_lock);
 	intfdata->suspended = 0;
-	spin_unlock_irq(&intfdata->susp_lock);
-
 	for (i = 0; i < serial->num_ports; i++) {
 		/* walk all ports */
 		port = serial->port[i];
 		portdata = usb_get_serial_port_data(port);
 
 		/* skip closed ports */
-		spin_lock_irq(&intfdata->susp_lock);
-		if (!portdata->opened) {
-			spin_unlock_irq(&intfdata->susp_lock);
+		if (!portdata->opened)
 			continue;
-		}
 
 		for (j = 0; j < N_IN_URB; j++) {
 			urb = portdata->in_urbs[j];
+			usb_anchor_urb(urb, &portdata->submitted);
 			err = usb_submit_urb(urb, GFP_ATOMIC);
 			if (err < 0) {
 				err("%s: Error %d for bulk URB %d",
 				    __func__, err, i);
+				usb_unanchor_urb(urb);
+				intfdata->suspended = 1;
 				spin_unlock_irq(&intfdata->susp_lock);
 				goto err_out;
 			}
 		}
 		play_delayed(port);
-		spin_unlock_irq(&intfdata->susp_lock);
 	}
+	spin_unlock_irq(&intfdata->susp_lock);
+
 err_out:
 	return err;
 }
diff --git a/drivers/video/msm/mipi_NT35510.c b/drivers/video/msm/mipi_NT35510.c
index edbc952..e605aed 100644
--- a/drivers/video/msm/mipi_NT35510.c
+++ b/drivers/video/msm/mipi_NT35510.c
@@ -19,6 +19,8 @@
 static struct dsi_buf nt35510_tx_buf;
 static struct dsi_buf nt35510_rx_buf;
 
+static int mipi_nt35510_bl_ctrl;
+
 #define NT35510_SLEEP_OFF_DELAY 150
 #define NT35510_DISPLAY_ON_DELAY 150
 
@@ -528,8 +530,63 @@
 	return 0;
 }
 
+static ssize_t mipi_nt35510_wta_bl_ctrl(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	ssize_t ret = strnlen(buf, PAGE_SIZE);
+	int err;
+
+	err =  kstrtoint(buf, 0, &mipi_nt35510_bl_ctrl);
+	if (err)
+		return ret;
+
+	pr_info("%s: bl ctrl set to %d\n", __func__, mipi_nt35510_bl_ctrl);
+
+	return ret;
+}
+
+static DEVICE_ATTR(bl_ctrl, S_IWUSR, NULL, mipi_nt35510_wta_bl_ctrl);
+
+static struct attribute *mipi_nt35510_fs_attrs[] = {
+	&dev_attr_bl_ctrl.attr,
+	NULL,
+};
+
+static struct attribute_group mipi_nt35510_fs_attr_group = {
+	.attrs = mipi_nt35510_fs_attrs,
+};
+
+static int mipi_nt35510_create_sysfs(struct platform_device *pdev)
+{
+	int rc;
+	struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
+
+	if (!mfd) {
+		pr_err("%s: mfd not found\n", __func__);
+		return -ENODEV;
+	}
+	if (!mfd->fbi) {
+		pr_err("%s: mfd->fbi not found\n", __func__);
+		return -ENODEV;
+	}
+	if (!mfd->fbi->dev) {
+		pr_err("%s: mfd->fbi->dev not found\n", __func__);
+		return -ENODEV;
+	}
+	rc = sysfs_create_group(&mfd->fbi->dev->kobj,
+		&mipi_nt35510_fs_attr_group);
+	if (rc) {
+		pr_err("%s: sysfs group creation failed, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	return 0;
+}
+
 static int __devinit mipi_nt35510_lcd_probe(struct platform_device *pdev)
 {
+	struct platform_device *pthisdev = NULL;
 	pr_debug("%s\n", __func__);
 
 	if (pdev->id == 0) {
@@ -539,7 +596,8 @@
 		return 0;
 	}
 
-	msm_fb_add_device(pdev);
+	pthisdev = msm_fb_add_device(pdev);
+	mipi_nt35510_create_sysfs(pthisdev);
 
 	return 0;
 }
@@ -551,6 +609,8 @@
 	},
 };
 
+static int old_bl_level;
+
 static void mipi_nt35510_set_backlight(struct msm_fb_data_type *mfd)
 {
 	int bl_level;
@@ -558,11 +618,33 @@
 	bl_level = mfd->bl_level;
 
 	if (mipi_nt35510_pdata->bl_lock) {
-		spin_lock_irqsave(&mipi_nt35510_pdata->bl_spinlock, flags);
-		mipi_nt35510_pdata->pmic_backlight(bl_level);
-		spin_unlock_irqrestore(&mipi_nt35510_pdata->bl_spinlock, flags);
-	} else
-		mipi_nt35510_pdata->pmic_backlight(bl_level);
+		if (!mipi_nt35510_bl_ctrl) {
+			/* Level received is of range 1 to bl_max,
+			   We need to convert the levels to 1
+			   to 31 */
+			bl_level = (2 * bl_level * 31 + mfd->panel_info.bl_max)
+					/(2 * mfd->panel_info.bl_max);
+			if (bl_level == old_bl_level)
+				return;
+
+			if (bl_level == 0)
+				mipi_nt35510_pdata->backlight(0, 1);
+
+			if (old_bl_level == 0)
+				mipi_nt35510_pdata->backlight(50, 1);
+
+			spin_lock_irqsave(&mipi_nt35510_pdata->bl_spinlock,
+						flags);
+			mipi_nt35510_pdata->backlight(bl_level, 0);
+			spin_unlock_irqrestore(&mipi_nt35510_pdata->bl_spinlock,
+						flags);
+			old_bl_level = bl_level;
+		} else {
+			mipi_nt35510_pdata->backlight(bl_level, 1);
+		}
+	} else {
+		mipi_nt35510_pdata->backlight(bl_level, mipi_nt35510_bl_ctrl);
+	}
 }
 
 static struct msm_fb_panel_data nt35510_panel_data = {
diff --git a/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c b/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c
index f052e93..1524ce6 100644
--- a/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c
+++ b/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c
@@ -56,7 +56,7 @@
 	pinfo.lcdc.border_clr = 0;	/* blk */
 	pinfo.lcdc.underflow_clr = 0xff;	/* blue */
 	pinfo.lcdc.hsync_skew = 0;
-	pinfo.bl_max = 31;
+	pinfo.bl_max = 255;
 	pinfo.bl_min = 1;
 	pinfo.fb_num = 2;
 
diff --git a/drivers/video/msm/mipi_NT35510_video_wvga_pt.c b/drivers/video/msm/mipi_NT35510_video_wvga_pt.c
index 4e97d99..8a364ba 100644
--- a/drivers/video/msm/mipi_NT35510_video_wvga_pt.c
+++ b/drivers/video/msm/mipi_NT35510_video_wvga_pt.c
@@ -59,7 +59,7 @@
 	delayed from VSYNC active edge */
 	pinfo.lcdc.hsync_skew = 0;
 	pinfo.clk_rate = 499000000;
-	pinfo.bl_max = 31;
+	pinfo.bl_max = 255;
 	pinfo.bl_min = 1;
 	pinfo.fb_num = 2;
 
diff --git a/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c b/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c
index 7f5ac70..2ebfad4 100644
--- a/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c
+++ b/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.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
@@ -93,7 +93,7 @@
 	pinfo.lcdc.border_clr = 0;	/* blk */
 	pinfo.lcdc.underflow_clr = 0xff;	/* blue */
 	pinfo.lcdc.hsync_skew = 0;
-	pinfo.bl_max = 100;
+	pinfo.bl_max = 255;
 	pinfo.bl_min = 1;
 	pinfo.fb_num = 2;
 
diff --git a/drivers/video/msm/mipi_renesas_video_fwvga_pt.c b/drivers/video/msm/mipi_renesas_video_fwvga_pt.c
index e826773..144d9ff 100644
--- a/drivers/video/msm/mipi_renesas_video_fwvga_pt.c
+++ b/drivers/video/msm/mipi_renesas_video_fwvga_pt.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
@@ -105,7 +105,7 @@
 	pinfo.lcdc.border_clr = 0;	/* blk */
 	pinfo.lcdc.underflow_clr = 0xff;	/* blue */
 	pinfo.lcdc.hsync_skew = 0;
-	pinfo.bl_max = 100;
+	pinfo.bl_max = 255;
 	pinfo.bl_min = 1;
 	pinfo.fb_num = 2;
 
diff --git a/drivers/video/msm/mipi_toshiba.h b/drivers/video/msm/mipi_toshiba.h
index 4107161..dd446b9 100644
--- a/drivers/video/msm/mipi_toshiba.h
+++ b/drivers/video/msm/mipi_toshiba.h
@@ -21,7 +21,7 @@
 int mipi_toshiba_device_register(struct msm_panel_info *pinfo,
 					u32 channel, u32 panel);
 
-#define MIPI_TOSHIBA_PWM_FREQ_HZ 3921
+#define MIPI_TOSHIBA_PWM_FREQ_HZ 300
 #define MIPI_TOSHIBA_PWM_PERIOD_USEC (USEC_PER_SEC / MIPI_TOSHIBA_PWM_FREQ_HZ)
 #define MIPI_TOSHIBA_PWM_LEVEL 255
 #define MIPI_TOSHIBA_PWM_DUTY_LEVEL \
diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e.c b/drivers/video/msm/mipi_truly_tft540960_1_e.c
index e465d46..98b24b1 100644
--- a/drivers/video/msm/mipi_truly_tft540960_1_e.c
+++ b/drivers/video/msm/mipi_truly_tft540960_1_e.c
@@ -19,6 +19,8 @@
 static struct dsi_buf truly_tx_buf;
 static struct dsi_buf truly_rx_buf;
 
+static int mipi_truly_bl_ctrl;
+
 #define TRULY_CMD_DELAY 0
 #define MIPI_SETTING_DELAY 10
 #define TRULY_SLEEP_OFF_DELAY 150
@@ -720,8 +722,64 @@
 	return 0;
 }
 
+static ssize_t mipi_truly_wta_bl_ctrl(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	ssize_t ret = strnlen(buf, PAGE_SIZE);
+	int err;
+
+	err =  kstrtoint(buf, 0, &mipi_truly_bl_ctrl);
+	if (err)
+		return ret;
+
+	pr_info("%s: bl ctrl set to %d\n", __func__, mipi_truly_bl_ctrl);
+
+	return ret;
+}
+
+static DEVICE_ATTR(bl_ctrl, S_IWUSR, NULL, mipi_truly_wta_bl_ctrl);
+
+static struct attribute *mipi_truly_fs_attrs[] = {
+	&dev_attr_bl_ctrl.attr,
+	NULL,
+};
+
+static struct attribute_group mipi_truly_fs_attr_group = {
+	.attrs = mipi_truly_fs_attrs,
+};
+
+static int mipi_truly_create_sysfs(struct platform_device *pdev)
+{
+	int rc;
+	struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
+
+	if (!mfd) {
+		pr_err("%s: mfd not found\n", __func__);
+		return -ENODEV;
+	}
+	if (!mfd->fbi) {
+		pr_err("%s: mfd->fbi not found\n", __func__);
+		return -ENODEV;
+	}
+	if (!mfd->fbi->dev) {
+		pr_err("%s: mfd->fbi->dev not found\n", __func__);
+		return -ENODEV;
+	}
+	rc = sysfs_create_group(&mfd->fbi->dev->kobj,
+		&mipi_truly_fs_attr_group);
+	if (rc) {
+		pr_err("%s: sysfs group creation failed, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+
 static int __devinit mipi_truly_lcd_probe(struct platform_device *pdev)
 {
+	struct platform_device *pthisdev = NULL;
 	int rc = 0;
 
 	if (pdev->id == 0) {
@@ -731,7 +789,8 @@
 		return rc;
 	}
 
-	msm_fb_add_device(pdev);
+	pthisdev = msm_fb_add_device(pdev);
+	mipi_truly_create_sysfs(pthisdev);
 
 	return rc;
 }
@@ -743,6 +802,8 @@
 	},
 };
 
+static int old_bl_level;
+
 static void mipi_truly_set_backlight(struct msm_fb_data_type *mfd)
 {
 	int bl_level;
@@ -750,11 +811,33 @@
 	bl_level = mfd->bl_level;
 
 	if (mipi_truly_pdata->bl_lock) {
-		spin_lock_irqsave(&mipi_truly_pdata->bl_spinlock, flags);
-		mipi_truly_pdata->pmic_backlight(bl_level);
-		spin_unlock_irqrestore(&mipi_truly_pdata->bl_spinlock, flags);
-	} else
-		mipi_truly_pdata->pmic_backlight(bl_level);
+		if (!mipi_truly_bl_ctrl) {
+			/* Level received is of range 1 to bl_max,
+			   We need to convert the levels to 1
+			   to 31 */
+			bl_level = (2 * bl_level * 31 + mfd->panel_info.bl_max)
+					/(2 * mfd->panel_info.bl_max);
+			if (bl_level == old_bl_level)
+				return;
+
+			if (bl_level == 0)
+				mipi_truly_pdata->backlight(0, 1);
+
+			if (old_bl_level == 0)
+				mipi_truly_pdata->backlight(50, 1);
+
+			spin_lock_irqsave(&mipi_truly_pdata->bl_spinlock,
+						flags);
+			mipi_truly_pdata->backlight(bl_level, 0);
+			spin_unlock_irqrestore(&mipi_truly_pdata->bl_spinlock,
+						flags);
+			old_bl_level = bl_level;
+		} else {
+			mipi_truly_pdata->backlight(bl_level, 1);
+		}
+	} else {
+		mipi_truly_pdata->backlight(bl_level, mipi_truly_bl_ctrl);
+	}
 }
 
 static struct msm_fb_panel_data truly_panel_data = {
diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c b/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c
index de98177..3423241 100644
--- a/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c
+++ b/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c
@@ -56,7 +56,7 @@
 	pinfo.lcdc.border_clr = 0;	/* blk */
 	pinfo.lcdc.underflow_clr = 0xff;	/* blue */
 	pinfo.lcdc.hsync_skew = 0;
-	pinfo.bl_max = 31;
+	pinfo.bl_max = 255;
 	pinfo.bl_min = 1;
 	pinfo.fb_num = 2;
 
diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c b/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c
index ea2ff47..3c0c0b7 100644
--- a/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c
+++ b/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c
@@ -59,7 +59,7 @@
 	pinfo.lcdc.hsync_skew = 0;
 	pinfo.clk_rate = 699000000;
 	pinfo.lcd.refx100 = 6000; /* FB driver calc FPS based on this value */
-	pinfo.bl_max = 31;
+	pinfo.bl_max = 255;
 	pinfo.bl_min = 1;
 	pinfo.fb_num = 2;
 
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index b71212c..dcdbf28 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -745,7 +745,8 @@
 		return VCD_ERR_ILLEGAL_PARM;
 	}
 	if (buf_entry->in_use) {
-		VCD_MSG_ERROR("\n Buffer is in use and is not flushed");
+		VCD_MSG_ERROR("Buffer is in use and is not flushed: %p, %d\n",
+			buf_entry, buf_entry->in_use);
 		return VCD_ERR_ILLEGAL_OP;
 	}
 
@@ -1043,6 +1044,7 @@
 {
 	u32 rc = VCD_S_SUCCESS;
 	struct vcd_buffer_entry *buf_entry;
+	struct vcd_buffer_entry *orig_frame = NULL;
 
 	VCD_MSG_LOW("vcd_flush_buffers:");
 
@@ -1066,9 +1068,19 @@
 							 vcd_frame_data),
 						cctxt,
 						cctxt->client_data);
+				orig_frame = vcd_find_buffer_pool_entry(
+						&cctxt->in_buf_pool,
+						buf_entry->virtual);
 				}
 
-			buf_entry->in_use = false;
+			if (orig_frame) {
+				orig_frame->in_use--;
+				if (orig_frame != buf_entry)
+					kfree(buf_entry);
+			} else {
+				buf_entry->in_use = false;
+				VCD_MSG_ERROR("Original frame not found in buffer pool\n");
+			}
 			VCD_BUFFERPOOL_INUSE_DECREMENT(
 				cctxt->in_buf_pool.in_use);
 			buf_entry = NULL;
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 271079e..bcd0afb 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -605,6 +605,7 @@
 
 	struct ion_allocation_data ion_alloc;
 	struct ion_fd_data fd_data;
+	int ion_dev_fd;
 };
 
 enum msm_st_frame_packing {
diff --git a/sound/soc/msm/mdm9615.c b/sound/soc/msm/mdm9615.c
index 363635f..90d8723 100644
--- a/sound/soc/msm/mdm9615.c
+++ b/sound/soc/msm/mdm9615.c
@@ -39,8 +39,8 @@
 #define MDM9615_SLIM_0_RX_MAX_CHANNELS		2
 #define MDM9615_SLIM_0_TX_MAX_CHANNELS		4
 
-#define BTSCO_RATE_8KHZ 8000
-#define BTSCO_RATE_16KHZ 16000
+#define SAMPLE_RATE_8KHZ 8000
+#define SAMPLE_RATE_16KHZ 16000
 
 #define BOTTOM_SPK_AMP_POS	0x1
 #define BOTTOM_SPK_AMP_NEG	0x2
@@ -261,9 +261,11 @@
 static int mdm9615_slim_0_rx_ch = 1;
 static int mdm9615_slim_0_tx_ch = 1;
 
-static int mdm9615_btsco_rate = BTSCO_RATE_8KHZ;
+static int mdm9615_btsco_rate = SAMPLE_RATE_8KHZ;
 static int mdm9615_btsco_ch = 1;
 
+static int mdm9615_auxpcm_rate = SAMPLE_RATE_8KHZ;
+
 static struct clk *codec_clk;
 static int clk_users;
 
@@ -679,6 +681,11 @@
 		SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
 };
 
+static const char * const auxpcm_rate_text[] = {"rate_8000", "rate_16000"};
+static const struct soc_enum mdm9615_auxpcm_enum[] = {
+		SOC_ENUM_SINGLE_EXT(2, auxpcm_rate_text),
+};
+
 static int mdm9615_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
@@ -730,19 +737,49 @@
 {
 	switch (ucontrol->value.integer.value[0]) {
 	case 0:
-		mdm9615_btsco_rate = BTSCO_RATE_8KHZ;
+		mdm9615_btsco_rate = SAMPLE_RATE_8KHZ;
 		break;
 	case 1:
-		mdm9615_btsco_rate = BTSCO_RATE_16KHZ;
+		mdm9615_btsco_rate = SAMPLE_RATE_16KHZ;
 		break;
 	default:
-		mdm9615_btsco_rate = BTSCO_RATE_8KHZ;
+		mdm9615_btsco_rate = SAMPLE_RATE_8KHZ;
 		break;
 	}
 	pr_debug("%s: mdm9615_btsco_rate = %d\n", __func__, mdm9615_btsco_rate);
 	return 0;
 }
 
+static int mdm9615_auxpcm_rate_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: mdm9615_auxpcm_rate  = %d", __func__,
+		mdm9615_auxpcm_rate);
+	ucontrol->value.integer.value[0] = mdm9615_auxpcm_rate;
+	return 0;
+}
+
+static int mdm9615_auxpcm_rate_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		mdm9615_auxpcm_rate = SAMPLE_RATE_8KHZ;
+		break;
+	case 1:
+		mdm9615_auxpcm_rate = SAMPLE_RATE_16KHZ;
+		break;
+	default:
+		mdm9615_auxpcm_rate = SAMPLE_RATE_8KHZ;
+		break;
+	}
+	pr_debug("%s: mdm9615_auxpcm_rate = %d\n"
+		 "ucontrol->value.integer.value[0] = %d\n", __func__,
+		 mdm9615_auxpcm_rate,
+		 (int)ucontrol->value.integer.value[0]);
+	return 0;
+}
+
 static const struct snd_kcontrol_new tabla_mdm9615_controls[] = {
 	SOC_ENUM_EXT("Speaker Function", mdm9615_enum[0], mdm9615_get_spk,
 		mdm9615_set_spk),
@@ -752,6 +789,8 @@
 		mdm9615_slim_0_tx_ch_get, mdm9615_slim_0_tx_ch_put),
 	SOC_ENUM_EXT("Internal BTSCO SampleRate", mdm9615_btsco_enum[0],
 		     mdm9615_btsco_rate_get, mdm9615_btsco_rate_put),
+	SOC_ENUM_EXT("AUX PCM SampleRate", mdm9615_auxpcm_enum[0],
+		mdm9615_auxpcm_rate_get, mdm9615_auxpcm_rate_put),
 };
 
 static void *def_tabla_mbhc_cal(void)
@@ -1554,8 +1593,8 @@
 	struct snd_interval *channels = hw_param_interval(params,
 					SNDRV_PCM_HW_PARAM_CHANNELS);
 
-	/* PCM only supports mono output with 8khz sample rate */
-	rate->min = rate->max = 8000;
+	rate->min = rate->max = mdm9615_auxpcm_rate;
+	/* PCM only supports mono output */
 	channels->min = channels->max = 1;
 
 	return 0;
diff --git a/sound/soc/msm/mpq8064.c b/sound/soc/msm/mpq8064.c
index 9395e8f..4ecd8df 100644
--- a/sound/soc/msm/mpq8064.c
+++ b/sound/soc/msm/mpq8064.c
@@ -1062,7 +1062,8 @@
 		.cpu_dai_name	= "MultiMedia1",
 		.platform_name  = "msm-pcm-dsp",
 		.dynamic = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 		.ignore_suspend = 1,
@@ -1075,7 +1076,8 @@
 		.cpu_dai_name	= "MultiMedia2",
 		.platform_name  = "msm-multi-ch-pcm-dsp",
 		.dynamic = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 		.ignore_suspend = 1,
@@ -1088,7 +1090,8 @@
 		.cpu_dai_name   = "CS-VOICE",
 		.platform_name  = "msm-pcm-voice",
 		.dynamic = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 		.ignore_suspend = 1,
 		.ignore_pmdown_time = 1, /* this dainlink has playback support */
@@ -1102,7 +1105,8 @@
 		.cpu_dai_name	= "VoIP",
 		.platform_name  = "msm-voip-dsp",
 		.dynamic = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 		.ignore_suspend = 1,
@@ -1115,7 +1119,8 @@
 		.cpu_dai_name	= "MultiMedia3",
 		.platform_name  = "msm-pcm-dsp",
 		.dynamic = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 		.ignore_suspend = 1,
@@ -1129,7 +1134,8 @@
 		.cpu_dai_name	= "SLIMBUS0_HOSTLESS",
 		.platform_name  = "msm-pcm-hostless",
 		.dynamic = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 		.ignore_suspend = 1,
 		.ignore_pmdown_time = 1, /* this dainlink has playback support */
@@ -1142,7 +1148,8 @@
 		.cpu_dai_name	= "INT_FM_HOSTLESS",
 		.platform_name  = "msm-pcm-hostless",
 		.dynamic = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 		.ignore_suspend = 1,
 		.ignore_pmdown_time = 1, /* this dainlink has playback support */
@@ -1178,7 +1185,8 @@
 		.cpu_dai_name   = "MultiMedia4",
 		.platform_name  = "msm-compr-dsp",
 		.dynamic = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 		.ignore_suspend = 1,
@@ -1191,7 +1199,8 @@
 		.cpu_dai_name = "VOICE_STUB",
 		.platform_name = "msm-pcm-hostless",
 		.dynamic = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 		.ignore_suspend = 1,
 		.ignore_pmdown_time = 1, /* this dainlink has playback support */
@@ -1205,7 +1214,8 @@
 		.cpu_dai_name = "HDMI_HOSTLESS",
 		.platform_name = "msm-pcm-hostless",
 		.dynamic = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 		.ignore_suspend = 1,
 		.ignore_pmdown_time = 1, /* this dainlink has playback support */
@@ -1219,7 +1229,8 @@
 		.cpu_dai_name = "MI2S_TX_HOSTLESS",
 		.platform_name = "msm-pcm-hostless",
 		.dynamic = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 		.ignore_suspend = 1,
 		.codec_dai_name = "snd-soc-dummy-dai",
@@ -1232,7 +1243,8 @@
 		.cpu_dai_name = "SEC_I2S_RX_HOSTLESS",
 		.platform_name = "msm-pcm-hostless",
 		.dynamic = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 		.ignore_suspend = 1,
 		.ignore_pmdown_time = 1, /* this dainlink has playback support */
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index e137a66..4e1ce52 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -2316,6 +2316,8 @@
 	{"BE_OUT", NULL, "PCM_RX"},
 	{"PCM_TX", NULL, "BE_IN"},
 	{"BE_OUT", NULL, "SLIMBUS_3_RX"},
+	{"BE_OUT", NULL, "STUB_RX"},
+	{"STUB_TX", NULL, "BE_IN"},
 };
 
 static int msm_pcm_routing_hw_params(struct snd_pcm_substream *substream,