Merge "hwmon: qpnp-adc: Add PMIC QPNP IADC driver" into msm-3.4
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index f144421..0c6b9e6 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -359,9 +359,9 @@
 		l2_hfpll_b-supply = <&pm8941_l12_ao>;
 	};
 
-	qcom,ssusb@F9200000 {
+	qcom,ssusb@f9200000 {
 		compatible = "qcom,dwc-usb3-msm";
-		reg = <0xF9200000 0xFA000>;
+		reg = <0xf9200000 0xfc000>;
 		interrupts = <0 131 0 0 179 0>;
 		interrupt-names = "irq", "otg_irq";
 		SSUSB_VDDCX-supply = <&pm8841_s2>;
@@ -628,6 +628,42 @@
 		interrupts = <0 235 0>;
 		qcom,bam-pipes = <1>;
 	};
+
+	qcom,usbbam@f9304000 {
+		compatible = "qcom,usb-bam-msm";
+		reg = <0xf9304000 0x9000>;
+		interrupts = <0 132 0>;
+		qcom,usb-active-bam = <0>;
+		qcom,usb-total-bam-num = <1>;
+		qcom,usb-bam-num-pipes = <16>;
+		qcom,usb-base-address = <0xf9200000>;
+
+		qcom,pipe1 {
+			label = "usb-to-peri-qdss-dwc3";
+			qcom,usb-bam-type = <0>;
+			qcom,src-bam-physical-address = <0>;
+			qcom,src-bam-pipe-index = <0>;
+			qcom,dst-bam-physical-address = <0>;
+			qcom,dst-bam-pipe-index = <0>;
+			qcom,data-fifo-offset = <0>;
+			qcom,data-fifo-size = <0>;
+			qcom,descriptor-fifo-offset = <0>;
+			qcom,descriptor-fifo-size = <0>;
+		};
+
+		qcom,pipe2 {
+			label = "peri-to-usb-qdss-dwc3";
+			qcom,usb-bam-type = <0>;
+			qcom,src-bam-physical-address = <0xfc37C000>;
+			qcom,src-bam-pipe-index = <0>;
+			qcom,dst-bam-physical-address = <0xf9304000>;
+			qcom,dst-bam-pipe-index = <2>;
+			qcom,data-fifo-offset = <0xf0000>;
+			qcom,data-fifo-size = <0x4000>;
+			qcom,descriptor-fifo-offset = <0xf4000>;
+			qcom,descriptor-fifo-size = <0x1400>;
+		};
+	};
 };
 
 /include/ "msm-pm8x41-rpm-regulator.dtsi"
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index 37cbfcb..0d0103a 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -108,6 +108,12 @@
 	enum arm_pmu_type type;
 	cpumask_t	active_irqs;
 	const char	*name;
+	int		num_events;
+	atomic_t	active_events;
+	struct mutex	reserve_mutex;
+	u64		max_period;
+	struct platform_device	*plat_device;
+	u32		from_idle;
 	irqreturn_t	(*handle_irq)(int irq_num, void *dev);
 	int     	(*request_pmu_irq)(int irq, irq_handler_t *irq_h);
 	void    	(*free_pmu_irq)(int irq);
@@ -123,11 +129,6 @@
 	void		(*stop)(void);
 	void		(*reset)(void *);
 	int		(*map_event)(struct perf_event *event);
-	int		num_events;
-	atomic_t	active_events;
-	struct mutex	reserve_mutex;
-	u64		max_period;
-	struct platform_device	*plat_device;
 	struct pmu_hw_events	*(*get_hw_events)(void);
 	int	(*test_set_event_constraints)(struct perf_event *event);
 	int	(*clear_event_constraints)(struct perf_event *event);
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 778128b..e97aef2 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -600,6 +600,21 @@
 	struct arm_pmu *armpmu = to_arm_pmu(pmu);
 	struct pmu_hw_events *hw_events = armpmu->get_hw_events();
 	int enabled = bitmap_weight(hw_events->used_mask, armpmu->num_events);
+	int idx;
+
+	if (armpmu->from_idle) {
+		for (idx = 0; idx <= cpu_pmu->num_events; ++idx) {
+			struct perf_event *event = hw_events->events[idx];
+
+			if (!event)
+				continue;
+
+			armpmu->enable(&event->hw, idx, event->cpu);
+		}
+
+		/* Reset bit so we don't needlessly re-enable counters.*/
+		armpmu->from_idle = 0;
+	}
 
 	if (enabled)
 		armpmu->start();
@@ -716,6 +731,7 @@
  * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
  * junk values out of them.
  */
+
 static int __cpuinit pmu_cpu_notify(struct notifier_block *b,
 					unsigned long action, void *hcpu)
 {
@@ -785,6 +801,11 @@
 	case CPU_PM_ENTER_FAILED:
 	case CPU_PM_EXIT:
 		if (cpu_has_active_perf() && cpu_pmu->reset) {
+			/*
+			 * Flip this bit so armpmu_enable knows it needs
+			 * to re-enable active counters.
+			 */
+			cpu_pmu->from_idle = 1;
 			cpu_pmu->reset(NULL);
 			perf_pmu_enable(&cpu_pmu->pmu);
 		}
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index 7898cf6..f57771c 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -493,6 +493,22 @@
 		},
 	},
 };
