Merge "defconfig:msm8610 Enable camera front sensor (sp1628) for 8x10"
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index fbe2d25..e3a6721 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -135,6 +135,21 @@
 		qcom,usb2-power-budget = <500>;
 	};
 
+MSM HSUSB controller
+
+Required properties :
+- compatible : should be "qcom,ci13xxx_msm"
+
+Optional properties :
+- qcom,itc-level: value of 2^itc-level will be used for as the interrupt threshold
+	(ITC), when itc-level is between 0 to 6.
+
+Example MSM HSUSB controller device node :
+	msm_hsusb: qcom,ci13xxx_msm {
+		compatible = "qcom,ci13xxx_msm";
+		qcom,itc-level = <4>;
+};
+
 ANDROID USB:
 
 Required properties:
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 1877f40..0e446e2 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -22,6 +22,11 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 
+		qcom,revid@100 {
+			compatible = "qcom,qpnp-revid";
+			reg = <0x100 0x100>;
+		};
+
 		qcom,power-on@800 {
 			compatible = "qcom,qpnp-power-on";
 			reg = <0x800 0x100>;
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index d429f72..2008e1e 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -22,6 +22,11 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 
+		qcom,revid@100 {
+			compatible = "qcom,qpnp-revid";
+			reg = <0x100 0x100>;
+		};
+
 		qcom,power-on@800 {
 			compatible = "qcom,qpnp-power-on";
 			reg = <0x800 0x100>;
diff --git a/arch/arm/boot/dts/msm8610-cdp.dts b/arch/arm/boot/dts/msm8610-cdp.dts
index bbdc2b8..6891b90 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-cdp.dts
@@ -51,7 +51,7 @@
 				/* Object 6, Instance = 0 */
 				00 00 00 00 00 00
 				/* Object 38, Instance = 0 */
-				1D 01 00 0C 04 0D 00 00
+				1D 02 00 0A 06 0D 00 00
 				/* Object 7, Instance = 0 */
 				20 08 32
 				/* Object 8, Instance = 0 */
@@ -59,7 +59,7 @@
 				/* Object 9, Instance = 0 */
 				83 00 00 13 0B 00 20 32 01 03
 				00 32 05 30 0A 05 0A 00 70 03
-				FC 01 00 36 2F 2C 00 00 40 00
+				FC 01 00 36 2F D8 00 00 40 00
 				00 0A 00 00 02
 				/* Object 18, Instance = 0 */
 				00 00
diff --git a/arch/arm/boot/dts/msm8610-mtp.dts b/arch/arm/boot/dts/msm8610-mtp.dts
index 9406a09..ddbe3a0 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-mtp.dts
@@ -51,7 +51,7 @@
 				/* Object 6, Instance = 0 */
 				00 00 00 00 00 00
 				/* Object 38, Instance = 0 */
-				1D 01 00 0C 04 0D 00 00
+				1D 02 00 0A 06 0D 00 00
 				/* Object 7, Instance = 0 */
 				20 08 32
 				/* Object 8, Instance = 0 */
@@ -59,7 +59,7 @@
 				/* Object 9, Instance = 0 */
 				83 00 00 13 0B 00 20 32 01 03
 				00 32 05 30 0A 05 0A 00 70 03
-				FC 01 00 36 2F 2C 00 00 40 00
+				FC 01 00 36 2F D8 00 00 40 00
 				00 0A 00 00 02
 				/* Object 18, Instance = 0 */
 				00 00
diff --git a/arch/arm/boot/dts/msm8610-qrd.dts b/arch/arm/boot/dts/msm8610-qrd.dts
index 5f9365a..42367b3 100644
--- a/arch/arm/boot/dts/msm8610-qrd.dts
+++ b/arch/arm/boot/dts/msm8610-qrd.dts
@@ -157,6 +157,7 @@
 				qcom,id = <6>;
 				qcom,source-sel = <1>;
 				qcom,mode-ctrl = <0x61>;
+				qcom,mode = "manual";
 			};
 		};
 
@@ -171,6 +172,7 @@
 				qcom,id = <6>;
 				qcom,source-sel = <1>;
 				qcom,mode-ctrl = <0x10>;
+				qcom,mode = "manual";
 			};
 		};
 	};
@@ -265,3 +267,33 @@
 		status = "ok";
 	};
 };
+
+&pm8110_gpios {
+	gpio@c000 { /* GPIO 1 */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+	};
+
+	gpio@c200 { /* GPIO 3 */
+	};
+
+	gpio@c300 { /* GPIO 4 */
+	};
+};
+
+&pm8110_mpps {
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+		status = "disabled";
+	};
+
+	mpp@a200 { /* MPP 3 */
+		status = "disabled";
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+};
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index d617c27..f184a00 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -175,6 +175,11 @@
 				<87 512 40000 640000>;
 	};
 
+	msm_hsusb: qcom,ci13xxx_msm {
+		compatible = "qcom,ci13xxx_msm";
+		qcom,itc-level = <4>;
+	};
+
 	hsic_host: hsic@f9a15000 {
 		compatible = "qcom,hsic-host";
 		reg = <0xf9a15000 0x400>;
diff --git a/arch/arm/boot/dts/msmkrypton-sim.dts b/arch/arm/boot/dts/msmkrypton-sim.dts
index 1872a36..29f0df4 100644
--- a/arch/arm/boot/dts/msmkrypton-sim.dts
+++ b/arch/arm/boot/dts/msmkrypton-sim.dts
@@ -23,3 +23,13 @@
 &uartdm3{
 	status = "ok";
 };
+
+&spi_6 {
+	ethernet-switch@0 {
+		compatible = "simtec,ks8851";
+		reg = <0>;
+		interrupt-parent = <&msmgpio>;
+		spi-max-frequency = <19200000>;
+		interrupts = <75 0>;
+	};
+};
diff --git a/arch/arm/boot/dts/msmkrypton.dtsi b/arch/arm/boot/dts/msmkrypton.dtsi
index 4b032d8..7bbd528 100644
--- a/arch/arm/boot/dts/msmkrypton.dtsi
+++ b/arch/arm/boot/dts/msmkrypton.dtsi
@@ -117,4 +117,19 @@
 		interrupts = <0 109 0>;
 		status = "disabled";
 	};
+
+	spi_6: spi@f9928000 { /* BLSP1 QUP6 */
+		cell-index = <0>;
+		compatible = "qcom,spi-qup-v2";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0xf9928000 0x1000>;
+		interrupts = <0 100 0>;
+		spi-max-frequency = <19200000>;
+
+		gpios = <&msmgpio 23 0>, /* CLK  */
+		<&msmgpio 21 0>, /* MISO */
+		<&msmgpio 20 0>; /* MOSI */
+		cs-gpios = <&msmgpio 22 0>;
+	};
 };
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 7420092..71249c9 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -205,6 +205,15 @@
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_QSEECOM=y
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
 CONFIG_MD=y
 CONFIG_BLK_DEV_DM=y
 CONFIG_DM_CRYPT=y
@@ -359,6 +368,7 @@
 CONFIG_QPNP_PWM=y
 CONFIG_QPNP_POWER_ON=y
 CONFIG_QPNP_VIBRATOR=y
+CONFIG_QPNP_REVID=y
 CONFIG_MSM_IOMMU_V1=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 3798987..6c604ff 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -205,6 +205,15 @@
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_QSEECOM=y
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
 CONFIG_MD=y
 CONFIG_BLK_DEV_DM=y
 CONFIG_DM_CRYPT=y
@@ -384,6 +393,7 @@
 CONFIG_QPNP_PWM=y
 CONFIG_QPNP_POWER_ON=y
 CONFIG_QPNP_VIBRATOR=y
+CONFIG_QPNP_REVID=y
 CONFIG_MSM_IOMMU_V1=y
 CONFIG_CORESIGHT=y
 CONFIG_CORESIGHT_TMC=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index acd6adc..d5e230d 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -349,6 +349,7 @@
 CONFIG_QPNP_PWM=y
 CONFIG_QPNP_POWER_ON=y
 CONFIG_QPNP_VIBRATOR=y
+CONFIG_QPNP_REVID=y
 CONFIG_MSM_IOMMU_V0=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 4870575..b435924 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -368,6 +368,7 @@
 CONFIG_QPNP_PWM=y
 CONFIG_QPNP_POWER_ON=y
 CONFIG_QPNP_VIBRATOR=y
+CONFIG_QPNP_REVID=y
 CONFIG_MSM_IOMMU_V0=y
 CONFIG_CORESIGHT=y
 CONFIG_CORESIGHT_TMC=y
diff --git a/arch/arm/configs/msmkrypton_defconfig b/arch/arm/configs/msmkrypton_defconfig
index 69bc36e..f073d2b 100644
--- a/arch/arm/configs/msmkrypton_defconfig
+++ b/arch/arm/configs/msmkrypton_defconfig
@@ -65,9 +65,28 @@
 CONFIG_MTD_BLOCK=y
 # CONFIG_MTD_MSM_NAND is not set
 CONFIG_MTD_MSM_QPIC_NAND=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IPV6=y
+# CONFIG_WIRELESS is not set
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 # CONFIG_ANDROID_PMEM is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+CONFIG_KS8851=y
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_MSM_RMNET is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_KEYBOARD is not set
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index cf10056..a70b300 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -573,6 +573,8 @@
 	local_fiq_disable();
 	local_irq_disable();
 
+	flush_cache_all();
+
 	while (1)
 		cpu_relax();
 }
diff --git a/arch/arm/mach-msm/include/mach/qseecomi.h b/arch/arm/mach-msm/include/mach/qseecomi.h
index 3a997be..a4021d4 100644
--- a/arch/arm/mach-msm/include/mach/qseecomi.h
+++ b/arch/arm/mach-msm/include/mach/qseecomi.h
@@ -18,13 +18,13 @@
 
 #define QSEECOM_KEY_ID_SIZE   32
 