+static struct msm_gpiomux_config cyts_gpio_alt_config[] __initdata = {
+	{	/* TS INTERRUPT */
+		.gpio = 6,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cyts_int_act_cfg,
+			[GPIOMUX_SUSPENDED] = &cyts_int_sus_cfg,
+		},
+	},
+	{	/* TS SLEEP */
+		.gpio = 12,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cyts_sleep_act_cfg,
+			[GPIOMUX_SUSPENDED] = &cyts_sleep_sus_cfg,
+		},
+	},
+};
 
 static struct gpiomux_setting hsic_act_cfg = {
 	.func = GPIOMUX_FUNC_1,
@@ -1202,6 +1218,7 @@
 void __init apq8064_init_gpiomux(void)
 {
 	int rc;
+	int platform_version = socinfo_get_platform_version();
 
 	rc = msm_gpiomux_init(NR_GPIO_IRQS);
 	if (rc) {
@@ -1260,11 +1277,17 @@
 		msm_gpiomux_install(mdm_configs,
 			ARRAY_SIZE(mdm_configs));
 
-#ifdef CONFIG_USB_EHCI_MSM_HSIC
-	if (machine_is_apq8064_mtp())
-		msm_gpiomux_install(cyts_gpio_configs,
-				ARRAY_SIZE(cyts_gpio_configs));
+	if (machine_is_apq8064_mtp()) {
+		if (SOCINFO_VERSION_MINOR(platform_version) == 1) {
+			msm_gpiomux_install(cyts_gpio_alt_config,
+					ARRAY_SIZE(cyts_gpio_alt_config));
+		} else {
+			msm_gpiomux_install(cyts_gpio_configs,
+					ARRAY_SIZE(cyts_gpio_configs));
+		}
+	}
 
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
 	if (machine_is_apq8064_mtp())
 		msm_gpiomux_install(apq8064_hsic_configs,
 				ARRAY_SIZE(apq8064_hsic_configs));
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index da849c8..f733ba6 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -1379,6 +1379,7 @@
 };
 #define CYTTSP_TS_GPIO_IRQ		6
 #define CYTTSP_TS_GPIO_SLEEP		33
+#define CYTTSP_TS_GPIO_SLEEP_ALT	12
 
 static ssize_t tma340_vkeys_show(struct kobject *kobj,
 			struct kobj_attribute *attr, char *buf)
@@ -2972,6 +2973,9 @@
 {
 	if (meminfo_init(SYS_MEMORY, SZ_256M) < 0)
 		pr_err("meminfo_init() failed!\n");
+	if (machine_is_apq8064_mtp() &&
+		SOCINFO_VERSION_MINOR(socinfo_get_platform_version()) == 1)
+			cyttsp_pdata.sleep_gpio = CYTTSP_TS_GPIO_SLEEP_ALT;
 	apq8064_common_init();
 	if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
 		machine_is_mpq8064_dtv()) {
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 240e094..a44d67b 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -469,6 +469,8 @@
 			"msm_otg", NULL),
 	OF_DEV_AUXDATA("qcom,dwc-usb3-msm", 0xF9200000, \
 			"msm_dwc3", NULL),
+	OF_DEV_AUXDATA("qcom,usb-bam-msm", 0xF9304000, \
+			"usb_bam", NULL),
 	OF_DEV_AUXDATA("qcom,spi-qup-v2", 0xF9924000, \
 			"spi_qsd.1", NULL),
 	OF_DEV_AUXDATA("qcom,spmi-pmic-arb", 0xFC4C0000, \
diff --git a/arch/arm/mach-msm/include/mach/sps.h b/arch/arm/mach-msm/include/mach/sps.h
index 319a3ec..70f91f3 100644
--- a/arch/arm/mach-msm/include/mach/sps.h
+++ b/arch/arm/mach-msm/include/mach/sps.h
@@ -103,6 +103,9 @@
 #define SPS_BAM_SEC_DO_NOT_CONFIG   0
 #define SPS_BAM_SEC_DO_CONFIG       0x0A434553
 
+/* BAM pipe selection */
+#define SPS_BAM_PIPE(n)             (1UL << (n))
+
 /* This enum specifies the operational mode for an SPS connection */
 enum sps_mode {
 	SPS_MODE_SRC = 0,  /* end point is the source (producer) */
@@ -1232,6 +1235,20 @@
  */
 int sps_get_unused_desc_num(struct sps_pipe *h, u32 *desc_num);
 
+/**
+ * Get the debug info of BAM registers and descriptor FIFOs
+ *
+ * @dev - BAM device handle
+ *
+ * @option - debugging option
+ *
+ * @para - parameter used for an option (such as pipe combination)
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_get_bam_debug_info(u32 dev, u32 option, u32 para);
+
 #else
 static inline int sps_register_bam_device(const struct sps_bam_props
 			*bam_props, u32 *dev_handle)
@@ -1388,6 +1405,11 @@
 {
 	return -EPERM;
 }
+
+static inline int sps_get_bam_debug_info(u32 dev, u32 option, u32 para)
+{
+	return -EPERM;
+}
 #endif
 
 #endif /* _SPS_H_ */
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index c0bff63..7dc8d0f 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -130,7 +130,6 @@
 	uint32_t remote_node_id;
 	uint32_t initialized;
 	struct list_head pkt_list;
-	wait_queue_head_t read_wait;
 	struct wake_lock wakelock;
 	struct mutex rx_lock;
 	struct mutex tx_lock;
@@ -262,16 +261,15 @@
 		return NULL;
 
 	mutex_lock(&xprt_info->rx_lock);
-	while (!(xprt_info->abort_data_read) &&
-		list_empty(&xprt_info->pkt_list)) {
-		mutex_unlock(&xprt_info->rx_lock);
-		wait_event(xprt_info->read_wait,
-			   ((xprt_info->abort_data_read) ||
-			   !list_empty(&xprt_info->pkt_list)));
-		mutex_lock(&xprt_info->rx_lock);
-	}
 	if (xprt_info->abort_data_read) {
 		mutex_unlock(&xprt_info->rx_lock);
+		pr_err("%s detected SSR & exiting now\n",
+			xprt_info->xprt->name);
+		return NULL;
+	}
+
+	if (list_empty(&xprt_info->pkt_list)) {
+		mutex_unlock(&xprt_info->rx_lock);
 		return NULL;
 	}
 
@@ -1364,144 +1362,135 @@
 			     struct msm_ipc_router_xprt_info,
 			     read_data);
 
-	pkt = rr_read(xprt_info);
-	if (!pkt) {
-		pr_err("%s: rr_read failed\n", __func__);
-		goto fail_io;
-	}
+	while ((pkt = rr_read(xprt_info)) != NULL) {
+		if (pkt->length < IPC_ROUTER_HDR_SIZE ||
+		    pkt->length > MAX_IPC_PKT_SIZE) {
+			pr_err("%s: Invalid pkt length %d\n",
+				__func__, pkt->length);
+			goto fail_data;
+		}
 
-	if (pkt->length < IPC_ROUTER_HDR_SIZE ||
-	    pkt->length > MAX_IPC_PKT_SIZE) {
-		pr_err("%s: Invalid pkt length %d\n", __func__, pkt->length);
-		goto fail_data;
-	}
+		head_skb = skb_peek(pkt->pkt_fragment_q);
+		if (!head_skb) {
+			pr_err("%s: head_skb is invalid\n", __func__);
+			goto fail_data;
+		}
 
-	head_skb = skb_peek(pkt->pkt_fragment_q);
-	if (!head_skb) {
-		pr_err("%s: head_skb is invalid\n", __func__);
-		goto fail_data;
-	}
+		hdr = (struct rr_header *)(head_skb->data);
+		RR("- ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
+		   hdr->version, hdr->type, hdr->src_node_id, hdr->src_port_id,
+		   hdr->confirm_rx, hdr->size, hdr->dst_node_id,
+		   hdr->dst_port_id);
 
-	hdr = (struct rr_header *)(head_skb->data);
-	RR("- ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
-	   hdr->version, hdr->type, hdr->src_node_id, hdr->src_port_id,
-	   hdr->confirm_rx, hdr->size, hdr->dst_node_id, hdr->dst_port_id);
-	RAW_HDR("[r rr_h] "
-		"ver=%i,type=%s,src_node_id=%08x,src_port_id=%08x,"
-		"confirm_rx=%i,size=%3i,dst_node_id=%08x,dst_port_id=%08x\n",
-		hdr->version, type_to_str(hdr->type), hdr->src_node_id,
-		hdr->src_port_id, hdr->confirm_rx, hdr->size, hdr->dst_node_id,
-		hdr->dst_port_id);
+		if (hdr->version != IPC_ROUTER_VERSION) {
+			pr_err("version %d != %d\n",
+				hdr->version, IPC_ROUTER_VERSION);
+			goto fail_data;
+		}
 
-	if (hdr->version != IPC_ROUTER_VERSION) {
-		pr_err("version %d != %d\n", hdr->version, IPC_ROUTER_VERSION);
-		goto fail_data;
-	}
+		if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
+		    ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
+		     (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
+			forward_msg(xprt_info, pkt);
+			release_pkt(pkt);
+			continue;
+		}
 
-	if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
-	    ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
-	     (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
-		forward_msg(xprt_info, pkt);
-		release_pkt(pkt);
-		goto done;
-	}
-
-	if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
-	    (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
-		process_control_msg(xprt_info, pkt);
-		release_pkt(pkt);
-		goto done;
-	}
+		if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
+		    (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
+			process_control_msg(xprt_info, pkt);
+			release_pkt(pkt);
+			continue;
+		}
 #if defined(CONFIG_MSM_SMD_LOGGING)
 #if defined(DEBUG)
-	if (msm_ipc_router_debug_mask & SMEM_LOG) {
-		smem_log_event((SMEM_LOG_PROC_ID_APPS |
-			SMEM_LOG_RPC_ROUTER_EVENT_BASE |
-			IPC_ROUTER_LOG_EVENT_RX),
-			(hdr->src_node_id << 24) |
-			(hdr->src_port_id & 0xffffff),
-			(hdr->dst_node_id << 24) |
-			(hdr->dst_port_id & 0xffffff),
-			(hdr->type << 24) | (hdr->confirm_rx << 16) |
-			(hdr->size & 0xffff));
-	}
+		if (msm_ipc_router_debug_mask & SMEM_LOG) {
+			smem_log_event((SMEM_LOG_PROC_ID_APPS |
+				SMEM_LOG_RPC_ROUTER_EVENT_BASE |
+				IPC_ROUTER_LOG_EVENT_RX),
+				(hdr->src_node_id << 24) |
+				(hdr->src_port_id & 0xffffff),
+				(hdr->dst_node_id << 24) |
+				(hdr->dst_port_id & 0xffffff),
+				(hdr->type << 24) | (hdr->confirm_rx << 16) |
+				(hdr->size & 0xffff));
+		}
 #endif
 #endif
 
-	resume_tx = hdr->confirm_rx;
-	resume_tx_node_id = hdr->dst_node_id;
-	resume_tx_port_id = hdr->dst_port_id;
+		resume_tx = hdr->confirm_rx;
+		resume_tx_node_id = hdr->dst_node_id;
+		resume_tx_port_id = hdr->dst_port_id;
 
-	rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
+		rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
 						      hdr->src_port_id);
 
-	mutex_lock(&local_ports_lock);
-	port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
-	if (!port_ptr) {
-		pr_err("%s: No local port id %08x\n", __func__,
-			hdr->dst_port_id);
-		mutex_unlock(&local_ports_lock);
-		release_pkt(pkt);
-		goto process_done;
-	}
-
-	if (!rport_ptr) {
-		rport_ptr = msm_ipc_router_create_remote_port(
-							hdr->src_node_id,
-							hdr->src_port_id);
-		if (!rport_ptr) {
-			pr_err("%s: Remote port %08x:%08x creation failed\n",
-				__func__, hdr->src_node_id, hdr->src_port_id);
+		mutex_lock(&local_ports_lock);
+		port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
+		if (!port_ptr) {
+			pr_err("%s: No local port id %08x\n", __func__,
+				hdr->dst_port_id);
 			mutex_unlock(&local_ports_lock);
+			release_pkt(pkt);
 			goto process_done;
 		}
-	}
 
-	if (!port_ptr->notify) {
-		mutex_lock(&port_ptr->port_rx_q_lock);
-		wake_lock(&port_ptr->port_rx_wake_lock);
-		list_add_tail(&pkt->list, &port_ptr->port_rx_q);
-		wake_up(&port_ptr->port_rx_wait_q);
-		mutex_unlock(&port_ptr->port_rx_q_lock);
-		mutex_unlock(&local_ports_lock);
-	} else {
-		mutex_lock(&port_ptr->port_rx_q_lock);
-		src_addr = kmalloc(sizeof(struct msm_ipc_port_addr),
-				   GFP_KERNEL);
-		if (src_addr) {
-			src_addr->node_id = hdr->src_node_id;
-			src_addr->port_id = hdr->src_port_id;
+		if (!rport_ptr) {
+			rport_ptr = msm_ipc_router_create_remote_port(
+							hdr->src_node_id,
+							hdr->src_port_id);
+			if (!rport_ptr) {
+				pr_err("%s: Rmt Prt %08x:%08x create failed\n",
+					__func__, hdr->src_node_id,
+					hdr->src_port_id);
+				mutex_unlock(&local_ports_lock);
+				goto process_done;
+			}
 		}
-		skb_pull(head_skb, IPC_ROUTER_HDR_SIZE);
-		mutex_unlock(&local_ports_lock);
-		port_ptr->notify(MSM_IPC_ROUTER_READ_CB, pkt->pkt_fragment_q,
-				 src_addr, port_ptr->priv);
-		mutex_unlock(&port_ptr->port_rx_q_lock);
-		pkt->pkt_fragment_q = NULL;
-		src_addr = NULL;
-		release_pkt(pkt);
-	}
+
+		if (!port_ptr->notify) {
+			mutex_lock(&port_ptr->port_rx_q_lock);
+			wake_lock(&port_ptr->port_rx_wake_lock);
+			list_add_tail(&pkt->list, &port_ptr->port_rx_q);
+			wake_up(&port_ptr->port_rx_wait_q);
+			mutex_unlock(&port_ptr->port_rx_q_lock);
+			mutex_unlock(&local_ports_lock);
+		} else {
+			mutex_lock(&port_ptr->port_rx_q_lock);
+			src_addr = kmalloc(sizeof(struct msm_ipc_port_addr),
+					   GFP_KERNEL);
+			if (src_addr) {
+				src_addr->node_id = hdr->src_node_id;
+				src_addr->port_id = hdr->src_port_id;
+			}
+			skb_pull(head_skb, IPC_ROUTER_HDR_SIZE);
+			mutex_unlock(&local_ports_lock);
+			port_ptr->notify(MSM_IPC_ROUTER_READ_CB,
+				pkt->pkt_fragment_q, src_addr, port_ptr->priv);
+			mutex_unlock(&port_ptr->port_rx_q_lock);
+			pkt->pkt_fragment_q = NULL;
+			src_addr = NULL;
+			release_pkt(pkt);
+		}
 
 process_done:
-	if (resume_tx) {
-		union rr_control_msg msg;
+		if (resume_tx) {
+			union rr_control_msg msg;
 
-		msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
-		msg.cli.node_id = resume_tx_node_id;
-		msg.cli.port_id = resume_tx_port_id;
+			msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
+			msg.cli.node_id = resume_tx_node_id;
+			msg.cli.port_id = resume_tx_port_id;
 
-		RR("x RESUME_TX id=%d:%08x\n",
-		   msg.cli.node_id, msg.cli.port_id);
-		msm_ipc_router_send_control_msg(xprt_info, &msg);
+			RR("x RESUME_TX id=%d:%08x\n",
+			   msg.cli.node_id, msg.cli.port_id);
+			msm_ipc_router_send_control_msg(xprt_info, &msg);
+		}
+
 	}
-
-done:
-	queue_work(xprt_info->workqueue, &xprt_info->read_data);
 	return;
 
 fail_data:
 	release_pkt(pkt);
-fail_io:
 	pr_err("ipc_router has died\n");
 }
 
@@ -2334,7 +2323,6 @@
 	xprt_info->initialized = 0;
 	xprt_info->remote_node_id = -1;
 	INIT_LIST_HEAD(&xprt_info->pkt_list);
-	init_waitqueue_head(&xprt_info->read_wait);
 	mutex_init(&xprt_info->rx_lock);
 	mutex_init(&xprt_info->tx_lock);
 	wake_lock_init(&xprt_info->wakelock,
@@ -2368,8 +2356,6 @@
 	}
 	mutex_unlock(&routing_table_lock);
 
-	queue_work(xprt_info->workqueue, &xprt_info->read_data);
-
 	xprt->priv = xprt_info;
 
 	return 0;
@@ -2382,8 +2368,9 @@
 	if (xprt && xprt->priv) {
 		xprt_info = xprt->priv;
 
+		mutex_lock(&xprt_info->rx_lock);
 		xprt_info->abort_data_read = 1;
-		wake_up(&xprt_info->read_wait);
+		mutex_unlock(&xprt_info->rx_lock);
 
 		mutex_lock(&xprt_info_list_lock);
 		list_del(&xprt_info->list);
@@ -2481,8 +2468,8 @@
 	mutex_lock(&xprt_info->rx_lock);
 	list_add_tail(&pkt->list, &xprt_info->pkt_list);
 	wake_lock(&xprt_info->wakelock);
-	wake_up(&xprt_info->read_wait);
 	mutex_unlock(&xprt_info->rx_lock);
+	queue_work(xprt_info->workqueue, &xprt_info->read_data);
 }
 
 static int modem_restart_notifier_cb(struct notifier_block *this,
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 90673fc..6d82e11 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -246,6 +246,12 @@
 	},
 };
 
+static struct mfd_cell taiko_devs[] = {
+	{
+		.name = "taiko_codec",
+	},
+};
+
 static void wcd9xxx_bring_up(struct wcd9xxx *wcd9xxx)
 {
 	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x4);
@@ -336,13 +342,16 @@
 	} else if (wcd9xxx->idbyte_0 == 0x1) {
 		wcd9xxx_dev = tabla1x_devs;
 		wcd9xxx_dev_size = ARRAY_SIZE(tabla1x_devs);
+	} else if (wcd9xxx->idbyte_0 == 0x0 && wcd9xxx->idbyte_1 == 0x0 &&
+		   wcd9xxx->idbyte_2 == 0x2 && wcd9xxx->idbyte_3 == 0x1) {
+		wcd9xxx_dev = taiko_devs;
+		wcd9xxx_dev_size = ARRAY_SIZE(taiko_devs);
 	} else if (wcd9xxx->idbyte_0 == 0x0) {
 		wcd9xxx_dev = sitar_devs;
 		wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
 	}
-	ret = mfd_add_devices(wcd9xxx->dev, -1,
-		      wcd9xxx_dev, wcd9xxx_dev_size,
-		      NULL, 0);
+	ret = mfd_add_devices(wcd9xxx->dev, -1, wcd9xxx_dev, wcd9xxx_dev_size,
+			      NULL, 0);
 	if (ret != 0) {
 		dev_err(wcd9xxx->dev, "Failed to add children: %d\n", ret);
 		goto err_irq;
@@ -883,7 +892,9 @@
 		pr_err("%s: error, initializing device failed\n", __func__);
 		goto err_slim_add;
 	}
+
 	wcd9xxx_init_slimslave(wcd9xxx, wcd9xxx_pgd_la);
+
 #ifdef CONFIG_DEBUG_FS
 	debugCodec = wcd9xxx;
 
@@ -1091,6 +1102,23 @@
 	.suspend = wcd9xxx_slim_suspend,
 };
 
+static const struct slim_device_id taiko_slimtest_id[] = {
+	{"taiko-slim", 0},
+	{}
+};
+
+static struct slim_driver taiko_slim_driver = {
+	.driver = {
+		.name = "taiko-slim",
+		.owner = THIS_MODULE,
+	},
+	.probe = wcd9xxx_slim_probe,
+	.remove = wcd9xxx_slim_remove,
+	.id_table = taiko_slimtest_id,
+	.resume = wcd9xxx_slim_resume,
+	.suspend = wcd9xxx_slim_suspend,
+};
+
 #define WCD9XXX_I2C_TOP_LEVEL	0
 #define WCD9XXX_I2C_ANALOG	1
 #define WCD9XXX_I2C_DIGITAL_1	2
@@ -1119,7 +1147,7 @@
 
 static int __init wcd9xxx_init(void)
 {
-	int ret1, ret2, ret3, ret4, ret5;
+	int ret1, ret2, ret3, ret4, ret5, ret6;
 
 	ret1 = slim_driver_register(&tabla_slim_driver);
 	if (ret1 != 0)
@@ -1141,7 +1169,11 @@
 	if (ret5 != 0)
 		pr_err("Failed to register sitar SB driver: %d\n", ret5);
 
-	return (ret1 && ret2 && ret3 && ret4 && ret5) ? -1 : 0;
+	ret6 = slim_driver_register(&taiko_slim_driver);
+	if (ret6 != 0)
+		pr_err("Failed to register taiko SB driver: %d\n", ret6);
+
+	return (ret1 && ret2 && ret3 && ret4 && ret5 && ret6) ? -1 : 0;
 }
 module_init(wcd9xxx_init);
 
diff --git a/drivers/mfd/wcd9xxx-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
index 789242d..5f839a8 100644
--- a/drivers/mfd/wcd9xxx-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -12,6 +12,9 @@
 #include <linux/slab.h>
 #include <linux/mutex.h>
 #include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+
+#define WCD9XXX_CHIP_ID_TAIKO 0x00000201
 
 struct wcd9xxx_slim_sch_rx {
 	u32 sph;
@@ -30,37 +33,111 @@
 struct wcd9xxx_slim_sch {
 	struct wcd9xxx_slim_sch_rx rx[SLIM_MAX_RX_PORTS];
 	struct wcd9xxx_slim_sch_tx tx[SLIM_MAX_TX_PORTS];
+
+	u16 rx_port_start_offset;
+	u16 num_rx_slave_port;
+	u16 port_ch_0_start_port_id;
+	u16 port_ch_0_end_port_id;
+	u16 pgd_tx_port_ch_1_end_port_id;
+	u16 rx_port_ch_reg_base;
+	u16 port_tx_cfg_reg_base;
+	u16 port_rx_cfg_reg_base;
+	int number_of_tx_slave_dev_ports;
+	int number_of_rx_slave_dev_ports;
 };
 
 static struct wcd9xxx_slim_sch sh_ch;
 
 static int wcd9xxx_alloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx,
-					u8 wcd9xxx_pgd_la);
+				       u8 wcd9xxx_pgd_la);
 static int wcd9xxx_alloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx,
 					u8 wcd9xxx_pgd_la);
 static int wcd9xxx_dealloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx);
 static int wcd9xxx_dealloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx);
 
+static int wcd9xxx_configure_ports(struct wcd9xxx *wcd9xxx)
+{
+	int i;
+	u32 id;
+	for (i = 0; i < 4; i++)
+		((u8 *)&id)[i] = wcd9xxx_reg_read(wcd9xxx,
+						  WCD9XXX_A_CHIP_ID_BYTE_0 + i);
+	id = cpu_to_be32(id);
+	pr_debug("%s: chip id 0x%08x\n", __func__, id);
+	if (id != WCD9XXX_CHIP_ID_TAIKO) {
+		sh_ch.rx_port_start_offset =
+		    TABLA_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS;
+		sh_ch.num_rx_slave_port =
+		    TABLA_SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS;
+		sh_ch.port_ch_0_start_port_id =
+		    TABLA_SB_PGD_RX_PORT_MULTI_CHANNEL_0_START_PORT_ID;
+		sh_ch.port_ch_0_end_port_id =
+		    TABLA_SB_PGD_RX_PORT_MULTI_CHANNEL_0_END_PORT_ID;
+		sh_ch.pgd_tx_port_ch_1_end_port_id =
+		    TABLA_SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID;
+
+		sh_ch.rx_port_ch_reg_base =
+		    0x180 + (TABLA_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS * 4);
+		sh_ch.port_rx_cfg_reg_base =
+		    0x040 + (TABLA_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS);
+		sh_ch.port_tx_cfg_reg_base = 0x040;
+
+		sh_ch.number_of_tx_slave_dev_ports =
+		    TABLA_SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS;
+		sh_ch.number_of_rx_slave_dev_ports =
+		    TABLA_SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS;
+	} else {
+		sh_ch.rx_port_start_offset =
+		    TAIKO_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS;
+		sh_ch.num_rx_slave_port =
+		    TAIKO_SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS;
+		sh_ch.port_ch_0_start_port_id =
+		    TAIKO_SB_PGD_RX_PORT_MULTI_CHANNEL_0_START_PORT_ID;
+		sh_ch.port_ch_0_end_port_id =
+		    TAIKO_SB_PGD_RX_PORT_MULTI_CHANNEL_0_END_PORT_ID;
+		sh_ch.pgd_tx_port_ch_1_end_port_id =
+		    TAIKO_SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID;
+
+		sh_ch.rx_port_ch_reg_base = 0x180;
+		sh_ch.port_rx_cfg_reg_base = 0x040;
+		sh_ch.port_tx_cfg_reg_base = 0x050;
+
+		sh_ch.number_of_tx_slave_dev_ports =
+		    TAIKO_SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS;
+		sh_ch.number_of_rx_slave_dev_ports =
+		    TAIKO_SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS;
+	}
+
+	return 0;
+}
+
 int wcd9xxx_init_slimslave(struct wcd9xxx *wcd9xxx, u8 wcd9xxx_pgd_la)
 {
 	int ret = 0;
 
+	ret = wcd9xxx_configure_ports(wcd9xxx);
+	if (ret) {
+		pr_err("%s: Failed to configure register address offset\n",
+		       __func__);
+		goto err;
+	}
+
 	ret = wcd9xxx_alloc_slim_sh_ch_rx(wcd9xxx, wcd9xxx_pgd_la);
 	if (ret) {
 		pr_err("%s: Failed to alloc rx slimbus shared channels\n",
-								__func__);
-		goto rx_err;
+		       __func__);
+		goto err;
 	}
 	ret = wcd9xxx_alloc_slim_sh_ch_tx(wcd9xxx, wcd9xxx_pgd_la);
 	if (ret) {
 		pr_err("%s: Failed to alloc tx slimbus shared channels\n",
-								__func__);
+		       __func__);
 		goto tx_err;
 	}
 	return 0;
 tx_err:
 	wcd9xxx_dealloc_slim_sh_ch_rx(wcd9xxx);
-rx_err:
+err:
 	return ret;
 }
 
@@ -82,23 +159,22 @@
 	return ret;
 }
 
-int wcd9xxx_get_channel(struct wcd9xxx *wcd9xxx,
-		unsigned int *rx_ch,
-		unsigned int *tx_ch)
+int wcd9xxx_get_channel(struct wcd9xxx *wcd9xxx, unsigned int *rx_ch,
+			unsigned int *tx_ch)
 {
 	int ch_idx = 0;
 	struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
 	struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
 
-	for (ch_idx = 0; ch_idx < SLIM_MAX_RX_PORTS; ch_idx++)
+	for (ch_idx = 0; ch_idx < sh_ch.number_of_rx_slave_dev_ports; ch_idx++)
 		rx_ch[ch_idx] = rx[ch_idx].ch_num;
-	for (ch_idx = 0; ch_idx < SLIM_MAX_TX_PORTS; ch_idx++)
+	for (ch_idx = 0; ch_idx < sh_ch.number_of_tx_slave_dev_ports; ch_idx++)
 		tx_ch[ch_idx] = tx[ch_idx].ch_num;
 	return 0;
 }
 
 static int wcd9xxx_alloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx,
-			u8 wcd9xxx_pgd_la)
+				       u8 wcd9xxx_pgd_la)
 {
 	int ret = 0;
 	u8 ch_idx ;
@@ -109,35 +185,38 @@
 	 * DSP requires channel number to be between 128 and 255.
 	 */
 	pr_debug("%s: pgd_la[%d]\n", __func__, wcd9xxx_pgd_la);
-	for (ch_idx = 0; ch_idx < SLIM_MAX_RX_PORTS; ch_idx++) {
-		slave_port_id = (ch_idx + 1 +
-				SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS);
+	for (ch_idx = 0; ch_idx < sh_ch.number_of_rx_slave_dev_ports;
+	     ch_idx++) {
+		slave_port_id = (ch_idx + sh_ch.rx_port_start_offset);
 		rx[ch_idx].ch_num = slave_port_id + BASE_CH_NUM;
 		ret = slim_get_slaveport(wcd9xxx_pgd_la, slave_port_id,
 					&rx[ch_idx].sph, SLIM_SINK);
 		if (ret < 0) {
 			pr_err("%s: slave port failure id[%d] ret[%d]\n",
-					__func__, slave_port_id, ret);
+			       __func__, slave_port_id, ret);
 			goto err;
 		}
 
 		ret = slim_query_ch(wcd9xxx->slim, rx[ch_idx].ch_num,
-							&rx[ch_idx].ch_h);
+				    &rx[ch_idx].ch_h);
 		if (ret < 0) {
 			pr_err("%s: slim_query_ch failed ch-num[%d] ret[%d]\n",
-					__func__, rx[ch_idx].ch_num, ret);
+			       __func__, rx[ch_idx].ch_num, ret);
 			goto err;
 		}
+		pr_debug("%s:ch_num=%d ch_h=%d sph=%d la=%d slave_port_id %d\n",
+			 __func__, rx[ch_idx].ch_num, rx[ch_idx].ch_h,
+			 rx[ch_idx].sph, wcd9xxx_pgd_la, slave_port_id);
 	}
 err:
 	return ret;
 }
 
 static int wcd9xxx_alloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx,
-			u8 wcd9xxx_pgd_la)
+				       u8 wcd9xxx_pgd_la)
 {
 	int ret = 0;
-	u8 ch_idx ;
+	u8 ch_idx;
 	struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
 	u16 slave_port_id = 0;
 
@@ -146,21 +225,22 @@
 	 * use channel numbers from 138 to 144, for TX port
 	 * use channel numbers from 128 to 137
 	 */
-	for (ch_idx = 0; ch_idx < SLIM_MAX_TX_PORTS; ch_idx++) {
+	for (ch_idx = 0; ch_idx < sh_ch.number_of_tx_slave_dev_ports;
+	     ch_idx++) {
 		slave_port_id = ch_idx;
 		tx[ch_idx].ch_num = slave_port_id + BASE_CH_NUM;
 		ret = slim_get_slaveport(wcd9xxx_pgd_la, slave_port_id,
-					&tx[ch_idx].sph, SLIM_SRC);
+					 &tx[ch_idx].sph, SLIM_SRC);
 		if (ret < 0) {
 			pr_err("%s: slave port failure id[%d] ret[%d]\n",
-					__func__, slave_port_id, ret);
+			       __func__, slave_port_id, ret);
 			goto err;
 		}
 		ret = slim_query_ch(wcd9xxx->slim, tx[ch_idx].ch_num,
-							&tx[ch_idx].ch_h);
+				    &tx[ch_idx].ch_h);
 		if (ret < 0) {
 			pr_err("%s: slim_query_ch failed ch-num[%d] ret[%d]\n",
-					__func__, tx[ch_idx].ch_num, ret);
+			       __func__, tx[ch_idx].ch_num, ret);
 			goto err;
 		}
 	}