-#define	QSEOS_RESULT_FAIL_LOAD_KS         -48
-#define	QSEOS_RESULT_FAIL_SAVE_KS         -49
-#define	QSEOS_RESULT_FAIL_MAX_KEYS        -50
-#define	QSEOS_RESULT_FAIL_KEY_ID_EXISTS   -51
-#define	QSEOS_RESULT_FAIL_KEY_ID_DNE      -52
-#define	QSEOS_RESULT_FAIL_KS_OP           -53
-#define	QSEOS_RESULT_FAIL_CE_PIPE_INVALID -54
+#define	QSEOS_RESULT_FAIL_LOAD_KS         -57
+#define	QSEOS_RESULT_FAIL_SAVE_KS         -58
+#define	QSEOS_RESULT_FAIL_MAX_KEYS        -59
+#define	QSEOS_RESULT_FAIL_KEY_ID_EXISTS   -60
+#define	QSEOS_RESULT_FAIL_KEY_ID_DNE      -61
+#define	QSEOS_RESULT_FAIL_KS_OP           -62
+#define	QSEOS_RESULT_FAIL_CE_PIPE_INVALID -63
 
 enum qseecom_command_scm_resp_type {
 	QSEOS_APP_ID = 0xEE01,
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index a5e04cd..7b1a4c3 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -952,8 +952,8 @@
 static irqreturn_t subsys_err_ready_intr_handler(int irq, void *subsys)
 {
 	struct subsys_device *subsys_dev = subsys;
-	pr_info("Error ready interrupt occured for %s\n",
-		 subsys_dev->desc->name);
+	dev_info(subsys_dev->desc->dev,
+		"Subsystem error monitoring/handling services are up\n");
 
 	if (subsys_dev->desc->is_not_loadable)
 		return IRQ_HANDLED;
diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c
index efcace6..8dbac64 100644
--- a/drivers/input/touchscreen/ft5x06_ts.c
+++ b/drivers/input/touchscreen/ft5x06_ts.c
@@ -18,6 +18,7 @@
 
 #include <linux/i2c.h>
 #include <linux/input.h>
+#include <linux/input/mt.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
@@ -168,7 +169,15 @@
 #define FT_REG_CAL		0x00
 #define FT_CAL_MASK		0x70
 
-#define FT_DEBUG_DIR_NAME	"ft_debug"
+#define FT_INFO_MAX_LEN		200
+
+#define FT_STORE_TS_INFO(buf, id, fw_ver) \
+			snprintf(buf, FT_INFO_MAX_LEN, \
+				"controller\t= focaltech\n" \
+				"model\t\t= 0x%x\n" \
+				"fw_ver\t\t= 0x%x\n", id, fw_ver)
+
+#define FT_DEBUG_DIR_NAME	"ts_debug"
 
 struct ts_event {
 	u16 x[CFG_MAX_TOUCH_POINTS];	/*x coordinate */
@@ -202,6 +211,7 @@
 	struct dentry *dir;
 	u16 addr;
 	bool suspended;
+	char *ts_info;
 #if defined(CONFIG_FB)
 	struct notifier_block fb_notif;
 #elif defined(CONFIG_HAS_EARLYSUSPEND)
@@ -298,17 +308,22 @@
 			event->pressure = 0;
 		}
 
-		input_report_abs(data->input_dev, ABS_MT_POSITION_X,
-				 event->x[i]);
-		input_report_abs(data->input_dev, ABS_MT_POSITION_Y,
-				 event->y[i]);
-		input_report_abs(data->input_dev, ABS_MT_PRESSURE,
-				 event->pressure);
-		input_report_abs(data->input_dev, ABS_MT_TRACKING_ID,
-				 event->finger_id[i]);
-		input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR,
-				 event->pressure);
-		input_mt_sync(data->input_dev);
+		input_mt_slot(data->input_dev, i);
+		input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER,
+					!!event->pressure);
+
+		if (event->pressure == FT_PRESS) {
+			input_report_abs(data->input_dev, ABS_MT_POSITION_X,
+					 event->x[i]);
+			input_report_abs(data->input_dev, ABS_MT_POSITION_Y,
+					 event->y[i]);
+			input_report_abs(data->input_dev, ABS_MT_PRESSURE,
+					 event->pressure);
+			input_report_abs(data->input_dev, ABS_MT_TRACKING_ID,
+					 event->finger_id[i]);
+			input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR,
+					 event->pressure);
+		}
 	}
 
 	input_report_key(data->input_dev, BTN_TOUCH, !!fingerdown);
@@ -809,6 +824,7 @@
 		rc = -EIO;
 	}
 
+	FT_STORE_TS_INFO(data->ts_info, data->family_id, FT_FW_FILE_VER(fw));
 rel_fw:
 	release_firmware(fw);
 	return rc;
@@ -1015,6 +1031,27 @@
 DEFINE_SIMPLE_ATTRIBUTE(debug_suspend_fops, ft5x06_debug_suspend_get,
 			ft5x06_debug_suspend_set, "%lld\n");
 
+static int ft5x06_debug_dump_info(struct seq_file *m, void *v)
+{
+	struct ft5x06_ts_data *data = m->private;
+
+	seq_printf(m, "%s\n", data->ts_info);
+
+	return 0;
+}
+
+static int debugfs_dump_info_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ft5x06_debug_dump_info, inode->i_private);
+}
+
+static const struct file_operations debug_dump_info_fops = {
+	.owner		= THIS_MODULE,
+	.open		= debugfs_dump_info_open,
+	.read		= seq_read,
+	.release	= single_release,
+};
+
 #ifdef CONFIG_OF
 static int ft5x06_get_dt_coords(struct device *dev, char *name,
 				struct ft5x06_ts_platform_data *pdata)
@@ -1130,7 +1167,7 @@
 	struct ft5x06_ts_platform_data *pdata;
 	struct ft5x06_ts_data *data;
 	struct input_dev *input_dev;
-	struct dentry *dir, *temp;
+	struct dentry *temp;
 	u8 reg_value;
 	u8 reg_addr;
 	int err;
@@ -1188,12 +1225,11 @@
 	__set_bit(BTN_TOUCH, input_dev->keybit);
 	__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
 
+	input_mt_init_slots(input_dev, CFG_MAX_TOUCH_POINTS);
 	input_set_abs_params(input_dev, ABS_MT_POSITION_X, pdata->x_min,
 			     pdata->x_max, 0, 0);
 	input_set_abs_params(input_dev, ABS_MT_POSITION_Y, pdata->y_min,
 			     pdata->y_max, 0, 0);
-	input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0,
-			     CFG_MAX_TOUCH_POINTS, 0, 0);
 	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, FT_PRESS, 0, 0);
 	input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, FT_PRESS, 0, 0);
 
@@ -1282,28 +1318,6 @@
 
 	data->family_id = reg_value;
 
-	/*get some register information */
-	reg_addr = FT_REG_FW_VER;
-	err = ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
-	if (err < 0)
-		dev_err(&client->dev, "version read failed");
-
-	dev_info(&client->dev, "Firmware version = 0x%x\n", reg_value);
-
-	reg_addr = FT_REG_POINT_RATE;
-	ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
-	if (err < 0)
-		dev_err(&client->dev, "report rate read failed");
-
-	dev_info(&client->dev, "report rate = %dHz\n", reg_value * 10);
-
-	reg_addr = FT_REG_THGROUP;
-	err = ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
-	if (err < 0)
-		dev_err(&client->dev, "threshold read failed");
-
-	dev_dbg(&client->dev, "touch threshold = %d\n", reg_value * 4);
-
 	err = request_threaded_irq(client->irq, NULL,
 				   ft5x06_ts_interrupt, pdata->irqflags,
 				   client->dev.driver->name, data);
@@ -1330,14 +1344,14 @@
 		goto free_update_fw_sys;
 	}
 
-	dir = debugfs_create_dir(FT_DEBUG_DIR_NAME, NULL);
-	if (dir == NULL || IS_ERR(dir)) {
-		pr_err("debugfs_create_dir failed: rc=%ld\n", PTR_ERR(dir));
-		err = PTR_ERR(dir);
+	data->dir = debugfs_create_dir(FT_DEBUG_DIR_NAME, NULL);
+	if (data->dir == NULL || IS_ERR(data->dir)) {
+		pr_err("debugfs_create_dir failed(%ld)\n", PTR_ERR(data->dir));
+		err = PTR_ERR(data->dir);
 		goto free_force_update_fw_sys;
 	}
 
-	temp = debugfs_create_file("addr", S_IRUSR | S_IWUSR, dir, data,
+	temp = debugfs_create_file("addr", S_IRUSR | S_IWUSR, data->dir, data,
 				   &debug_addr_fops);
 	if (temp == NULL || IS_ERR(temp)) {
 		pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
@@ -1345,7 +1359,7 @@
 		goto free_debug_dir;
 	}
 
-	temp = debugfs_create_file("data", S_IRUSR | S_IWUSR, dir, data,
+	temp = debugfs_create_file("data", S_IRUSR | S_IWUSR, data->dir, data,
 				   &debug_data_fops);
 	if (temp == NULL || IS_ERR(temp)) {
 		pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
@@ -1353,14 +1367,52 @@
 		goto free_debug_dir;
 	}
 
-	temp = debugfs_create_file("suspend", S_IRUSR | S_IWUSR, dir, data,
-				   &debug_suspend_fops);
+	temp = debugfs_create_file("suspend", S_IRUSR | S_IWUSR, data->dir,
+					data, &debug_suspend_fops);
 	if (temp == NULL || IS_ERR(temp)) {
 		pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
 		err = PTR_ERR(temp);
 		goto free_debug_dir;
 	}
 
+	temp = debugfs_create_file("dump_info", S_IRUSR | S_IWUSR, data->dir,
+					data, &debug_dump_info_fops);
+	if (temp == NULL || IS_ERR(temp)) {
+		pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
+		err = PTR_ERR(temp);
+		goto free_debug_dir;
+	}
+
+	data->ts_info = kzalloc(FT_INFO_MAX_LEN, GFP_KERNEL);
+	if (!data->ts_info) {
+		dev_err(&client->dev, "Not enough memory\n");
+		goto free_debug_dir;
+	}
+
+	/*get some register information */
+	reg_addr = FT_REG_POINT_RATE;
+	ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
+	if (err < 0)
+		dev_err(&client->dev, "report rate read failed");
+
+	dev_info(&client->dev, "report rate = %dHz\n", reg_value * 10);
+
+	reg_addr = FT_REG_THGROUP;
+	err = ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
+	if (err < 0)
+		dev_err(&client->dev, "threshold read failed");
+
+	dev_dbg(&client->dev, "touch threshold = %d\n", reg_value * 4);
+
+	reg_addr = FT_REG_FW_VER;
+	err = ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
+	if (err < 0)
+		dev_err(&client->dev, "version read failed");
+
+	dev_info(&client->dev, "Firmware version = 0x%x\n", reg_value);
+
+	FT_STORE_TS_INFO(data->ts_info, data->family_id, reg_value);
+
 #if defined(CONFIG_FB)
 	data->fb_notif.notifier_call = fb_notifier_callback;
 
@@ -1449,6 +1501,7 @@
 		ft5x06_power_init(data, false);
 
 	input_unregister_device(data->input_dev);
+	kfree(data->ts_info);
 	kfree(data);
 
 	return 0;
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index ac2ecbb..a990f43 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -128,6 +128,16 @@
 	struct mmc_driver *drv = to_mmc_driver(dev->driver);
 	struct mmc_card *card = mmc_dev_to_card(dev);
 
+	if (!drv) {
+		pr_debug("%s: %s: drv is NULL\n", dev_name(dev), __func__);
+		return;
+	}
+
+	if (!card) {
+		pr_debug("%s: %s: card is NULL\n", dev_name(dev), __func__);
+		return;
+	}
+
 	if (drv->shutdown)
 		drv->shutdown(card);
 }
diff --git a/drivers/platform/msm/ipa/a2_service.c b/drivers/platform/msm/ipa/a2_service.c
index 0d77741..8e79185 100644
--- a/drivers/platform/msm/ipa/a2_service.c
+++ b/drivers/platform/msm/ipa/a2_service.c
@@ -278,7 +278,8 @@
 					A2_MUX_COMPLETION_TIMEOUT);
 		a2_mux_ctx->wait_for_ack = 0;
 		if (unlikely(ret == 0)) {
-			IPADBG("%s timeout previous ack\n", __func__);
+			IPAERR("%s previous ack from modem timed out\n",
+				__func__);
 			goto bail;
 		}
 	}
@@ -288,7 +289,7 @@
 	ret = wait_for_completion_timeout(&a2_mux_ctx->ul_wakeup_ack_completion,
 					A2_MUX_COMPLETION_TIMEOUT);
 	if (unlikely(ret == 0)) {
-		IPADBG("%s timeout wakeup ack\n", __func__);
+		IPAERR("%s wakup ack from modem timed out\n", __func__);
 		goto bail;
 	}
 	INIT_COMPLETION(a2_mux_ctx->bam_connection_completion);
@@ -297,7 +298,7 @@
 			&a2_mux_ctx->bam_connection_completion,
 			A2_MUX_COMPLETION_TIMEOUT);
 		if (unlikely(ret == 0)) {
-			IPADBG("%s timeout power on\n", __func__);
+			IPAERR("%s modem power on timed out\n", __func__);
 			goto bail;
 		}
 	}
@@ -450,7 +451,8 @@
 			&a2_mux_ctx->dl_wakeup_completion,
 			A2_MUX_COMPLETION_TIMEOUT);
 		if (unlikely(ret == 0)) {
-			IPAERR("%s timeout A2 PROD\n", __func__);
+			IPAERR("%s timeout waiting for A2 PROD granted\n",
+				__func__);
 			BUG();
 			return;
 		}
@@ -475,8 +477,8 @@
 			&a2_mux_ctx->request_resource_completion,
 			A2_MUX_COMPLETION_TIMEOUT);
 		if (unlikely(ret == 0)) {
-			IPADBG("%s timeout request A2 PROD resource\n",
-				     __func__);
+			IPAERR("%s timeout waiting for A2 PROD granted\n",
+				__func__);
 			BUG();
 			return;
 		}
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index f4ad172..1cbd514 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -50,7 +50,6 @@
 #define IPA_AGGR_STR_IN_BYTES(str) \
 	(strnlen((str), IPA_AGGR_MAX_STR_LENGTH - 1) + 1)
 