@@ -174,7 +254,7 @@
 	int ret = 0;
 	struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
 	/* slim_dealloc_ch */
-	for (idx = 0; idx < SLIM_MAX_RX_PORTS; idx++) {
+	for (idx = 0; idx < sh_ch.number_of_rx_slave_dev_ports; idx++) {
 		ret = slim_dealloc_ch(wcd9xxx->slim, rx[idx].ch_h);
 		if (ret < 0) {
 			pr_err("%s: slim_dealloc_ch fail ret[%d] ch_h[%d]\n",
@@ -191,7 +271,7 @@
 	int ret = 0;
 	struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
 	/* slim_dealloc_ch */
-	for (idx = 0; idx < SLIM_MAX_TX_PORTS; idx++) {
+	for (idx = 0; idx < sh_ch.number_of_tx_slave_dev_ports; idx++) {
 		ret = slim_dealloc_ch(wcd9xxx->slim, tx[idx].ch_h);
 		if (ret < 0) {
 			pr_err("%s: slim_dealloc_ch fail ret[%d] ch_h[%d]\n",
@@ -204,9 +284,9 @@
 
 /* Enable slimbus slave device for RX path */
 int wcd9xxx_cfg_slim_sch_rx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
-				unsigned int ch_cnt, unsigned int rate)
+			    unsigned int ch_cnt, unsigned int rate)
 {
-	u8 i = 0;
+	u8 i;
 	u16 grph;
 	u32 sph[SLIM_MAX_RX_PORTS] = {0};
 	u16 ch_h[SLIM_MAX_RX_PORTS] = {0};
@@ -221,53 +301,56 @@
 	pr_debug("%s: ch_cnt[%d] rate=%d\n", __func__, ch_cnt, rate);
 
 	for (i = 0; i < ch_cnt; i++) {
-		idx = (ch_num[i] - BASE_CH_NUM -
-			SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
+		idx = (ch_num[i] - BASE_CH_NUM - sh_ch.rx_port_start_offset);
 		ch_h[i] = rx[idx].ch_h;
 		sph[i] = rx[idx].sph;
-		slave_port_id = idx + 1;
-		if ((slave_port_id > SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS) ||
-			(slave_port_id == 0)) {
+		slave_port_id = idx;
+		pr_debug("%s: idx %d, ch_h %d, sph %d\n",
+			 __func__, idx, ch_h[i], sph[i]);
+		if ((slave_port_id > sh_ch.num_rx_slave_port)) {
 			pr_err("Slimbus: invalid slave port id: %d",
-							slave_port_id);
+			       slave_port_id);
 			ret = -EINVAL;
 			goto err;
 		}
-		slave_port_id += SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS;
+		slave_port_id += sh_ch.rx_port_start_offset;
+		pr_debug("%s: slave_port_id %d\n", __func__, slave_port_id);
 		/* look for the valid port range and chose the
 		 * payload accordingly
 		 */
-		if ((slave_port_id >
-				SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID) &&
-			(slave_port_id <=
-			 SB_PGD_RX_PORT_MULTI_CHANNEL_0_END_PORT_ID)) {
-				payload_rx = payload_rx  |
-				(1 <<
-				(slave_port_id -
-				SB_PGD_RX_PORT_MULTI_CHANNEL_0_START_PORT_ID));
+		if ((slave_port_id > sh_ch.pgd_tx_port_ch_1_end_port_id) &&
+		    (slave_port_id <= sh_ch.port_ch_0_end_port_id)) {
+			payload_rx = payload_rx |
+				(1 << (slave_port_id -
+				      sh_ch.port_ch_0_start_port_id));
 		} else {
 			ret = -EINVAL;
 			goto err;
 		}
+
 		multi_chan_cfg_reg_addr =
-				SB_PGD_RX_PORT_MULTI_CHANNEL_0(slave_port_id);
+		    SB_PGD_RX_PORT_MULTI_CHANNEL_0(sh_ch.rx_port_ch_reg_base,
+						   idx);
+		pr_debug("%s: multi_chan_cfg_reg_addr 0x%x\n", __func__,
+			 multi_chan_cfg_reg_addr);
+
 		/* write to interface device */
 		ret = wcd9xxx_interface_reg_write(wcd9xxx,
-				multi_chan_cfg_reg_addr,
-				payload_rx);
+						  multi_chan_cfg_reg_addr,
+						  payload_rx);
 		if (ret < 0) {
 			pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
-							__func__,
-							multi_chan_cfg_reg_addr,
-							payload_rx, ret);
+			       __func__, multi_chan_cfg_reg_addr,
+			       payload_rx, ret);
 			goto err;
 		}
 		/* configure the slave port for water mark and enable*/
 		wm_payload = (SLAVE_PORT_WATER_MARK_VALUE <<
-				SLAVE_PORT_WATER_MARK_SHIFT) +
-				SLAVE_PORT_ENABLE;
-		ret = wcd9xxx_interface_reg_write(wcd9xxx,
-				SB_PGD_PORT_CFG_BYTE_ADDR(slave_port_id),
+			      SLAVE_PORT_WATER_MARK_SHIFT) + SLAVE_PORT_ENABLE;
+		ret = wcd9xxx_interface_reg_write(
+				wcd9xxx,
+				SB_PGD_PORT_CFG_BYTE_ADDR(
+				    sh_ch.port_rx_cfg_reg_base, idx),
 				wm_payload);
 		if (ret < 0) {
 			pr_err("%s:watermark set failure for port[%d] ret[%d]",
@@ -283,16 +366,14 @@
 	prop.ratem = (rate/4000);
 	prop.sampleszbits = 16;
 
-	ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt,
-					true, &grph);
+	ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt, true, &grph);
 	if (ret < 0) {
 		pr_err("%s: slim_define_ch failed ret[%d]\n",
 					__func__, ret);
 		goto err;
 	}
 	for (i = 0; i < ch_cnt; i++) {
-		ret = slim_connect_sink(wcd9xxx->slim, &sph[i],
-							1, ch_h[i]);
+		ret = slim_connect_sink(wcd9xxx->slim, &sph[i], 1, ch_h[i]);
 		if (ret < 0) {
 			pr_err("%s: slim_connect_sink failed ret[%d]\n",
 						__func__, ret);
@@ -300,16 +381,14 @@
 		}
 	}
 	/* slim_control_ch */
-	ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_ACTIVATE,
-					true);
+	ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_ACTIVATE, true);
 	if (ret < 0) {
 		pr_err("%s: slim_control_ch failed ret[%d]\n",
 				__func__, ret);
 		goto err_close_slim_sch;
 	}
 	for (i = 0; i < ch_cnt; i++) {
-		idx = (ch_num[i] - BASE_CH_NUM -
-				SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
+		idx = (ch_num[i] - BASE_CH_NUM - sh_ch.rx_port_start_offset);
 		rx[idx].grph = grph;
 	}
 	return 0;
@@ -324,7 +403,7 @@
 
 /* Enable slimbus slave device for RX path */
 int wcd9xxx_cfg_slim_sch_tx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
-				unsigned int ch_cnt, unsigned int rate)
+			    unsigned int ch_cnt, unsigned int rate)
 {
 	u8 i = 0;
 	u8  payload_tx_0 = 0, payload_tx_1 = 0, wm_payload = 0;
@@ -333,7 +412,7 @@
 	u16 ch_h[SLIM_MAX_TX_PORTS] = {0};
 	u16 idx = 0, slave_port_id;
 	int ret = 0;
-	unsigned short  multi_chan_cfg_reg_addr;
+	unsigned short multi_chan_cfg_reg_addr;
 
 	struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
 	struct slim_ch prop;
@@ -343,10 +422,12 @@
 		idx = (ch_num[i] - BASE_CH_NUM);
 		ch_h[i] = tx[idx].ch_h;
 		sph[i] = tx[idx].sph;
-		slave_port_id = idx ;
-		if (slave_port_id > SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS) {
+		slave_port_id = idx;
+		pr_debug("%s: idx %d, ch_h %d, sph %d, slave_port_id %d\n",
+			 __func__, idx, ch_h[i], sph[i], slave_port_id);
+		if (slave_port_id > sh_ch.number_of_tx_slave_dev_ports) {
 			pr_err("SLIMbus: invalid slave port id: %d",
-							slave_port_id);
+			       slave_port_id);
 			ret = -EINVAL;
 			goto err;
 		}
@@ -354,55 +435,60 @@
 		 *  payload accordingly
 		 */
 		if (slave_port_id <=
-			SB_PGD_TX_PORT_MULTI_CHANNEL_0_END_PORT_ID) {
+		    SB_PGD_TX_PORT_MULTI_CHANNEL_0_END_PORT_ID) {
 			payload_tx_0 = payload_tx_0 | (1 << slave_port_id);
 		} else if (slave_port_id <=
-				SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID) {
-				payload_tx_1 = payload_tx_1 |
-				(1 <<
-				(slave_port_id -
-				SB_PGD_TX_PORT_MULTI_CHANNEL_1_START_PORT_ID));
+			   sh_ch.pgd_tx_port_ch_1_end_port_id) {
+			payload_tx_1 = payload_tx_1 |
+			    (1 << (slave_port_id -
+				 SB_PGD_TX_PORT_MULTI_CHANNEL_1_START_PORT_ID));
 		} else {
+			pr_err("%s: slave port id %d error\n", __func__,
+			       slave_port_id);
 			ret = -EINVAL;
 			goto err;
 		}
 		multi_chan_cfg_reg_addr =
-				SB_PGD_TX_PORT_MULTI_CHANNEL_0(slave_port_id);
+		    SB_PGD_TX_PORT_MULTI_CHANNEL_0(slave_port_id);
+		pr_debug("%s: multi_chan_cfg_reg_addr 0x%x\n", __func__,
+			 multi_chan_cfg_reg_addr);
 		/* write to interface device */
 		ret = wcd9xxx_interface_reg_write(wcd9xxx,
 				multi_chan_cfg_reg_addr,
 				payload_tx_0);
 		if (ret < 0) {
 			pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
-								__func__,
-						multi_chan_cfg_reg_addr,
-						payload_tx_0, ret);
+			       __func__, multi_chan_cfg_reg_addr, payload_tx_0,
+			       ret);
 			goto err;
 		}
 		multi_chan_cfg_reg_addr =
-				SB_PGD_TX_PORT_MULTI_CHANNEL_1(slave_port_id);
+		    SB_PGD_TX_PORT_MULTI_CHANNEL_1(slave_port_id);
 		/* ports 8,9 */
 		ret = wcd9xxx_interface_reg_write(wcd9xxx,
-				multi_chan_cfg_reg_addr,
-				payload_tx_1);
+						  multi_chan_cfg_reg_addr,
+						  payload_tx_1);
 		if (ret < 0) {
 			pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
-								__func__,
-						multi_chan_cfg_reg_addr,
-						payload_tx_1, ret);
+			       __func__, multi_chan_cfg_reg_addr,
+			       payload_tx_1, ret);
 			goto err;
 		}
 		/* configure the slave port for water mark and enable*/
 		wm_payload = (SLAVE_PORT_WATER_MARK_VALUE <<
-				SLAVE_PORT_WATER_MARK_SHIFT) +
-				SLAVE_PORT_ENABLE;
-		ret = wcd9xxx_interface_reg_write(wcd9xxx,
-				SB_PGD_PORT_CFG_BYTE_ADDR(slave_port_id),
-				wm_payload);
+			      SLAVE_PORT_WATER_MARK_SHIFT) + SLAVE_PORT_ENABLE;
+		pr_debug("%s: tx_cfg_reg 0x%x wm 0x%x\n", __func__,
+			 SB_PGD_PORT_CFG_BYTE_ADDR(sh_ch.port_tx_cfg_reg_base,
+						   slave_port_id), wm_payload);
+		ret = wcd9xxx_interface_reg_write(
+					wcd9xxx,
+					SB_PGD_PORT_CFG_BYTE_ADDR(
+					    sh_ch.port_tx_cfg_reg_base,
+					    slave_port_id),
+					wm_payload);
 		if (ret < 0) {
-			pr_err("%s:watermark set failure for port[%d] ret[%d]",
-						__func__,
-						slave_port_id, ret);
+			pr_err("%s: watermark set failure for port[%d] ret[%d]",
+			       __func__, slave_port_id, ret);
 		}
 	}
 