-
 static struct ipa_plat_drv_res ipa_res = {0, };
 static struct of_device_id ipa_plat_drv_match[] = {
 	{
@@ -1735,6 +1734,22 @@
 		result = -ENOMEM;
 		goto fail_rt_tbl_cache;
 	}
+	ipa_ctx->tx_pkt_wrapper_cache =
+	   kmem_cache_create("IPA TX PKT WRAPPER",
+			   sizeof(struct ipa_tx_pkt_wrapper), 0, 0, NULL);
+	if (!ipa_ctx->tx_pkt_wrapper_cache) {
+		IPAERR(":ipa tx pkt wrapper cache create failed\n");
+		result = -ENOMEM;
+		goto fail_tx_pkt_wrapper_cache;
+	}
+	ipa_ctx->rx_pkt_wrapper_cache =
+	   kmem_cache_create("IPA RX PKT WRAPPER",
+			   sizeof(struct ipa_rx_pkt_wrapper), 0, 0, NULL);
+	if (!ipa_ctx->rx_pkt_wrapper_cache) {
+		IPAERR(":ipa rx pkt wrapper cache create failed\n");
+		result = -ENOMEM;
+		goto fail_rx_pkt_wrapper_cache;
+	}
 	ipa_ctx->tree_node_cache =
 	   kmem_cache_create("IPA TREE", sizeof(struct ipa_tree_node), 0, 0,
 			   NULL);
@@ -1803,8 +1818,6 @@
 	mutex_init(&ipa_ctx->lock);
 	mutex_init(&ipa_ctx->nat_mem.lock);
 
-	skb_queue_head_init(&ipa_ctx->rx_list);
-
 	for (i = 0; i < IPA_A5_SYS_MAX; i++) {
 		INIT_LIST_HEAD(&ipa_ctx->sys[i].head_desc_list);
 		spin_lock_init(&ipa_ctx->sys[i].spinlock);
@@ -1818,15 +1831,15 @@
 			atomic_set(&ipa_ctx->sys[i].curr_polling_state, 0);
 	}
 
-	ipa_ctx->rx_wq = alloc_workqueue("ipa rx wq", WQ_MEM_RECLAIM |
-			WQ_CPU_INTENSIVE, 1);
+	ipa_ctx->rx_wq = create_singlethread_workqueue("ipa rx wq");
 	if (!ipa_ctx->rx_wq) {
 		IPAERR(":fail to create rx wq\n");
 		result = -ENOMEM;
 		goto fail_rx_wq;
 	}
 
-	ipa_ctx->tx_wq = create_singlethread_workqueue("ipa tx wq");
+	ipa_ctx->tx_wq = alloc_workqueue("ipa tx wq", WQ_MEM_RECLAIM |
+			WQ_CPU_INTENSIVE, 2);
 	if (!ipa_ctx->tx_wq) {
 		IPAERR(":fail to create tx wq\n");
 		result = -ENOMEM;
@@ -1979,6 +1992,10 @@
 fail_dma_pool:
 	kmem_cache_destroy(ipa_ctx->tree_node_cache);
 fail_tree_node_cache:
+	kmem_cache_destroy(ipa_ctx->rx_pkt_wrapper_cache);
+fail_rx_pkt_wrapper_cache:
+	kmem_cache_destroy(ipa_ctx->tx_pkt_wrapper_cache);
+fail_tx_pkt_wrapper_cache:
 	kmem_cache_destroy(ipa_ctx->rt_tbl_cache);
 fail_rt_tbl_cache:
 	kmem_cache_destroy(ipa_ctx->hdr_offset_cache);
diff --git a/drivers/platform/msm/ipa/ipa_client.c b/drivers/platform/msm/ipa/ipa_client.c
index ae59f37..5c343e8 100644
--- a/drivers/platform/msm/ipa/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_client.c
@@ -9,7 +9,6 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
-
 #include <linux/delay.h>
 #include "ipa_i.h"
 
@@ -251,26 +250,6 @@
 
 	memset(&ipa_ctx->ep[ipa_ep_idx], 0, sizeof(struct ipa_ep_context));
 
-	if (IPA_CLIENT_IS_CONS(in->client)) {
-		ep->cmd = kzalloc(sizeof(struct ipa_ip_packet_init),
-				GFP_KERNEL);
-		if (!ep->cmd) {
-			IPAERR("failed to alloc immediate command object\n");
-			result = -ENOMEM;
-			goto fail;
-		}
-		ep->cmd->destination_pipe_index = ipa_ep_idx;
-		ep->dma_addr = dma_map_single(NULL, ep->cmd,
-				sizeof(struct ipa_ip_packet_init),
-				DMA_TO_DEVICE);
-		if (ep->dma_addr == 0 || ep->dma_addr == ~0) {
-			IPAERR("failed to DMA MAP pkt_init\n");
-			result = -ENOMEM;
-			kfree(ep->cmd);
-			goto fail;
-		}
-	}
-
 	ep->valid = 1;
 	ep->client = in->client;
 	ep->client_notify = in->notify;
@@ -447,13 +426,6 @@
 		return -EPERM;
 	}
 
-	if (IPA_CLIENT_IS_CONS(ep->client)) {
-		dma_unmap_single(NULL, ep->dma_addr,
-				sizeof(struct ipa_ip_packet_init),
-				DMA_TO_DEVICE);
-		kfree(ep->cmd);
-	}
-
 	ipa_enable_data_path(clnt_hdl);
 	memset(&ipa_ctx->ep[clnt_hdl], 0, sizeof(struct ipa_ep_context));
 
diff --git a/drivers/platform/msm/ipa/ipa_dp.c b/drivers/platform/msm/ipa/ipa_dp.c
index c564922..38a1a9c 100644
--- a/drivers/platform/msm/ipa/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_dp.c
@@ -17,23 +17,21 @@
 #include <linux/netdevice.h>
 #include "ipa_i.h"
 
+
 #define list_next_entry(pos, member) \
 	list_entry(pos->member.next, typeof(*pos), member)
+#define IPA_LAST_DESC_CNT 0xFFFF
 #define POLLING_INACTIVITY_RX 40
-#define POLLING_MIN_SLEEP_RX 2350
-#define POLLING_MAX_SLEEP_RX 2450
-#define POLLING_INACTIVITY_TX 10
-#define POLLING_MIN_SLEEP_TX 100
-#define POLLING_MAX_SLEEP_TX 200
-#define RX_MAX_IND 40
+#define POLLING_MIN_SLEEP_RX 950
+#define POLLING_MAX_SLEEP_RX 1050
+#define POLLING_INACTIVITY_TX 40
+#define POLLING_MIN_SLEEP_TX 400
+#define POLLING_MAX_SLEEP_TX 500
 
 static void replenish_rx_work_func(struct work_struct *work);
 static struct delayed_work replenish_rx_work;
 static void ipa_wq_handle_rx(struct work_struct *work);
 static DECLARE_WORK(rx_work, ipa_wq_handle_rx);
-static void ipa_wq_handle_tx(struct work_struct *work);
-static DECLARE_WORK(tx_work, ipa_wq_handle_tx);
-
 /**
  * ipa_write_done() - this function will be (eventually) called when a Tx
  * operation is complete
@@ -83,7 +81,7 @@
 	if (tx_pkt->callback)
 		tx_pkt->callback(tx_pkt->user1, tx_pkt->user2);
 
-	kfree(tx_pkt);
+	kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
 }
 
 int ipa_handle_tx_core(struct ipa_sys_context *sys, bool process_all,
@@ -121,13 +119,23 @@
 
 		IPADBG("--curr_cnt=%d\n", sys->len);
 
-		if (tx_pkt->callback) {
+		if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0))
+			dma_pool_free(ipa_ctx->dma_pool,
+					tx_pkt->bounce,
+					tx_pkt->mem.phys_base);
+		else
 			dma_unmap_single(NULL, tx_pkt->mem.phys_base,
-					tx_pkt->mem.size, DMA_TO_DEVICE);
-			tx_pkt->callback(tx_pkt->user1, tx_pkt->user2);
-		}
+					tx_pkt->mem.size,
+					DMA_TO_DEVICE);
 
-		kfree(tx_pkt);
+		if (tx_pkt->callback)
+			tx_pkt->callback(tx_pkt->user1, tx_pkt->user2);
+
+		if (tx_pkt->cnt > 1 && tx_pkt->cnt != IPA_LAST_DESC_CNT)
+			dma_pool_free(ipa_ctx->dma_pool, tx_pkt->mult.base,
+					tx_pkt->mult.phys_base);
+
+		kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
 		cnt++;
 	};
 
@@ -146,6 +154,11 @@
 		goto fail;
 	}
 
+	ret = sps_get_config(sys->ep->ep_hdl, &sys->ep->connect);
+	if (ret) {
+		IPAERR("sps_get_config() failed %d\n", ret);
+		goto fail;
+	}
 	sys->event.options = SPS_O_EOT;
 	ret = sps_register_event(sys->ep->ep_hdl, &sys->event);
 	if (ret) {
@@ -192,7 +205,9 @@
 
 static void ipa_wq_handle_tx(struct work_struct *work)
 {
-	ipa_handle_tx(&ipa_ctx->sys[IPA_A5_LAN_WAN_OUT]);
+	struct ipa_tx_pkt_wrapper *tx_pkt;
+	tx_pkt = container_of(work, struct ipa_tx_pkt_wrapper, work);
+	ipa_handle_tx(tx_pkt->sys);
 }
 
 /**
@@ -225,7 +240,7 @@
 	if (unlikely(!in_atomic))
 		mem_flag = GFP_KERNEL;
 
-	tx_pkt = kmalloc(sizeof(struct ipa_tx_pkt_wrapper), mem_flag);
+	tx_pkt = kmem_cache_zalloc(ipa_ctx->tx_pkt_wrapper_cache, mem_flag);
 	if (!tx_pkt) {
 		IPAERR("failed to alloc tx wrapper\n");
 		goto fail_mem_alloc;
@@ -281,11 +296,14 @@
 		IPADBG("sending cmd=%d pyld_len=%d sps_flags=%x\n",
 				desc->opcode, desc->len, sps_flags);
 		IPA_DUMP_BUFF(desc->pyld, dma_address, desc->len);
+		INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
 	} else {
 		len = desc->len;
+		INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
 	}
 
-	INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
+	if (unlikely(ipa_ctx->polling_mode))
+		INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
 
 	spin_lock_irqsave(&sys->spinlock, irq_flags);
 	list_add_tail(&tx_pkt->link, &sys->head_desc_list);
@@ -309,12 +327,192 @@
 	else
 		dma_unmap_single(NULL, dma_address, desc->len, DMA_TO_DEVICE);
 fail_dma_map:
-	kfree(tx_pkt);
+	kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
 fail_mem_alloc:
 	return -EFAULT;
 }
 
 /**
+ * ipa_send() - Send multiple descriptors in one HW transaction
+ * @sys: system pipe context
+ * @num_desc: number of packets
+ * @desc: packets to send (may be immediate command or data)
+ * @in_atomic:  whether caller is in atomic context
+ *
+ * This function is used for system-to-bam connection.
+ * - SPS driver expect struct sps_transfer which will contain all the data
+ *   for a transaction
+ * - The sps_transfer struct will be pointing to bounce buffers for
+ *   its DMA command (immediate command and data)
+ * - ipa_tx_pkt_wrapper will be used for each ipa
+ *   descriptor (allocated from wrappers cache)
+ * - The wrapper struct will be configured for each ipa-desc payload and will
+ *   contain information which will be later used by the user callbacks
+ * - each transfer will be made by calling to sps_transfer()
+ * - Each packet (command or data) that will be sent will also be saved in
+ *   ipa_sys_context for later check that all data was sent
+ *
+ * Return codes: 0: success, -EFAULT: failure
+ */
+int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc,
+		bool in_atomic)
+{
+	struct ipa_tx_pkt_wrapper *tx_pkt;
+	struct ipa_tx_pkt_wrapper *next_pkt;
+	struct sps_transfer transfer = { 0 };
+	struct sps_iovec *iovec;
+	unsigned long irq_flags;
+	dma_addr_t dma_addr;
+	int i = 0;
+	int j;
+	int result;
+	int fail_dma_wrap = 0;
+	uint size = num_desc * sizeof(struct sps_iovec);
+	u32 mem_flag = GFP_ATOMIC;
+
+	if (unlikely(!in_atomic))
+		mem_flag = GFP_KERNEL;
+
+	transfer.iovec = dma_pool_alloc(ipa_ctx->dma_pool, mem_flag, &dma_addr);
+	transfer.iovec_phys = dma_addr;
+	transfer.iovec_count = num_desc;
+	spin_lock_irqsave(&sys->spinlock, irq_flags);
+	if (!transfer.iovec) {
+		IPAERR("fail to alloc DMA mem for sps xfr buff\n");
+		goto failure_coherent;
+	}
+
+	for (i = 0; i < num_desc; i++) {
+		fail_dma_wrap = 0;
+		tx_pkt = kmem_cache_zalloc(ipa_ctx->tx_pkt_wrapper_cache,
+					   mem_flag);
+		if (!tx_pkt) {
+			IPAERR("failed to alloc tx wrapper\n");
+			goto failure;
+		}
+		/*
+		 * first desc of set is "special" as it holds the count and
+		 * other info
+		 */
+		if (i == 0) {
+			transfer.user = tx_pkt;
+			tx_pkt->mult.phys_base = dma_addr;
+			tx_pkt->mult.base = transfer.iovec;
+			tx_pkt->mult.size = size;
+			tx_pkt->cnt = num_desc;
+		}
+		INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
+
+		iovec = &transfer.iovec[i];
+		iovec->flags = 0;
+
+		INIT_LIST_HEAD(&tx_pkt->link);
+		tx_pkt->type = desc[i].type;
+
+		tx_pkt->mem.base = desc[i].pyld;
+		tx_pkt->mem.size = desc[i].len;
+
+		if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0)) {
+			WARN_ON(tx_pkt->mem.size > 512);
+
+			/*
+			 * Due to a HW limitation, we need to make sure that the
+			 * packet does not cross a 1KB boundary
+			 */
+			tx_pkt->bounce =
+			   dma_pool_alloc(ipa_ctx->dma_pool,
+					   mem_flag,
+					   &tx_pkt->mem.phys_base);
+			if (!tx_pkt->bounce) {
+				tx_pkt->mem.phys_base = 0;
+			} else {
+				WARN_ON(!ipa_straddle_boundary(
+						(u32)tx_pkt->mem.phys_base,
+						(u32)tx_pkt->mem.phys_base +
+						tx_pkt->mem.size - 1, 1024));
+				memcpy(tx_pkt->bounce, tx_pkt->mem.base,
+						tx_pkt->mem.size);
+			}
+		} else {
+			tx_pkt->mem.phys_base =
+			   dma_map_single(NULL, tx_pkt->mem.base,
+					   tx_pkt->mem.size,
+					   DMA_TO_DEVICE);
+		}
+		if (!tx_pkt->mem.phys_base) {
+			IPAERR("failed to alloc tx wrapper\n");
+			fail_dma_wrap = 1;
+			goto failure;
+		}
+
+		tx_pkt->sys = sys;
+		tx_pkt->callback = desc[i].callback;
+		tx_pkt->user1 = desc[i].user1;
+		tx_pkt->user2 = desc[i].user2;
+
+		/*
+		 * Point the iovec to the bounce buffer and
+		 * add this packet to system pipe context.
+		 */
+		iovec->addr = tx_pkt->mem.phys_base;
+		list_add_tail(&tx_pkt->link, &sys->head_desc_list);
+
+		/*
+		 * Special treatment for immediate commands, where the structure
+		 * of the descriptor is different
+		 */
+		if (desc[i].type == IPA_IMM_CMD_DESC) {
+			iovec->size = desc[i].opcode;
+			iovec->flags |= SPS_IOVEC_FLAG_IMME;
+		} else {
+			iovec->size = desc[i].len;
+		}
+
+		if (i == (num_desc - 1)) {
+			iovec->flags |= SPS_IOVEC_FLAG_EOT;
+			/* "mark" the last desc */
+			tx_pkt->cnt = IPA_LAST_DESC_CNT;
+		}
+	}
+
+	result = sps_transfer(sys->ep->ep_hdl, &transfer);
+	if (result) {
+		IPAERR("sps_transfer failed rc=%d\n", result);
+		goto failure;
+	}
+
+	spin_unlock_irqrestore(&sys->spinlock, irq_flags);
+	return 0;
+
+failure:
+	tx_pkt = transfer.user;
+	for (j = 0; j < i; j++) {
+		next_pkt = list_next_entry(tx_pkt, link);
+		list_del(&tx_pkt->link);
+		if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0))
+			dma_pool_free(ipa_ctx->dma_pool,
+					tx_pkt->bounce,
+					tx_pkt->mem.phys_base);
+		else
+			dma_unmap_single(NULL, tx_pkt->mem.phys_base,
+					tx_pkt->mem.size,
+					DMA_TO_DEVICE);
+		kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
+		tx_pkt = next_pkt;
+	}
+	if (i < num_desc)
+		/* last desc failed */
+		if (fail_dma_wrap)
+			kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
+	if (transfer.iovec_phys)
+		dma_pool_free(ipa_ctx->dma_pool, transfer.iovec,
+				  transfer.iovec_phys);
+failure_coherent:
+	spin_unlock_irqrestore(&sys->spinlock, irq_flags);
+	return -EFAULT;
+}
+
+/**
  * ipa_sps_irq_cmd_ack - callback function which will be called by SPS driver after an
  * immediate command is complete.
  * @user1:	pointer to the descriptor of the transfer
@@ -345,6 +543,7 @@
  */
 int ipa_send_cmd(u16 num_desc, struct ipa_desc *descr)
 {
+	struct ipa_desc *desc;
 	int result = 0;
 
 	ipa_inc_client_enable_clks();
@@ -364,10 +563,22 @@
 		}
 		wait_for_completion(&descr->xfer_done);
 	} else {
-		IPAERR("unsupported chaining multiple IC\n");
+		desc = &descr[num_desc - 1];
+		init_completion(&desc->xfer_done);
+
+		if (desc->callback || desc->user1)
+			WARN_ON(1);
+
+		desc->callback = ipa_sps_irq_cmd_ack;
+		desc->user1 = desc;
+		if (ipa_send(&ipa_ctx->sys[IPA_A5_CMD], num_desc,
+					descr, false)) {
+			IPAERR("fail to send multiple immediate command set\n");
 			result = -EFAULT;
 			goto bail;
 		}
+		wait_for_completion(&desc->xfer_done);
+	}
 
 	IPA_STATS_INC_IC_CNT(num_desc, descr, ipa_ctx->stats.imm_cmds);
 bail:
@@ -386,13 +597,21 @@
 static void ipa_sps_irq_tx_notify(struct sps_event_notify *notify)
 {
 	struct ipa_sys_context *sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_OUT];
+	struct ipa_tx_pkt_wrapper *tx_pkt;
 	int ret;
 
 	IPADBG("event %d notified\n", notify->event_id);
 
 	switch (notify->event_id) {
 	case SPS_EVENT_EOT:
+		tx_pkt = notify->data.transfer.user;
 		if (!atomic_read(&sys->curr_polling_state)) {
+			ret = sps_get_config(sys->ep->ep_hdl,
+					&sys->ep->connect);
+			if (ret) {
+				IPAERR("sps_get_config() failed %d\n", ret);
+				break;
+			}
 			sys->ep->connect.options = SPS_O_AUTO_ENABLE |
 				SPS_O_ACK_TRANSFERS | SPS_O_POLL;
 			ret = sps_set_config(sys->ep->ep_hdl,
@@ -402,7 +621,7 @@
 				break;
 			}
 			atomic_set(&sys->curr_polling_state, 1);
-			queue_work(ipa_ctx->tx_wq, &tx_work);
+			queue_work(ipa_ctx->tx_wq, &tx_pkt->work);
 		}
 		break;
 	default:
@@ -435,47 +654,6 @@
 	}
 }
 
-static void ipa_handle_tag_rsp(struct ipa_a5_mux_hdr *mux_hdr)
-{
-	struct completion *compl;
-	struct ipa_tree_node *node;
-
-	/* retrieve the compl object from tag value */
-	mux_hdr++;
-	compl = (struct completion *) ntohl(*((u32 *)mux_hdr));
-	IPADBG("%x %x %p\n", *(u32 *)mux_hdr, *((u32 *)mux_hdr + 1), compl);
-
-	mutex_lock(&ipa_ctx->lock);
-	node = ipa_search(&ipa_ctx->tag_tree, (u32)compl);
-	if (node) {
-		complete_all(compl);
-		rb_erase(&node->node, &ipa_ctx->tag_tree);
-		kmem_cache_free(ipa_ctx->tree_node_cache, node);
-	} else {
-		WARN_ON(1);
-	}
-	mutex_unlock(&ipa_ctx->lock);
-}
-
-static void ipa_dejitter(bool limit)
-{
-	struct sk_buff *skb;
-	int len = skb_queue_len(&ipa_ctx->rx_list);
-	int i;
-	void *cookie;
-	ipa_notify_cb cb;
-
-	if (limit && len >= RX_MAX_IND)
-		len = RX_MAX_IND;
-
-	for (i = len; i > 0; i--) {
-		skb = __skb_dequeue(&ipa_ctx->rx_list);
-		cb = (ipa_notify_cb)*(u32 *)&(skb->cb[0]);
-		cookie = (void *)*(u32 *)&(skb->cb[4]);
-		cb(cookie, IPA_RECEIVE, (unsigned long)skb);
-	}
-}
-
 /**
  * ipa_handle_rx_core() - The core functionality of packet reception. This
  * function is read from multiple code paths.
@@ -497,9 +675,13 @@
 	struct ipa_rx_pkt_wrapper *rx_pkt;
 	struct sk_buff *rx_skb;
 	struct sps_iovec iov;
+	unsigned int pull_len;
+	unsigned int padding;
 	int ret;
 	struct ipa_ep_context *ep;
 	int cnt = 0;
+	struct completion *compl;
+	struct ipa_tree_node *node;
 	unsigned int src_pipe;
 
 	while ((in_poll_state ? atomic_read(&sys->curr_polling_state) :
@@ -539,7 +721,7 @@
 		rx_skb->tail = rx_skb->data + rx_pkt->len;
 		rx_skb->len = rx_pkt->len;
 		rx_skb->truesize = rx_pkt->len + sizeof(struct sk_buff);
-		kfree(rx_pkt);
+		kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt);
 
 		mux_hdr = (struct ipa_a5_mux_hdr *)rx_skb->data;
 
@@ -554,9 +736,29 @@
 		IPA_STATS_INC_CNT(ipa_ctx->stats.rx_pkts);
 		IPA_STATS_EXCP_CNT(mux_hdr->flags, ipa_ctx->stats.rx_excp_pkts);
 
-		if (mux_hdr->flags & IPA_A5_MUX_HDR_EXCP_FLAG_TAG) {
-			if (ipa_ctx->ipa_hw_mode != IPA_HW_MODE_VIRTUAL)
-				ipa_handle_tag_rsp(mux_hdr);
+		if (unlikely(mux_hdr->flags & IPA_A5_MUX_HDR_EXCP_FLAG_TAG)) {
+			if (ipa_ctx->ipa_hw_mode != IPA_HW_MODE_VIRTUAL) {
+				/* retrieve the compl object from tag value */
+				mux_hdr++;
+				compl = (struct completion *)
+					ntohl(*((u32 *)mux_hdr));
+				IPADBG("%x %x %p\n", *(u32 *)mux_hdr,
+						*((u32 *)mux_hdr + 1), compl);
+
+				mutex_lock(&ipa_ctx->lock);
+				node = ipa_search(&ipa_ctx->tag_tree,
+						(u32)compl);
+				if (node) {
+					complete_all(compl);
+					rb_erase(&node->node,
+							&ipa_ctx->tag_tree);
+					kmem_cache_free(
+						ipa_ctx->tree_node_cache, node);
+				} else {
+					WARN_ON(1);
+				}
+				mutex_unlock(&ipa_ctx->lock);
+			}
 			dev_kfree_skb(rx_skb);
 			ipa_replenish_rx_cache();
 			++cnt;
@@ -567,22 +769,38 @@
 		 * Any packets arriving over AMPDU_TX should be dispatched
 		 * to the regular WLAN RX data-path.
 		 */
-		if (src_pipe == WLAN_AMPDU_TX_EP)
+		if (unlikely(src_pipe == WLAN_AMPDU_TX_EP))
 			src_pipe = WLAN_PROD_TX_EP;
 
-		WARN_ON(src_pipe >= IPA_NUM_PIPES);
+		if (unlikely(src_pipe >= IPA_NUM_PIPES ||
+			!ipa_ctx->ep[src_pipe].valid ||
+			!ipa_ctx->ep[src_pipe].client_notify)) {
+			IPAERR("drop pipe=%d ep_valid=%d client_notify=%p\n",
+			  src_pipe, ipa_ctx->ep[src_pipe].valid,
+			  ipa_ctx->ep[src_pipe].client_notify);
+			dev_kfree_skb(rx_skb);
+			ipa_replenish_rx_cache();
+			++cnt;
+			continue;
+		}
 
 		ep = &ipa_ctx->ep[src_pipe];
-		IPADBG("pulling %d bytes from skb\n", ep->pull_len);
-		skb_pull(rx_skb, ep->pull_len);
+		pull_len = sizeof(struct ipa_a5_mux_hdr);
+
+		/*
+		 * IP packet starts on word boundary
+		 * remove the MUX header and any padding and pass the frame to
+		 * the client which registered a rx callback on the "src pipe"
+		 */
+		padding = ep->cfg.hdr.hdr_len & 0x3;
+		if (padding)
+			pull_len += 4 - padding;
+
+		IPADBG("pulling %d bytes from skb\n", pull_len);
+		skb_pull(rx_skb, pull_len);
 		ipa_replenish_rx_cache();
-		if (ep->client_notify) {
-			__skb_queue_tail(&ipa_ctx->rx_list, rx_skb);
-			*(u32 *)&(rx_skb->cb[0]) = (u32)ep->client_notify;
-			*(u32 *)&(rx_skb->cb[4]) = (u32)ep->priv;
-		} else {
-			dev_kfree_skb(rx_skb);
-		}
+		ep->client_notify(ep->priv, IPA_RECEIVE,
+				(unsigned long)(rx_skb));
 		cnt++;
 	};
 
@@ -601,6 +819,11 @@
 		goto fail;
 	}
 
+	ret = sps_get_config(sys->ep->ep_hdl, &sys->ep->connect);
+	if (ret) {
+		IPAERR("sps_get_config() failed %d\n", ret);
+		goto fail;
+	}
 	sys->event.options = SPS_O_EOT;
 	ret = sps_register_event(sys->ep->ep_hdl, &sys->event);
 	if (ret) {
@@ -647,6 +870,12 @@
 	switch (notify->event_id) {
 	case SPS_EVENT_EOT:
 		if (!atomic_read(&sys->curr_polling_state)) {
+			ret = sps_get_config(sys->ep->ep_hdl,
+					&sys->ep->connect);
+			if (ret) {
+				IPAERR("sps_get_config() failed %d\n", ret);
+				break;
+			}
 			sys->ep->connect.options = SPS_O_AUTO_ENABLE |
 				SPS_O_ACK_TRANSFERS | SPS_O_POLL;
 			ret = sps_set_config(sys->ep->ep_hdl,
@@ -696,10 +925,8 @@
 		} else {
 			inactive_cycles = 0;
 		}
-		ipa_dejitter(true);
 	} while (inactive_cycles <= POLLING_INACTIVITY_RX);
 
-	ipa_dejitter(false);
 	ipa_rx_switch_to_intr_mode(sys);
 	ipa_dec_client_disable_clks();
 }
@@ -835,7 +1062,6 @@
 		break;
 	case 2:
 		sys_idx = ipa_ep_idx;
-		ipa_ctx->sys[sys_idx].max_len = sys_in->desc_fifo_sz / 8 - 2;
 		INIT_DELAYED_WORK(&ipa_ctx->sys[sys_idx].switch_to_intr_work,
 				switch_to_intr_tx_work_func);
 		break;
@@ -950,87 +1176,9 @@
 		dev_kfree_skb(skb);
 }
 
-static int ipa_send_two(struct sk_buff *skb, struct ipa_sys_context *sys,
-		int dst_ep_idx)
+static void ipa_tx_cmd_comp(void *user1, void *user2)
 {
-	struct ipa_tx_pkt_wrapper *tx_pktc;
-	struct ipa_tx_pkt_wrapper *tx_pktd;
-	struct ipa_ep_context *ep = &ipa_ctx->ep[dst_ep_idx];
-	unsigned long irq_flags;
-	dma_addr_t dma_addrd;
-	int rc = -ENOMEM;
-
-	tx_pktc = kmalloc(sizeof(struct ipa_tx_pkt_wrapper), GFP_ATOMIC);
-	if (!tx_pktc) {
-		IPAERR("failed to alloc tx wrapper C\n");
-		goto fail_mem_alloc_c;
-	}
-
-	tx_pktd = kmalloc(sizeof(struct ipa_tx_pkt_wrapper), GFP_ATOMIC);
-	if (!tx_pktd) {
-		IPAERR("failed to alloc tx wrapper D\n");
-		goto fail_mem_alloc_d;
-	}
-
-	dma_addrd = dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE);
-	if (!dma_addrd) {
-		IPAERR("failed to DMA wrap\n");
-		goto fail_dma_map_d;
-	}
-
-	INIT_LIST_HEAD(&tx_pktc->link);
-	tx_pktc->callback = NULL;
-
-	INIT_LIST_HEAD(&tx_pktd->link);
-	tx_pktd->mem.phys_base = dma_addrd;
-	tx_pktd->mem.base = skb->data;
-	tx_pktd->mem.size = skb->len;
-	tx_pktd->callback = ipa_tx_comp_usr_notify_release;
-	tx_pktd->user1 = skb;
-	tx_pktd->user2 = (void *)dst_ep_idx;
-
-	spin_lock_irqsave(&sys->spinlock, irq_flags);
-	if (sys->len >= sys->max_len)
-		goto fail_oom;
-	list_add_tail(&tx_pktc->link, &sys->head_desc_list);
-	if (sps_transfer_one(sys->ep->ep_hdl, ep->dma_addr, IPA_IP_PACKET_INIT,
-			tx_pktc, SPS_IOVEC_FLAG_IMME |
-			SPS_IOVEC_FLAG_NO_SUBMIT))
-		IPAERR("sps_transfer_one 0 failed\n");
-	list_add_tail(&tx_pktd->link, &sys->head_desc_list);
-	if (sps_transfer_one(sys->ep->ep_hdl, dma_addrd, skb->len, tx_pktd,
-			SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_INT))
-		IPAERR("sps_transfer_one 1 failed\n");
-	sys->len += 2;
-	spin_unlock_irqrestore(&sys->spinlock, irq_flags);
-	return 0;
-
-fail_oom:
-	dma_unmap_single(NULL, dma_addrd, skb->len, DMA_TO_DEVICE);
-fail_dma_map_d:
-	kfree(tx_pktd);
-fail_mem_alloc_d:
-	kfree(tx_pktc);
-fail_mem_alloc_c:
-	return rc;
-}
-
-static int ipa_send_data_hw_path(struct sk_buff *skb,
-		struct ipa_sys_context *sys, int dst_ep_idx)
-{
-	struct ipa_desc desc;
-
-	desc.pyld = skb->data;
-	desc.len = skb->len;
-	desc.type = IPA_DATA_DESC_SKB;
-	desc.callback = ipa_tx_comp_usr_notify_release;
-	desc.user1 = skb;
-	desc.user2 = (void *)dst_ep_idx;
-
-	if (ipa_send_one(sys, &desc, true))
-		return -EFAULT;
-
-	return 0;
+	kfree(user1);
 }
 
 /**
@@ -1063,42 +1211,76 @@
 int ipa_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
 		struct ipa_tx_meta *meta)
 {
+	struct ipa_desc desc[2];
 	int ipa_ep_idx;
+	struct ipa_ip_packet_init *cmd;
+
+	memset(&desc, 0, 2 * sizeof(struct ipa_desc));
 
 	ipa_ep_idx = ipa_get_ep_mapping(ipa_ctx->mode, dst);
 	if (unlikely(ipa_ep_idx == -1)) {
 		IPAERR("dest EP does not exist.\n");
-		goto fail;
+		goto fail_gen;
 	}
 
 	if (unlikely(ipa_ctx->ep[ipa_ep_idx].valid == 0)) {
 		IPAERR("dest EP not valid.\n");
-		goto fail;
+		goto fail_gen;
 	}
 
 	if (IPA_CLIENT_IS_CONS(dst)) {
-		if (ipa_send_two(skb, &ipa_ctx->sys[IPA_A5_LAN_WAN_OUT],
-					ipa_ep_idx)) {
-			IPAERR("fail to send pkt_init+skb dst=%d skb=%p\n",
-					dst, skb);
-			goto fail;
+		cmd = kzalloc(sizeof(struct ipa_ip_packet_init), GFP_ATOMIC);
+		if (!cmd) {
+			IPAERR("failed to alloc immediate command object\n");
+			goto fail_mem_alloc;
+		}
+
+		cmd->destination_pipe_index = ipa_ep_idx;
+		if (meta && meta->mbim_stream_id_valid)
+			cmd->metadata = meta->mbim_stream_id;
+		desc[0].opcode = IPA_IP_PACKET_INIT;
+		desc[0].pyld = cmd;
+		desc[0].len = sizeof(struct ipa_ip_packet_init);
+		desc[0].type = IPA_IMM_CMD_DESC;
+		desc[0].callback = ipa_tx_cmd_comp;
+		desc[0].user1 = cmd;
+		desc[1].pyld = skb->data;
+		desc[1].len = skb->len;
+		desc[1].type = IPA_DATA_DESC_SKB;
+		desc[1].callback = ipa_tx_comp_usr_notify_release;
+		desc[1].user1 = skb;
+		desc[1].user2 = (void *)ipa_ep_idx;
+
+		if (ipa_send(&ipa_ctx->sys[IPA_A5_LAN_WAN_OUT], 2, desc,
+					true)) {
+			IPAERR("fail to send immediate command\n");
+			goto fail_send;
 		}
 		IPA_STATS_INC_CNT(ipa_ctx->stats.imm_cmds[IPA_IP_PACKET_INIT]);
 	} else if (dst == IPA_CLIENT_A5_WLAN_AMPDU_PROD) {
-		if (ipa_send_data_hw_path(skb,
-					&ipa_ctx->sys[IPA_A5_WLAN_AMPDU_OUT],
-					ipa_ep_idx)) {
-			IPAERR("fail to send skb dst=%d skb=%p\n", dst, skb);
-			goto fail;
+		desc[0].pyld = skb->data;
+		desc[0].len = skb->len;
+		desc[0].type = IPA_DATA_DESC_SKB;
+		desc[0].callback = ipa_tx_comp_usr_notify_release;
+		desc[0].user1 = skb;
+		desc[0].user2 = (void *)ipa_ep_idx;
+
+		if (ipa_send_one(&ipa_ctx->sys[IPA_A5_WLAN_AMPDU_OUT],
+					&desc[0], true)) {
+			IPAERR("fail to send skb\n");
+			goto fail_gen;
 		}
 	} else {
 		IPAERR("%d PROD is not supported.\n", dst);
-		goto fail;
+		goto fail_gen;
 	}
 
 	return 0;
 
-fail:
+fail_send:
+	kfree(cmd);
+fail_mem_alloc:
+fail_gen:
 	return -EFAULT;
 }
 EXPORT_SYMBOL(ipa_tx_dp);
@@ -1134,7 +1316,8 @@
 	rx_len_cached = sys->len;
 
 	while (rx_len_cached < IPA_RX_POOL_CEIL) {
-		rx_pkt = kmalloc(sizeof(struct ipa_rx_pkt_wrapper), flag);
+		rx_pkt = kmem_cache_zalloc(ipa_ctx->rx_pkt_wrapper_cache,
+					   flag);
 		if (!rx_pkt) {
 			IPAERR("failed to alloc rx wrapper\n");
 			goto fail_kmem_cache_alloc;
@@ -1182,7 +1365,7 @@
 fail_dma_mapping:
 	dev_kfree_skb(rx_pkt->skb);
 fail_skb_alloc:
-	kfree(rx_pkt);
+	kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt);
 fail_kmem_cache_alloc:
 	if (rx_len_cached == 0) {
 		IPA_STATS_INC_CNT(ipa_ctx->stats.rx_repl_repost);
@@ -1214,7 +1397,7 @@
 		dma_unmap_single(NULL, rx_pkt->dma_address, IPA_RX_SKB_SIZE,
 				 DMA_FROM_DEVICE);
 		dev_kfree_skb(rx_pkt->skb);
-		kfree(rx_pkt);
+		kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt);
 	}
 }
 
diff --git a/drivers/platform/msm/ipa/ipa_i.h b/drivers/platform/msm/ipa/ipa_i.h
index 790898a..8ad0b5a 100644
--- a/drivers/platform/msm/ipa/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_i.h
@@ -119,7 +119,6 @@
 #define IPA_DFLT_HDR_NAME "ipa_excp_hdr"
 #define IPA_INVALID_L4_PROTOCOL 0xFF
 
-
 #define IPA_CLIENT_IS_PROD(x) (x >= IPA_CLIENT_PROD && x < IPA_CLIENT_CONS)
 #define IPA_CLIENT_IS_CONS(x) (x >= IPA_CLIENT_CONS && x < IPA_CLIENT_MAX)
 #define IPA_SETFIELD(val, shift, mask) (((val) << (shift)) & (mask))
@@ -364,9 +363,6 @@
 	bool desc_fifo_client_allocated;
 	bool data_fifo_client_allocated;
 	bool suspended;
-	unsigned int pull_len;
-	struct ipa_ip_packet_init *cmd;
-	dma_addr_t dma_addr;
 };
 
 /**
@@ -382,7 +378,6 @@
 struct ipa_sys_context {
 	struct list_head head_desc_list;
 	u32 len;
-	u32 max_len;
 	spinlock_t spinlock;
 	struct sps_register_event event;
 	struct ipa_ep_context *ep;
@@ -641,6 +636,8 @@
 	struct kmem_cache *hdr_cache;
 	struct kmem_cache *hdr_offset_cache;
 	struct kmem_cache *rt_tbl_cache;
+	struct kmem_cache *tx_pkt_wrapper_cache;
+	struct kmem_cache *rx_pkt_wrapper_cache;
 	struct kmem_cache *tree_node_cache;
 	unsigned long rt_idx_bitmap[IPA_IP_MAX];
 	struct mutex lock;
@@ -687,7 +684,6 @@
 	/* featurize if memory footprint becomes a concern */
 	struct ipa_stats stats;
 	void *smem_pipe_mem;