@@ -413,25 +499,21 @@
 	prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE;
 	prop.ratem = (rate/4000);
 	prop.sampleszbits = 16;
-	ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt,
-					true, &grph);
+	ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt, true, &grph);
 	if (ret < 0) {
-		pr_err("%s: slim_define_ch failed ret[%d]\n",
-					__func__, ret);
+		pr_err("%s: slim_define_ch failed ret[%d]\n", __func__, ret);
 		goto err;
 	}
 	for (i = 0; i < ch_cnt; i++) {
-		ret = slim_connect_src(wcd9xxx->slim, sph[i],
-							ch_h[i]);
+		ret = slim_connect_src(wcd9xxx->slim, sph[i], ch_h[i]);
 		if (ret < 0) {
 			pr_err("%s: slim_connect_src failed ret[%d]\n",
-						__func__, ret);
+			       __func__, ret);
 			goto err;
 		}
 	}
 	/* slim_control_ch */
-	ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_ACTIVATE,
-					true);
+	ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_ACTIVATE, true);
 	if (ret < 0) {
 		pr_err("%s: slim_control_ch failed ret[%d]\n",
 				__func__, ret);
@@ -460,34 +542,33 @@
 
 	pr_debug("%s: ch_cnt[%d]\n", __func__, ch_cnt);
 	for (i = 0; i < ch_cnt; i++) {
-		idx = (ch_num[i] - BASE_CH_NUM -
-			SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
+		idx = (ch_num[i] - BASE_CH_NUM - sh_ch.rx_port_start_offset);
 		if (idx < 0) {
 			pr_err("%s: Error:-Invalid index found = %d\n",
-				__func__, idx);
+			       __func__, idx);
 			ret = -EINVAL;
 			goto err;
 		}
 		sph[i] = rx[idx].sph;
 		grph = rx[idx].grph;
+		pr_debug("%s: ch_num[%d] %d, idx %d, sph[%d] %x, grph %x\n",
+			 __func__, i, ch_num[i], idx, i, sph[i], grph);
 	}
 
 	/* slim_disconnect_port */
 	ret = slim_disconnect_ports(wcd9xxx->slim, sph, ch_cnt);
 	if (ret < 0) {
 		pr_err("%s: slim_disconnect_ports failed ret[%d]\n",
-				__func__, ret);
+		       __func__, ret);
 	}
 	/* slim_control_ch (REMOVE) */
 	ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_REMOVE, true);
 	if (ret < 0) {
-		pr_err("%s: slim_control_ch failed ret[%d]\n",
-				__func__, ret);
+		pr_err("%s: slim_control_ch failed ret[%d]\n", __func__, ret);
 		goto err;
 	}
 	for (i = 0; i < ch_cnt; i++) {
-		idx = (ch_num[i] - BASE_CH_NUM -
-				SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
+		idx = (ch_num[i] - BASE_CH_NUM - sh_ch.rx_port_start_offset);
 		rx[idx].grph = 0;
 	}
 err:
@@ -496,7 +577,7 @@
 EXPORT_SYMBOL_GPL(wcd9xxx_close_slim_sch_rx);
 
 int wcd9xxx_close_slim_sch_tx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
-				unsigned int ch_cnt)
+			      unsigned int ch_cnt)
 {
 	u16 grph = 0;
 	u32 sph[SLIM_MAX_TX_PORTS] = {0};
diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c
index cf98f68..31b405a 100644
--- a/drivers/platform/msm/sps/bam.c
+++ b/drivers/platform/msm/sps/bam.c
@@ -1152,7 +1152,6 @@
 	return bam_read_reg(base, P_TIMER(pipe));
 }
 
-#ifdef CONFIG_DEBUG_FS
 /* output the content of BAM-level registers */
 void print_bam_reg(void *virt_addr)
 {
@@ -1399,4 +1398,3 @@
 
 	SPS_INFO("--------------------  end of FIFO  --------------------\n");
 }
-#endif
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index 0371f5a..a7f07a6 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -461,6 +461,98 @@
 }
 #endif
 
+/* Get the debug info of BAM registers and descriptor FIFOs */
+int sps_get_bam_debug_info(u32 dev, u32 option, u32 para)
+{
+	int res = 0;
+	struct sps_bam *bam;
+	u32 i;
+	u32 num_pipes = 0;
+	void *vir_addr;
+
+	if (dev == 0) {
+		SPS_ERR("sps:%s:device handle should not be 0.\n", __func__);
+		return SPS_ERROR;
+	}
+
+	mutex_lock(&sps->lock);
+	/* Search for the target BAM device */
+	bam = sps_h2bam(dev);
+	if (bam == NULL) {
+		pr_err("sps:Can't find any BAM with handle 0x%x.", dev);
+		mutex_unlock(&sps->lock);
+		return SPS_ERROR;
+	}
+	mutex_unlock(&sps->lock);
+
+	vir_addr = bam->base;
+	num_pipes = bam->props.num_pipes;
+
+	switch (option) {
+	case 1: /* output all registers of this BAM */
+		print_bam_reg(vir_addr);
+		for (i = 0; i < num_pipes; i++)
+			print_bam_pipe_reg(vir_addr, i);
+		break;
+	case 2: /* output BAM-level registers */
+		print_bam_reg(vir_addr);
+		break;
+	case 3: /* output selected BAM-level registers */
+		print_bam_selected_reg(vir_addr);
+		break;
+	case 4: /* output selected registers of all pipes */
+		for (i = 0; i < num_pipes; i++)
+			print_bam_pipe_selected_reg(vir_addr, i);
+		break;
+	case 5: /* output selected registers of selected pipes */
+		for (i = 0; i < num_pipes; i++)
+			if (para & (1UL << i))
+				print_bam_pipe_selected_reg(vir_addr, i);
+		break;
+	case 6: /* output selected registers of typical pipes */
+		print_bam_pipe_selected_reg(vir_addr, 4);
+		print_bam_pipe_selected_reg(vir_addr, 5);
+		break;
+	case 7: /* output desc FIFO of all pipes */
+		for (i = 0; i < num_pipes; i++)
+			print_bam_pipe_desc_fifo(vir_addr, i);
+		break;
+	case 8: /* output desc FIFO of selected pipes */
+		for (i = 0; i < num_pipes; i++)
+			if (para & (1UL << i))
+				print_bam_pipe_desc_fifo(vir_addr, i);
+		break;
+	case 9: /* output desc FIFO of typical pipes */
+		print_bam_pipe_desc_fifo(vir_addr, 4);
+		print_bam_pipe_desc_fifo(vir_addr, 5);
+		break;
+	case 10: /* output selected registers and desc FIFO of all pipes */
+		for (i = 0; i < num_pipes; i++) {
+			print_bam_pipe_selected_reg(vir_addr, i);
+			print_bam_pipe_desc_fifo(vir_addr, i);
+		}
+		break;
+	case 11: /* output selected registers and desc FIFO of selected pipes */
+		for (i = 0; i < num_pipes; i++)
+			if (para & (1UL << i)) {
+				print_bam_pipe_selected_reg(vir_addr, i);
+				print_bam_pipe_desc_fifo(vir_addr, i);
+			}
+		break;
+	case 12: /* output selected registers and desc FIFO of typical pipes */
+		print_bam_pipe_selected_reg(vir_addr, 4);
+		print_bam_pipe_desc_fifo(vir_addr, 4);
+		print_bam_pipe_selected_reg(vir_addr, 5);
+		print_bam_pipe_desc_fifo(vir_addr, 5);
+		break;
+	default:
+		pr_info("sps:no option is chosen yet.");
+	}
+
+	return res;
+}
+EXPORT_SYMBOL(sps_get_bam_debug_info);
+
 /**
  * Initialize SPS device
  *
diff --git a/drivers/platform/msm/sps/spsi.h b/drivers/platform/msm/sps/spsi.h
index 5a141ca..43a50bd 100644
--- a/drivers/platform/msm/sps/spsi.h
+++ b/drivers/platform/msm/sps/spsi.h
@@ -183,6 +183,7 @@
 #ifdef CONFIG_DEBUG_FS
 /* record debug info for debugfs */
 void sps_debugfs_record(const char *);
+#endif
 
 /* output the content of BAM-level registers */
 void print_bam_reg(void *);
@@ -198,7 +199,6 @@
 
 /* output descriptor FIFO of a pipe */
 void print_bam_pipe_desc_fifo(void *, u32);
-#endif
 
 /**
  * Translate physical to virtual address
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index 72564b0..2198954 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -2516,6 +2516,18 @@
 	u32 segdist;
 	struct slim_pending_ch *pch;
 
+	/*
+	 * If there are no pending changes from this client, avoid sending
+	 * the reconfiguration sequence
+	 */
+	if (sb->pending_msgsl == sb->cur_msgsl &&
+		list_empty(&sb->mark_define) &&
+		list_empty(&sb->mark_removal) &&
+		list_empty(&sb->mark_suspend)) {
+		pr_debug("SLIM_CL: skip reconfig sequence");
+		return 0;
+	}
+
 	mutex_lock(&ctrl->sched.m_reconf);
 	mutex_lock(&ctrl->m_ctrl);
 	ctrl->sched.pending_msgsl += sb->pending_msgsl - sb->cur_msgsl;
@@ -2538,7 +2550,6 @@
 		struct slim_ich *slc = &ctrl->chans[pch->chan];
 		slc->state = SLIM_CH_SUSPENDED;
 	}
-	mutex_unlock(&ctrl->m_ctrl);
 
 	ret = slim_allocbw(sb, &subframe, &clkgear);
 
@@ -2688,7 +2699,6 @@
 			NULL, 0, 3, NULL, 0, NULL);
 	dev_dbg(&ctrl->dev, "reconfig now:ret:%d\n", ret);
 	if (!ret) {
-		mutex_lock(&ctrl->m_ctrl);
 		ctrl->sched.subfrmcode = subframe;
 		ctrl->clkgear = clkgear;
 		ctrl->sched.msgsl = ctrl->sched.pending_msgsl;
@@ -2700,7 +2710,6 @@
 	}
 
 revert_reconfig:
-	mutex_lock(&ctrl->m_ctrl);
 	/* Revert channel changes */
 	slim_chan_changes(sb, true);
 	mutex_unlock(&ctrl->m_ctrl);
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index 422e99e..ae1eff8 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -79,6 +79,7 @@
 #define PMIC_ARB_MAX_PERIPHS		256
 #define PMIC_ARB_PERIPH_ID_VALID	(1 << 15)
 #define PMIC_ARB_TIMEOUT_US		100
+#define PMIC_ARB_MAX_TRANS_BYTES	(8)
 
 #define PMIC_ARB_APID_MASK				0xFF
 #define PMIC_ARB_PPID_MASK				0xFFF
@@ -160,49 +161,29 @@
 	return -ETIMEDOUT;
 }
 
+/**
+ * pa_read_data: reads pmic-arb's register and copy 1..4 bytes to buf
+ * @bc byte count -1. range: 0..3
+ * @reg register's address
+ * @buf output parameter, length must be bc+1
+ */
 static void pa_read_data(struct spmi_pmic_arb_dev *dev, u8 *buf, u32 reg, u8 bc)
 {
 	u32 data = pmic_arb_read(dev, reg);
-
-	switch (bc & 0x3) {
-	case 3:
-		*buf++ = data & 0xff;
-		data >>= 8;
-	case 2:
-		*buf++ = data & 0xff;
-		data >>= 8;
-	case 1:
-		*buf++ = data & 0xff;
-		data >>= 8;
-	case 0:
-		*buf++ = data & 0xff;
-	default:
-		break;
-	}
+	memcpy(buf, &data, (bc & 3) + 1);
 }
 