-	struct sk_buff_head rx_list;
 };
 
 /**
@@ -776,6 +772,8 @@
 		u32 *consumer_handle);
 int ipa_send_one(struct ipa_sys_context *sys, struct ipa_desc *desc,
 		bool in_atomic);
+int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc,
+		bool in_atomic);
 int ipa_get_ep_mapping(enum ipa_operating_mode mode,
 		       enum ipa_client_type client);
 int ipa_get_client_mapping(enum ipa_operating_mode mode, int pipe_idx);
diff --git a/drivers/platform/msm/ipa/ipa_utils.c b/drivers/platform/msm/ipa/ipa_utils.c
index 912d93c..23de300 100644
--- a/drivers/platform/msm/ipa/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_utils.c
@@ -32,24 +32,6 @@
 	{ 19, -1, -1, -1, -1, 11, 15, 8, 6, 2, 1, 5, 14, 16, 17, 18, -1, 10, 9, 7, 3, 4 },
 };
 
-static unsigned int ipa_calc_pull_len(u32 hdr_len)
-{
-	unsigned int pull_len, padding;
-
-	pull_len = sizeof(struct ipa_a5_mux_hdr);
-
-	/*
-	 * IP packet starts on word boundary
-	 * remove the MUX header and any padding and pass the frame to
-	 * the client which registered a rx callback on the "src pipe"
-	 */
-	padding = hdr_len & 0x3;
-	if (padding)
-		pull_len += 4 - padding;
-
-	return pull_len;
-}
-
 /**
  * ipa_cfg_route() - configure IPA route
  * @route: IPA route
@@ -769,9 +751,6 @@
 		ipa_write_reg(ipa_ctx->mmio,
 			IPA_ENDP_INIT_HDR_n_OFST_v2(clnt_hdl), val);
 
-	if (IPA_CLIENT_IS_PROD(ep->client))
-		ep->pull_len = ipa_calc_pull_len(ipa_ep_cfg->hdr_len);
-
 	return 0;
 }
 EXPORT_SYMBOL(ipa_cfg_ep_hdr);
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index e91e5d6..53aa475 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -14,6 +14,7 @@
  * SPI driver for Qualcomm MSM platforms
  *
  */
+
 #include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -2604,11 +2605,12 @@
 }
 
 /**
- * msm_spi_dt_to_pdata: copy device-tree data to platfrom data struct
+ * msm_spi_dt_to_pdata: create pdata and read gpio config from device tree
  */
-struct msm_spi_platform_data *
-__init msm_spi_dt_to_pdata(struct platform_device *pdev)
+struct msm_spi_platform_data * __init msm_spi_dt_to_pdata(
+			struct platform_device *pdev, struct msm_spi *dd)
 {
+	int i;
 	struct msm_spi_platform_data *pdata;
 
 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
@@ -2618,22 +2620,36 @@
 	} else {
 		struct msm_spi_dt_to_pdata_map map[] = {
 		{"spi-max-frequency",
-			&pdata->max_clock_speed,         DT_SGST, DT_U32,  0},
+			&pdata->max_clock_speed,         DT_SGST, DT_U32,   0},
 		{"qcom,infinite-mode",
-			&pdata->infinite_mode,           DT_OPT,  DT_U32,  0},
+			&pdata->infinite_mode,           DT_OPT,  DT_U32,   0},
 		{"qcom,active-only",
-			&pdata->active_only,             DT_OPT,  DT_BOOL, 0},
+			&pdata->active_only,             DT_OPT,  DT_BOOL,  0},
 		{"qcom,master-id",
-			&pdata->master_id,               DT_SGST, DT_U32,  0},
+			&pdata->master_id,               DT_SGST, DT_U32,   0},
 		{"qcom,ver-reg-exists",
-			&pdata->ver_reg_exists,          DT_OPT,  DT_BOOL, 0},
+			&pdata->ver_reg_exists,          DT_OPT,  DT_BOOL,  0},
 		{"qcom,use-bam",
-			&pdata->use_bam,                 DT_OPT,  DT_BOOL, 0},
+			&pdata->use_bam,                 DT_OPT,  DT_BOOL,  0},
 		{"qcom,bam-consumer-pipe-index",
-			&pdata->bam_consumer_pipe_index, DT_OPT,  DT_U32,  0},
+			&pdata->bam_consumer_pipe_index, DT_OPT,  DT_U32,   0},
 		{"qcom,bam-producer-pipe-index",
-			&pdata->bam_producer_pipe_index, DT_OPT,  DT_U32,  0},
-		{NULL,  NULL,                            0,       0,       0},
+			&pdata->bam_producer_pipe_index, DT_OPT,  DT_U32,   0},
+		{"qcom,gpio-clk",
+			&dd->spi_gpios[0],               DT_OPT,  DT_GPIO, -1},
+		{"qcom,gpio-miso",
+			&dd->spi_gpios[1],               DT_OPT,  DT_GPIO, -1},
+		{"qcom,gpio-mosi",
+			&dd->spi_gpios[2],               DT_OPT,  DT_GPIO, -1},
+		{"qcom,gpio-cs0",
+			&dd->cs_gpios[0].gpio_num,       DT_OPT,  DT_GPIO, -1},
+		{"qcom,gpio-cs1",
+			&dd->cs_gpios[1].gpio_num,       DT_OPT,  DT_GPIO, -1},
+		{"qcom,gpio-cs2",
+			&dd->cs_gpios[2].gpio_num,       DT_OPT,  DT_GPIO, -1},
+		{"qcom,gpio-cs3",
+			&dd->cs_gpios[3].gpio_num,       DT_OPT,  DT_GPIO, -1},
+		{NULL,  NULL,                            0,       0,        0},
 		};
 
 		if (msm_spi_dt_to_pdata_populate(pdev, pdata, map)) {
@@ -2655,6 +2671,10 @@
 			pdata->use_bam = false;
 		}
 	}
+
+	for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i)
+		dd->cs_gpios[i].valid = (dd->cs_gpios[i].gpio_num >= 0);
+
 	return pdata;
 }
 
@@ -2714,7 +2734,6 @@
 	int                     clk_enabled = 0;
 	int                     pclk_enabled = 0;
 	struct msm_spi_platform_data *pdata;