+/**
+ * pa_write_data: write 1..4 bytes from buf to pmic-arb's register
+ * @bc byte-count -1. range: 0..3
+ * @reg register's address
+ * @buf buffer to write. length must be bc+1
+ */
 static void
 pa_write_data(struct spmi_pmic_arb_dev *dev, u8 *buf, u32 reg, u8 bc)
 {
 	u32 data = 0;
-
-	switch (bc & 0x3) {
-	case 3:
-		data = (buf[0]|buf[1]<<8|buf[2]<<16|buf[3]<<24);
-		break;
-	case 2:
-		data = (buf[0]|buf[1]<<8|buf[2]<<16);
-		break;
-	case 1:
-		data = (buf[0]|buf[1]<<8);
-		break;
-	case 0:
-		data = (buf[0]);
-		break;
-	default:
-		break;
-	}
-
+	memcpy(&data, buf, (bc & 3) + 1);
 	pmic_arb_write(dev, reg, data);
 }
 
@@ -238,6 +219,12 @@
 	u32 cmd;
 	int rc;
 
+	if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
+		dev_err(pmic_arb->dev
+		, "pmic-arb supports 1..%d bytes per trans, but:%d requested"
+					, PMIC_ARB_MAX_TRANS_BYTES, bc+1);
+		return  -EINVAL;
+	}
 	pr_debug("op:0x%x sid:%d bc:%d addr:0x%x\n", opc, sid, bc, addr);
 
 	/* Check the opcode */
@@ -259,11 +246,12 @@
 		goto done;
 
 	/* Read from FIFO, note 'bc' is actually number of bytes minus 1 */
-	pa_read_data(pmic_arb, buf, PMIC_ARB_RDATA0(pmic_arb->channel), bc);
+	pa_read_data(pmic_arb, buf, PMIC_ARB_RDATA0(pmic_arb->channel)
+							, min_t(u8, bc, 3));
 
 	if (bc > 3)
 		pa_read_data(pmic_arb, buf + 4,
-				PMIC_ARB_RDATA1(pmic_arb->channel), bc);
+				PMIC_ARB_RDATA1(pmic_arb->channel), bc - 4);
 
 done:
 	spin_unlock_irqrestore(&pmic_arb->lock, flags);
@@ -278,6 +266,12 @@
 	u32 cmd;
 	int rc;
 
+	if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
+		dev_err(pmic_arb->dev
+		, "pmic-arb supports 1..%d bytes per trans, but:%d requested"
+					, PMIC_ARB_MAX_TRANS_BYTES, bc+1);
+		return  -EINVAL;
+	}
 	pr_debug("op:0x%x sid:%d bc:%d addr:0x%x\n", opc, sid, bc, addr);
 
 	/* Check the opcode */
@@ -296,11 +290,11 @@
 
 	/* Write data to FIFOs */
 	spin_lock_irqsave(&pmic_arb->lock, flags);
-	pa_write_data(pmic_arb, buf, PMIC_ARB_WDATA0(pmic_arb->channel), bc);
-
+	pa_write_data(pmic_arb, buf, PMIC_ARB_WDATA0(pmic_arb->channel)
+							, min_t(u8, bc, 3));
 	if (bc > 3)
 		pa_write_data(pmic_arb, buf + 4,
-				PMIC_ARB_WDATA1(pmic_arb->channel), bc);
+				PMIC_ARB_WDATA1(pmic_arb->channel), bc - 4);
 
 	/* Start the transaction */
 	pmic_arb_write(pmic_arb, PMIC_ARB_CMD(pmic_arb->channel), cmd);
diff --git a/drivers/tty/smux_ctl.c b/drivers/tty/smux_ctl.c
index 0078b04..7e0e6f8 100644
--- a/drivers/tty/smux_ctl.c
+++ b/drivers/tty/smux_ctl.c
@@ -33,6 +33,7 @@
 #include <linux/smux.h>
 #include <linux/slab.h>
 #include <linux/debugfs.h>
+#include <linux/poll.h>
 
 #include <asm/ioctls.h>
 
@@ -753,6 +754,33 @@
 	return ret;
 }
 
+static unsigned int smux_ctl_poll(struct file *file, poll_table *wait)
+{
+	struct smux_ctl_dev *devp;
+	unsigned int mask = 0;
+	int readable;
+
+	devp = file->private_data;
+	if (!devp)
+		return -ENODEV;
+
+	SMUXCTL_DBG(SMUX_CTL_MODULE_NAME ": %s called on smuxctl%d\n",
+			__func__, devp->id);
+
+	poll_wait(file, &devp->read_wait_queue, wait);
+
+	readable = smux_ctl_readable(devp->id);
+	if (readable < 0) {
+		pr_err(SMUX_CTL_MODULE_NAME ": %s err%d during poll for smuxctl%d\n",
+			__func__, readable, devp->id);
+		mask = POLLERR;
+	} else if (readable) {
+		mask = POLLIN | POLLRDNORM;
+	}
+
+	return mask;
+}
+
 static const struct file_operations smux_ctl_fops = {
 	.owner = THIS_MODULE,
 	.open = smux_ctl_open,
@@ -760,6 +788,7 @@
 	.read = smux_ctl_read,
 	.write = smux_ctl_write,
 	.unlocked_ioctl = smux_ctl_ioctl,
+	.poll = smux_ctl_poll,
 };
 
 static void smux_ctl_reset_channel(struct smux_ctl_dev *devp)
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 78ab8b7..fd10394 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -46,6 +46,8 @@
 
 #define UETH__VERSION	"29-May-2008"
 
+static struct workqueue_struct	*uether_wq;
+
 struct eth_dev {
 	/* lock is held while accessing port_usb
 	 * or updating its backlink port_usb->ioport
@@ -74,6 +76,7 @@
 						struct sk_buff_head *list);
 
 	struct work_struct	work;
+	struct work_struct	rx_work;
 
 	unsigned long		todo;
 #define	WORK_RX_MEMORY		0
@@ -88,7 +91,6 @@
 
 #define DEFAULT_QLEN	2	/* double buffering by default */
 
-
 #ifdef CONFIG_USB_GADGET_DUALSPEED
 
 static unsigned qmult = 10;
@@ -265,18 +267,16 @@
 		DBG(dev, "rx submit --> %d\n", retval);
 		if (skb)
 			dev_kfree_skb_any(skb);
-		spin_lock_irqsave(&dev->req_lock, flags);
-		list_add(&req->list, &dev->rx_reqs);
-		spin_unlock_irqrestore(&dev->req_lock, flags);
 	}
 	return retval;
 }
 
 static void rx_complete(struct usb_ep *ep, struct usb_request *req)
 {
-	struct sk_buff	*skb = req->context, *skb2;
+	struct sk_buff	*skb = req->context;
 	struct eth_dev	*dev = ep->driver_data;
 	int		status = req->status;
+	bool		queue = 0;
 
 	switch (status) {
 
@@ -300,30 +300,9 @@
 		} else {
 			skb_queue_tail(&dev->rx_frames, skb);
 		}
-		skb = NULL;
 
-		skb2 = skb_dequeue(&dev->rx_frames);
-		while (skb2) {
-			if (status < 0
-					|| ETH_HLEN > skb2->len
-					|| skb2->len > ETH_FRAME_LEN) {
-				dev->net->stats.rx_errors++;
-				dev->net->stats.rx_length_errors++;
-				DBG(dev, "rx length %d\n", skb2->len);
-				dev_kfree_skb_any(skb2);
-				goto next_frame;
-			}
-			skb2->protocol = eth_type_trans(skb2, dev->net);
-			dev->net->stats.rx_packets++;
-			dev->net->stats.rx_bytes += skb2->len;
-
-			/* no buffer copies needed, unless hardware can't
-			 * use skb buffers.
-			 */
-			status = netif_rx(skb2);
-next_frame:
-			skb2 = skb_dequeue(&dev->rx_frames);
-		}
+		if (!status)
+			queue = 1;
 		break;
 
 	/* software-driven interface shutdown */
@@ -346,22 +325,20 @@
 		/* FALLTHROUGH */
 
 	default:
+		queue = 1;
+		dev_kfree_skb_any(skb);
 		dev->net->stats.rx_errors++;
 		DBG(dev, "rx status %d\n", status);
 		break;
 	}
 
-	if (skb)
-		dev_kfree_skb_any(skb);
-	if (!netif_running(dev->net)) {
 clean:
-		spin_lock(&dev->req_lock);
-		list_add(&req->list, &dev->rx_reqs);
-		spin_unlock(&dev->req_lock);
-		req = NULL;
-	}
-	if (req)
-		rx_submit(dev, req, GFP_ATOMIC);
+	spin_lock(&dev->req_lock);
+	list_add(&req->list, &dev->rx_reqs);
+	spin_unlock(&dev->req_lock);
+
+	if (queue)
+		queue_work(uether_wq, &dev->rx_work);
 }
 
 static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n)