-	enum of_gpio_flags flags;
 
 	master = spi_alloc_master(&pdev->dev, sizeof(struct msm_spi));
 	if (!master) {
@@ -2734,7 +2753,7 @@
 	if (pdev->dev.of_node) {
 		dd->qup_ver = SPI_QUP_VERSION_BFAM;
 		master->dev.of_node = pdev->dev.of_node;
-		pdata = msm_spi_dt_to_pdata(pdev);
+		pdata = msm_spi_dt_to_pdata(pdev, dd);
 		if (!pdata) {
 			rc = -ENOMEM;
 			goto err_probe_exit;
@@ -2746,18 +2765,6 @@
 				"using default bus_num %d\n", pdev->id);
 		else
 			master->bus_num = pdev->id = rc;
-
-		for (i = 0; i < ARRAY_SIZE(spi_rsrcs); ++i) {
-			dd->spi_gpios[i] = of_get_gpio_flags(pdev->dev.of_node,
-								i, &flags);
-		}
-
-		for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i) {
-			dd->cs_gpios[i].gpio_num = of_get_named_gpio_flags(
-						pdev->dev.of_node, "cs-gpios",
-						i, &flags);
-			dd->cs_gpios[i].valid = 0;
-		}
 	} else {
 		pdata = pdev->dev.platform_data;
 		dd->qup_ver = SPI_QUP_VERSION_NONE;
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index bb0b2fb..0cfd515 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -393,6 +393,7 @@
 	u32			recip;
 	u32			wValue;
 	u32			wIndex;
+	u32			reg;
 	int			ret;
 
 	wValue = le16_to_cpu(ctrl->wValue);
@@ -413,6 +414,13 @@
 				return -EINVAL;
 			if (dwc->speed != DWC3_DSTS_SUPERSPEED)
 				return -EINVAL;
+
+			reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+			if (set)
+				reg |= DWC3_DCTL_INITU1ENA;
+			else
+				reg &= ~DWC3_DCTL_INITU1ENA;
+			dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 			break;
 
 		case USB_DEVICE_U2_ENABLE:
@@ -420,6 +428,13 @@
 				return -EINVAL;
 			if (dwc->speed != DWC3_DSTS_SUPERSPEED)
 				return -EINVAL;
+
+			reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+			if (set)
+				reg |= DWC3_DCTL_INITU2ENA;
+			else
+				reg &= ~DWC3_DCTL_INITU2ENA;
+			dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 			break;
 
 		case USB_DEVICE_LTM_ENABLE:
@@ -524,6 +539,7 @@
 {
 	u32 cfg;
 	int ret;
+	u32 reg;
 
 	dwc->start_config_issued = false;
 	cfg = le16_to_cpu(ctrl->wValue);
@@ -538,6 +554,14 @@
 		/* if the cfg matches and the cfg is non zero */
 		if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) {
 			dwc->dev_state = DWC3_CONFIGURED_STATE;
+			/*
+			 * Enable transition to U1/U2 state when
+			 * nothing is pending from application.
+			 */
+			reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+			reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA);
+			dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
 			dwc->resize_fifos = true;
 			dev_dbg(dwc->dev, "resize fifos flag SET\n");
 		}
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index 3cad3ce..8d8c30e 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -16,6 +16,8 @@
 
 #define MSM_USB_BASE	(udc->regs)
 
+#define CI13XXX_MSM_MAX_ITC_LEVEL	6
+
 struct ci13xxx_udc_context {
 	int irq;
 	void __iomem *regs;
@@ -177,7 +179,7 @@
 				  CI13XXX_ZERO_ITC |
 				  CI13XXX_DISABLE_STREAMING |
 				  CI13XXX_IS_OTG,
-
+	.nz_itc			= 0,
 	.notify_event		= ci13xxx_msm_notify_event,
 };
 
@@ -230,10 +232,21 @@
 static int ci13xxx_msm_probe(struct platform_device *pdev)
 {
 	struct resource *res;
-	int ret;
+	int ret, rc;
+	int itc_level = 0;
 
 	dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n");
 
+	if (pdev->dev.of_node) {
+		rc = of_property_read_u32(pdev->dev.of_node, "qcom,itc-level",
+			&itc_level);
+		/* Acceptable values for nz_itc are: 0,1,2,4,8,16,32,64 */
+		if (itc_level > CI13XXX_MSM_MAX_ITC_LEVEL || rc)
+			ci13xxx_msm_udc_driver.nz_itc = 0;
+		else
+			ci13xxx_msm_udc_driver.nz_itc = 1 << itc_level;
+	}
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
 		dev_err(&pdev->dev, "failed to get platform resource mem\n");
@@ -313,9 +326,18 @@
 	writel_relaxed(val, USB_GENCONFIG);
 }
 
+static const struct of_device_id ci13xx_msm_dt_match[] = {
+	{ .compatible = "qcom,ci13xxx_msm",
+	},
+	{}
+};
+
 static struct platform_driver ci13xxx_msm_driver = {
 	.probe = ci13xxx_msm_probe,
-	.driver = { .name = "msm_hsusb", },
+	.driver = {
+		.name = "msm_hsusb",
+		.of_match_table = ci13xx_msm_dt_match,
+	},
 	.remove = ci13xxx_msm_remove,
 };
 MODULE_ALIAS("platform:msm_hsusb");
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 939eb6d..e7074a2 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -367,7 +367,10 @@
 	 * 8 micro frames. If CPU can handle interrupts at faster rate, ITC
 	 * can be set to lesser value to gain performance.
 	 */
-	if (udc->udc_driver->flags & CI13XXX_ZERO_ITC)
+	if (udc->udc_driver->nz_itc)
+		hw_cwrite(CAP_USBCMD, USBCMD_ITC_MASK,
+			USBCMD_ITC(udc->udc_driver->nz_itc));
+	else if (udc->udc_driver->flags & CI13XXX_ZERO_ITC)
 		hw_cwrite(CAP_USBCMD, USBCMD_ITC_MASK, USBCMD_ITC(0));
 
 	if (hw_cread(CAP_USBMODE, USBMODE_CM) != USBMODE_CM_DEVICE) {
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index 4c5b38d..09404c8 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -129,6 +129,7 @@
 struct ci13xxx_udc_driver {
 	const char	*name;
 	unsigned long	 flags;
+	unsigned int nz_itc;
 #define CI13XXX_REGS_SHARED		BIT(0)
 #define CI13XXX_REQUIRE_TRANSCEIVER	BIT(1)
 #define CI13XXX_PULLUP_ON_VBUS		BIT(2)
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index 9dd9978..edcafcc 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -848,6 +848,7 @@
 	d->rx_req->context = port;
 	d->rx_req->complete = gbam_endless_rx_complete;
 	d->rx_req->length = 0;
+	d->rx_req->no_interrupt = 1;
 	sps_params = (MSM_SPS_MODE | d->src_pipe_idx |
 				 MSM_VENDOR_ID) & ~MSM_IS_FINITE_TRANSFER;
 	d->rx_req->udc_priv = sps_params;
@@ -863,6 +864,7 @@
 	d->tx_req->context = port;
 	d->tx_req->complete = gbam_endless_tx_complete;
 	d->tx_req->length = 0;
+	d->tx_req->no_interrupt = 1;
 	sps_params = (MSM_SPS_MODE | d->dst_pipe_idx |
 				 MSM_VENDOR_ID) & ~MSM_IS_FINITE_TRANSFER;
 	d->tx_req->udc_priv = sps_params;
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index 5c7e52f..d470edf 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -296,6 +296,7 @@
 	d->rx_req->context = port;
 	d->rx_req->complete = bam_data_endless_rx_complete;
 	d->rx_req->length = 0;
+	d->rx_req->no_interrupt = 1;
 	sps_params = (SPS_PARAMS_SPS_MODE | d->src_pipe_idx |
 				 MSM_VENDOR_ID) & ~SPS_PARAMS_TBE;
 	d->rx_req->udc_priv = sps_params;
@@ -306,6 +307,7 @@
 	d->tx_req->context = port;
 	d->tx_req->complete = bam_data_endless_tx_complete;
 	d->tx_req->length = 0;
+	d->tx_req->no_interrupt = 1;
 	sps_params = (SPS_PARAMS_SPS_MODE | d->dst_pipe_idx |
 				 MSM_VENDOR_ID) & ~SPS_PARAMS_TBE;
 	d->tx_req->udc_priv = sps_params;
diff --git a/drivers/video/msm/mdss/dsi_io_v2.c b/drivers/video/msm/mdss/dsi_io_v2.c
index cbdd241..273fb54 100644
--- a/drivers/video/msm/mdss/dsi_io_v2.c
+++ b/drivers/video/msm/mdss/dsi_io_v2.c
@@ -437,5 +437,9 @@
 
 void msm_dsi_phy_off(unsigned char *ctrl_base)
 {
+	MIPI_OUTP(ctrl_base + DSI_DSIPHY_PLL_CTRL_5, 0x05f);
+	MIPI_OUTP(ctrl_base + DSI_DSIPHY_REGULATOR_CTRL_0, 0x02);
 	MIPI_OUTP(ctrl_base + DSI_DSIPHY_CTRL_0, 0x00);
+	MIPI_OUTP(ctrl_base + DSI_DSIPHY_CTRL_1, 0x7f);
+	MIPI_OUTP(ctrl_base + DSI_CLK_CTRL, 0);
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 52140b2..963d3fb 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -2549,7 +2549,7 @@
 				hist_info = &mdss_pp_res->dspp_hist[dspp_num];
 				mutex_lock(&hist_info->hist_mutex);
 				for (j = 0; j < HIST_V_SIZE; j++)
-					hist_concat[i] += hist_info->data[i];
+					hist_concat[j] += hist_info->data[j];
 				mutex_unlock(&hist_info->hist_mutex);
 			}
 			hist_data_addr = hist_concat;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 4fd90f9..97803b3 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -2249,6 +2249,9 @@
 	SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_AUXPCM_RX,
 	MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer,
 	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+	MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
 };
 
 static const struct snd_kcontrol_new sec_auxpcm_rx_port_mixer_controls[] = {
@@ -2258,6 +2261,9 @@
 	SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
 	MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer,
 	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+	MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
 };
 
 static const struct snd_kcontrol_new sbus_1_rx_port_mixer_controls[] = {
@@ -3384,8 +3390,10 @@
 
 	{"AUXPCM_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
 	{"AUXPCM_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+	{"AUXPCM_RX Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
 	{"AUX_PCM_RX", NULL, "AUXPCM_RX Port Mixer"},
 
+	{"SEC_AUXPCM_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
 	{"SEC_AUXPCM_RX Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
 	{"SEC_AUXPCM_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"SEC_AUX_PCM_RX", NULL, "SEC_AUXPCM_RX Port Mixer"},