@@ -426,16 +403,24 @@
 {
 	struct usb_request	*req;
 	unsigned long		flags;
+	int			req_cnt = 0;
 
 	/* fill unused rxq slots with some skb */
 	spin_lock_irqsave(&dev->req_lock, flags);
 	while (!list_empty(&dev->rx_reqs)) {
+		/* break the nexus of continuous completion and re-submission*/
+		if (++req_cnt > qlen(dev->gadget))
+			break;
+
 		req = container_of(dev->rx_reqs.next,
 				struct usb_request, list);
 		list_del_init(&req->list);
 		spin_unlock_irqrestore(&dev->req_lock, flags);
 
 		if (rx_submit(dev, req, gfp_flags) < 0) {
+			spin_lock_irqsave(&dev->req_lock, flags);
+			list_add(&req->list, &dev->rx_reqs);
+			spin_unlock_irqrestore(&dev->req_lock, flags);
 			defer_kevent(dev, WORK_RX_MEMORY);
 			return;
 		}
@@ -445,6 +430,36 @@
 	spin_unlock_irqrestore(&dev->req_lock, flags);
 }
 
+static void process_rx_w(struct work_struct *work)
+{
+	struct eth_dev	*dev = container_of(work, struct eth_dev, rx_work);
+	struct sk_buff	*skb;
+	int		status = 0;
+
+	if (!dev->port_usb)
+		return;
+
+	while ((skb = skb_dequeue(&dev->rx_frames))) {
+		if (status < 0
+				|| ETH_HLEN > skb->len
+				|| skb->len > ETH_FRAME_LEN) {
+			dev->net->stats.rx_errors++;
+			dev->net->stats.rx_length_errors++;
+			DBG(dev, "rx length %d\n", skb->len);
+			dev_kfree_skb_any(skb);
+			continue;
+		}
+		skb->protocol = eth_type_trans(skb, dev->net);
+		dev->net->stats.rx_packets++;
+		dev->net->stats.rx_bytes += skb->len;
+
+		status = netif_rx_ni(skb);
+	}
+
+	if (netif_running(dev->net))
+		rx_fill(dev, GFP_KERNEL);
+}
+
 static void eth_work(struct work_struct *work)
 {
 	struct eth_dev	*dev = container_of(work, struct eth_dev, work);
@@ -931,6 +946,7 @@
 	spin_lock_init(&dev->lock);
 	spin_lock_init(&dev->req_lock);
 	INIT_WORK(&dev->work, eth_work);
+	INIT_WORK(&dev->rx_work, process_rx_w);
 	INIT_LIST_HEAD(&dev->tx_reqs);
 	INIT_LIST_HEAD(&dev->rx_reqs);
 
@@ -1096,6 +1112,7 @@
 {
 	struct eth_dev		*dev = link->ioport;
 	struct usb_request	*req;
+	struct sk_buff		*skb;
 
 	if (!dev)
 		return;
@@ -1138,6 +1155,12 @@
 		spin_lock(&dev->req_lock);
 	}
 	spin_unlock(&dev->req_lock);
+
+	spin_lock(&dev->rx_frames.lock);
+	while ((skb = __skb_dequeue(&dev->rx_frames)))
+		dev_kfree_skb_any(skb);
+	spin_unlock(&dev->rx_frames.lock);
+
 	link->out_ep->driver_data = NULL;
 	link->out_ep->desc = NULL;
 
@@ -1151,3 +1174,23 @@
 	link->ioport = NULL;
 	spin_unlock(&dev->lock);
 }
+
+static int __init gether_init(void)
+{
+	uether_wq  = create_singlethread_workqueue("uether");
+	if (!uether_wq) {
+		pr_err("%s: Unable to create workqueue: uether\n", __func__);
+		return -ENOMEM;
+	}
+	return 0;
+}
+module_init(gether_init);
+
+static void __exit gether_exit(void)
+{
+	destroy_workqueue(uether_wq);
+
+}
+module_exit(gether_exit);
+MODULE_DESCRIPTION("ethernet over USB driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index c397f84..ee73eea 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -68,6 +68,8 @@
 boolean mdp_current_clk_on = FALSE;
 boolean mdp_is_in_isr = FALSE;
 
+struct vsync vsync_cntrl;
+
 /*
  * legacy mdp_in_processing is only for DMA2-MDDI
  * this applies to DMA2 block only
@@ -95,13 +97,13 @@
 static struct delayed_work mdp_pipe_ctrl_worker;
 
 static boolean mdp_suspended = FALSE;
+ulong mdp4_display_intf;
 DEFINE_MUTEX(mdp_suspend_mutex);
 
 #ifdef CONFIG_FB_MSM_MDP40
 struct mdp_dma_data dma2_data;
 struct mdp_dma_data dma_s_data;
 struct mdp_dma_data dma_e_data;
-ulong mdp4_display_intf;
 #else
 static struct mdp_dma_data dma2_data;
 static struct mdp_dma_data dma_s_data;
@@ -1270,8 +1272,56 @@
 }
 #endif
 
-/* Returns < 0 on error, 0 on timeout, or > 0 on successful wait */
+static void send_vsync_work(struct work_struct *work)
+{
+	char buf[64];
+	char *envp[2];
 
+	snprintf(buf, sizeof(buf), "VSYNC=%llu",
+			ktime_to_ns(vsync_cntrl.vsync_time));
+	envp[0] = buf;
+	envp[1] = NULL;
+	kobject_uevent_env(&(vsync_cntrl.dev->kobj), KOBJ_CHANGE, envp);
+}
+
+void mdp3_vsync_irq_enable(int intr, int term)
+{
+	unsigned long flag;
+
+	spin_lock_irqsave(&mdp_spin_lock, flag);
+	outp32(MDP_INTR_CLEAR, intr);
+	mdp_intr_mask |= intr;
+	outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+	mdp_enable_irq(term);
+	spin_unlock_irqrestore(&mdp_spin_lock, flag);
+}
+
+void mdp3_vsync_irq_disable(int intr, int term)
+{
+	unsigned long flag;
+
+	spin_lock_irqsave(&mdp_spin_lock, flag);
+	/* required to synchronize between frame update and vsync
+	 * since both use the same LCDC_FRAME_START interrupt
+	 */
+	if (intr == LCDC_FRAME_START && dma2_data.waiting == FALSE) {
+		mdp_intr_mask &= ~intr;
+		outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+	}
+	mdp_disable_irq(term);
+	spin_unlock_irqrestore(&mdp_spin_lock, flag);
+}
+
+#ifdef CONFIG_FB_MSM_MDP303
+/* vsync_isr_handler: Called from isr context*/
+static void vsync_isr_handler(void)
+{
+	vsync_cntrl.vsync_time = ktime_get();
+	schedule_work(&(vsync_cntrl.vsync_work));
+}
+#endif
+
+/* Returns < 0 on error, 0 on timeout, or > 0 on successful wait */
 int mdp_ppp_pipe_wait(void)
 {
 	int ret = 1;
@@ -1729,6 +1779,10 @@
 	if (!mdp_interrupt)
 		goto out;
 
+	/*Primary Vsync interrupt*/
+	if (mdp_interrupt & MDP_PRIM_RDPTR)
+		vsync_isr_handler();
+
 	/* DMA3 TV-Out Start */
 	if (mdp_interrupt & TV_OUT_DMA3_START) {
 		/* let's disable TV out interrupt */
@@ -1776,12 +1830,19 @@
 			dma = &dma2_data;
 			spin_lock_irqsave(&mdp_spin_lock, flag);
 			/* let's disable LCDC interrupt */
-			mdp_intr_mask &= ~LCDC_FRAME_START;
-			outp32(MDP_INTR_ENABLE, mdp_intr_mask);
 			if (dma->waiting) {
 				dma->waiting = FALSE;
 				complete(&dma->comp);
 			}
+
+			if (vsync_cntrl.vsync_irq_enabled)
+				vsync_isr_handler();
+
+			if (!vsync_cntrl.vsync_irq_enabled && !(dma->waiting)) {
+				mdp_intr_mask &= ~LCDC_FRAME_START;
+				outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+			}
+
 			spin_unlock_irqrestore(&mdp_spin_lock, flag);
 		}
 
@@ -1912,7 +1973,7 @@
 	for (i = 0; i < MDP_MAX_BLOCK; i++) {
 		atomic_set(&mdp_block_power_cnt[i], 0);
 	}
-
+	INIT_WORK(&(vsync_cntrl.vsync_work), send_vsync_work);
 #ifdef MSM_FB_ENABLE_DBGFS
 	{
 		struct dentry *root;
@@ -2030,33 +2091,39 @@
 static int mdp_on(struct platform_device *pdev)
 {
 	int ret = 0;
-#ifdef CONFIG_FB_MSM_MDP40
 	struct msm_fb_data_type *mfd;
-
 	mfd = platform_get_drvdata(pdev);
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	mdp_clk_ctrl(1);
-	mdp4_hw_init();
-	outpdw(MDP_BASE + 0x0038, mdp4_display_intf);
-	if (mfd->panel.type == MIPI_CMD_PANEL) {
-		mdp_vsync_cfg_regs(mfd, FALSE);
-		mdp4_dsi_cmd_on(pdev);
-	} else if (mfd->panel.type == MIPI_VIDEO_PANEL)
-		mdp4_dsi_video_on(pdev);
-	else if (mfd->panel.type == HDMI_PANEL ||
-			mfd->panel.type == LCDC_PANEL ||
-			mfd->panel.type == LVDS_PANEL)
-		mdp4_lcdc_on(pdev);
 
-	mdp_clk_ctrl(0);
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-#endif
+	if (mdp_rev >= MDP_REV_40) {
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+		mdp_clk_ctrl(1);
+		mdp4_hw_init();
+		outpdw(MDP_BASE + 0x0038, mdp4_display_intf);
+		if (mfd->panel.type == MIPI_CMD_PANEL) {
+			mdp_vsync_cfg_regs(mfd, FALSE);
+			mdp4_dsi_cmd_on(pdev);
+		} else if (mfd->panel.type == MIPI_VIDEO_PANEL) {
+			mdp4_dsi_video_on(pdev);
+		} else if (mfd->panel.type == HDMI_PANEL ||
+				mfd->panel.type == LCDC_PANEL ||
+				mfd->panel.type == LVDS_PANEL) {
+			mdp4_lcdc_on(pdev);
+		}
+
+		mdp_clk_ctrl(0);
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+	}
+
+	if ((mdp_rev == MDP_REV_303) &&
+			(mfd->panel.type == MIPI_CMD_PANEL))
+		vsync_cntrl.dev = mfd->fbi->dev;
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 
 	ret = panel_next_on(pdev);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
+
 	mdp_histogram_ctrl_all(TRUE);
 
 	return ret;
@@ -2518,6 +2585,7 @@
 		mfd->do_histogram = mdp_do_histogram;
 		mfd->start_histogram = mdp_histogram_start;
 		mfd->stop_histogram = mdp_histogram_stop;
+		mfd->vsync_ctrl = mdp_dma_video_vsync_ctrl;
 		if (mfd->panel_info.pdest == DISPLAY_1)
 			mfd->dma = &dma2_data;
 		else {
@@ -2564,6 +2632,7 @@
 		mfd->do_histogram = mdp_do_histogram;
 		mfd->start_histogram = mdp_histogram_start;
 		mfd->stop_histogram = mdp_histogram_stop;
+		mfd->vsync_ctrl = mdp_dma_vsync_ctrl;
 		if (mfd->panel_info.pdest == DISPLAY_1)
 			mfd->dma = &dma2_data;
 		else {
@@ -2631,6 +2700,7 @@
 		}
 #else
 		mfd->dma = &dma2_data;
+		mfd->vsync_ctrl = mdp_dma_lcdc_vsync_ctrl;
 		spin_lock_irqsave(&mdp_spin_lock, flag);
 		mdp_intr_mask &= ~MDP_DMA_P_DONE;
 		outp32(MDP_INTR_ENABLE, mdp_intr_mask);
@@ -2683,11 +2753,12 @@
 		mdp_clk_ctrl(0);
 		goto mdp_probe_err;
 	}
-#ifdef CONFIG_FB_MSM_MDP40
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	mdp4_display_intf = inpdw(MDP_BASE + 0x0038);
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-#endif
+
+	if (mdp_rev >= MDP_REV_40) {
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+		mdp4_display_intf = inpdw(MDP_BASE + 0x0038);
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+	}
 
 	mdp_clk_ctrl(0);
 
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 2411dca..12bd1d4 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -44,9 +44,10 @@
 extern int mdp_rev;
 extern int mdp_iommu_split_domain;
 extern struct mdp_csc_cfg mdp_csc_convert[4];
-
 extern struct workqueue_struct *mdp_hist_wq;
 
+extern uint32 mdp_intr_mask;
+
 #define MDP4_REVISION_V1		0
 #define MDP4_REVISION_V2		1
 #define MDP4_REVISION_V2_1	2
@@ -90,6 +91,15 @@
 extern unsigned char hdmi_prim_display;
 extern unsigned char hdmi_prim_resolution;
 
+struct vsync {
+	ktime_t vsync_time;
+	struct device *dev;
+	struct work_struct vsync_work;
+	int vsync_irq_enabled;
+};
+
+extern struct vsync vsync_cntrl;
+
 /*
  * MDP Image Structure
  */
@@ -287,6 +297,7 @@
 #define MDP_HISTOGRAM_TERM_DMA_S 0x20000
 #define MDP_HISTOGRAM_TERM_VG_1 0x40000
 #define MDP_HISTOGRAM_TERM_VG_2 0x80000
+#define MDP_VSYNC_TERM 0x1000
 
 #define ACTIVE_START_X_EN BIT(31)
 #define ACTIVE_START_Y_EN BIT(31)
@@ -306,6 +317,7 @@
 #define MDP_PPP_DONE 				BIT(0)
 #define TV_OUT_DMA3_DONE    BIT(6)
 #define TV_ENC_UNDERRUN     BIT(7)
+#define MDP_PRIM_RDPTR      BIT(8)
 #define TV_OUT_DMA3_START   BIT(13)
 #define MDP_HIST_DONE       BIT(20)
 
@@ -812,6 +824,11 @@
 	return 0;
 }
 #endif
+void mdp_dma_vsync_ctrl(int enable);
+void mdp_dma_video_vsync_ctrl(int enable);
+void mdp_dma_lcdc_vsync_ctrl(int enable);
+void mdp3_vsync_irq_enable(int intr, int term);
+void mdp3_vsync_irq_disable(int intr, int term);
 
 #ifdef MDP_HW_VSYNC
 void vsync_clk_enable(void);
@@ -862,6 +879,11 @@
 {
 	/* empty */
 }
+static inline int msmfb_overlay_vsync_ctrl(struct fb_info *info,
+						void __user *argp)
+{
+	return 0;
+}
 #endif
 
 int mdp_ppp_v4l2_overlay_set(struct fb_info *info, struct mdp_overlay *req);
diff --git a/drivers/video/msm/mdp_dma.c b/drivers/video/msm/mdp_dma.c
index 3a7513a..a506648 100644
--- a/drivers/video/msm/mdp_dma.c
+++ b/drivers/video/msm/mdp_dma.c
@@ -512,6 +512,23 @@
 	up(&mfd->dma->mutex);
 }
 
+void mdp_dma_vsync_ctrl(int enable)
+{
+	if (vsync_cntrl.vsync_irq_enabled == enable)
+		return;
+
+	vsync_cntrl.vsync_irq_enabled = enable;
+
+	if (enable) {
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+		MDP_OUTP(MDP_BASE + 0x021c, 0x10); /* read pointer */
+		mdp3_vsync_irq_enable(MDP_PRIM_RDPTR, MDP_VSYNC_TERM);
+	} else {
+		mdp3_vsync_irq_disable(MDP_PRIM_RDPTR, MDP_VSYNC_TERM);
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+	}
+}
+
 void mdp_lcd_update_workqueue_handler(struct work_struct *work)
 {
 	struct msm_fb_data_type *mfd = NULL;
diff --git a/drivers/video/msm/mdp_dma_dsi_video.c b/drivers/video/msm/mdp_dma_dsi_video.c
index 3d6448f..d94896f 100644
--- a/drivers/video/msm/mdp_dma_dsi_video.c
+++ b/drivers/video/msm/mdp_dma_dsi_video.c
@@ -87,6 +87,7 @@
 	fbi = mfd->fbi;
 	var = &fbi->var;
 
+	vsync_cntrl.dev = mfd->fbi->dev;
 	bpp = fbi->var.bits_per_pixel / 8;
 	buf = (uint8 *) fbi->fix.smem_start;
 
@@ -246,6 +247,22 @@
 	return ret;
 }
 
+void mdp_dma_video_vsync_ctrl(int enable)
+{
+	if (vsync_cntrl.vsync_irq_enabled == enable)
+		return;
+
+	vsync_cntrl.vsync_irq_enabled = enable;
+
+	if (enable) {
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+		mdp3_vsync_irq_enable(LCDC_FRAME_START, MDP_VSYNC_TERM);
+	} else {
+		mdp3_vsync_irq_disable(LCDC_FRAME_START, MDP_VSYNC_TERM);
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+	}
+}
+
 void mdp_dsi_video_update(struct msm_fb_data_type *mfd)
 {
 	struct fb_info *fbi = mfd->fbi;
diff --git a/drivers/video/msm/mdp_dma_lcdc.c b/drivers/video/msm/mdp_dma_lcdc.c
index f9bf269..e030c99 100644
--- a/drivers/video/msm/mdp_dma_lcdc.c
+++ b/drivers/video/msm/mdp_dma_lcdc.c
@@ -105,6 +105,7 @@
 
 	fbi = mfd->fbi;
 	var = &fbi->var;
+	vsync_cntrl.dev = mfd->fbi->dev;
 
 	/* MDP cmd block enable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
@@ -327,6 +328,22 @@
 	return ret;
 }
 
+void mdp_dma_lcdc_vsync_ctrl(int enable)
+{
+	if (vsync_cntrl.vsync_irq_enabled == enable)
+		return;
+
+	vsync_cntrl.vsync_irq_enabled = enable;
+
+	if (enable) {
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+		mdp3_vsync_irq_enable(LCDC_FRAME_START, MDP_VSYNC_TERM);
+	} else {
+		mdp3_vsync_irq_disable(LCDC_FRAME_START, MDP_VSYNC_TERM);
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+	}
+}
+
 void mdp_lcdc_update(struct msm_fb_data_type *mfd)
 {
 	struct fb_info *fbi = mfd->fbi;
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index a984637..18ec3f1 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -377,6 +377,7 @@
 	if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
 		return -ENOMEM;
 
+	vsync_cntrl.dev = mfd->fbi->dev;
 	mfd->panel_info.frame_count = 0;
 	mfd->bl_level = 0;
 	bl_scale = 1024;
@@ -2819,6 +2820,27 @@
 	return 0;
 }
 
+static int msmfb_vsync_ctrl(struct fb_info *info, void __user *argp)
+{
+	int enable, ret;
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+
+	ret = copy_from_user(&enable, argp, sizeof(enable));
+	if (ret) {
+		pr_err("%s:msmfb_overlay_vsync ioctl failed", __func__);
+		return ret;
+	}
+
+	if (mfd->vsync_ctrl)
+		mfd->vsync_ctrl(enable);
+	else {
+		pr_err("%s: Vsync IOCTL not supported", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 #ifdef CONFIG_FB_MSM_OVERLAY
 static int msmfb_overlay_get(struct fb_info *info, void __user *p)
 {
@@ -2881,25 +2903,6 @@
 	return mdp4_overlay_unset(info, ndx);
 }
 
-static int msmfb_overlay_wait4vsync(struct fb_info *info, void __user *argp)
-{
-	int ret;
-	long long vtime;
-
-	ret = mdp4_overlay_wait4vsync(info, &vtime);
-	if (ret) {
-		pr_err("%s: ioctl failed\n", __func__);
-		return ret;
-	}
-
-	if (copy_to_user(argp, &vtime, sizeof(vtime))) {
-		pr_err("%s: copy2user failed\n", __func__);
-		return -EFAULT;
-	}
-
-	return 0;
-}
-
 static int msmfb_overlay_vsync_ctrl(struct fb_info *info, void __user *argp)
 {
 	int ret;
@@ -3331,16 +3334,6 @@
 
 	switch (cmd) {
 #ifdef CONFIG_FB_MSM_OVERLAY
-	case FBIO_WAITFORVSYNC:
-		down(&msm_fb_ioctl_ppp_sem);
-		ret = msmfb_overlay_wait4vsync(info, argp);
-		up(&msm_fb_ioctl_ppp_sem);
-		break;
-	case MSMFB_OVERLAY_VSYNC_CTRL:
-		down(&msm_fb_ioctl_ppp_sem);
-		ret = msmfb_overlay_vsync_ctrl(info, argp);
-		up(&msm_fb_ioctl_ppp_sem);
-		break;
 	case MSMFB_OVERLAY_GET:
 		down(&msm_fb_ioctl_ppp_sem);
 		ret = msmfb_overlay_get(info, argp);
@@ -3409,6 +3402,15 @@
 		ret = msmfb_overlay_ioctl_writeback_terminate(info);
 		break;
 #endif
+	case MSMFB_VSYNC_CTRL:
+	case MSMFB_OVERLAY_VSYNC_CTRL:
+		down(&msm_fb_ioctl_ppp_sem);
+		if (mdp_rev >= MDP_REV_40)
+			ret = msmfb_overlay_vsync_ctrl(info, argp);
+		else
+			ret = msmfb_vsync_ctrl(info, argp);
+		up(&msm_fb_ioctl_ppp_sem);
+		break;
 	case MSMFB_BLIT:
 		down(&msm_fb_ioctl_ppp_sem);
 		ret = msmfb_blit(info, argp);
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index 0658365..efe6160 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -80,6 +80,7 @@
 	DISP_TARGET dest;
 	struct fb_info *fbi;
 
+	struct device *dev;
 	boolean op_enable;
 	uint32 fb_imgType;
 	boolean sw_currently_refreshing;
@@ -134,6 +135,7 @@
 			      struct mdp_histogram_data *hist);
 	int (*start_histogram) (struct mdp_histogram_start_req *req);
 	int (*stop_histogram) (struct fb_info *info, uint32_t block);
+	void (*vsync_ctrl) (int enable);
 	void *cursor_buf;
 	void *cursor_buf_phys;
 
diff --git a/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h b/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
index 93c21ce..9619527 100644
--- a/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
+++ b/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
@@ -16,10 +16,6 @@
 #include <linux/slimbus/slimbus.h>
 #include <linux/mfd/wcd9xxx/core.h>
 
-/* Local to the core only */
-#define SLIM_MAX_RX_PORTS 7
-#define SLIM_MAX_TX_PORTS 10
-
 /* Channel numbers to be used for each port */
 enum {
 	SLIM_TX_1   = 128,
@@ -43,20 +39,43 @@
 };
 
 /*
- *  client is expected to give port ids in the range of 1-10 for Tx ports and
- *  1-7 for Rx ports, we need to add offset for getting the absolute slave
+ *  client is expected to give port ids in the range of
+ *  1-10 for pre Taiko Tx ports and 1-16 for Taiko
+ *  1-7 for pre Taiko Rx ports and 1-16 for Tako,
+ *  we need to add offset for getting the absolute slave
  *  port id before configuring the HW
  */
-#define SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS 10
-#define SB_PGD_OFFSET_OF_TX_SLAVE_DEV_PORTS     -1
-#define SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS 7
-#define SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS     9
+#define TABLA_SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS 10
+#define TAIKO_SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS 16
+
+#define SLIM_MAX_TX_PORTS TAIKO_SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS
+
+#define TABLA_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS \
+	TABLA_SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS
+#define TAIKO_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS \
+	TAIKO_SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS
+
+#define TABLA_SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS 7
+#define TAIKO_SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS 13
+
+#define SLIM_MAX_RX_PORTS TAIKO_SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS
+
+#define TABLA_SB_PGD_RX_PORT_MULTI_CHANNEL_0_START_PORT_ID \
+	TABLA_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS
+#define TAIKO_SB_PGD_RX_PORT_MULTI_CHANNEL_0_START_PORT_ID \
+	TAIKO_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS
+
+#define TABLA_SB_PGD_RX_PORT_MULTI_CHANNEL_0_END_PORT_ID 16
+#define TAIKO_SB_PGD_RX_PORT_MULTI_CHANNEL_0_END_PORT_ID 31
+
+#define TABLA_SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID 9
+#define TAIKO_SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID 15
 
 /* below details are taken from SLIMBUS slave SWI */
 #define SB_PGD_PORT_BASE 0x000
 
-#define SB_PGD_PORT_CFG_BYTE_ADDR(port_num) \
-		(SB_PGD_PORT_BASE + 0x040 + 1*port_num)
+#define SB_PGD_PORT_CFG_BYTE_ADDR(offset, port_num) \
+		(SB_PGD_PORT_BASE + offset + (1 * port_num))
 
 #define SB_PGD_TX_PORT_MULTI_CHANNEL_0(port_num) \
 		(SB_PGD_PORT_BASE + 0x100 + 4*port_num)
@@ -66,12 +85,9 @@
 #define SB_PGD_TX_PORT_MULTI_CHANNEL_1(port_num) \
 		(SB_PGD_PORT_BASE + 0x101 + 4*port_num)
 #define SB_PGD_TX_PORT_MULTI_CHANNEL_1_START_PORT_ID   8
-#define SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID     9
 
-#define SB_PGD_RX_PORT_MULTI_CHANNEL_0(port_num) \
-		(SB_PGD_PORT_BASE + 0x180 + 4*port_num)
-#define SB_PGD_RX_PORT_MULTI_CHANNEL_0_START_PORT_ID   10
-#define SB_PGD_RX_PORT_MULTI_CHANNEL_0_END_PORT_ID     16
+#define SB_PGD_RX_PORT_MULTI_CHANNEL_0(offset, port_num) \
+		(SB_PGD_PORT_BASE + offset + (4 * port_num))
 
 /* slave port water mark level
  *   (0: 6bytes, 1: 9bytes, 2: 12 bytes, 3: 15 bytes)
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 4c42623..2519a6e 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -68,10 +68,8 @@
 						struct msmfb_data)
 #define MSMFB_WRITEBACK_TERMINATE _IO(MSMFB_IOCTL_MAGIC, 155)
 #define MSMFB_MDP_PP _IOWR(MSMFB_IOCTL_MAGIC, 156, struct msmfb_mdp_pp)
-
-#define MSMFB_OVERLAY_VSYNC_CTRL  _IOW(MSMFB_IOCTL_MAGIC, 160, unsigned int)
-
-
+#define MSMFB_OVERLAY_VSYNC_CTRL _IOW(MSMFB_IOCTL_MAGIC, 160, unsigned int)
+#define MSMFB_VSYNC_CTRL  _IOW(MSMFB_IOCTL_MAGIC, 161, unsigned int)
 #define FB_TYPE_3D_PANEL 0x10101010
 #define MDP_IMGTYPE2_START 0x10000
 #define MSMFB_DRIVER_VERSION	0xF9E8D701