Merge "sync: use correct signed type when handling SYNC_IOC_WAIT"
diff --git a/Documentation/devicetree/bindings/arm/msm/rpm-regulator-smd.txt b/Documentation/devicetree/bindings/arm/msm/rpm-regulator-smd.txt
index 93b5144..d930799 100644
--- a/Documentation/devicetree/bindings/arm/msm/rpm-regulator-smd.txt
+++ b/Documentation/devicetree/bindings/arm/msm/rpm-regulator-smd.txt
@@ -113,8 +113,14 @@
 					14 = 1.37
 					15 = 1.28
 					16 = 1.20
-- qcom,init-head-room:         Voltage head room in uV required for the
-				regulator
+- qcom,init-head-room:         Voltage head room in mV required for the
+				regulator.  This head room value should be used
+				in situations where the device connected to the
+				output of the regulator has low noise tolerance.
+				Note that the RPM independently enforces a
+				safety head room value for subregulated LDOs
+				which is sufficient to account for LDO drop-out
+				voltage.
 - qcom,init-quiet-mode:        Specify that quiet mode is needed for an SMPS
 				regulator in order to have lower output noise.
 				Supported values are:
diff --git a/Documentation/devicetree/bindings/regulator/fixed-regulator.txt b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt
index 9cf57fd..7637adc 100644
--- a/Documentation/devicetree/bindings/regulator/fixed-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt
@@ -8,6 +8,7 @@
 - startup-delay-us: startup time in microseconds
 - enable-active-high: Polarity of GPIO is Active high
 If this property is missing, the default assumed is Active low.
+- parent-supply: phandle to the parent supply/regulator node if one exists.
 
 Any property defined as part of the core regulator
 binding, defined in regulator.txt, can also be used.
diff --git a/Documentation/devicetree/bindings/tty/serial/msm_serial_hs.txt b/Documentation/devicetree/bindings/tty/serial/msm_serial_hs.txt
new file mode 100644
index 0000000..3534823
--- /dev/null
+++ b/Documentation/devicetree/bindings/tty/serial/msm_serial_hs.txt
@@ -0,0 +1,70 @@
+* Qualcomm MSM HSUART
+
+Required properties:
+- compatible :
+	- "qcom,msm-hsuart-v14" to be used for UARTDM Core v1.4
+- reg : offset and length of the register set for both the device,
+	uart core and bam core
+- reg-names : names of the uart core and bam core.
+- interrupts : should contain the uart interrupt.
+- interrupt-names : names of interrupts to be used.
+- bam-tx-ep-pipe-index : BAM TX Endpoint Pipe Index for HSUART
+- bam-rx-ep-pipe-index : BAM RX Endpoint Pipe Index for HSUART
+
+BLSP has a static pipe allocation and assumes a pair-pipe for each uart core.
+Pipes [2*i : 2*i+1] are allocated for UART cores where i = [0 : 5].
+Hence, Minimum and Maximum permitted value of endpoint pipe index to be used
+with uart core is 0 and 11 respectively.
+
+There is one HSUART block used in MSM devices,
+"qcom,msm-hsuart-v14". The msm-serial-hs driver is
+able to handle this, and matches against the "qcom,msm-hsuart-v14"
+as the compatibility.
+
+The registers for the "qcom,msm-hsuart-v14" device need to specify both
+register blocks - uart core and bam core.
+
+Example:
+
+	uart7@f995d000 {
+		compatible = "qcom,msm-hsuart-v14";
+		reg = <0xf995d000 0x1000>,
+		      <0xf9944000 0x5000>;
+		reg-names = "core_mem", "bam_mem";
+		interrupts = <0 113 0>, <0 239 0>;
+		interrupt-names = "core_irq", "bam_irq";
+	};
+
+Optional properties:
+- qcom,<gpio-name>-gpio : handle to the GPIO node, see "gpios property" in
+Documentation/devicetree/bindings/gpio/gpio.txt.
+"gpio-name" can be "tx", "rx", "cts" and "rfr" based on number of UART GPIOs
+need to configured.
+Gpio's are optional if it is required to be not configured by UART driver or
+case where there is nothing connected and we want to use internal loopback mode
+for uart.
+- qcom, wakeup_irq : UART RX GPIO IRQ line to be configured as wakeup source.
+- qcom,inject_rx_on_wakeup : inject_rx_on_wakeup enables feature where on
+receiving interrupt with UART RX GPIO IRQ line (i.e. above wakeup_irq property),
+HSUART driver injects provided character with property rx_to_inject.
+- qcom, rx_to_inject : The character to be inserted on wakeup.
+
+
+Example:
+
+	uart7: uart@f995d000 {
+		compatible = "qcom,msm-hsuart-v14"
+		reg = <0x19c40000 0x1000">,
+		      <0xf9944000 0x5000>;
+		reg-names = "core_mem", "bam_mem";
+		interrupts = <0 113 0>, <0 239 0>;
+		interrupt-names = "core_irq", "bam_irq";
+
+		qcom,tx-gpio = <&msmgpio 41 0x00>;
+		qcom,rx-gpio = <&msmgpio 42 0x00>;
+		qcom,cts-gpio = <&msmgpio 43 0x00>;
+		qcom,rfr-gpio = <&msmgpio 44 0x00>;
+
+		qcom,bam-tx-ep-pipe-index = <0>;
+		qcom,bam-rx-ep-pipe-index = <1>;
+	};
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 5e65ca4..3b3402d 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -180,6 +180,15 @@
 		qcom,model = "msm8974-taiko-cdp-snd-card";
 		qcom,hdmi-audio-rx;
 	};
+
+	usb2_otg_sw: regulator-tpd4s214 {
+		compatible = "regulator-fixed";
+		regulator-name = "usb2_otg_sw";
+		gpio = <&pm8941_gpios 18 0>;
+		parent-supply = <&pm8941_boost>;
+		startup-delay-us = <17000>;
+		enable-active-high;
+	};
 };
 
 &spmi_bus {
@@ -374,6 +383,14 @@
 	};
 
 	gpio@d100 { /* GPIO 18 */
+		/* usb2_otg_sw regulator enable */
+		qcom,mode = <1>;		/* Digital output */
+		qcom,output-type = <0>;		/* CMOS logic */
+		qcom,invert = <0>; 		/* Output low initially */
+		qcom,vin-sel = <2>; 		/* PM8941 S3 = 1.8 V */
+		qcom,src-sel = <0>; 		/* Constant */
+		qcom,out-strength = <2>;	/* Medium drive strength */
+		qcom,master-en = <1>;		/* Enable GPIO */
 	};
 
 	gpio@d200 { /* GPIO 19 */
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index f464a55..4e9f707 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -253,7 +253,6 @@
 CONFIG_PMIC8XXX_VIBRATOR=y
 CONFIG_QSEECOM=y
 CONFIG_USB_HSIC_SMSC_HUB=y
-CONFIG_SCSI=y
 CONFIG_SCSI_TGT=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_SG=y
@@ -262,6 +261,8 @@
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_LOGGING=y
 CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_ATA=y
+CONFIG_SATA_AHCI_MSM=y
 CONFIG_MD=y
 CONFIG_BLK_DEV_DM=y
 CONFIG_DM_CRYPT=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index e54459d..5d37dd0 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -258,7 +258,6 @@
 CONFIG_PMIC8XXX_VIBRATOR=y
 CONFIG_QSEECOM=y
 CONFIG_USB_HSIC_SMSC_HUB=y
-CONFIG_SCSI=y
 CONFIG_SCSI_TGT=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_SG=y
@@ -267,6 +266,8 @@
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_LOGGING=y
 CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_ATA=y
+CONFIG_SATA_AHCI_MSM=y
 CONFIG_MD=y
 CONFIG_BLK_DEV_DM=y
 CONFIG_DM_CRYPT=y
diff --git a/arch/arm/mach-msm/include/mach/msm_serial_hs.h b/arch/arm/mach-msm/include/mach/msm_serial_hs.h
index d2905d4..cc50955 100644
--- a/arch/arm/mach-msm/include/mach/msm_serial_hs.h
+++ b/arch/arm/mach-msm/include/mach/msm_serial_hs.h
@@ -17,15 +17,34 @@
 
 #include<linux/serial_core.h>
 
-/* Optional platform device data for msm_serial_hs driver.
- * Used to configure low power wakeup */
+/**
+ * struct msm_serial_hs_platform_data - platform device data
+ *					for msm hsuart device
+ * @wakeup_irq : IRQ line to be configured as Wakeup source.
+ * @inject_rx_on_wakeup : Set 1 if specific character to be inserted on wakeup
+ * @rx_to_inject : Character to be inserted on wakeup
+ * @gpio_config : Configure gpios that are used for uart communication
+ * @userid : User-defined number to be used to enumerate device as tty<userid>
+ * @uart_tx_gpio: GPIO number for UART Tx Line.
+ * @uart_rx_gpio: GPIO number for UART Rx Line.
+ * @uart_cts_gpio: GPIO number for UART CTS Line.
+ * @uart_rfr_gpio: GPIO number for UART RFR Line.
+ * @bam_tx_ep_pipe_index : BAM TX Endpoint Pipe Index for HSUART
+ * @bam_tx_ep_pipe_index : BAM RX Endpoint Pipe Index for HSUART
+ */
 struct msm_serial_hs_platform_data {
 	int wakeup_irq;  /* wakeup irq */
-	/* bool: inject char into rx tty on wakeup */
 	unsigned char inject_rx_on_wakeup;
 	char rx_to_inject;
 	int (*gpio_config)(int);
 	int userid;
+
+	unsigned uart_tx_gpio;
+	unsigned uart_rx_gpio;
+	unsigned uart_cts_gpio;
+	unsigned uart_rfr_gpio;
+	unsigned bam_tx_ep_pipe_index;
+	unsigned bam_rx_ep_pipe_index;
 };
 
 unsigned int msm_hs_tx_empty(struct uart_port *uport);
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index fde43b0..cdacd87 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -2288,13 +2288,19 @@
 			RR("x REMOVE_SERVER Name=%d:%08x Id=%d:%08x\n",
 			   msg.srv.service, msg.srv.instance,
 			   msg.srv.node_id, msg.srv.port_id);
-		} else if (port_ptr->type == CLIENT_PORT) {
-			msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
-			msg.cli.node_id = port_ptr->this_port.node_id;
-			msg.cli.port_id = port_ptr->this_port.port_id;
-			RR("x REMOVE_CLIENT id=%d:%08x\n",
-			   msg.cli.node_id, msg.cli.port_id);
+			broadcast_ctl_msg(&msg);
+			broadcast_ctl_msg_locally(&msg);
 		}
+
+		/*
+		 * Server port could have been a client port earlier.
+		 * Send REMOVE_CLIENT message in either case.
+		 */
+		msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
+		msg.cli.node_id = port_ptr->this_port.node_id;
+		msg.cli.port_id = port_ptr->this_port.port_id;
+		RR("x REMOVE_CLIENT id=%d:%08x\n",
+		   msg.cli.node_id, msg.cli.port_id);
 		broadcast_ctl_msg(&msg);
 		broadcast_ctl_msg_locally(&msg);
 	} else if (port_ptr->type == CONTROL_PORT) {
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 6bdedd7..83ef121 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -83,6 +83,17 @@
 
 	  If unsure, say N.
 
+config SATA_AHCI_MSM
+	tristate "Qualcomm MSM AHCI SATA support"
+	depends on ARCH_MSM
+	select SATA_AHCI_PLATFORM
+	help
+	  This option enables support for AHCI SATA controller
+	  integrated into Qualcomm MSM chipsets. For more
+	  information please refer to http://www.qualcomm.com/chipsets.
+
+	  If unsure, say N.
+
 config SATA_FSL
 	tristate "Freescale 3.0Gbps SATA support"
 	depends on FSL_SOC
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 6ece5b7..bc40152 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -9,6 +9,7 @@
 obj-$(CONFIG_SATA_INIC162X)	+= sata_inic162x.o
 obj-$(CONFIG_SATA_SIL24)	+= sata_sil24.o
 obj-$(CONFIG_SATA_DWC)		+= sata_dwc_460ex.o
+obj-$(CONFIG_SATA_AHCI_MSM)	+= ahci_msm.o
 
 # SFF w/ custom DMA
 obj-$(CONFIG_PDC_ADMA)		+= pdc_adma.o
diff --git a/drivers/ata/ahci_msm.c b/drivers/ata/ahci_msm.c
new file mode 100644
index 0000000..8536040
--- /dev/null
+++ b/drivers/ata/ahci_msm.c
@@ -0,0 +1,778 @@
+/*
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * SATA init module.
+ * To be used with SATA interface on MSM targets.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/regulator/consumer.h>
+#include <linux/ahci_platform.h>
+#include <mach/clk.h>
+
+/* PHY registers */
+#define UNIPHY_PLL_REFCLK_CFG		0x000
+#define UNIPHY_PLL_POSTDIV1_CFG		0x004
+#define UNIPHY_PLL_CHGPUMP_CFG		0x008
+#define UNIPHY_PLL_VCOLPF_CFG		0x00C
+#define UNIPHY_PLL_VREG_CFG		0x010
+#define UNIPHY_PLL_PWRGEN_CFG		0x014
+#define UNIPHY_PLL_DMUX_CFG		0x018
+#define UNIPHY_PLL_AMUX_CFG		0x01C
+#define UNIPHY_PLL_GLB_CFG		0x020
+#define UNIPHY_PLL_POSTDIV2_CFG		0x024
+#define UNIPHY_PLL_POSTDIV3_CFG		0x028
+#define UNIPHY_PLL_LPFR_CFG		0x02C
+#define UNIPHY_PLL_LPFC1_CFG		0x030
+#define UNIPHY_PLL_LPFC2_CFG		0x034
+#define UNIPHY_PLL_SDM_CFG0		0x038
+#define UNIPHY_PLL_SDM_CFG1		0x03C
+#define UNIPHY_PLL_SDM_CFG2		0x040
+#define UNIPHY_PLL_SDM_CFG3		0x044
+#define UNIPHY_PLL_SDM_CFG4		0x048
+#define UNIPHY_PLL_SSC_CFG0		0x04C
+#define UNIPHY_PLL_SSC_CFG1		0x050
+#define UNIPHY_PLL_SSC_CFG2		0x054
+#define UNIPHY_PLL_SSC_CFG3		0x058
+#define UNIPHY_PLL_LKDET_CFG0		0x05C
+#define UNIPHY_PLL_LKDET_CFG1		0x060
+#define UNIPHY_PLL_LKDET_CFG2		0x064
+#define UNIPHY_PLL_TEST_CFG		0x068
+#define UNIPHY_PLL_CAL_CFG0		0x06C
+#define UNIPHY_PLL_CAL_CFG1		0x070
+#define UNIPHY_PLL_CAL_CFG2		0x074
+#define UNIPHY_PLL_CAL_CFG3		0x078
+#define UNIPHY_PLL_CAL_CFG4		0x07C
+#define UNIPHY_PLL_CAL_CFG5		0x080
+#define UNIPHY_PLL_CAL_CFG6		0x084
+#define UNIPHY_PLL_CAL_CFG7		0x088
+#define UNIPHY_PLL_CAL_CFG8		0x08C
+#define UNIPHY_PLL_CAL_CFG9		0x090
+#define UNIPHY_PLL_CAL_CFG10		0x094
+#define UNIPHY_PLL_CAL_CFG11		0x098
+#define UNIPHY_PLL_EFUSE_CFG		0x09C
+#define UNIPHY_PLL_DEBUG_BUS_SEL	0x0A0
+#define UNIPHY_PLL_CTRL_42		0x0A4
+#define UNIPHY_PLL_CTRL_43		0x0A8
+#define UNIPHY_PLL_CTRL_44		0x0AC
+#define UNIPHY_PLL_CTRL_45		0x0B0
+#define UNIPHY_PLL_CTRL_46		0x0B4
+#define UNIPHY_PLL_CTRL_47		0x0B8
+#define UNIPHY_PLL_CTRL_48		0x0BC
+#define UNIPHY_PLL_STATUS		0x0C0
+#define UNIPHY_PLL_DEBUG_BUS0		0x0C4
+#define UNIPHY_PLL_DEBUG_BUS1		0x0C8
+#define UNIPHY_PLL_DEBUG_BUS2		0x0CC
+#define UNIPHY_PLL_DEBUG_BUS3		0x0D0
+#define UNIPHY_PLL_CTRL_54		0x0D4
+
+#define SATA_PHY_SER_CTRL		0x100
+#define SATA_PHY_TX_DRIV_CTRL0		0x104
+#define SATA_PHY_TX_DRIV_CTRL1		0x108
+#define SATA_PHY_TX_DRIV_CTRL2		0x10C
+#define SATA_PHY_TX_DRIV_CTRL3		0x110
+#define SATA_PHY_TX_RESV0		0x114
+#define SATA_PHY_TX_RESV1		0x118
+#define SATA_PHY_TX_IMCAL0		0x11C
+#define SATA_PHY_TX_IMCAL1		0x120
+#define SATA_PHY_TX_IMCAL2		0x124
+#define SATA_PHY_RX_IMCAL0		0x128
+#define SATA_PHY_RX_IMCAL1		0x12C
+#define SATA_PHY_RX_IMCAL2		0x130
+#define SATA_PHY_RX_TERM		0x134
+#define SATA_PHY_RX_TERM_RESV		0x138
+#define SATA_PHY_EQUAL			0x13C
+#define SATA_PHY_EQUAL_RESV		0x140
+#define SATA_PHY_OOB_TERM		0x144
+#define SATA_PHY_CDR_CTRL0		0x148
+#define SATA_PHY_CDR_CTRL1		0x14C
+#define SATA_PHY_CDR_CTRL2		0x150
+#define SATA_PHY_CDR_CTRL3		0x154
+#define SATA_PHY_CDR_CTRL4		0x158
+#define SATA_PHY_FA_LOAD0		0x15C
+#define SATA_PHY_FA_LOAD1		0x160
+#define SATA_PHY_CDR_CTRL_RESV		0x164
+#define SATA_PHY_PI_CTRL0		0x168
+#define SATA_PHY_PI_CTRL1		0x16C
+#define SATA_PHY_DESER_RESV		0x170
+#define SATA_PHY_RX_RESV0		0x174
+#define SATA_PHY_AD_TPA_CTRL		0x178
+#define SATA_PHY_REFCLK_CTRL		0x17C
+#define SATA_PHY_POW_DWN_CTRL0		0x180
+#define SATA_PHY_POW_DWN_CTRL1		0x184
+#define SATA_PHY_TX_DATA_CTRL		0x188
+#define SATA_PHY_BIST_GEN0		0x18C
+#define SATA_PHY_BIST_GEN1		0x190
+#define SATA_PHY_BIST_GEN2		0x194
+#define SATA_PHY_BIST_GEN3		0x198
+#define SATA_PHY_LBK_CTRL		0x19C
+#define SATA_PHY_TEST_DEBUG_CTRL	0x1A0
+#define SATA_PHY_ALIGNP			0x1A4
+#define SATA_PHY_PRBS_CFG0		0x1A8
+#define SATA_PHY_PRBS_CFG1		0x1AC
+#define SATA_PHY_PRBS_CFG2		0x1B0
+#define SATA_PHY_PRBS_CFG3		0x1B4
+#define SATA_PHY_CHAN_COMP_CHK_CNT	0x1B8
+#define SATA_PHY_RESET_CTRL		0x1BC
+#define SATA_PHY_RX_CLR			0x1C0
+#define SATA_PHY_RX_EBUF_CTRL		0x1C4
+#define SATA_PHY_ID0			0x1C8
+#define SATA_PHY_ID1			0x1CC
+#define SATA_PHY_ID2			0x1D0
+#define SATA_PHY_ID3			0x1D4
+#define SATA_PHY_RX_CHK_ERR_CNT0	0x1D8
+#define SATA_PHY_RX_CHK_ERR_CNT1	0x1DC
+#define SATA_PHY_RX_CHK_STAT		0x1E0
+#define SATA_PHY_TX_IMCAL_STAT		0x1E4
+#define SATA_PHY_RX_IMCAL_STAT		0x1E8
+#define SATA_PHY_RX_EBUF_STAT		0x1EC
+#define SATA_PHY_DEBUG_BUS_STAT0	0x1F0
+#define SATA_PHY_DEBUG_BUS_STAT1	0x1F4
+#define SATA_PHY_DEBUG_BUS_STAT2	0x1F8
+#define SATA_PHY_DEBUG_BUS_STAT3	0x1FC
+
+#define AHCI_HOST_CAP		0x00
+#define AHCI_HOST_CAP_MASK	0x1F
+#define AHCI_HOST_CAP_PMP	(1 << 17)
+
+struct msm_sata_hba {
+	struct platform_device *ahci_pdev;
+	struct clk *slave_iface_clk;
+	struct clk *bus_clk;
+	struct clk *iface_clk;
+	struct clk *src_clk;
+	struct clk *rxoob_clk;
+	struct clk *pmalive_clk;
+	struct clk *cfg_clk;
+	struct regulator *clk_pwr;
+	struct regulator *pmp_pwr;
+	void __iomem *phy_base;
+	void __iomem *ahci_base;
+};
+
+static inline void msm_sata_delay_us(unsigned int delay)
+{
+	/* sleep for max. 50us more to combine processor wakeups */
+	usleep_range(delay, delay + 50);
+}
+
+static int msm_sata_clk_get_prepare_enable_set_rate(struct device *dev,
+		const char *name, struct clk **out_clk, int rate)
+{
+	int ret = 0;
+	struct clk *clk;
+
+	clk = devm_clk_get(dev, name);
+	if (IS_ERR(clk)) {
+		ret = PTR_ERR(clk);
+		dev_err(dev, "failed to get clk: %s err = %d\n", name, ret);
+		goto out;
+	}
+
+	if (rate >= 0) {
+		ret = clk_set_rate(clk, rate);
+		if (ret) {
+			dev_err(dev, "failed to set rate: %d clk: %s err = %d\n",
+					rate, name, ret);
+			goto out;
+		}
+	}
+
+	ret = clk_prepare_enable(clk);
+	if (ret)
+		dev_err(dev, "failed to enable clk: %s err = %d\n", name, ret);
+out:
+	if (!ret)
+		*out_clk = clk;
+
+	return ret;
+}
+
+static int msm_sata_clk_get_prepare_enable(struct device *dev,
+		const char *name, struct clk **out_clk)
+{
+	return msm_sata_clk_get_prepare_enable_set_rate(dev, name, out_clk, -1);
+}
+
+static void msm_sata_clk_put_unprepare_disable(struct clk **clk)
+{
+	if (*clk) {
+		clk_disable_unprepare(*clk);
+		clk_put(*clk);
+		*clk = NULL;
+	}
+}
+
+static int msm_sata_hard_reset(struct device *dev)
+{
+	int ret;
+	struct msm_sata_hba *hba = dev_get_drvdata(dev);
+
+	ret = clk_reset(hba->iface_clk, CLK_RESET_ASSERT);
+	if (ret) {
+		dev_err(dev, "iface_clk assert failed %d\n", ret);
+		goto out;
+	}
+
+	ret = clk_reset(hba->iface_clk, CLK_RESET_DEASSERT);
+	if (ret) {
+		dev_err(dev, "iface_clk de-assert failed %d\n", ret);
+		goto out;
+	}
+out:
+	return ret;
+}
+
+static int msm_sata_clk_init(struct device *dev)
+{
+	int ret = 0;
+	struct msm_sata_hba *hba = dev_get_drvdata(dev);
+
+	/* Enable AHB clock for system fabric slave port connected to SATA */
+	ret = msm_sata_clk_get_prepare_enable(dev,
+			"slave_iface_clk", &hba->slave_iface_clk);
+	if (ret)
+		goto out;
+
+	/* Enable AHB clock for system fabric and SATA core interface */
+	ret = msm_sata_clk_get_prepare_enable(dev,
+			"iface_clk", &hba->iface_clk);
+	if (ret)
+		goto put_dis_slave_iface_clk;
+
+	/* Enable AXI clock for SATA AXI master and slave interfaces */
+	ret = msm_sata_clk_get_prepare_enable(dev,
+			"bus_clk", &hba->bus_clk);
+	if (ret)
+		goto put_dis_iface_clk;
+
+	/* Enable the source clock for pmalive, rxoob and phy ref clocks */
+	ret = msm_sata_clk_get_prepare_enable_set_rate(dev,
+			"src_clk", &hba->src_clk, 100000000);
+	if (ret)
+		goto put_dis_bus_clk;
+
+	/*
+	 * Enable RX OOB detection clock. The clock rate is
+	 * same as PHY reference clock (100MHz).
+	 */
+	ret = msm_sata_clk_get_prepare_enable(dev,
+			"core_rxoob_clk", &hba->rxoob_clk);
+	if (ret)
+		goto put_dis_src_clk;
+
+	/*
+	 * Enable power management always-on clock. The clock rate
+	 * is same as PHY reference clock (100MHz).
+	 */
+	ret = msm_sata_clk_get_prepare_enable(dev,
+			"core_pmalive_clk", &hba->pmalive_clk);
+	if (ret)
+		goto put_dis_rxoob_clk;
+
+	/* Enable PHY configuration AHB clock, fixed 64MHz clock */
+	ret = msm_sata_clk_get_prepare_enable(dev,
+			"cfg_clk", &hba->cfg_clk);
+	if (ret)
+		goto put_dis_pmalive_clk;
+
+	return ret;
+
+put_dis_pmalive_clk:
+	msm_sata_clk_put_unprepare_disable(&hba->pmalive_clk);
+put_dis_rxoob_clk:
+	msm_sata_clk_put_unprepare_disable(&hba->rxoob_clk);
+put_dis_src_clk:
+	msm_sata_clk_put_unprepare_disable(&hba->src_clk);
+put_dis_bus_clk:
+	msm_sata_clk_put_unprepare_disable(&hba->bus_clk);
+put_dis_iface_clk:
+	msm_sata_clk_put_unprepare_disable(&hba->iface_clk);
+put_dis_slave_iface_clk:
+	msm_sata_clk_put_unprepare_disable(&hba->slave_iface_clk);
+out:
+	return ret;
+}
+
+static void msm_sata_clk_deinit(struct device *dev)
+{
+	struct msm_sata_hba *hba = dev_get_drvdata(dev);
+
+	msm_sata_clk_put_unprepare_disable(&hba->cfg_clk);
+	msm_sata_clk_put_unprepare_disable(&hba->pmalive_clk);
+	msm_sata_clk_put_unprepare_disable(&hba->rxoob_clk);
+	msm_sata_clk_put_unprepare_disable(&hba->src_clk);
+	msm_sata_clk_put_unprepare_disable(&hba->bus_clk);
+	msm_sata_clk_put_unprepare_disable(&hba->iface_clk);
+	msm_sata_clk_put_unprepare_disable(&hba->slave_iface_clk);
+}
+
+static int msm_sata_vreg_get_enable_set_vdd(struct device *dev,
+			const char *name, struct regulator **out_vreg,
+			int min_uV, int max_uV, int hpm_uA)
+{
+	int ret = 0;
+	struct regulator *vreg;
+
+	vreg = devm_regulator_get(dev, name);
+	if (IS_ERR(vreg)) {
+		ret = PTR_ERR(vreg);
+		dev_err(dev, "Regulator: %s get failed, err=%d\n", name, ret);
+		goto out;
+	}
+
+	if (regulator_count_voltages(vreg) > 0) {
+		ret = regulator_set_voltage(vreg, min_uV, max_uV);
+		if (ret) {
+			dev_err(dev, "Regulator: %s set voltage failed, err=%d\n",
+					name, ret);
+			goto err;
+		}
+
+		ret = regulator_set_optimum_mode(vreg, hpm_uA);
+		if (ret < 0) {
+			dev_err(dev, "Regulator: %s set optimum mode(uA_load=%d) failed, err=%d\n",
+					name, hpm_uA, ret);
+			goto err;
+		} else {
+			/*
+			 * regulator_set_optimum_mode() can return non zero
+			 * value even for success case.
+			 */
+			ret = 0;
+		}
+	}
+
+	ret = regulator_enable(vreg);
+	if (ret)
+		dev_err(dev, "Regulator: %s enable failed, err=%d\n",
+				name, ret);
+err:
+	if (!ret)
+		*out_vreg = vreg;
+	else
+		devm_regulator_put(vreg);
+out:
+	return ret;
+}
+
+static int msm_sata_vreg_put_disable(struct device *dev,
+		struct regulator *reg, const char *name, int max_uV)
+{
+	int ret;
+
+	if (!reg)
+		return 0;
+
+	ret = regulator_disable(reg);
+	if (ret) {
+		dev_err(dev, "Regulator: %s disable failed err=%d\n",
+				name, ret);
+		goto err;
+	}
+
+	if (regulator_count_voltages(reg) > 0) {
+		ret = regulator_set_voltage(reg, 0, max_uV);
+		if (ret < 0) {
+			dev_err(dev, "Regulator: %s set voltage to 0 failed, err=%d\n",
+					name, ret);
+			goto err;
+		}
+
+		ret = regulator_set_optimum_mode(reg, 0);
+		if (ret < 0) {
+			dev_err(dev, "Regulator: %s set optimum mode(uA_load = 0) failed, err=%d\n",
+					name, ret);
+			goto err;
+		} else {
+			/*
+			 * regulator_set_optimum_mode() can return non zero
+			 * value even for success case.
+			 */
+			ret = 0;
+		}
+	}
+
+err:
+	devm_regulator_put(reg);
+	return ret;
+}
+
+static int msm_sata_vreg_init(struct device *dev)
+{
+	int ret = 0;
+	struct msm_sata_hba *hba = dev_get_drvdata(dev);
+
+	/*
+	 * The SATA clock generator needs 3.3V supply and can consume
+	 * max. 850mA during functional mode.
+	 */
+	ret = msm_sata_vreg_get_enable_set_vdd(dev, "sata_ext_3p3v",
+				&hba->clk_pwr, 3300000, 3300000, 850000);
+	if (ret)
+		goto out;
+
+	/* Add 1ms regulator ramp-up delay */
+	msm_sata_delay_us(1000);
+
+	/* Read AHCI capability register to check if PMP is supported.*/
+	if (readl_relaxed(hba->ahci_base +
+				AHCI_HOST_CAP) & AHCI_HOST_CAP_PMP) {
+		/* Power up port-multiplier */
+		ret = msm_sata_vreg_get_enable_set_vdd(dev, "sata_pmp_pwr",
+				&hba->pmp_pwr, 1800000, 1800000, 200000);
+		if (ret) {
+			msm_sata_vreg_put_disable(dev, hba->clk_pwr,
+					"sata_ext_3p3v", 3300000);
+			goto out;
+		}
+
+		/* Add 1ms regulator ramp-up delay */
+		msm_sata_delay_us(1000);
+	}
+
+out:
+	return ret;
+}
+
+static void msm_sata_vreg_deinit(struct device *dev)
+{
+	struct msm_sata_hba *hba = dev_get_drvdata(dev);
+
+	msm_sata_vreg_put_disable(dev, hba->clk_pwr,
+			"sata_ext_3p3v", 3300000);
+
+	if (hba->pmp_pwr)
+		msm_sata_vreg_put_disable(dev, hba->pmp_pwr,
+				"sata_pmp_pwr", 1800000);
+}
+
+static void msm_sata_phy_deinit(struct device *dev)
+{
+	struct msm_sata_hba *hba = dev_get_drvdata(dev);
+
+	/* Power down PHY */
+	writel_relaxed(0xF8, hba->phy_base + SATA_PHY_POW_DWN_CTRL0);
+	writel_relaxed(0xFE, hba->phy_base + SATA_PHY_POW_DWN_CTRL1);
+
+	/* Power down PLL block */
+	writel_relaxed(0x00, hba->phy_base + UNIPHY_PLL_GLB_CFG);
+	mb();
+
+	devm_iounmap(dev, hba->phy_base);
+}
+
+static int msm_sata_phy_init(struct device *dev)
+{
+	int ret = 0;
+	u32 reg = 0;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct msm_sata_hba *hba = dev_get_drvdata(dev);
+	struct resource *mem;
+
+	mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_mem");
+	if (!mem) {
+		dev_err(dev, "no mmio space\n");
+		return -EINVAL;
+	}
+
+	hba->phy_base = devm_ioremap(dev, mem->start, resource_size(mem));
+	if (!hba->phy_base) {
+		dev_err(dev, "failed to allocate memory for SATA PHY\n");
+		return -ENOMEM;
+	}
+
+	/* SATA phy initialization */
+
+	writel_relaxed(0x01, hba->phy_base + SATA_PHY_SER_CTRL);
+
+	writel_relaxed(0xB1, hba->phy_base + SATA_PHY_POW_DWN_CTRL0);
+	mb();
+	msm_sata_delay_us(10);
+
+	writel_relaxed(0x01, hba->phy_base + SATA_PHY_POW_DWN_CTRL0);
+	writel_relaxed(0x3E, hba->phy_base + SATA_PHY_POW_DWN_CTRL1);
+	writel_relaxed(0x01, hba->phy_base + SATA_PHY_RX_IMCAL0);
+	writel_relaxed(0x01, hba->phy_base + SATA_PHY_TX_IMCAL0);
+	writel_relaxed(0x02, hba->phy_base + SATA_PHY_TX_IMCAL2);
+
+	/* Write UNIPHYPLL registers to configure PLL */
+	writel_relaxed(0x04, hba->phy_base + UNIPHY_PLL_REFCLK_CFG);
+	writel_relaxed(0x00, hba->phy_base + UNIPHY_PLL_PWRGEN_CFG);
+
+	writel_relaxed(0x0A, hba->phy_base + UNIPHY_PLL_CAL_CFG0);
+	writel_relaxed(0xF3, hba->phy_base + UNIPHY_PLL_CAL_CFG8);
+	writel_relaxed(0x01, hba->phy_base + UNIPHY_PLL_CAL_CFG9);
+	writel_relaxed(0xED, hba->phy_base + UNIPHY_PLL_CAL_CFG10);
+	writel_relaxed(0x02, hba->phy_base + UNIPHY_PLL_CAL_CFG11);
+
+	writel_relaxed(0x36, hba->phy_base + UNIPHY_PLL_SDM_CFG0);
+	writel_relaxed(0x0D, hba->phy_base + UNIPHY_PLL_SDM_CFG1);
+	writel_relaxed(0xA3, hba->phy_base + UNIPHY_PLL_SDM_CFG2);
+	writel_relaxed(0xF0, hba->phy_base + UNIPHY_PLL_SDM_CFG3);
+	writel_relaxed(0x00, hba->phy_base + UNIPHY_PLL_SDM_CFG4);
+
+	writel_relaxed(0x19, hba->phy_base + UNIPHY_PLL_SSC_CFG0);
+	writel_relaxed(0xE1, hba->phy_base + UNIPHY_PLL_SSC_CFG1);
+	writel_relaxed(0x00, hba->phy_base + UNIPHY_PLL_SSC_CFG2);
+	writel_relaxed(0x11, hba->phy_base + UNIPHY_PLL_SSC_CFG3);
+
+	writel_relaxed(0x04, hba->phy_base + UNIPHY_PLL_LKDET_CFG0);
+	writel_relaxed(0xFF, hba->phy_base + UNIPHY_PLL_LKDET_CFG1);
+
+	writel_relaxed(0x02, hba->phy_base + UNIPHY_PLL_GLB_CFG);
+	mb();
+	msm_sata_delay_us(40);
+
+	writel_relaxed(0x03, hba->phy_base + UNIPHY_PLL_GLB_CFG);
+	mb();
+	msm_sata_delay_us(400);
+
+	writel_relaxed(0x05, hba->phy_base + UNIPHY_PLL_LKDET_CFG2);
+	mb();
+
+	/* poll for ready status, timeout after 1 sec */
+	ret = readl_poll_timeout(hba->phy_base + UNIPHY_PLL_STATUS, reg,
+			(reg & 1 << 0), 100, 1000000);
+	if (ret) {
+		dev_err(dev, "poll timeout UNIPHY_PLL_STATUS\n");
+		goto out;
+	}
+
+	ret = readl_poll_timeout(hba->phy_base + SATA_PHY_TX_IMCAL_STAT, reg,
+			(reg & 1 << 0), 100, 1000000);
+	if (ret) {
+		dev_err(dev, "poll timeout SATA_PHY_TX_IMCAL_STAT\n");
+		goto out;
+	}
+
+	ret = readl_poll_timeout(hba->phy_base + SATA_PHY_RX_IMCAL_STAT, reg,
+			(reg & 1 << 0), 100, 1000000);
+	if (ret) {
+		dev_err(dev, "poll timeout SATA_PHY_RX_IMCAL_STAT\n");
+		goto out;
+	}
+
+	/* SATA phy calibrated succesfully, power up to functional mode */
+	writel_relaxed(0x3E, hba->phy_base + SATA_PHY_POW_DWN_CTRL1);
+	writel_relaxed(0x01, hba->phy_base + SATA_PHY_RX_IMCAL0);
+	writel_relaxed(0x01, hba->phy_base + SATA_PHY_TX_IMCAL0);
+
+	writel_relaxed(0x00, hba->phy_base + SATA_PHY_POW_DWN_CTRL1);
+	writel_relaxed(0x59, hba->phy_base + SATA_PHY_CDR_CTRL0);
+	writel_relaxed(0x04, hba->phy_base + SATA_PHY_CDR_CTRL1);
+	writel_relaxed(0x00, hba->phy_base + SATA_PHY_CDR_CTRL2);
+	writel_relaxed(0x00, hba->phy_base + SATA_PHY_PI_CTRL0);
+	writel_relaxed(0x00, hba->phy_base + SATA_PHY_CDR_CTRL3);
+	writel_relaxed(0x01, hba->phy_base + SATA_PHY_POW_DWN_CTRL0);
+
+	writel_relaxed(0x11, hba->phy_base + SATA_PHY_TX_DATA_CTRL);
+	writel_relaxed(0x43, hba->phy_base + SATA_PHY_ALIGNP);
+	writel_relaxed(0x04, hba->phy_base + SATA_PHY_OOB_TERM);
+
+	writel_relaxed(0x01, hba->phy_base + SATA_PHY_EQUAL);
+	writel_relaxed(0x09, hba->phy_base + SATA_PHY_TX_DRIV_CTRL0);
+	writel_relaxed(0x09, hba->phy_base + SATA_PHY_TX_DRIV_CTRL1);
+	mb();
+
+	dev_dbg(dev, "SATA PHY powered up in functional mode\n");
+
+out:
+	/* power down PHY in case of failure */
+	if (ret)
+		msm_sata_phy_deinit(dev);
+
+	return ret;
+}
+
+int msm_sata_init(struct device *ahci_dev, void __iomem *mmio)
+{
+	int ret;
+	struct device *dev = ahci_dev->parent;
+	struct msm_sata_hba *hba = dev_get_drvdata(dev);
+
+	/* Save ahci mmio to access vendor specific registers */
+	hba->ahci_base = mmio;
+
+	ret = msm_sata_clk_init(dev);
+	if (ret) {
+		dev_err(dev, "SATA clk init failed with err=%d\n", ret);
+		goto out;
+	}
+
+	ret = msm_sata_vreg_init(dev);
+	if (ret) {
+		dev_err(dev, "SATA vreg init failed with err=%d\n", ret);
+		msm_sata_clk_deinit(dev);
+		goto out;
+	}
+
+	ret = msm_sata_phy_init(dev);
+	if (ret) {
+		dev_err(dev, "SATA PHY init failed with err=%d\n", ret);
+		msm_sata_vreg_deinit(dev);
+		msm_sata_clk_deinit(dev);
+		goto out;
+	}
+
+out:
+	return ret;
+}
+
+void msm_sata_deinit(struct device *ahci_dev)
+{
+	struct device *dev = ahci_dev->parent;
+
+	msm_sata_phy_deinit(dev);
+	msm_sata_vreg_deinit(dev);
+	msm_sata_clk_deinit(dev);
+}
+
+static int msm_sata_suspend(struct device *ahci_dev)
+{
+	msm_sata_deinit(ahci_dev);
+
+	return 0;
+}
+
+static int msm_sata_resume(struct device *ahci_dev)
+{
+	int ret;
+	struct device *dev = ahci_dev->parent;
+
+	ret = msm_sata_clk_init(dev);
+	if (ret) {
+		dev_err(dev, "SATA clk init failed with err=%d\n", ret);
+		/*
+		 * If clock initialization failed, that means ahci driver
+		 * cannot access any register going further. Since there is
+		 * no check within ahci driver to check for clock failures,
+		 * panic here instead of making an unclocked register access.
+		 */
+		BUG();
+	}
+
+	/* Issue asynchronous reset to reset PHY */
+	ret = msm_sata_hard_reset(dev);
+	if (ret)
+		goto out;
+
+	ret = msm_sata_vreg_init(dev);
+	if (ret) {
+		dev_err(dev, "SATA vreg init failed with err=%d\n", ret);
+		/* Do not turn off clks, AHCI driver might do register access */
+		goto out;
+	}
+
+	ret = msm_sata_phy_init(dev);
+	if (ret) {
+		dev_err(dev, "SATA PHY init failed with err=%d\n", ret);
+		/* Do not turn off clks, AHCI driver might do register access */
+		msm_sata_vreg_deinit(dev);
+		goto out;
+	}
+out:
+	return ret;
+}
+
+static struct ahci_platform_data msm_ahci_pdata = {
+	.init = msm_sata_init,
+	.exit = msm_sata_deinit,
+	.suspend = msm_sata_suspend,
+	.resume = msm_sata_resume,
+};
+
+static int __devinit msm_sata_probe(struct platform_device *pdev)
+{
+	struct platform_device *ahci;
+	struct msm_sata_hba *hba;
+	int ret = 0;
+
+	hba = devm_kzalloc(&pdev->dev, sizeof(struct msm_sata_hba), GFP_KERNEL);
+	if (!hba) {
+		dev_err(&pdev->dev, "no memory\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	platform_set_drvdata(pdev, hba);
+
+	ahci = platform_device_alloc("ahci", pdev->id);
+	if (!ahci) {
+		dev_err(&pdev->dev, "couldn't allocate ahci device\n");
+		ret = -ENOMEM;
+		goto err_free;
+	}
+
+	dma_set_coherent_mask(&ahci->dev, pdev->dev.coherent_dma_mask);
+
+	ahci->dev.parent = &pdev->dev;
+	ahci->dev.dma_mask = pdev->dev.dma_mask;
+	ahci->dev.dma_parms = pdev->dev.dma_parms;
+	hba->ahci_pdev = ahci;
+
+	ret = platform_device_add_resources(ahci, pdev->resource,
+			pdev->num_resources);
+	if (ret) {
+		dev_err(&pdev->dev, "couldn't add resources to ahci device\n");
+		goto err_put_device;
+	}
+
+	ahci->dev.platform_data = &msm_ahci_pdata;
+	ret = platform_device_add(ahci);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register ahci device\n");
+		goto err_put_device;
+	}
+
+	return 0;
+
+err_put_device:
+	platform_device_put(ahci);
+err_free:
+	devm_kfree(&pdev->dev, hba);
+err:
+	return ret;
+}
+
+static int __devexit msm_sata_remove(struct platform_device *pdev)
+{
+	struct msm_sata_hba *hba = platform_get_drvdata(pdev);
+
+	platform_device_unregister(hba->ahci_pdev);
+
+	return 0;
+}
+
+static struct platform_driver msm_sata_driver = {
+	.probe		= msm_sata_probe,
+	.remove		= __devexit_p(msm_sata_remove),
+	.driver		= {
+		.name	= "msm_sata",
+	},
+};
+
+module_platform_driver(msm_sata_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("AHCI platform MSM Glue Layer");
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index ced7a80..0f82142 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -21,6 +21,7 @@
 #include <linux/platform_device.h>
 #include <linux/libata.h>
 #include <linux/ahci_platform.h>
+#include <linux/pm_runtime.h>
 #include "ahci.h"
 
 enum ahci_type {
@@ -192,6 +193,14 @@
 	if (rc)
 		goto err0;
 
+	rc = pm_runtime_set_active(dev);
+	if (rc) {
+		dev_warn(dev, "Unable to set runtime pm active err=%d\n", rc);
+	} else {
+		pm_runtime_enable(dev);
+		pm_runtime_forbid(dev);
+	}
+
 	return 0;
 err0:
 	if (pdata && pdata->exit)
@@ -275,6 +284,8 @@
 static struct dev_pm_ops ahci_pm_ops = {
 	.suspend		= &ahci_suspend,
 	.resume			= &ahci_resume,
+	.runtime_suspend	= &ahci_suspend,
+	.runtime_resume		= &ahci_resume,
 };
 #endif
 
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index bc129da..cc021c0 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -334,7 +334,7 @@
 {
 	int ret;
 
-	if (wcd9xxx->reset_gpio) {
+	if (wcd9xxx->reset_gpio && wcd9xxx->slim_device_bootup) {
 		ret = gpio_request(wcd9xxx->reset_gpio, "CDC_RESET");
 		if (ret) {
 			pr_err("%s: Failed to request gpio %d\n", __func__,
@@ -342,7 +342,8 @@
 			wcd9xxx->reset_gpio = 0;
 			return ret;
 		}
-
+	}
+	if (wcd9xxx->reset_gpio) {
 		gpio_direction_output(wcd9xxx->reset_gpio, 0);
 		msleep(20);
 		gpio_direction_output(wcd9xxx->reset_gpio, 1);
@@ -1259,6 +1260,7 @@
 	wcd9xxx->reset_gpio = pdata->reset_gpio;
 	wcd9xxx->dev = &slim->dev;
 	wcd9xxx->mclk_rate = pdata->mclk_rate;
+	wcd9xxx->slim_device_bootup = true;
 
 	ret = wcd9xxx_enable_supplies(wcd9xxx, pdata);
 	if (ret)
@@ -1378,6 +1380,29 @@
 	return ret;
 }
 
+static int wcd9xxx_device_up(struct wcd9xxx *wcd9xxx)
+{
+	int ret = 0;
+
+	if (wcd9xxx->slim_device_bootup) {
+		wcd9xxx->slim_device_bootup = false;
+		return 0;
+	}
+	ret = wcd9xxx_reset(wcd9xxx);
+	if (ret)
+		pr_err("%s: Resetting Codec failed\n", __func__);
+
+	wcd9xxx_bring_up(wcd9xxx);
+	wcd9xxx->post_reset(wcd9xxx);
+	return ret;
+}
+
+static int wcd9xxx_slim_device_up(struct slim_device *sldev)
+{
+	struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+	return wcd9xxx_device_up(wcd9xxx);
+}
+
 static int wcd9xxx_slim_resume(struct slim_device *sldev)
 {
 	struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
@@ -1533,6 +1558,7 @@
 	.id_table = taiko_slimtest_id,
 	.resume = wcd9xxx_slim_resume,
 	.suspend = wcd9xxx_slim_suspend,
+	.device_up = wcd9xxx_slim_device_up,
 };
 
 static const struct slim_device_id tapan_slimtest_id[] = {
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index f4fc7b6..3d3563a 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -2277,12 +2277,16 @@
 		ret = qsee_vote_for_clock(data, CLK_DFAB);
 		if (ret)
 			pr_err("Failed to vote for DFAB clock%d\n", ret);
+		ret = qsee_vote_for_clock(data, CLK_SFPB);
+		if (ret)
+			pr_err("Failed to vote for SFPB clock%d\n", ret);
 		atomic_dec(&data->ioctl_count);
 		break;
 	}
 	case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
 		atomic_inc(&data->ioctl_count);
 		qsee_disable_clock_vote(data, CLK_DFAB);
+		qsee_disable_clock_vote(data, CLK_SFPB);
 		atomic_dec(&data->ioctl_count);
 		break;
 	}
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index a09e5ee..5485e27 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -4210,7 +4210,7 @@
 			return rc;
 		}
 		/* Check if die 3.0.1 is present */
-		if (subrev == 0x1)
+		if (subrev & 0x1)
 			pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xA4);
 		else
 			pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xAC);
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index 7e74eca..d0410a4 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -104,6 +104,9 @@
 	if (of_find_property(np, "enable-active-high", NULL))
 		config->enable_high = true;
 
+	if (of_find_property(np, "parent-supply", NULL))
+		init_data->supply_regulator = "parent";
+
 	return config;
 }
 
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index 9c69f47..d4fb02b 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1409,7 +1409,7 @@
 err_request_irq_failed:
 	kthread_stop(dev->rx_msgq_thread);
 err_thread_create_failed:
-	msm_slim_sps_exit(dev);
+	msm_slim_sps_exit(dev, true);
 err_sps_init_failed:
 	if (dev->hclk) {
 		clk_disable_unprepare(dev->hclk);
@@ -1453,7 +1453,7 @@
 	clk_put(dev->rclk);
 	if (dev->hclk)
 		clk_put(dev->hclk);
-	msm_slim_sps_exit(dev);
+	msm_slim_sps_exit(dev, true);
 	kthread_stop(dev->rx_msgq_thread);
 	iounmap(dev->bam.base);
 	iounmap(dev->base);
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 78e8a6f..a37a7803 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -33,6 +33,7 @@
 #define NGD_SLIM_NAME	"ngd_msm_ctrl"
 #define SLIM_LA_MGR	0xFF
 #define SLIM_ROOT_FREQ	24576000
+#define LADDR_RETRY	5
 
 #define NGD_BASE_V1(r)	(((r) % 2) ? 0x800 : 0xA00)
 #define NGD_BASE_V2(r)	(((r) % 2) ? 0x1000 : 0x2000)
@@ -78,6 +79,12 @@
 	NGD_TX_BUSY		= 0x0,
 };
 
+enum ngd_status {
+	NGD_LADDR		= 1 << 1,
+};
+
+static int ngd_slim_runtime_resume(struct device *device);
+
 static irqreturn_t ngd_slim_interrupt(int irq, void *d)
 {
 	struct msm_slim_ctrl *dev = (struct msm_slim_ctrl *)d;
@@ -144,23 +151,24 @@
 	return IRQ_HANDLED;
 }
 
-static int ngd_clk_pause_wakeup(struct slim_controller *ctrl)
-{
-	struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
-	return msm_slim_qmi_power_request(dev, true);
-}
-
 static int ngd_qmi_available(struct notifier_block *n, unsigned long code,
 				void *_cmd)
 {
 	struct msm_slim_qmi *qmi = container_of(n, struct msm_slim_qmi, nb);
+	struct msm_slim_ctrl *dev =
+		container_of(qmi, struct msm_slim_ctrl, qmi);
 	pr_info("Slimbus QMI NGD CB received event:%ld", code);
 	switch (code) {
 	case QMI_SERVER_ARRIVE:
-		complete(&qmi->qmi_comp);
+		schedule_work(&qmi->ssr_up);
 		break;
 	case QMI_SERVER_EXIT:
-		/* SSR implementation */
+		dev->state = MSM_CTRL_DOWN;
+		/* make sure autosuspend is not called until ADSP comes up*/
+		pm_runtime_get_noresume(dev->dev);
+		/* Reset ctrl_up completion */
+		init_completion(&dev->ctrl_up);
+		schedule_work(&qmi->ssr_down);
 		break;
 	default:
 		break;
@@ -227,22 +235,43 @@
 		 txn->mc <= SLIM_MSG_MC_RECONFIGURE_NOW)) {
 		return 0;
 	}
-	msm_slim_get_ctrl(dev);
+	/* If txn is tried when controller is down, wait for ADSP to boot */
+	if (txn->mc != SLIM_USR_MC_REPORT_SATELLITE) {
+		if (dev->state == MSM_CTRL_DOWN) {
+			u8 mc = (u8)txn->mc;
+			int timeout;
+			dev_err(dev->dev, "ADSP slimbus not up yet");
+			/*
+			 * Messages related to data channel management can't
+			 * wait since they are holding reconfiguration lock.
+			 * clk_pause in resume (which can change state back to
+			 * MSM_CTRL_AWAKE), will need that lock
+			 */
+			if ((txn->mt == SLIM_MSG_MT_CORE) &&
+				((mc >= SLIM_MSG_MC_CONNECT_SOURCE &&
+				mc <= SLIM_MSG_MC_CHANGE_CONTENT) ||
+				(mc >= SLIM_MSG_MC_BEGIN_RECONFIGURATION &&
+				mc <= SLIM_MSG_MC_RECONFIGURE_NOW)))
+				return -EREMOTEIO;
+			if ((txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER) &&
+				((mc >= SLIM_USR_MC_DEFINE_CHAN &&
+				mc <= SLIM_USR_MC_DISCONNECT_PORT)))
+				return -EREMOTEIO;
+			timeout = wait_for_completion_timeout(&dev->ctrl_up,
+							HZ);
+			if (!timeout)
+				return -ETIMEDOUT;
+		}
+		msm_slim_get_ctrl(dev);
+	}
 	mutex_lock(&dev->tx_lock);
+
 	if (txn->mc != SLIM_USR_MC_REPORT_SATELLITE &&
-		(dev->state == MSM_CTRL_ASLEEP ||
-		dev->state == MSM_CTRL_SLEEPING)) {
-		int timeout;
+		(dev->state != MSM_CTRL_AWAKE)) {
 		dev_err(dev->dev, "controller not ready");
 		mutex_unlock(&dev->tx_lock);
-		/* Reconf is signalled when master responds */
-		timeout = wait_for_completion_timeout(&dev->reconf, HZ);
-		if (timeout) {
-			mutex_lock(&dev->tx_lock);
-		} else {
-			msm_slim_put_ctrl(dev);
-			return -EBUSY;
-		}
+		msm_slim_put_ctrl(dev);
+		return -EREMOTEIO;
 	}
 	if (txn->mt == SLIM_MSG_MT_CORE &&
 		(txn->mc == SLIM_MSG_MC_CONNECT_SOURCE ||
@@ -370,24 +399,23 @@
 		mutex_unlock(&dev->tx_lock);
 		msm_slim_put_ctrl(dev);
 		timeout = wait_for_completion_timeout(txn->comp, HZ);
-		if (!timeout) {
-			pr_err("connect/disc :0x%x, tid:%d timed out", txn->mc,
-					txn->tid);
+		if (!timeout)
 			ret = -ETIMEDOUT;
+		else
+			ret = txn->ec;
+		if (ret) {
+			pr_err("connect/disconnect:0x%x,tid:%d err:%d", txn->mc,
+					txn->tid, ret);
 			mutex_lock(&ctrl->m_ctrl);
 			ctrl->txnt[txn->tid] = NULL;
 			mutex_unlock(&ctrl->m_ctrl);
-		} else {
-			ret = txn->ec;
 		}
-		if (ret)
-			pr_err("connect/disconnect:0x%x,tid:%d err:%d", txn->mc,
-					txn->tid, ret);
 		return ret ? ret : dev->err;
 	}
 ngd_xfer_err:
 	mutex_unlock(&dev->tx_lock);
-	msm_slim_put_ctrl(dev);
+	if (txn->mc != SLIM_USR_MC_REPORT_SATELLITE)
+		msm_slim_put_ctrl(dev);
 	return ret ? ret : dev->err;
 }
 
@@ -398,20 +426,18 @@
 	if (!ret) {
 		int timeout;
 		timeout = wait_for_completion_timeout(txn->comp, HZ);
-		if (!timeout) {
-			pr_err("master req:0x%x, tid:%d timed out", txn->mc,
-					txn->tid);
+		if (!timeout)
 			ret = -ETIMEDOUT;
-			mutex_lock(&ctrl->m_ctrl);
-			ctrl->txnt[txn->tid] = NULL;
-			mutex_unlock(&ctrl->m_ctrl);
-		} else {
+		else
 			ret = txn->ec;
-		}
 	}
-	if (ret)
+	if (ret) {
 		pr_err("master msg:0x%x,tid:%d ret:%d", txn->mc,
 				txn->tid, ret);
+		mutex_lock(&ctrl->m_ctrl);
+		ctrl->txnt[txn->tid] = NULL;
+		mutex_unlock(&ctrl->m_ctrl);
+	}
 
 	return ret;
 }
@@ -582,26 +608,31 @@
 		txn.wbuf = wbuf;
 		txn.len = 4;
 		pr_info("SLIM SAT: Received master capability");
-		dev->use_rx_msgqs = 1;
-		msm_slim_sps_init(dev, dev->bam_mem,
-			NGD_BASE(dev->ctrl.nr, dev->ver) + NGD_STATUS, true);
-		if (dev->use_rx_msgqs)
-			msgq_en |= NGD_CFG_RX_MSGQ_EN;
-		writel_relaxed(msgq_en, dev->base +
-				NGD_BASE(dev->ctrl.nr, dev->ver));
-		/* make sure NGD MSG-Q config goes through */
-		mb();
+		if (dev->state == MSM_CTRL_DOWN) {
+			dev->use_rx_msgqs = 1;
+			msm_slim_sps_init(dev, dev->bam_mem,
+				NGD_BASE(dev->ctrl.nr, dev->ver) + NGD_STATUS,
+				true);
+			if (dev->use_rx_msgqs)
+				msgq_en |= NGD_CFG_RX_MSGQ_EN;
+			writel_relaxed(msgq_en, dev->base +
+					NGD_BASE(dev->ctrl.nr, dev->ver));
+			/* make sure NGD MSG-Q config goes through */
+			mb();
+		}
 
 		ret = ngd_xfer_msg(&dev->ctrl, &txn);
 		if (!ret) {
+			enum msm_ctrl_state prev_state = dev->state;
 			dev->state = MSM_CTRL_AWAKE;
-
-			pm_runtime_use_autosuspend(dev->dev);
-			pm_runtime_set_autosuspend_delay(dev->dev,
-							MSM_SLIM_AUTOSUSPEND);
-			pm_runtime_set_active(dev->dev);
-			pm_runtime_enable(dev->dev);
-			complete(&dev->reconf);
+			if (prev_state >= MSM_CTRL_ASLEEP)
+				complete(&dev->reconf);
+			else
+				pr_err("SLIM: unexpected capability, state:%d",
+					prev_state);
+			/* ADSP SSR, send device_up notifications */
+			if (prev_state == MSM_CTRL_DOWN)
+				schedule_work(&dev->slave_notify);
 		}
 	}
 	if (mc == SLIM_MSG_MC_REPLY_INFORMATION ||
@@ -654,38 +685,116 @@
 	}
 }
 
-static int ngd_slim_enable(struct msm_slim_ctrl *dev, bool enable)
+static int ngd_slim_power_up(struct msm_slim_ctrl *dev)
 {
+	void __iomem *ngd;
+	int timeout, ret;
+	enum msm_ctrl_state cur_state = dev->state;
+	u32 laddr;
+	u32 msgq_en = 1;
 	u32 ngd_int = (NGD_INT_RECFG_DONE | NGD_INT_TX_NACKED_2 |
 			NGD_INT_MSG_BUF_CONTE | NGD_INT_MSG_TX_INVAL |
 			NGD_INT_IE_VE_CHG | NGD_INT_DEV_ERR |
 			NGD_INT_TX_MSG_SENT | NGD_INT_RX_MSG_RCVD);
-	if (enable) {
-		int ret = msm_slim_qmi_init(dev, false);
-		if (ret)
-			return ret;
-		ret = msm_slim_qmi_power_request(dev, true);
-		if (ret)
-			return ret;
-		writel_relaxed(ngd_int, dev->base + NGD_INT_EN +
-					NGD_BASE(dev->ctrl.nr, dev->ver));
+
+	if (cur_state == MSM_CTRL_DOWN) {
+		int timeout = wait_for_completion_timeout(&dev->qmi.qmi_comp,
+						HZ);
+		if (!timeout)
+			pr_err("slimbus QMI init timed out");
+	}
+
+	ret = msm_slim_qmi_power_request(dev, true);
+	if (ret) {
+		pr_err("SLIM QMI power request failed:%d", ret);
+		return ret;
+	}
+	if (!dev->ver) {
+		dev->ver = readl_relaxed(dev->base);
+		/* Version info in 16 MSbits */
+		dev->ver >>= 16;
+	}
+	ngd = dev->base + NGD_BASE(dev->ctrl.nr, dev->ver);
+	laddr = readl_relaxed(ngd + NGD_STATUS);
+	if (laddr & NGD_LADDR) {
 		/*
-		 * Enable NGD. Configure NGD in register acc. mode until master
-		 * announcement is received
+		 * ADSP power collapse case, where HW wasn't reset.
+		 * Reconnect BAM pipes if disconnected
 		 */
-		writel_relaxed(1, dev->base + NGD_BASE(dev->ctrl.nr, dev->ver));
-		/* make sure NGD enabling goes through */
-		mb();
-	} else {
-		writel_relaxed(0, dev->base + NGD_BASE(dev->ctrl.nr, dev->ver));
-		writel_relaxed(0, dev->base + NGD_INT_EN +
+		return 0;
+	} else if (cur_state != MSM_CTRL_DOWN) {
+		pr_info("ADSP P.C. CTRL state:%d NGD not enumerated:0x%x",
+					dev->state, laddr);
+		if (dev->use_rx_msgqs)
+			msgq_en |= NGD_CFG_RX_MSGQ_EN;
+	}
+
+	/*
+	 * ADSP power collapse case (OR SSR), where HW was reset
+	 * BAM programming will happen when capability message is received
+	 */
+	writel_relaxed(ngd_int, dev->base + NGD_INT_EN +
 				NGD_BASE(dev->ctrl.nr, dev->ver));
-		/* make sure NGD disabling goes through */
-		mb();
+	/*
+	 * Enable NGD. Configure NGD in register acc. mode until master
+	 * announcement is received
+	 */
+	writel_relaxed(msgq_en, dev->base + NGD_BASE(dev->ctrl.nr, dev->ver));
+	/* make sure NGD enabling goes through */
+	mb();
+
+	timeout = wait_for_completion_timeout(&dev->reconf, HZ);
+	if (!timeout) {
+		pr_err("failed to received master capability");
+		return -ETIMEDOUT;
+	}
+	if (cur_state == MSM_CTRL_DOWN)
+		complete(&dev->ctrl_up);
+	return 0;
+}
+
+static int ngd_slim_enable(struct msm_slim_ctrl *dev, bool enable)
+{
+	int ret = 0;
+	if (enable) {
+		ret = msm_slim_qmi_init(dev, false);
+		/* controller state should be in sync with framework state */
+		if (!ret) {
+			ret = slim_ctrl_clk_pause(&dev->ctrl, false,
+						SLIM_CLK_UNSPECIFIED);
+			complete(&dev->qmi.qmi_comp);
+			/*
+			 * Power-up won't be called if clock pause failed.
+			 * This can happen if ADSP SSR happened when audio
+			 * session is in progress. Framework will think that
+			 * clock pause failed so no need to wakeup controller.
+			 * Call power-up explicitly in that case, since slimbus
+			 * HW needs to be powered-on to be in sync with
+			 * framework state
+			 */
+			if (ret)
+				ngd_slim_power_up(dev);
+			if (!pm_runtime_enabled(dev->dev) ||
+					!pm_runtime_suspended(dev->dev))
+				ngd_slim_runtime_resume(dev->dev);
+			else
+				pm_runtime_resume(dev->dev);
+			pm_runtime_mark_last_busy(dev->dev);
+			pm_runtime_put(dev->dev);
+		} else
+			dev_err(dev->dev, "qmi init fail, ret:%d, state:%d",
+					ret, dev->state);
+	} else {
 		msm_slim_qmi_exit(dev);
 	}
 
-	return 0;
+	return ret;
+}
+
+static int ngd_clk_pause_wakeup(struct slim_controller *ctrl)
+{
+	struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
+	return ngd_slim_power_up(dev);
 }
 
 static int ngd_slim_rx_msgq_thread(void *data)
@@ -698,14 +807,6 @@
 	u32 buffer[10];
 	u8 msg_len = 0;
 
-	wait_for_completion_interruptible(&dev->qmi.qmi_comp);
-	ret = ngd_slim_enable(dev, true);
-	/* Exit the thread if component can't be enabled */
-	if (ret) {
-		pr_err("Enabling NGD failed:%d", ret);
-		return 0;
-	}
-
 	while (!kthread_should_stop()) {
 		set_current_state(TASK_INTERRUPTIBLE);
 		ret = wait_for_completion_interruptible(notify);
@@ -741,6 +842,64 @@
 	return 0;
 }
 
+static void ngd_laddr_lookup(struct work_struct *work)
+{
+	struct msm_slim_ctrl *dev =
+		container_of(work, struct msm_slim_ctrl, slave_notify);
+	struct slim_controller *ctrl = &dev->ctrl;
+	struct slim_device *sbdev;
+	int i;
+	mutex_lock(&ctrl->m_ctrl);
+	list_for_each_entry(sbdev, &ctrl->devs, dev_list) {
+		int ret = 0;
+		mutex_unlock(&ctrl->m_ctrl);
+		for (i = 0; i < LADDR_RETRY; i++) {
+			ret = slim_get_logical_addr(sbdev, sbdev->e_addr,
+					6, &sbdev->laddr);
+			if (!ret)
+				break;
+			else /* time for ADSP to assign LA */
+				msleep(20);
+		}
+		mutex_lock(&ctrl->m_ctrl);
+	}
+	mutex_unlock(&ctrl->m_ctrl);
+}
+
+static void ngd_adsp_down(struct work_struct *work)
+{
+	struct msm_slim_qmi *qmi =
+		container_of(work, struct msm_slim_qmi, ssr_down);
+	struct msm_slim_ctrl *dev =
+		container_of(qmi, struct msm_slim_ctrl, qmi);
+	struct slim_controller *ctrl = &dev->ctrl;
+	struct slim_device *sbdev;
+	int i;
+
+	ngd_slim_enable(dev, false);
+	/* disconnect BAM pipes */
+	msm_slim_sps_exit(dev, false);
+	dev->use_rx_msgqs = 0;
+	mutex_lock(&ctrl->m_ctrl);
+	/* device up should be called again after SSR */
+	list_for_each_entry(sbdev, &ctrl->devs, dev_list)
+		sbdev->notified = false;
+	/* invalidate logical addresses */
+	for (i = 0; i < ctrl->num_dev; i++)
+		ctrl->addrt[i].valid = false;
+	mutex_unlock(&ctrl->m_ctrl);
+	pr_info("SLIM ADSP SSR (DOWN) done");
+}
+
+static void ngd_adsp_up(struct work_struct *work)
+{
+	struct msm_slim_qmi *qmi =
+		container_of(work, struct msm_slim_qmi, ssr_up);
+	struct msm_slim_ctrl *dev =
+		container_of(qmi, struct msm_slim_ctrl, qmi);
+	ngd_slim_enable(dev, true);
+}
+
 static int __devinit ngd_slim_probe(struct platform_device *pdev)
 {
 	struct msm_slim_ctrl *dev;
@@ -834,15 +993,13 @@
 	dev->bam_mem = bam_mem;
 
 	init_completion(&dev->reconf);
+	init_completion(&dev->ctrl_up);
 	mutex_init(&dev->tx_lock);
 	spin_lock_init(&dev->rx_lock);
 	dev->ee = 1;
 	dev->irq = irq->start;
 	dev->bam.irq = bam_irq->start;
 
-	dev->ver = readl_relaxed(dev->base);
-	/* Version info in 16 MSbits */
-	dev->ver >>= 16;
 	init_completion(&dev->rx_msgq_notify);
 
 	/* Register with framework */
@@ -854,7 +1011,7 @@
 
 	dev->ctrl.dev.parent = &pdev->dev;
 	dev->ctrl.dev.of_node = pdev->dev.of_node;
-	dev->state = MSM_CTRL_ASLEEP;
+	dev->state = MSM_CTRL_DOWN;
 
 	ret = request_irq(dev->irq, ngd_slim_interrupt,
 			IRQF_TRIGGER_HIGH, "ngd_slim_irq", dev);
@@ -865,7 +1022,16 @@
 	}
 
 	init_completion(&dev->qmi.qmi_comp);
+	pm_runtime_use_autosuspend(dev->dev);
+	pm_runtime_set_autosuspend_delay(dev->dev, MSM_SLIM_AUTOSUSPEND);
+	pm_runtime_set_suspended(dev->dev);
+	pm_runtime_enable(dev->dev);
+
+	INIT_WORK(&dev->slave_notify, ngd_laddr_lookup);
+	INIT_WORK(&dev->qmi.ssr_down, ngd_adsp_down);
+	INIT_WORK(&dev->qmi.ssr_up, ngd_adsp_up);
 	dev->qmi.nb.notifier_call = ngd_qmi_available;
+	pm_runtime_get_noresume(dev->dev);
 	ret = qmi_svc_event_notifier_register(SLIMBUS_QMI_SVC_ID,
 				SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
 	if (ret) {
@@ -873,6 +1039,7 @@
 		goto qmi_register_failed;
 	}
 
+
 	/* Fire up the Rx message queue thread */
 	dev->rx_msgq_thread = kthread_run(ngd_slim_rx_msgq_thread, dev,
 					NGD_SLIM_NAME "_ngd_msgq_thread");
@@ -914,7 +1081,6 @@
 	qmi_svc_event_notifier_unregister(SLIMBUS_QMI_SVC_ID,
 				SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
 	pm_runtime_disable(&pdev->dev);
-	pm_runtime_set_suspended(&pdev->dev);
 	free_irq(dev->irq, dev);
 	slim_del_controller(&dev->ctrl);
 	kthread_stop(dev->rx_msgq_thread);
@@ -938,31 +1104,12 @@
  * functions to be called from system suspend/resume. So they are not
  * inside ifdef CONFIG_PM_RUNTIME
  */
-#ifdef CONFIG_PM_SLEEP
-static int ngd_slim_runtime_suspend(struct device *device)
-{
-	struct platform_device *pdev = to_platform_device(device);
-	struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
-	int ret;
-	dev_dbg(device, "pm_runtime: suspending...\n");
-	dev->state = MSM_CTRL_SLEEPING;
-	ret = slim_ctrl_clk_pause(&dev->ctrl, false, SLIM_CLK_UNSPECIFIED);
-	if (ret) {
-		dev_err(device, "clk pause not entered:%d", ret);
-		dev->state = MSM_CTRL_AWAKE;
-	} else {
-		dev->state = MSM_CTRL_ASLEEP;
-	}
-	return ret;
-}
-
 static int ngd_slim_runtime_resume(struct device *device)
 {
 	struct platform_device *pdev = to_platform_device(device);
 	struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
 	int ret = 0;
-	dev_dbg(device, "pm_runtime: resuming...\n");
-	if (dev->state == MSM_CTRL_ASLEEP)
+	if (dev->state >= MSM_CTRL_ASLEEP)
 		ret = slim_ctrl_clk_pause(&dev->ctrl, true, 0);
 	if (ret) {
 		dev_err(device, "clk pause not exited:%d", ret);
@@ -973,6 +1120,24 @@
 	return ret;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int ngd_slim_runtime_suspend(struct device *device)
+{
+	struct platform_device *pdev = to_platform_device(device);
+	struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
+	int ret = 0;
+	dev->state = MSM_CTRL_SLEEPING;
+	ret = slim_ctrl_clk_pause(&dev->ctrl, false, SLIM_CLK_UNSPECIFIED);
+	if (ret) {
+		if (ret != -EBUSY)
+			dev_err(device, "clk pause not entered:%d", ret);
+		dev->state = MSM_CTRL_AWAKE;
+	} else {
+		dev->state = MSM_CTRL_ASLEEP;
+	}
+	return ret;
+}
+
 static int ngd_slim_suspend(struct device *dev)
 {
 	int ret = -EBUSY;
diff --git a/drivers/slimbus/slim-msm.c b/drivers/slimbus/slim-msm.c
index 137f85e..72a8669 100644
--- a/drivers/slimbus/slim-msm.c
+++ b/drivers/slimbus/slim-msm.c
@@ -517,6 +517,8 @@
 		},
 	};
 
+	if (dev->bam.hdl)
+		goto init_rx_msgq;
 	bam_props.ee = dev->ee;
 	bam_props.virt_addr = dev->bam.base;
 	bam_props.phys_addr = bam_mem->start;
@@ -565,7 +567,7 @@
 	return ret;
 }
 
-void msm_slim_sps_exit(struct msm_slim_ctrl *dev)
+void msm_slim_sps_exit(struct msm_slim_ctrl *dev, bool dereg)
 {
 	if (dev->use_rx_msgqs) {
 		struct msm_slim_endp *endpoint = &dev->rx_msgq;
@@ -579,7 +581,10 @@
 		sps_disconnect(endpoint->sps);
 		msm_slim_sps_mem_free(dev, descr);
 		msm_slim_free_endpoint(endpoint);
+	}
+	if (dereg) {
 		sps_deregister_bam_device(dev->bam.hdl);
+		dev->bam.hdl = 0L;
 	}
 }
 
diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h
index 3daf7ee..1c6db32 100644
--- a/drivers/slimbus/slim-msm.h
+++ b/drivers/slimbus/slim-msm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -152,6 +152,7 @@
 	MSM_CTRL_AWAKE,
 	MSM_CTRL_SLEEPING,
 	MSM_CTRL_ASLEEP,
+	MSM_CTRL_DOWN,
 };
 
 struct msm_slim_sps_bam {
@@ -176,6 +177,8 @@
 	struct kthread_worker		kworker;
 	struct completion		qmi_comp;
 	struct notifier_block		nb;
+	struct work_struct		ssr_down;
+	struct work_struct		ssr_up;
 };
 
 struct msm_slim_ctrl {
@@ -212,8 +215,10 @@
 	bool			reconf_busy;
 	bool			chan_active;
 	enum msm_ctrl_state	state;
+	struct completion	ctrl_up;
 	int			nsats;
 	u32			ver;
+	struct work_struct	slave_notify;
 	struct msm_slim_qmi	qmi;
 };
 
@@ -266,7 +271,7 @@
 int msm_slim_rx_msgq_get(struct msm_slim_ctrl *dev, u32 *data, int offset);
 int msm_slim_sps_init(struct msm_slim_ctrl *dev, struct resource *bam_mem,
 			u32 pipe_reg, bool remote);
-void msm_slim_sps_exit(struct msm_slim_ctrl *dev);
+void msm_slim_sps_exit(struct msm_slim_ctrl *dev, bool dereg);
 
 void msm_slim_qmi_exit(struct msm_slim_ctrl *dev);
 int msm_slim_qmi_init(struct msm_slim_ctrl *dev, bool apps_is_master);
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index c320e46..e5b3158 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -3047,6 +3047,7 @@
 	for (i = 0; i < ctrl->last_tid; i++) {
 		if (ctrl->txnt[i]) {
 			ret = -EBUSY;
+			pr_info("slim_clk_pause: txn-rsp for %d pending", i);
 			mutex_unlock(&ctrl->m_ctrl);
 			return -EBUSY;
 		}
@@ -3057,6 +3058,7 @@
 	mutex_lock(&ctrl->sched.m_reconf);
 	/* Data channels active */
 	if (ctrl->sched.usedslots) {
+		pr_info("slim_clk_pause: data channel active");
 		ret = -EBUSY;
 		goto clk_pause_ret;
 	}
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 2d73af6..8ff6cff 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -54,18 +54,34 @@
 #include <linux/device.h>
 #include <linux/wakelock.h>
 #include <linux/debugfs.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
 #include <asm/atomic.h>
 #include <asm/irq.h>
 
 #include <mach/hardware.h>
 #include <mach/dma.h>
+#include <mach/sps.h>
 #include <mach/msm_serial_hs.h>
 
 #include "msm_serial_hs_hwreg.h"
+#define UART_SPS_CONS_PERIPHERAL 0
+#define UART_SPS_PROD_PERIPHERAL 1
 
 static int hs_serial_debug_mask = 1;
 module_param_named(debug_mask, hs_serial_debug_mask,
 		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+/*
+ * There are 3 different kind of UART Core available on MSM.
+ * High Speed UART (i.e. Legacy HSUART), GSBI based HSUART
+ * and BSLP based HSUART.
+ */
+enum uart_core_type {
+	LEGACY_HSUART,
+	GSBI_HSUART,
+	BLSP_HSUART,
+};
 
 enum flush_reason {
 	FLUSH_NONE,
@@ -92,6 +108,17 @@
 	CLK_REQ_OFF_RXSTALE_FLUSHED,
 };
 
+/* SPS data structures to support HSUART with BAM
+ * @sps_pipe - This struct defines BAM pipe descriptor
+ * @sps_connect - This struct defines a connection's end point
+ * @sps_register - This struct defines a event registration parameters
+ */
+struct msm_hs_sps_ep_conn_data {
+	struct sps_pipe *pipe_handle;
+	struct sps_connect config;
+	struct sps_register_event event;
+};
+
 struct msm_hs_tx {
 	unsigned int tx_ready_int_en;  /* ok to dma more tx */
 	unsigned int dma_in_flight;    /* tx dma in progress */
@@ -105,6 +132,7 @@
 	int tx_count;
 	dma_addr_t dma_base;
 	struct tasklet_struct tlet;
+	struct msm_hs_sps_ep_conn_data cons;
 };
 
 struct msm_hs_rx {
@@ -122,6 +150,7 @@
 	struct wake_lock wake_lock;
 	struct delayed_work flip_insert_work;
 	struct tasklet_struct tlet;
+	struct msm_hs_sps_ep_conn_data prod;
 };
 
 enum buffer_states {
@@ -168,7 +197,20 @@
 	struct work_struct clock_off_w; /* work for actual clock off */
 	struct workqueue_struct *hsuart_wq; /* hsuart workqueue */
 	struct mutex clk_mutex; /* mutex to guard against clock off/clock on */
+	struct work_struct reset_bam_rx; /* work for reset bam rx endpoint */
+	struct work_struct disconnect_rx_endpoint; /* disconnect rx_endpoint */
 	bool tty_flush_receive;
+	enum uart_core_type uart_type;
+	u32 bam_handle;
+	resource_size_t bam_mem;
+	int bam_irq;
+	unsigned char __iomem *bam_base;
+	unsigned int bam_tx_ep_pipe_index;
+	unsigned int bam_rx_ep_pipe_index;
+	/* struct sps_event_notify is an argument passed when triggering a
+	 * callback event object registered for an SPS connection end point.
+	 */
+	struct sps_event_notify notify;
 };
 
 #define MSM_UARTDM_BURST_SIZE 16   /* DM burst size (in bytes) */
@@ -176,12 +218,17 @@
 #define UARTDM_RX_BUF_SIZE 512
 #define RETRY_TIMEOUT 5
 #define UARTDM_NR 256
+#define BAM_PIPE_MIN 0
+#define BAM_PIPE_MAX 11
 
 static struct dentry *debug_base;
 static struct msm_hs_port q_uart_port[UARTDM_NR];
 static struct platform_driver msm_serial_hs_platform_driver;
 static struct uart_driver msm_hs_driver;
 static struct uart_ops msm_hs_ops;
+static void msm_hs_start_rx_locked(struct uart_port *uport);
+static void msm_serial_hs_rx_tlet(unsigned long tlet_ptr);
+static void flip_insert_work(struct work_struct *work);
 
 #define UARTDM_TO_MSM(uart_port) \
 	container_of((uart_port), struct msm_hs_port, uport)
@@ -244,7 +291,10 @@
 	/* assume gsbi uart if gsbi resource found in pdata */
 	return ((msm_uport->mapped_gsbi != NULL));
 }
-
+static unsigned int is_blsp_uart(struct msm_hs_port *msm_uport)
+{
+	return (msm_uport->uart_type == BLSP_HSUART);
+}
 static inline unsigned int msm_hs_read(struct uart_port *uport,
 				       unsigned int offset)
 {
@@ -320,13 +370,21 @@
 	if (val) {
 		spin_lock_irqsave(&uport->lock, flags);
 		ret = msm_hs_read(uport, UARTDM_MR2_ADDR);
-		ret |= UARTDM_MR2_LOOP_MODE_BMSK;
+		if (is_blsp_uart(msm_uport))
+			ret |= (UARTDM_MR2_LOOP_MODE_BMSK |
+				UARTDM_MR2_RFR_CTS_LOOP_MODE_BMSK);
+		else
+			ret |= UARTDM_MR2_LOOP_MODE_BMSK;
 		msm_hs_write(uport, UARTDM_MR2_ADDR, ret);
 		spin_unlock_irqrestore(&uport->lock, flags);
 	} else {
 		spin_lock_irqsave(&uport->lock, flags);
 		ret = msm_hs_read(uport, UARTDM_MR2_ADDR);
-		ret &= ~UARTDM_MR2_LOOP_MODE_BMSK;
+		if (is_blsp_uart(msm_uport))
+			ret &= ~(UARTDM_MR2_LOOP_MODE_BMSK |
+				UARTDM_MR2_RFR_CTS_LOOP_MODE_BMSK);
+		else
+			ret &= ~UARTDM_MR2_LOOP_MODE_BMSK;
 		msm_hs_write(uport, UARTDM_MR2_ADDR, ret);
 		spin_unlock_irqrestore(&uport->lock, flags);
 	}
@@ -470,6 +528,89 @@
 	return 0;
 }
 
+
+/* Connect a UART peripheral's SPS endpoint(consumer endpoint)
+ *
+ * Also registers a SPS callback function for the consumer
+ * process with the SPS driver
+ *
+ * @uport - Pointer to uart uport structure
+ *
+ * @return - 0 if successful else negative value.
+ *
+ */
+
+static int msm_hs_spsconnect_tx(struct uart_port *uport)
+{
+	int ret;
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+	struct msm_hs_tx *tx = &msm_uport->tx;
+	struct sps_pipe *sps_pipe_handle = tx->cons.pipe_handle;
+	struct sps_connect *sps_config = &tx->cons.config;
+	struct sps_register_event *sps_event = &tx->cons.event;
+
+	/* Establish connection between peripheral and memory endpoint */
+	ret = sps_connect(sps_pipe_handle, sps_config);
+	if (ret) {
+		pr_err("msm_serial_hs: sps_connect() failed for tx!!\n"
+		"pipe_handle=0x%x ret=%d", (u32)sps_pipe_handle, ret);
+		return ret;
+	}
+	/* Register callback event for EOT (End of transfer) event. */
+	ret = sps_register_event(sps_pipe_handle, sps_event);
+	if (ret) {
+		pr_err("msm_serial_hs: sps_connect() failed for tx!!\n"
+		"pipe_handle=0x%x ret=%d", (u32)sps_pipe_handle, ret);
+		goto reg_event_err;
+	}
+	return 0;
+
+reg_event_err:
+	sps_disconnect(sps_pipe_handle);
+	return ret;
+}
+
+/* Connect a UART peripheral's SPS endpoint(producer endpoint)
+ *
+ * Also registers a SPS callback function for the producer
+ * process with the SPS driver
+ *
+ * @uport - Pointer to uart uport structure
+ *
+ * @return - 0 if successful else negative value.
+ *
+ */
+
+static int msm_hs_spsconnect_rx(struct uart_port *uport)
+{
+	int ret;
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+	struct msm_hs_rx *rx = &msm_uport->rx;
+	struct sps_pipe *sps_pipe_handle = rx->prod.pipe_handle;
+	struct sps_connect *sps_config = &rx->prod.config;
+	struct sps_register_event *sps_event = &rx->prod.event;
+
+	/* Establish connection between peripheral and memory endpoint */
+	ret = sps_connect(sps_pipe_handle, sps_config);
+	if (ret) {
+		pr_err("msm_serial_hs: sps_connect() failed for rx!!\n"
+		"pipe_handle=0x%x ret=%d", (u32)sps_pipe_handle, ret);
+		return ret;
+	}
+	/* Register callback event for EOT (End of transfer) event. */
+	ret = sps_register_event(sps_pipe_handle, sps_event);
+	if (ret) {
+		pr_err("msm_serial_hs: sps_connect() failed for rx!!\n"
+		"pipe_handle=0x%x ret=%d", (u32)sps_pipe_handle, ret);
+		goto reg_event_err;
+	}
+	return 0;
+
+reg_event_err:
+	sps_disconnect(sps_pipe_handle);
+	return ret;
+}
+
 /*
  * programs the UARTDM_CSR register with correct bit rates
  *
@@ -479,9 +620,8 @@
  * Goal is to have around 8 ms before indicate stale.
  * roundup (((Bit Rate * .008) / 10) + 1
  */
-static unsigned long msm_hs_set_bps_locked(struct uart_port *uport,
-			       unsigned int bps,
-				unsigned long flags)
+static void msm_hs_set_bps_locked(struct uart_port *uport,
+			       unsigned int bps)
 {
 	unsigned long rxstale;
 	unsigned long data;
@@ -581,15 +721,11 @@
 		uport->uartclk = 7372800;
 	}
 
-	spin_unlock_irqrestore(&uport->lock, flags);
 	if (clk_set_rate(msm_uport->clk, uport->uartclk)) {
 		printk(KERN_WARNING "Error setting clock rate on UART\n");
 		WARN_ON(1);
-		spin_lock_irqsave(&uport->lock, flags);
-		return flags;
 	}
 
-	spin_lock_irqsave(&uport->lock, flags);
 	data = rxstale & UARTDM_IPR_STALE_LSB_BMSK;
 	data |= UARTDM_IPR_STALE_TIMEOUT_MSB_BMSK & (rxstale << 2);
 
@@ -601,7 +737,6 @@
 	 */
 	msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX);
 	msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX);
-	return flags;
 }
 
 
@@ -654,6 +789,23 @@
 	msm_hs_write(uport, UARTDM_IPR_ADDR, data);
 }
 
+
+/* Reset BAM RX Endpoint Pipe Index from workqueue context*/
+
+static void hsuart_reset_bam_rx_work(struct work_struct *w)
+{
+	struct msm_hs_port *msm_uport = container_of(w, struct msm_hs_port,
+							reset_bam_rx);
+	struct uart_port *uport = &msm_uport->uport;
+	struct msm_hs_rx *rx = &msm_uport->rx;
+	struct sps_pipe *sps_pipe_handle = rx->prod.pipe_handle;
+
+	sps_disconnect(sps_pipe_handle);
+	msm_hs_spsconnect_rx(uport);
+
+	msm_serial_hs_rx_tlet((unsigned long) &rx->tlet);
+}
+
 /*
  * termios :  new ktermios
  * oldtermios:  old ktermios previous setting
@@ -666,12 +818,12 @@
 {
 	unsigned int bps;
 	unsigned long data;
-	unsigned long flags;
 	unsigned int c_cflag = termios->c_cflag;
 	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+	struct msm_hs_rx *rx = &msm_uport->rx;
+	struct sps_pipe *sps_pipe_handle = rx->prod.pipe_handle;
 
 	mutex_lock(&msm_uport->clk_mutex);
-	spin_lock_irqsave(&uport->lock, flags);
 
 	/*
 	 * Disable Rx channel of UARTDM
@@ -683,7 +835,13 @@
 	 * suggested to do disable/reset or reset/disable at the same time.
 	 */
 	data = msm_hs_read(uport, UARTDM_DMEN_ADDR);
-	data &= ~UARTDM_RX_DM_EN_BMSK;
+	if (is_blsp_uart(msm_uport)) {
+		/* Disable UARTDM RX BAM Interface */
+		data &= ~UARTDM_RX_BAM_ENABLE_BMSK;
+	} else {
+		data &= ~UARTDM_RX_DM_EN_BMSK;
+	}
+
 	msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
 
 	/* 300 is the minimum baud support by the driver  */
@@ -697,7 +855,7 @@
 	if (!uport->uartclk)
 		msm_hs_set_std_bps_locked(uport, bps);
 	else
-		flags = msm_hs_set_bps_locked(uport, bps, flags);
+		msm_hs_set_bps_locked(uport, bps);
 
 	data = msm_hs_read(uport, UARTDM_MR2_ADDR);
 	data &= ~UARTDM_MR2_PARITY_MODE_BMSK;
@@ -775,13 +933,18 @@
 		 * dsb requires here.
 		 */
 		mb();
-		/* do discard flush */
-		msm_dmov_flush(msm_uport->dma_rx_channel, 0);
+		if (is_blsp_uart(msm_uport)) {
+			sps_disconnect(sps_pipe_handle);
+			msm_hs_spsconnect_rx(uport);
+			msm_serial_hs_rx_tlet((unsigned long) &rx->tlet);
+		} else {
+			/* do discard flush */
+			msm_dmov_flush(msm_uport->dma_rx_channel, 0);
+		}
 	}
 
 	msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
 	mb();
-	spin_unlock_irqrestore(&uport->lock, flags);
 	mutex_unlock(&msm_uport->clk_mutex);
 }
 
@@ -814,6 +977,20 @@
 	msm_uport->tx.tx_ready_int_en = 0;
 }
 
+/* Disconnect BAM RX Endpoint Pipe Index from workqueue context*/
+static void hsuart_disconnect_rx_endpoint_work(struct work_struct *w)
+{
+	struct msm_hs_port *msm_uport = container_of(w, struct msm_hs_port,
+						disconnect_rx_endpoint);
+	struct msm_hs_rx *rx = &msm_uport->rx;
+	struct sps_pipe *sps_pipe_handle = rx->prod.pipe_handle;
+
+	sps_disconnect(sps_pipe_handle);
+	wake_lock_timeout(&msm_uport->rx.wake_lock, HZ / 2);
+	msm_uport->rx.flush = FLUSH_SHUTDOWN;
+	wake_up(&msm_uport->rx.wait);
+}
+
 /*
  *  Standard API, Stop receiver as soon as possible.
  *
@@ -829,7 +1006,10 @@
 
 	/* disable dlink */
 	data = msm_hs_read(uport, UARTDM_DMEN_ADDR);
-	data &= ~UARTDM_RX_DM_EN_BMSK;
+	if (is_blsp_uart(msm_uport))
+		data &= ~UARTDM_RX_BAM_ENABLE_BMSK;
+	else
+		data &= ~UARTDM_RX_DM_EN_BMSK;
 	msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
 
 	/* calling DMOV or CLOCK API. Hence mb() */
@@ -837,10 +1017,17 @@
 	/* Disable the receiver */
 	if (msm_uport->rx.flush == FLUSH_NONE) {
 		wake_lock(&msm_uport->rx.wake_lock);
-		/* do discard flush */
-		msm_dmov_flush(msm_uport->dma_rx_channel, 0);
+		if (is_blsp_uart(msm_uport)) {
+			msm_uport->rx.flush = FLUSH_STOP;
+			/* workqueue for BAM rx endpoint disconnect */
+			queue_work(msm_uport->hsuart_wq,
+				&msm_uport->disconnect_rx_endpoint);
+		} else {
+			/* do discard flush */
+			msm_dmov_flush(msm_uport->dma_rx_channel, 0);
+		}
 	}
-	if (msm_uport->rx.flush != FLUSH_SHUTDOWN)
+	if (!is_blsp_uart(msm_uport) && msm_uport->rx.flush != FLUSH_SHUTDOWN)
 		msm_uport->rx.flush = FLUSH_STOP;
 }
 
@@ -852,9 +1039,11 @@
 	int aligned_tx_count;
 	dma_addr_t src_addr;
 	dma_addr_t aligned_src_addr;
+	u32 flags = SPS_IOVEC_FLAG_EOT;
 	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
 	struct msm_hs_tx *tx = &msm_uport->tx;
 	struct circ_buf *tx_buf = &msm_uport->uport.state->xmit;
+	struct sps_pipe *sps_pipe_handle;
 
 	if (uart_circ_empty(tx_buf) || uport->state->port.tty->stopped) {
 		msm_hs_stop_tx_locked(uport);
@@ -882,14 +1071,21 @@
 	dma_sync_single_for_device(uport->dev, aligned_src_addr,
 			aligned_tx_count, DMA_TO_DEVICE);
 
-	tx->command_ptr->num_rows = (((tx_count + 15) >> 4) << 16) |
-				     ((tx_count + 15) >> 4);
-	tx->command_ptr->src_row_addr = src_addr;
+	if (is_blsp_uart(msm_uport)) {
+		/* Issue TX BAM Start IFC command */
+		msm_hs_write(uport, UARTDM_CR_ADDR, START_TX_BAM_IFC);
+	} else {
+		tx->command_ptr->num_rows =
+				(((tx_count + 15) >> 4) << 16) |
+				((tx_count + 15) >> 4);
+		tx->command_ptr->src_row_addr = src_addr;
 
-	dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr,
-				   sizeof(dmov_box), DMA_TO_DEVICE);
+		dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr,
+				sizeof(dmov_box), DMA_TO_DEVICE);
 
-	*tx->command_ptr_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(tx->mapped_cmd_ptr);
+		*tx->command_ptr_ptr = CMD_PTR_LP |
+				DMOV_CMD_ADDR(tx->mapped_cmd_ptr);
+	}
 
 	/* Save tx_count to use in Callback */
 	tx->tx_count = tx_count;
@@ -901,16 +1097,28 @@
 	/* Calling next DMOV API. Hence mb() here. */
 	mb();
 
-	dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr_ptr,
-				   sizeof(u32), DMA_TO_DEVICE);
 	msm_uport->tx.flush = FLUSH_NONE;
-	msm_dmov_enqueue_cmd(msm_uport->dma_tx_channel, &tx->xfer);
+
+	if (is_blsp_uart(msm_uport)) {
+		sps_pipe_handle = tx->cons.pipe_handle;
+		/* Queue transfer request to SPS */
+		sps_transfer_one(sps_pipe_handle, src_addr, tx_count,
+					msm_uport, flags);
+	} else {
+		dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr_ptr,
+			sizeof(u32), DMA_TO_DEVICE);
+
+		msm_dmov_enqueue_cmd(msm_uport->dma_tx_channel, &tx->xfer);
+	}
 }
 
 /* Start to receive the next chunk of data */
 static void msm_hs_start_rx_locked(struct uart_port *uport)
 {
 	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+	struct msm_hs_rx *rx = &msm_uport->rx;
+	struct sps_pipe *sps_pipe_handle;
+	u32 flags = SPS_IOVEC_FLAG_EOT;
 	unsigned int buffer_pending = msm_uport->rx.buffer_pending;
 	unsigned int data;
 
@@ -919,6 +1127,10 @@
 		printk(KERN_ERR "Error: rx started in buffer state = %x",
 		       buffer_pending);
 
+	if (is_blsp_uart(msm_uport)) {
+		/* Issue RX BAM Start IFC command */
+		msm_hs_write(uport, UARTDM_CR_ADDR, START_RX_BAM_IFC);
+	}
 	msm_hs_write(uport, UARTDM_CR_ADDR, RESET_STALE_INT);
 	msm_hs_write(uport, UARTDM_DMRX_ADDR, UARTDM_RX_BUF_SIZE);
 	msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_ENABLE);
@@ -929,15 +1141,29 @@
 	 * disable in set_termios before configuring baud rate.
 	 */
 	data = msm_hs_read(uport, UARTDM_DMEN_ADDR);
-	data |= UARTDM_RX_DM_EN_BMSK;
+	if (is_blsp_uart(msm_uport)) {
+		/* Enable UARTDM Rx BAM Interface */
+		data |= UARTDM_RX_BAM_ENABLE_BMSK;
+	} else {
+		data |= UARTDM_RX_DM_EN_BMSK;
+	}
+
 	msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
 	msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
 	/* Calling next DMOV API. Hence mb() here. */
 	mb();
 
 	msm_uport->rx.flush = FLUSH_NONE;
-	msm_dmov_enqueue_cmd(msm_uport->dma_rx_channel, &msm_uport->rx.xfer);
 
+	if (is_blsp_uart(msm_uport)) {
+		sps_pipe_handle = rx->prod.pipe_handle;
+		/* Queue transfer request to SPS */
+		sps_transfer_one(sps_pipe_handle, rx->rbuffer,
+			UARTDM_RX_BUF_SIZE, msm_uport, flags);
+	} else {
+		msm_dmov_enqueue_cmd(msm_uport->dma_rx_channel,
+				&msm_uport->rx.xfer);
+	}
 }
 
 static void flip_insert_work(struct work_struct *work)
@@ -999,6 +1225,7 @@
 {
 	int retval;
 	int rx_count;
+	static int remaining_rx_count, bytes_pending;
 	unsigned long status;
 	unsigned long flags;
 	unsigned int error_f = 0;
@@ -1075,6 +1302,20 @@
 
 	rx_count = msm_hs_read(uport, UARTDM_RX_TOTAL_SNAP_ADDR);
 
+	if (is_blsp_uart(msm_uport)) {
+		if (rx_count > UARTDM_RX_BUF_SIZE) {
+			if (bytes_pending) {
+				rx_count = remaining_rx_count;
+				bytes_pending = 0;
+			} else {
+				remaining_rx_count = rx_count -
+						UARTDM_RX_BUF_SIZE;
+				if (remaining_rx_count)
+					bytes_pending = 1;
+				rx_count = UARTDM_RX_BUF_SIZE;
+			}
+		}
+	}
 	/* order the read of rx.buffer */
 	rmb();
 
@@ -1124,6 +1365,31 @@
 	}
 }
 
+/**
+ * Callback notification from SPS driver
+ *
+ * This callback function gets triggered called from
+ * SPS driver when requested SPS data transfer is
+ * completed.
+ *
+ */
+
+static void msm_hs_sps_tx_callback(struct sps_event_notify *notify)
+{
+	struct msm_hs_port *msm_uport =
+		(struct msm_hs_port *)
+		((struct sps_event_notify *)notify)->user;
+
+	msm_uport->notify = *notify;
+	pr_debug("%s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
+		__func__, notify->event_id,
+		notify->data.transfer.iovec.addr,
+		notify->data.transfer.iovec.size,
+		notify->data.transfer.iovec.flags);
+
+	tasklet_schedule(&msm_uport->tx.tlet);
+}
+
 /*
  *  This routine is called when we are done with a DMA transfer
  *
@@ -1170,6 +1436,33 @@
 	spin_unlock_irqrestore(&(msm_uport->uport.lock), flags);
 }
 
+/**
+ * Callback notification from SPS driver
+ *
+ * This callback function gets triggered called from
+ * SPS driver when requested SPS data transfer is
+ * completed.
+ *
+ */
+
+static void msm_hs_sps_rx_callback(struct sps_event_notify *notify)
+{
+
+	struct msm_hs_port *msm_uport =
+		(struct msm_hs_port *)
+		((struct sps_event_notify *)notify)->user;
+
+	msm_uport->notify = *notify;
+	pr_debug("%s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
+		__func__, notify->event_id,
+		notify->data.transfer.iovec.addr,
+		notify->data.transfer.iovec.size,
+		notify->data.transfer.iovec.flags);
+
+	if (msm_uport->rx.flush == FLUSH_NONE)
+		tasklet_schedule(&msm_uport->rx.tlet);
+}
+
 /*
  * This routine is called when we are done with a DMA transfer or the
  * a flush has been sent to the data mover driver.
@@ -1265,7 +1558,8 @@
 {
 	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
 
-	msm_uport->tty_flush_receive = true;
+	if (msm_uport->tx.dma_in_flight)
+		msm_uport->tty_flush_receive = true;
 }
 
 /*
@@ -1356,6 +1650,14 @@
 	switch (msm_uport->clk_req_off_state) {
 	case CLK_REQ_OFF_START:
 		msm_uport->clk_req_off_state = CLK_REQ_OFF_RXSTALE_ISSUED;
+		if (is_blsp_uart(msm_uport)) {
+			/* Stale interrupt when RX-FIFO is empty
+			 * will fire if STALE_IRQ_EMPTY bit is set
+			 * for UART Core v1.4
+			 */
+			msm_hs_write(uport, UARTDM_BCR_ADDR,
+					UARTDM_BCR_STALE_IRQ_EMPTY);
+		}
 		msm_hs_write(uport, UARTDM_CR_ADDR, FORCE_STALE_EVENT);
 		/*
 		 * Before returning make sure that device writel completed.
@@ -1458,13 +1760,25 @@
 		 */
 		mb();
 
-		if (msm_uport->clk_req_off_state == CLK_REQ_OFF_RXSTALE_ISSUED)
+		if (msm_uport->clk_req_off_state ==
+					CLK_REQ_OFF_RXSTALE_ISSUED) {
 			msm_uport->clk_req_off_state =
 				CLK_REQ_OFF_FLUSH_ISSUED;
 
+			if (is_blsp_uart(msm_uport)) {
+				/* Reset BCR Register for UARTDM Core v14*/
+				msm_hs_write(uport, UARTDM_BCR_ADDR, 0x0);
+			}
+		}
+
 		if (rx->flush == FLUSH_NONE) {
 			rx->flush = FLUSH_DATA_READY;
-			msm_dmov_flush(msm_uport->dma_rx_channel, 1);
+			if (is_blsp_uart(msm_uport)) {
+				queue_work(msm_uport->hsuart_wq,
+					&msm_uport->reset_bam_rx);
+			} else {
+				msm_dmov_flush(msm_uport->dma_rx_channel, 1);
+			}
 		}
 	}
 	/* tx ready interrupt */
@@ -1581,7 +1895,10 @@
 		    msm_uport->rx.flush == FLUSH_SHUTDOWN) {
 			msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX);
 			data = msm_hs_read(uport, UARTDM_DMEN_ADDR);
-			data |= UARTDM_RX_DM_EN_BMSK;
+			if (is_blsp_uart(msm_uport))
+				data |= UARTDM_RX_BAM_ENABLE_BMSK;
+			else
+				data |= UARTDM_RX_DM_EN_BMSK;
 			msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
 			/* Complete above device write. Hence mb() here. */
 			mb();
@@ -1661,6 +1978,9 @@
 					pdev->dev.platform_data;
 	struct circ_buf *tx_buf = &uport->state->xmit;
 	struct msm_hs_tx *tx = &msm_uport->tx;
+	struct msm_hs_rx *rx = &msm_uport->rx;
+	struct sps_pipe *sps_pipe_handle_tx = tx->cons.pipe_handle;
+	struct sps_pipe *sps_pipe_handle_rx = rx->prod.pipe_handle;
 
 	rfr_level = uport->fifosize;
 	if (rfr_level > 16)
@@ -1682,6 +2002,24 @@
 		if (unlikely(pdata->gpio_config(1)))
 			dev_err(uport->dev, "Cannot configure gpios\n");
 
+
+	/* SPS Connect for BAM endpoints */
+	if (is_blsp_uart(msm_uport)) {
+		/* SPS connect for TX */
+		ret = msm_hs_spsconnect_tx(uport);
+		if (ret) {
+			pr_err("msm_serial_hs: SPS connect failed for TX");
+			goto deinit_uart_clk;
+		}
+
+		/* SPS connect for RX */
+		ret = msm_hs_spsconnect_rx(uport);
+		if (ret) {
+			pr_err("msm_serial_hs: SPS connect failed for RX");
+			goto sps_disconnect_tx;
+		}
+	}
+
 	/* Set auto RFR Level */
 	data = msm_hs_read(uport, UARTDM_MR1_ADDR);
 	data &= ~UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK;
@@ -1697,8 +2035,13 @@
 		msm_hs_write(uport, UARTDM_IPR_ADDR, data);
 	}
 
-	/* Enable Data Mover Mode */
-	data = UARTDM_TX_DM_EN_BMSK | UARTDM_RX_DM_EN_BMSK;
+	if (is_blsp_uart(msm_uport)) {
+		/* Enable BAM mode */
+		data  = UARTDM_TX_BAM_ENABLE_BMSK | UARTDM_RX_BAM_ENABLE_BMSK;
+	} else {
+		/* Enable Data Mover Mode */
+		data = UARTDM_TX_DM_EN_BMSK | UARTDM_RX_DM_EN_BMSK;
+	}
 	msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
 
 	/* Reset TX */
@@ -1719,18 +2062,20 @@
 	tx->tx_ready_int_en = 0;
 	tx->dma_in_flight = 0;
 
-	tx->xfer.complete_func = msm_hs_dmov_tx_callback;
+	if (!is_blsp_uart(msm_uport)) {
+		tx->xfer.complete_func = msm_hs_dmov_tx_callback;
 
-	tx->command_ptr->cmd = CMD_LC |
-	    CMD_DST_CRCI(msm_uport->dma_tx_crci) | CMD_MODE_BOX;
+		tx->command_ptr->cmd = CMD_LC |
+			CMD_DST_CRCI(msm_uport->dma_tx_crci) | CMD_MODE_BOX;
 
-	tx->command_ptr->src_dst_len = (MSM_UARTDM_BURST_SIZE << 16)
+		tx->command_ptr->src_dst_len = (MSM_UARTDM_BURST_SIZE << 16)
 					   | (MSM_UARTDM_BURST_SIZE);
 
-	tx->command_ptr->row_offset = (MSM_UARTDM_BURST_SIZE << 16);
+		tx->command_ptr->row_offset = (MSM_UARTDM_BURST_SIZE << 16);
 
-	tx->command_ptr->dst_row_addr =
-	    msm_uport->uport.mapbase + UARTDM_TF_ADDR;
+		tx->command_ptr->dst_row_addr =
+			msm_uport->uport.mapbase + UARTDM_TF_ADDR;
+	}
 
 	msm_uport->imr_reg |= UARTDM_ISR_RXSTALE_BMSK;
 	/* Enable reading the current CTS, no harm even if CTS is ignored */
@@ -1747,7 +2092,7 @@
 		ret = irq_set_irq_wake(msm_uport->wakeup.irq, 1);
 		if (unlikely(ret)) {
 			pr_err("%s():Err setting wakeup irq\n", __func__);
-			goto deinit_uart_clk;
+			goto sps_disconnect_rx;
 		}
 	}
 
@@ -1787,6 +2132,12 @@
 	free_irq(uport->irq, msm_uport);
 free_wake_irq:
 	irq_set_irq_wake(msm_uport->wakeup.irq, 0);
+sps_disconnect_rx:
+	if (is_blsp_uart(msm_uport))
+		sps_disconnect(sps_pipe_handle_rx);
+sps_disconnect_tx:
+	if (is_blsp_uart(msm_uport))
+		sps_disconnect(sps_pipe_handle_tx);
 deinit_uart_clk:
 	clk_disable_unprepare(msm_uport->clk);
 	if (msm_uport->pclk)
@@ -1804,24 +2155,6 @@
 	struct msm_hs_tx *tx = &msm_uport->tx;
 	struct msm_hs_rx *rx = &msm_uport->rx;
 
-	/* Allocate the command pointer. Needs to be 64 bit aligned */
-	tx->command_ptr = kmalloc(sizeof(dmov_box), GFP_KERNEL | __GFP_DMA);
-	if (!tx->command_ptr)
-		return -ENOMEM;
-
-	tx->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA);
-	if (!tx->command_ptr_ptr) {
-		ret = -ENOMEM;
-		goto free_tx_command_ptr;
-	}
-
-	tx->mapped_cmd_ptr = dma_map_single(uport->dev, tx->command_ptr,
-					    sizeof(dmov_box), DMA_TO_DEVICE);
-	tx->mapped_cmd_ptr_ptr = dma_map_single(uport->dev,
-						tx->command_ptr_ptr,
-						sizeof(u32), DMA_TO_DEVICE);
-	tx->xfer.cmdptr = DMOV_CMD_ADDR(tx->mapped_cmd_ptr_ptr);
-
 	init_waitqueue_head(&rx->wait);
 	init_waitqueue_head(&tx->wait);
 	wake_lock_init(&rx->wake_lock, WAKE_LOCK_SUSPEND, "msm_serial_hs_rx");
@@ -1848,12 +2181,40 @@
 		goto free_pool;
 	}
 
+	/* Set up Uart Receive */
+	msm_hs_write(uport, UARTDM_RFWR_ADDR, 0);
+
+	INIT_DELAYED_WORK(&rx->flip_insert_work, flip_insert_work);
+
+	if (is_blsp_uart(msm_uport))
+		return ret;
+
+	/* Allocate the command pointer. Needs to be 64 bit aligned */
+	tx->command_ptr = kmalloc(sizeof(dmov_box), GFP_KERNEL | __GFP_DMA);
+	if (!tx->command_ptr) {
+		return -ENOMEM;
+		goto free_rx_buffer;
+	}
+
+	tx->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA);
+	if (!tx->command_ptr_ptr) {
+		ret = -ENOMEM;
+		goto free_tx_command_ptr;
+	}
+
+	tx->mapped_cmd_ptr = dma_map_single(uport->dev, tx->command_ptr,
+					sizeof(dmov_box), DMA_TO_DEVICE);
+	tx->mapped_cmd_ptr_ptr = dma_map_single(uport->dev,
+						tx->command_ptr_ptr,
+						sizeof(u32), DMA_TO_DEVICE);
+	tx->xfer.cmdptr = DMOV_CMD_ADDR(tx->mapped_cmd_ptr_ptr);
+
 	/* Allocate the command pointer. Needs to be 64 bit aligned */
 	rx->command_ptr = kmalloc(sizeof(dmov_box), GFP_KERNEL | __GFP_DMA);
 	if (!rx->command_ptr) {
 		pr_err("%s(): cannot allocate rx->command_ptr", __func__);
 		ret = -ENOMEM;
-		goto free_rx_buffer;
+		goto free_tx_command_ptr_ptr;
 	}
 
 	rx->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA);
@@ -1868,9 +2229,6 @@
 
 	rx->command_ptr->dst_row_addr = rx->rbuffer;
 
-	/* Set up Uart Receive */
-	msm_hs_write(uport, UARTDM_RFWR_ADDR, 0);
-
 	rx->xfer.complete_func = msm_hs_dmov_rx_callback;
 
 	rx->command_ptr->cmd = CMD_LC |
@@ -1890,13 +2248,21 @@
 					    sizeof(u32), DMA_TO_DEVICE);
 	rx->xfer.cmdptr = DMOV_CMD_ADDR(rx->cmdptr_dmaaddr);
 
-	INIT_DELAYED_WORK(&rx->flip_insert_work, flip_insert_work);
-
 	return ret;
 
 free_rx_command_ptr:
 	kfree(rx->command_ptr);
 
+free_tx_command_ptr_ptr:
+	kfree(msm_uport->tx.command_ptr_ptr);
+	dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr_ptr,
+			sizeof(u32), DMA_TO_DEVICE);
+	dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr,
+			sizeof(dmov_box), DMA_TO_DEVICE);
+
+free_tx_command_ptr:
+	kfree(msm_uport->tx.command_ptr);
+
 free_rx_buffer:
 	dma_pool_free(msm_uport->rx.pool, msm_uport->rx.buffer,
 			msm_uport->rx.rbuffer);
@@ -1909,47 +2275,386 @@
 	wake_lock_destroy(&msm_uport->dma_wake_lock);
 	tasklet_kill(&msm_uport->tx.tlet);
 	tasklet_kill(&msm_uport->rx.tlet);
-	dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr_ptr,
-			sizeof(u32), DMA_TO_DEVICE);
-	dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr,
-			sizeof(dmov_box), DMA_TO_DEVICE);
-	kfree(msm_uport->tx.command_ptr_ptr);
-
-free_tx_command_ptr:
-	kfree(msm_uport->tx.command_ptr);
 	return ret;
 }
 
+struct msm_serial_hs_platform_data
+	*msm_hs_dt_to_pdata(struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct msm_serial_hs_platform_data *pdata;
+	int rx_to_inject, ret;
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		pr_err("unable to allocate memory for platform data\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	/* UART TX GPIO */
+	pdata->uart_tx_gpio = of_get_named_gpio(node,
+					"qcom,tx-gpio", 0);
+	if (pdata->uart_tx_gpio < 0)
+		pr_debug("uart_tx_gpio is not available\n");
+
+	/* UART RX GPIO */
+	pdata->uart_rx_gpio = of_get_named_gpio(node,
+					"qcom,rx-gpio", 0);
+	if (pdata->uart_rx_gpio < 0)
+		pr_debug("uart_rx_gpio is not available\n");
+
+	/* UART CTS GPIO */
+	pdata->uart_cts_gpio = of_get_named_gpio(node,
+					"qcom,cts-gpio", 0);
+	if (pdata->uart_cts_gpio < 0)
+		pr_debug("uart_cts_gpio is not available\n");
+
+	/* UART RFR GPIO */
+	pdata->uart_rfr_gpio = of_get_named_gpio(node,
+					"qcom,rfr-gpio", 0);
+	if (pdata->uart_rfr_gpio < 0)
+		pr_debug("uart_rfr_gpio is not available\n");
+
+	pdata->inject_rx_on_wakeup = of_property_read_bool(node,
+				"qcom,inject-rx-on-wakeup");
+
+	if (pdata->inject_rx_on_wakeup) {
+		ret = of_property_read_u32(node, "qcom,rx-char-to-inject",
+						&rx_to_inject);
+		if (ret < 0) {
+			pr_err("Error: Rx_char_to_inject not specified.\n");
+			return ERR_PTR(ret);
+		}
+		pdata->rx_to_inject = (char)rx_to_inject;
+	}
+
+	ret = of_property_read_u32(node, "qcom,bam-tx-ep-pipe-index",
+				&pdata->bam_tx_ep_pipe_index);
+	if (ret < 0) {
+		pr_err("Error: Getting UART BAM TX EP Pipe Index.\n");
+		return ERR_PTR(ret);
+	}
+
+	if (!(pdata->bam_tx_ep_pipe_index >= BAM_PIPE_MIN &&
+		pdata->bam_tx_ep_pipe_index <= BAM_PIPE_MAX)) {
+		pr_err("Error: Invalid UART BAM TX EP Pipe Index.\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	ret = of_property_read_u32(node, "qcom,bam-rx-ep-pipe-index",
+					&pdata->bam_rx_ep_pipe_index);
+	if (ret < 0) {
+		pr_err("Error: Getting UART BAM RX EP Pipe Index.\n");
+		return ERR_PTR(ret);
+	}
+
+	if (!(pdata->bam_rx_ep_pipe_index >= BAM_PIPE_MIN &&
+		pdata->bam_rx_ep_pipe_index <= BAM_PIPE_MAX)) {
+		pr_err("Error: Invalid UART BAM RX EP Pipe Index.\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	pr_debug("tx_ep_pipe_index:%d rx_ep_pipe_index:%d\n"
+		"tx_gpio:%d rx_gpio:%d rfr_gpio:%d cts_gpio:%d",
+		pdata->bam_tx_ep_pipe_index, pdata->bam_rx_ep_pipe_index,
+		pdata->uart_tx_gpio, pdata->uart_rx_gpio, pdata->uart_cts_gpio,
+		pdata->uart_rfr_gpio);
+
+	return pdata;
+}
+
+
+/**
+ * Deallocate UART peripheral's SPS endpoint
+ * @msm_uport - Pointer to msm_hs_port structure
+ * @ep - Pointer to sps endpoint data structure
+ */
+
+static void msm_hs_exit_ep_conn(struct msm_hs_port *msm_uport,
+				struct msm_hs_sps_ep_conn_data *ep)
+{
+	struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
+	struct sps_connect *sps_config = &ep->config;
+
+	dma_free_coherent(msm_uport->uport.dev,
+			sps_config->desc.size,
+			&sps_config->desc.phys_base,
+			GFP_KERNEL);
+	sps_free_endpoint(sps_pipe_handle);
+}
+
+
+/**
+ * Allocate UART peripheral's SPS endpoint
+ *
+ * This function allocates endpoint context
+ * by calling appropriate SPS driver APIs.
+ *
+ * @msm_uport - Pointer to msm_hs_port structure
+ * @ep - Pointer to sps endpoint data structure
+ * @is_produce - 1 means Producer endpoint
+ *             - 0 means Consumer endpoint
+ *
+ * @return - 0 if successful else negative value
+ */
+
+static int msm_hs_sps_init_ep_conn(struct msm_hs_port *msm_uport,
+				struct msm_hs_sps_ep_conn_data *ep,
+				bool is_producer)
+{
+	int rc = 0;
+	struct sps_pipe *sps_pipe_handle;
+	struct sps_connect *sps_config = &ep->config;
+	struct sps_register_event *sps_event = &ep->event;
+
+	/* Allocate endpoint context */
+	sps_pipe_handle = sps_alloc_endpoint();
+	if (!sps_pipe_handle) {
+		pr_err("msm_serial_hs: sps_alloc_endpoint() failed!!\n"
+			"is_producer=%d", is_producer);
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	/* Get default connection configuration for an endpoint */
+	rc = sps_get_config(sps_pipe_handle, sps_config);
+	if (rc) {
+		pr_err("msm_serial_hs: sps_get_config() failed!!\n"
+		"pipe_handle=0x%x rc=%d", (u32)sps_pipe_handle, rc);
+		goto get_config_err;
+	}
+
+	/* Modify the default connection configuration */
+	if (is_producer) {
+		/* For UART producer transfer, source is UART peripheral
+		where as destination is system memory */
+		sps_config->source = msm_uport->bam_handle;
+		sps_config->destination = SPS_DEV_HANDLE_MEM;
+		sps_config->mode = SPS_MODE_SRC;
+		sps_config->src_pipe_index = msm_uport->bam_rx_ep_pipe_index;
+		sps_config->dest_pipe_index = 0;
+		sps_config->options = SPS_O_EOT;
+	} else {
+		/* For UART consumer transfer, source is system memory
+		where as destination is UART peripheral */
+		sps_config->source = SPS_DEV_HANDLE_MEM;
+		sps_config->destination = msm_uport->bam_handle;
+		sps_config->mode = SPS_MODE_DEST;
+		sps_config->src_pipe_index = 0;
+		sps_config->dest_pipe_index = msm_uport->bam_tx_ep_pipe_index;
+		sps_config->options = SPS_O_EOT;
+	}
+
+	sps_config->event_thresh = 0x10;
+
+	/* Allocate maximum descriptor fifo size */
+	sps_config->desc.size = 65532;
+	sps_config->desc.base = dma_alloc_coherent(msm_uport->uport.dev,
+						sps_config->desc.size,
+						&sps_config->desc.phys_base,
+						GFP_KERNEL);
+	if (!sps_config->desc.base) {
+		rc = -ENOMEM;
+		pr_err("msm_serial_hs: dma_alloc_coherent() failed!!\n");
+		goto get_config_err;
+	}
+	memset(sps_config->desc.base, 0x00, sps_config->desc.size);
+
+	sps_event->mode = SPS_TRIGGER_CALLBACK;
+	sps_event->options = SPS_O_EOT;
+	if (is_producer)
+		sps_event->callback = msm_hs_sps_rx_callback;
+	else
+		sps_event->callback = msm_hs_sps_tx_callback;
+
+	sps_event->user = (void *)msm_uport;
+
+	/* Now save the sps pipe handle */
+	ep->pipe_handle = sps_pipe_handle;
+	pr_debug("msm_serial_hs: success !! %s: pipe_handle=0x%x\n"
+		"desc_fifo.phys_base=0x%x\n",
+		is_producer ? "READ" : "WRITE",
+		(u32)sps_pipe_handle, sps_config->desc.phys_base);
+	return 0;
+
+get_config_err:
+	sps_free_endpoint(sps_pipe_handle);
+out:
+	return rc;
+}
+
+/**
+ * Initialize SPS HW connected with UART core
+ *
+ * This function register BAM HW resources with
+ * SPS driver and then initialize 2 SPS endpoints
+ *
+ * msm_uport - Pointer to msm_hs_port structure
+ *
+ * @return - 0 if successful else negative value
+ */
+
+static int msm_hs_sps_init(struct msm_hs_port *msm_uport)
+{
+	int rc = 0;
+	struct sps_bam_props bam = {0};
+	u32 bam_handle;
+
+	rc = sps_phy2h(msm_uport->bam_mem, &bam_handle);
+	if (rc || !bam_handle) {
+		bam.phys_addr = msm_uport->bam_mem;
+		bam.virt_addr = msm_uport->bam_base;
+		/*
+		 * This event thresold value is only significant for BAM-to-BAM
+		 * transfer. It's ignored for BAM-to-System mode transfer.
+		 */
+		bam.event_threshold = 0x10;	/* Pipe event threshold */
+		bam.summing_threshold = 1;	/* BAM event threshold */
+
+		/* SPS driver wll handle the UART BAM IRQ */
+		bam.irq = (u32)msm_uport->bam_irq;
+		bam.manage = SPS_BAM_MGR_LOCAL;
+
+		pr_debug("msm_serial_hs: bam physical base=0x%x\n",
+							(u32)bam.phys_addr);
+		pr_debug("msm_serial_hs: bam virtual base=0x%x\n",
+							(u32)bam.virt_addr);
+
+		/* Register UART Peripheral BAM device to SPS driver */
+		rc = sps_register_bam_device(&bam, &bam_handle);
+		if (rc) {
+			pr_err("msm_serial_hs: BAM device register failed\n");
+			return rc;
+		}
+		pr_info("msm_serial_hs: BAM device registered. bam_handle=0x%x",
+							msm_uport->bam_handle);
+	}
+	msm_uport->bam_handle = bam_handle;
+
+	rc = msm_hs_sps_init_ep_conn(msm_uport, &msm_uport->rx.prod,
+				UART_SPS_PROD_PERIPHERAL);
+	if (rc) {
+		pr_err("%s: Failed to Init Producer BAM-pipe", __func__);
+		goto deregister_bam;
+	}
+
+	rc = msm_hs_sps_init_ep_conn(msm_uport, &msm_uport->tx.cons,
+				UART_SPS_CONS_PERIPHERAL);
+	if (rc) {
+		pr_err("%s: Failed to Init Consumer BAM-pipe", __func__);
+		goto deinit_ep_conn_prod;
+	}
+	return 0;
+
+deinit_ep_conn_prod:
+	msm_hs_exit_ep_conn(msm_uport, &msm_uport->rx.prod);
+deregister_bam:
+	sps_deregister_bam_device(msm_uport->bam_handle);
+	return rc;
+}
+
 static int __devinit msm_hs_probe(struct platform_device *pdev)
 {
 	int ret;
 	struct uart_port *uport;
 	struct msm_hs_port *msm_uport;
+	struct resource *core_resource;
+	struct resource *bam_resource;
 	struct resource *resource;
+	int core_irqres, bam_irqres;
 	struct msm_serial_hs_platform_data *pdata = pdev->dev.platform_data;
+	struct device_node *node = pdev->dev.of_node;
+
+	if (pdev->dev.of_node) {
+		dev_dbg(&pdev->dev, "device tree enabled\n");
+		pdata = msm_hs_dt_to_pdata(pdev);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+
+		of_property_read_u32(node, "cell-index",
+					&pdev->id);
+
+		pdev->dev.platform_data = pdata;
+	}
 
 	if (pdev->id < 0 || pdev->id >= UARTDM_NR) {
-		printk(KERN_ERR "Invalid plaform device ID = %d\n", pdev->id);
+		pr_err("Invalid plaform device ID = %d\n", pdev->id);
 		return -EINVAL;
 	}
 
 	msm_uport = &q_uart_port[pdev->id];
 	uport = &msm_uport->uport;
-
 	uport->dev = &pdev->dev;
 
-	resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (unlikely(!resource))
-		return -ENXIO;
-	uport->mapbase = resource->start;  /* virtual address */
+	if (pdev->dev.of_node)
+		msm_uport->uart_type = BLSP_HSUART;
 
-	uport->membase = ioremap(uport->mapbase, PAGE_SIZE);
-	if (unlikely(!uport->membase))
-		return -ENOMEM;
+	/* Get required resources for BAM HSUART */
+	if (is_blsp_uart(msm_uport)) {
+		core_resource = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, "core_mem");
+		bam_resource = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, "bam_mem");
+		core_irqres = platform_get_irq_byname(pdev, "core_irq");
+		bam_irqres = platform_get_irq_byname(pdev, "bam_irq");
 
-	uport->irq = platform_get_irq(pdev, 0);
-	if (unlikely((int)uport->irq < 0))
-		return -ENXIO;
+		if (!core_resource) {
+			pr_err("Invalid core HSUART Resources.\n");
+			return -ENXIO;
+		}
+
+		if (!bam_resource) {
+			pr_err("Invalid BAM HSUART Resources.\n");
+			return -ENXIO;
+		}
+
+		if (!core_irqres) {
+			pr_err("Invalid core irqres Resources.\n");
+			return -ENXIO;
+		}
+		if (!bam_irqres) {
+			pr_err("Invalid bam irqres Resources.\n");
+			return -ENXIO;
+		}
+
+		uport->mapbase = core_resource->start;
+
+		uport->membase = ioremap(uport->mapbase,
+					resource_size(core_resource));
+		if (unlikely(!uport->membase)) {
+			pr_err("UART Resource ioremap Failed.\n");
+			return -ENOMEM;
+		}
+		msm_uport->bam_mem = bam_resource->start;
+		msm_uport->bam_base = ioremap(msm_uport->bam_mem,
+					resource_size(bam_resource));
+		if (unlikely(!msm_uport->bam_base)) {
+			pr_err("UART BAM Resource ioremap Failed.\n");
+			iounmap(uport->membase);
+			return -ENOMEM;
+		}
+
+		uport->irq = core_irqres;
+		msm_uport->bam_irq = bam_irqres;
+
+	} else {
+
+		resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		if (unlikely(!resource))
+			return -ENXIO;
+		uport->mapbase = resource->start;
+		uport->membase = ioremap(uport->mapbase,
+					resource_size(resource));
+		if (unlikely(!uport->membase))
+			return -ENOMEM;
+
+		uport->irq = platform_get_irq(pdev, 0);
+		if (unlikely((int)uport->irq < 0)) {
+			pr_err("UART IRQ Failed.\n");
+			iounmap(uport->membase);
+			return -ENXIO;
+		}
+	}
 
 	if (pdata == NULL)
 		msm_uport->wakeup.irq = -1;
@@ -1959,24 +2664,41 @@
 		msm_uport->wakeup.inject_rx = pdata->inject_rx_on_wakeup;
 		msm_uport->wakeup.rx_to_inject = pdata->rx_to_inject;
 
-		if (unlikely(msm_uport->wakeup.irq < 0))
-			return -ENXIO;
+		if (unlikely(msm_uport->wakeup.irq < 0)) {
+			ret = -ENXIO;
+			goto unmap_memory;
+		}
 
+		if (is_blsp_uart(msm_uport)) {
+			msm_uport->bam_tx_ep_pipe_index =
+					pdata->bam_tx_ep_pipe_index;
+			msm_uport->bam_rx_ep_pipe_index =
+					pdata->bam_rx_ep_pipe_index;
+		}
 	}
 
-	resource = platform_get_resource_byname(pdev, IORESOURCE_DMA,
-						"uartdm_channels");
-	if (unlikely(!resource))
-		return -ENXIO;
-	msm_uport->dma_tx_channel = resource->start;
-	msm_uport->dma_rx_channel = resource->end;
+	if (!is_blsp_uart(msm_uport)) {
 
-	resource = platform_get_resource_byname(pdev, IORESOURCE_DMA,
-						"uartdm_crci");
-	if (unlikely(!resource))
-		return -ENXIO;
-	msm_uport->dma_tx_crci = resource->start;
-	msm_uport->dma_rx_crci = resource->end;
+		resource = platform_get_resource_byname(pdev,
+					IORESOURCE_DMA, "uartdm_channels");
+		if (unlikely(!resource)) {
+			ret =  -ENXIO;
+			goto unmap_memory;
+		}
+
+		msm_uport->dma_tx_channel = resource->start;
+		msm_uport->dma_rx_channel = resource->end;
+
+		resource = platform_get_resource_byname(pdev,
+					IORESOURCE_DMA, "uartdm_crci");
+		if (unlikely(!resource)) {
+			ret = -ENXIO;
+			goto unmap_memory;
+		}
+
+		msm_uport->dma_tx_crci = resource->start;
+		msm_uport->dma_rx_crci = resource->end;
+	}
 
 	uport->iotype = UPIO_MEM;
 	uport->fifosize = 64;
@@ -1986,8 +2708,10 @@
 	msm_uport->imr_reg = 0x0;
 
 	msm_uport->clk = clk_get(&pdev->dev, "core_clk");
-	if (IS_ERR(msm_uport->clk))
-		return PTR_ERR(msm_uport->clk);
+	if (IS_ERR(msm_uport->clk)) {
+		ret = PTR_ERR(msm_uport->clk);
+		goto unmap_memory;
+	}
 
 	msm_uport->pclk = clk_get(&pdev->dev, "iface_clk");
 	/*
@@ -2000,7 +2724,7 @@
 	ret = clk_set_rate(msm_uport->clk, uport->uartclk);
 	if (ret) {
 		printk(KERN_WARNING "Error setting clock rate on UART\n");
-		return ret;
+		goto unmap_memory;
 	}
 
 	msm_uport->hsuart_wq = alloc_workqueue("k_hsuart",
@@ -2008,12 +2732,29 @@
 	if (!msm_uport->hsuart_wq) {
 		pr_err("%s(): Unable to create workqueue hsuart_wq\n",
 								__func__);
-		return -ENOMEM;
+		ret =  -ENOMEM;
+		goto unmap_memory;
 	}
 
 	INIT_WORK(&msm_uport->clock_off_w, hsuart_clock_off_work);
+
+	/* Init work for Reset Rx bam endpoints */
+	INIT_WORK(&msm_uport->reset_bam_rx, hsuart_reset_bam_rx_work);
+
+	/* Init work for sps_disconnect in stop_rx_locked */
+	INIT_WORK(&msm_uport->disconnect_rx_endpoint,
+				hsuart_disconnect_rx_endpoint_work);
 	mutex_init(&msm_uport->clk_mutex);
 
+	/* Initialize SPS HW connected with UART core */
+	if (is_blsp_uart(msm_uport)) {
+		ret = msm_hs_sps_init(msm_uport);
+		if (unlikely(ret)) {
+			pr_err("SPS Initialization failed ! err=%d", ret);
+			goto unmap_memory;
+		}
+	}
+
 	clk_prepare_enable(msm_uport->clk);
 	if (msm_uport->pclk)
 		clk_prepare_enable(msm_uport->pclk);
@@ -2023,7 +2764,7 @@
 		clk_disable_unprepare(msm_uport->clk);
 		if (msm_uport->pclk)
 			clk_disable_unprepare(msm_uport->pclk);
-		return ret;
+		goto unmap_memory;
 	}
 
 	/* configure the CR Protection to Enable */
@@ -2048,14 +2789,23 @@
 
 	ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_clock.attr);
 	if (unlikely(ret))
-		return ret;
+		goto unmap_memory;
 
 	msm_serial_debugfs_init(msm_uport, pdev->id);
 
 	uport->line = pdev->id;
 	if (pdata != NULL && pdata->userid && pdata->userid <= UARTDM_NR)
 		uport->line = pdata->userid;
-	return uart_add_one_port(&msm_hs_driver, uport);
+	ret = uart_add_one_port(&msm_hs_driver, uport);
+	if (!ret)
+		return ret;
+
+unmap_memory:
+	iounmap(uport->membase);
+	if (is_blsp_uart(msm_uport))
+		iounmap(msm_uport->bam_base);
+
+	return ret;
 }
 
 static int __init msm_serial_hs_init(void)
@@ -2102,27 +2852,35 @@
 	struct platform_device *pdev = to_platform_device(uport->dev);
 	const struct msm_serial_hs_platform_data *pdata =
 				pdev->dev.platform_data;
+	struct msm_hs_tx *tx = &msm_uport->tx;
+	struct sps_pipe *sps_pipe_handle = tx->cons.pipe_handle;
 
 	if (msm_uport->tx.dma_in_flight) {
-		spin_lock_irqsave(&uport->lock, flags);
-		/* disable UART TX interface to DM */
-		data = msm_hs_read(uport, UARTDM_DMEN_ADDR);
-		data &= ~UARTDM_TX_DM_EN_BMSK;
-		msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
-		/* turn OFF UART Transmitter */
-		msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_TX_DISABLE_BMSK);
-		/* reset UART TX */
-		msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX);
-		/* reset UART TX Error */
-		msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX_ERROR);
-		msm_uport->tx.flush = FLUSH_STOP;
-		spin_unlock_irqrestore(&uport->lock, flags);
-		/* discard flush */
-		msm_dmov_flush(msm_uport->dma_tx_channel, 0);
-		ret = wait_event_timeout(msm_uport->tx.wait,
-			msm_uport->tx.flush == FLUSH_SHUTDOWN, 100);
-		if (!ret)
-			pr_err("%s():HSUART TX Stalls.\n", __func__);
+		if (!is_blsp_uart(msm_uport)) {
+			spin_lock_irqsave(&uport->lock, flags);
+			/* disable UART TX interface to DM */
+			data = msm_hs_read(uport, UARTDM_DMEN_ADDR);
+			data &= ~UARTDM_TX_DM_EN_BMSK;
+			msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
+			/* turn OFF UART Transmitter */
+			msm_hs_write(uport, UARTDM_CR_ADDR,
+					UARTDM_CR_TX_DISABLE_BMSK);
+			/* reset UART TX */
+			msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX);
+			/* reset UART TX Error */
+			msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX_ERROR);
+			msm_uport->tx.flush = FLUSH_STOP;
+			spin_unlock_irqrestore(&uport->lock, flags);
+			/* discard flush */
+			msm_dmov_flush(msm_uport->dma_tx_channel, 0);
+			ret = wait_event_timeout(msm_uport->tx.wait,
+				msm_uport->tx.flush == FLUSH_SHUTDOWN, 100);
+			if (!ret)
+				pr_err("%s():HSUART TX Stalls.\n", __func__);
+		} else {
+			/* BAM Disconnect for TX */
+			sps_disconnect(sps_pipe_handle);
+		}
 	}
 	tasklet_kill(&msm_uport->tx.tlet);
 	BUG_ON(msm_uport->rx.flush < FLUSH_STOP);
@@ -2211,12 +2969,18 @@
 	.runtime_idle    = msm_hs_runtime_idle,
 };
 
+static struct of_device_id msm_hs_match_table[] = {
+	{ .compatible = "qcom,msm-hsuart-v14" },
+	{}
+};
+
 static struct platform_driver msm_serial_hs_platform_driver = {
 	.probe	= msm_hs_probe,
 	.remove = __devexit_p(msm_hs_remove),
 	.driver = {
 		.name = "msm_serial_hs",
 		.pm   = &msm_hs_dev_pm_ops,
+		.of_match_table = msm_hs_match_table,
 	},
 };
 
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 02cdd71..ed0a385 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -955,6 +955,7 @@
 int mdp4_pcc_cfg(struct mdp_pcc_cfg_data *cfg_ptr);
 int mdp4_argc_cfg(struct mdp_pgc_lut_data *pgc_ptr);
 int mdp4_qseed_cfg(struct mdp_qseed_cfg_data *cfg);
+int mdp4_calib_config(struct mdp_calib_config_data *cfg);
 int mdp4_qseed_access_cfg(struct mdp_qseed_cfg *cfg, uint32_t base);
 u32  mdp4_allocate_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num);
 void mdp4_init_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num);
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index 01ec10e..4858073 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -3080,6 +3080,108 @@
 error:
 	return ret;
 }
+
+static int is_valid_calib_addr(void *addr)
+{
+	int ret = 0;
+	unsigned int ptr;
+
+	if (addr == NULL)
+		goto end;
+
+	ptr = (unsigned int) addr;
+
+	if (mdp_rev >= MDP_REV_30 && mdp_rev < MDP_REV_40) {
+		/* if request is outside the MDP reg-map or is not aligned 4 */
+		if (ptr > 0xF0600 || ptr % 0x4)
+			goto end;
+
+		if (ptr >= 0x90000 && ptr < 0x94000) {
+			if (ptr == 0x90000 || ptr == 0x90070)
+				ret = 1;
+			else if (ptr >= 0x93400 && ptr <= 0x93420)
+				ret = 1;
+			else if (ptr >= 0x93500 && ptr <= 0x93508)
+				ret = 1;
+			else if (ptr >= 0x93580 && ptr <= 0x93588)
+				ret = 1;
+			else if (ptr >= 0x93600 && ptr <= 0x93614)
+				ret = 1;
+			else if (ptr >= 0x93680 && ptr <= 0x93694)
+				ret = 1;
+			else if (ptr >= 0x93800 && ptr <= 0x93BFC)
+				ret = 1;
+		}
+	} else if (mdp_rev >= MDP_REV_40 && mdp_rev <= MDP_REV_44) {
+		/* if request is outside the MDP reg-map or is not aligned 4 */
+		if (ptr > 0xF0600 || ptr % 0x4)
+			goto end;
+
+		if (ptr < 0x90000) {
+			if (ptr == 0x4 || ptr == 0x28200 || ptr == 0x28204)
+				ret = 1;
+		} else if (ptr < 0x95000) {
+			if (ptr == 0x90000 || ptr == 0x90070)
+				ret = 1;
+			else if (ptr >= 0x93400 && ptr <= 0x93420)
+				ret = 1;
+			else if (ptr >= 0x93500 && ptr <= 0x93508)
+				ret = 1;
+			else if (ptr >= 0x93580 && ptr <= 0x93588)
+				ret = 1;
+			else if (ptr >= 0x93600 && ptr <= 0x93614)
+				ret = 1;
+			else if (ptr >= 0x93680 && ptr <= 0x93694)
+				ret = 1;
+			else if (ptr >= 0x94800 && ptr <= 0x94BFC)
+				ret = 1;
+		} else if (ptr < 0x9A000) {
+			if (ptr >= 0x98800 && ptr <= 0x9883C)
+				ret = 1;
+			else if (ptr >= 0x98880 && ptr <= 0x988AC)
+				ret = 1;
+			else if (ptr >= 0x98900 && ptr <= 0x9893C)
+				ret = 1;
+			else if (ptr >= 0x98980 && ptr <= 0x989BC)
+				ret = 1;
+			else if (ptr >= 0x98A00 && ptr <= 0x98A3C)
+				ret = 1;
+			else if (ptr >= 0x98A80 && ptr <= 0x98ABC)
+				ret = 1;
+			else if (ptr >= 0x99000 && ptr <= 0x993FC)
+				ret = 1;
+			else if (ptr >= 0x99800 && ptr <= 0x99BFC)
+				ret = 1;
+		} else if (ptr >= 0x9A000 && ptr <= 0x9a08c) {
+			ret = 1;
+		}
+	}
+end:
+	return ret;
+}
+
+int mdp4_calib_config(struct mdp_calib_config_data *cfg)
+{
+	int ret = -1;
+	void *ptr = (void *) cfg->addr;
+
+	if (is_valid_calib_addr(ptr))
+		ret = 0;
+	else
+		return ret;
+
+	ptr = (void *)(((unsigned int) ptr) + MDP_BASE);
+	mdp_clk_ctrl(1);
+	if (cfg->ops & MDP_PP_OPS_READ) {
+		cfg->data = inpdw(ptr);
+		ret = 1;
+	} else if (cfg->ops & MDP_PP_OPS_WRITE) {
+		outpdw(ptr, cfg->data);
+	}
+	mdp_clk_ctrl(0);
+	return ret;
+}
+
 u32 mdp4_get_mixer_num(u32 panel_type)
 {
 	u32 mixer_num;
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 50723e7..4404b9d 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -2,7 +2,7 @@
  * Core MDSS framebuffer driver.
  *
  * Copyright (C) 2007 Google Incorporated
- * Copyright (c) 2008-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -889,20 +889,6 @@
 	var->hsync_len = panel_info->lcdc.h_pulse_width;
 	var->pixclock = panel_info->clk_rate / 1000;
 
-	if (panel_info->type == MIPI_VIDEO_PANEL) {
-		var->reserved[4] = panel_info->mipi.frame_rate;
-	} else {
-		var->reserved[4] = panel_info->clk_rate /
-			((panel_info->lcdc.h_back_porch +
-			  panel_info->lcdc.h_front_porch +
-			  panel_info->lcdc.h_pulse_width +
-			  panel_info->xres) *
-			 (panel_info->lcdc.v_back_porch +
-			  panel_info->lcdc.v_front_porch +
-			  panel_info->lcdc.v_pulse_width +
-			  panel_info->yres));
-	}
-
 	/* id field for fb app  */
 
 	id = (int *)&mfd->panel;
@@ -1589,6 +1575,23 @@
 	return ret;
 }
 
+static int mdss_fb_get_metadata(struct msm_fb_data_type *mfd,
+				struct msmfb_metadata *metadata)
+{
+	int ret = 0;
+	switch (metadata->op) {
+	case metadata_op_frame_rate:
+		metadata->data.panel_frame_rate =
+			mdss_get_panel_framerate(mfd);
+		break;
+	default:
+		pr_warn("Unsupported request to MDP META IOCTL.\n");
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
 static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
 			 unsigned long arg)
 {
@@ -1600,6 +1603,7 @@
 	struct mdp_page_protection fb_page_protection;
 	int ret = -ENOSYS;
 	struct mdp_buf_sync buf_sync;
+	struct msmfb_metadata metadata;
 
 	mdss_fb_power_setting_idle(mfd);
 
@@ -1683,6 +1687,15 @@
 		ret = mdss_fb_display_commit(info, argp);
 		break;
 
+	case MSMFB_METADATA_GET:
+		ret = copy_from_user(&metadata, argp, sizeof(metadata));
+		if (ret)
+			return ret;
+		ret = mdss_fb_get_metadata(mfd, &metadata);
+		if (!ret)
+			ret = copy_to_user(argp, &metadata, sizeof(metadata));
+		break;
+
 	default:
 		if (mfd->ioctl_handler)
 			ret = mfd->ioctl_handler(mfd, cmd, argp);
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index e9427da..ef6e5b4 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -341,6 +341,7 @@
 struct mdss_mdp_format_params *mdss_mdp_get_format_params(u32 format);
 int mdss_mdp_put_img(struct mdss_mdp_img_data *data);
 int mdss_mdp_get_img(struct msmfb_data *img, struct mdss_mdp_img_data *data);
+u32 mdss_get_panel_framerate(struct msm_fb_data_type *mfd);
 
 int mdss_mdp_wb_kickoff(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_wb_ioctl_handler(struct msm_fb_data_type *mfd, u32 cmd, void *arg);
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index 9f2df85..75a926a 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -29,6 +29,8 @@
 #include "mdss_mdp.h"
 #include "mdss_mdp_formats.h"
 
+#define DEFAULT_FRAME_RATE	60
+
 enum {
 	MDP_INTR_VSYNC_INTF_0,
 	MDP_INTR_VSYNC_INTF_1,
@@ -433,3 +435,26 @@
 
 	return ret;
 }
+
+u32 mdss_get_panel_framerate(struct msm_fb_data_type *mfd)
+{
+	u32 frame_rate = DEFAULT_FRAME_RATE;
+	u32 pixel_total;
+	struct mdss_panel_info *panel_info = mfd->panel_info;
+
+	if (panel_info->type == MIPI_VIDEO_PANEL) {
+		frame_rate = panel_info->mipi.frame_rate;
+	} else {
+		pixel_total = (panel_info->lcdc.h_back_porch +
+			  panel_info->lcdc.h_front_porch +
+			  panel_info->lcdc.h_pulse_width +
+			  panel_info->xres) *
+			 (panel_info->lcdc.v_back_porch +
+			  panel_info->lcdc.v_front_porch +
+			  panel_info->lcdc.v_pulse_width +
+			  panel_info->yres);
+		if (pixel_total)
+			frame_rate = panel_info->clk_rate / pixel_total;
+	}
+	return frame_rate;
+}
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 89e8e1e..3841498 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -1262,8 +1262,6 @@
 		((PAGE_SIZE - remainder)/fix->line_length) * mfd->fb_page;
 	var->bits_per_pixel = bpp * 8;	/* FrameBuffer color depth */
 
-	var->reserved[4] = mdp_get_panel_framerate(mfd);
-
 		/*
 		 * id field for fb app
 		 */
@@ -3249,6 +3247,10 @@
 		ret = mdp4_qseed_cfg((struct mdp_qseed_cfg_data *)
 						&pp_ptr->data.qseed_cfg_data);
 		break;
+	case mdp_op_calib_cfg:
+		ret = mdp4_calib_config((struct mdp_calib_config_data *)
+						&pp_ptr->data.calib_cfg);
+		break;
 #endif
 	case mdp_bl_scale_cfg:
 		ret = mdp_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
@@ -3281,6 +3283,24 @@
 	}
 	return ret;
 }
+
+static int msmfb_get_metadata(struct msm_fb_data_type *mfd,
+				struct msmfb_metadata *metadata_ptr)
+{
+	int ret = 0;
+	switch (metadata_ptr->op) {
+	case metadata_op_frame_rate:
+		metadata_ptr->data.panel_frame_rate =
+			mdp_get_panel_framerate(mfd);
+		break;
+	default:
+		pr_warn("Unsupported request to MDP META IOCTL.\n");
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
 static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd,
 			unsigned long arg)
 {
@@ -3583,6 +3603,8 @@
 			return ret;
 
 		ret = msmfb_handle_pp_ioctl(mfd, &mdp_pp);
+		if (ret == 1)
+			ret = copy_to_user(argp, &mdp_pp, sizeof(mdp_pp));
 		break;
 
 	case MSMFB_METADATA_SET:
@@ -3592,6 +3614,16 @@
 		ret = msmfb_handle_metadata_ioctl(mfd, &mdp_metadata);
 		break;
 
+	case MSMFB_METADATA_GET:
+		ret = copy_from_user(&mdp_metadata, argp, sizeof(mdp_metadata));
+		if (ret)
+			return ret;
+		ret = msmfb_get_metadata(mfd, &mdp_metadata);
+		if (!ret)
+			ret = copy_to_user(argp, &mdp_metadata,
+				sizeof(mdp_metadata));
+		break;
+
 	default:
 		MSM_FB_INFO("MDP: unknown ioctl (cmd=%x) received!\n", cmd);
 		ret = -EINVAL;
diff --git a/include/linux/fb.h b/include/linux/fb.h
index f6a2923..d31cb68 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -279,7 +279,7 @@
 	__u32 vmode;			/* see FB_VMODE_*		*/
 	__u32 rotate;			/* angle we rotate counter clockwise */
 	__u32 colorspace;		/* colorspace for FOURCC-based modes */
-	__u32 reserved[5];		/* Reserved for future compatibility */
+	__u32 reserved[4];		/* Reserved for future compatibility */
 };
 
 struct fb_cmap {
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index c947e45..458f060 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -157,6 +157,10 @@
 			int bytes, void *dest, bool interface_reg);
 	int (*write_dev)(struct wcd9xxx *wcd9xxx, unsigned short reg,
 			int bytes, void *src, bool interface_reg);
+	int (*post_reset)(struct wcd9xxx *wcd9xxx);
+
+	void *ssr_priv;
+	bool slim_device_bootup;
 
 	u32 num_of_supplies;
 	struct regulator_bulk_data *supplies;
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 7e67db0..fdb8fb6 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -1,7 +1,7 @@
 /* include/linux/msm_mdp.h
  *
  * Copyright (C) 2007 Google Incorporated
- * Copyright (c) 2012 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -75,6 +75,7 @@
 #define MSMFB_BUFFER_SYNC  _IOW(MSMFB_IOCTL_MAGIC, 164, struct mdp_buf_sync)
 #define MSMFB_DISPLAY_COMMIT      _IOW(MSMFB_IOCTL_MAGIC, 165, \
 						struct mdp_display_commit)
+#define MSMFB_METADATA_GET  _IOW(MSMFB_IOCTL_MAGIC, 166, struct msmfb_metadata)
 
 #define FB_TYPE_3D_PANEL 0x10101010
 #define MDP_IMGTYPE2_START 0x10000
@@ -555,6 +556,7 @@
 enum {
 	metadata_op_none,
 	metadata_op_base_blend,
+	metadata_op_frame_rate,
 	metadata_op_max
 };
 
@@ -567,6 +569,7 @@
 	uint32_t flags;
 	union {
 		struct mdp_blend_cfg blend_cfg;
+		uint32_t panel_frame_rate;
 	} data;
 };
 
diff --git a/include/linux/qmi_encdec.h b/include/linux/qmi_encdec.h
index 4c5f6d3..b1fd217 100644
--- a/include/linux/qmi_encdec.h
+++ b/include/linux/qmi_encdec.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -150,6 +150,15 @@
 int qmi_kernel_decode(struct msg_desc *desc, void *out_c_struct,
 		      void *in_buf, uint32_t in_buf_len);
 
+/**
+ * qmi_verify_max_msg_len() - Verify the maximum length of a QMI message
+ * @desc: Pointer to structure descriptor.
+ *
+ * @return: true if the maximum message length embedded in structure
+ *          descriptor matches the calculated value, else false.
+ */
+bool qmi_verify_max_msg_len(struct msg_desc *desc);
+
 #else
 static inline int qmi_kernel_encode(struct msg_desc *desc,
 				    void *out_buf, uint32_t out_buf_len,
@@ -164,6 +173,11 @@
 {
 	return -EOPNOTSUPP;
 }
+
+static inline bool qmi_verify_max_msg_len(struct msg_desc *desc)
+{
+	return false;
+}
 #endif
 
 #endif
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 5afbfad..c12cbbe 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1453,6 +1453,23 @@
 	u32                read_format;
 } __attribute__((packed));
 
+#define ASM_STREAM_CMD_OPEN_LOOPBACK	0x00010D6E
+struct asm_stream_cmd_open_loopback {
+	struct apr_hdr         hdr;
+	u32                    mode_flags;
+/* Mode flags.
+ * Bit 0-31: reserved; client should set these bits to 0
+ */
+	u16                    src_endpointype;
+	/* Endpoint type. 0 = Tx Matrix */
+	u16                    sink_endpointype;
+	/* Endpoint type. 0 = Rx Matrix */
+	u32                    postprocopo_id;
+/* Postprocessor topology ID. Specifies the topology of
+ * postprocessing algorithms.
+ */
+} __packed;
+
 #define ADM_CMD_CONNECT_AFE_PORT 0x00010320
 #define ADM_CMD_DISCONNECT_AFE_PORT 0x00010321
 
@@ -1898,5 +1915,4 @@
 
 int srs_ss3d_open(int port_id, int srs_tech_id, void *srs_params);
 /* SRS Studio Sound 3D end */
-
 #endif /*_APR_AUDIO_H_*/
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index dcdd816..275cdbe 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -206,6 +206,8 @@
 			uint32_t rd_format,
 			uint32_t wr_format);
 
+int q6asm_open_loopack(struct audio_client *ac);
+
 int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
 				uint32_t lsw_ts, uint32_t flags);
 int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
diff --git a/lib/qmi_encdec.c b/lib/qmi_encdec.c
index 5c489cf..3f618cb 100644
--- a/lib/qmi_encdec.c
+++ b/lib/qmi_encdec.c
@@ -90,6 +90,71 @@
 			      int dec_level);
 
 /**
+ * qmi_calc_max_msg_len() - Calculate the maximum length of a QMI message
+ * @ei_array: Struct info array describing the structure.
+ * @level: Level to identify the depth of the nested structures.
+ *
+ * @return: expected maximum length of the QMI message or 0 on failure.
+ */
+static int qmi_calc_max_msg_len(struct elem_info *ei_array,
+				int level)
+{
+	int max_msg_len = 0;
+	struct elem_info *temp_ei;
+
+	if (!ei_array)
+		return max_msg_len;
+
+	for (temp_ei = ei_array; temp_ei->data_type != QMI_EOTI; temp_ei++) {
+		/* Flag to identify the optional element is not encoded */
+		if (temp_ei->data_type == QMI_OPT_FLAG)
+			continue;
+
+		if (temp_ei->data_type == QMI_DATA_LEN) {
+			max_msg_len += (temp_ei->elem_size == sizeof(uint8_t) ?
+					sizeof(uint8_t) : sizeof(uint16_t));
+			continue;
+		} else if (temp_ei->data_type == QMI_STRUCT) {
+			max_msg_len += qmi_calc_max_msg_len(temp_ei->ei_array,
+							    (level + 1));
+		} else {
+			max_msg_len += (temp_ei->elem_len * temp_ei->elem_size);
+		}
+
+		/*
+		 * Type & Length info. not prepended for elements in the
+		 * nested structure.
+		 */
+		if (level == 1)
+			max_msg_len += (TLV_TYPE_SIZE + TLV_LEN_SIZE);
+	}
+	return max_msg_len;
+}
+
+/**
+ * qmi_verify_max_msg_len() - Verify the maximum length of a QMI message
+ * @desc: Pointer to structure descriptor.
+ *
+ * @return: true if the maximum message length embedded in structure
+ *          descriptor matches the calculated value, else false.
+ */
+bool qmi_verify_max_msg_len(struct msg_desc *desc)
+{
+	int calc_max_msg_len;
+
+	if (!desc)
+		return false;
+
+	calc_max_msg_len = qmi_calc_max_msg_len(desc->ei_array, 1);
+	if (calc_max_msg_len != desc->max_msg_len) {
+		pr_err("%s: Calc. len %d != Passed len %d\n",
+			__func__, calc_max_msg_len, desc->max_msg_len);
+		return false;
+	}
+	return true;
+}
+
+/**
  * qmi_kernel_encode() - Encode to QMI message wire format
  * @desc: Pointer to structure descriptor.
  * @out_buf: Buffer to hold the encoded QMI message.
@@ -103,6 +168,7 @@
 		      void *in_c_struct)
 {
 	int enc_level = 1;
+	int ret, calc_max_msg_len;
 
 	if (!desc || !desc->ei_array)
 		return -EINVAL;
@@ -113,8 +179,14 @@
 	if (desc->max_msg_len < out_buf_len)
 		return -ETOOSMALL;
 
-	return _qmi_kernel_encode(desc->ei_array, out_buf,
-				  in_c_struct, out_buf_len, enc_level);
+	ret = _qmi_kernel_encode(desc->ei_array, out_buf,
+				 in_c_struct, out_buf_len, enc_level);
+	if (ret == -ETOOSMALL) {
+		calc_max_msg_len = qmi_calc_max_msg_len(desc->ei_array, 1);
+		pr_err("%s: Calc. len %d != Out buf len %d\n",
+			__func__, calc_max_msg_len, out_buf_len);
+	}
+	return ret;
 }
 EXPORT_SYMBOL(qmi_kernel_encode);
 
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 1546b9e..ad1546d 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -4892,12 +4892,53 @@
 }
 EXPORT_SYMBOL_GPL(taiko_hs_detect);
 
+static int taiko_post_reset_cb(struct wcd9xxx *wcd9xxx)
+{
+	int ret = 0;
+	struct snd_soc_codec *codec;
+	struct taiko_priv *taiko;
+
+	codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
+	taiko = snd_soc_codec_get_drvdata(codec);
+	mutex_lock(&codec->mutex);
+	WCD9XXX_BCL_LOCK(&taiko->resmgr);
+	if (spkr_drv_wrnd == 1) {
+		wcd9xxx_resmgr_post_ssr(&taiko->resmgr);
+		snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_EN, 0x80, 0x80);
+	}
+	WCD9XXX_BCL_UNLOCK(&taiko->resmgr);
+
+	if (codec->reg_def_copy) {
+		pr_debug("%s: Update ASOC cache", __func__);
+		kfree(codec->reg_cache);
+		codec->reg_cache = kmemdup(codec->reg_def_copy,
+						codec->reg_size, GFP_KERNEL);
+	}
+
+	taiko_update_reg_defaults(codec);
+	taiko_codec_init_reg(codec);
+	ret = taiko_handle_pdata(taiko);
+	if (IS_ERR_VALUE(ret))
+		pr_err("%s: bad pdata\n", __func__);
+	mutex_unlock(&codec->mutex);
+	return ret;
+}
+
+
 static struct wcd9xxx_reg_address taiko_reg_address = {
 	.micb_4_mbhc = TAIKO_A_MICB_4_MBHC,
 	.micb_4_int_rbias = TAIKO_A_MICB_4_INT_RBIAS,
 	.micb_4_ctl = TAIKO_A_MICB_4_CTL,
 };
 
+static int wcd9xxx_ssr_register(struct wcd9xxx *control,
+		int (*post_reset_cb)(struct wcd9xxx *wcd9xxx), void *priv)
+{
+	control->post_reset = post_reset_cb;
+	control->ssr_priv = priv;
+	return 0;
+}
+
 static int taiko_codec_probe(struct snd_soc_codec *codec)
 {
 	struct wcd9xxx *control;
@@ -4912,6 +4953,8 @@
 	codec->control_data = dev_get_drvdata(codec->dev->parent);
 	control = codec->control_data;
 
+	wcd9xxx_ssr_register(control, taiko_post_reset_cb, (void *)codec);
+
 	dev_info(codec->dev, "%s()\n", __func__);
 
 	taiko = kzalloc(sizeof(struct taiko_priv), GFP_KERNEL);
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c
index d744cb9..0ab650e 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr.c
@@ -195,6 +195,24 @@
 	pr_debug("%s: leave\n", __func__);
 }
 
+void wcd9xxx_resmgr_post_ssr(struct wcd9xxx_resmgr *resmgr)
+{
+	int old_bg_audio_users, old_bg_mbhc_users;
+
+	WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
+
+	old_bg_audio_users = resmgr->bg_audio_users;
+	resmgr->bg_audio_users = 0;
+	old_bg_mbhc_users = resmgr->bg_mbhc_users;
+	resmgr->bg_mbhc_users = 0;
+
+	while (old_bg_audio_users && --old_bg_audio_users)
+		wcd9xxx_resmgr_get_bandgap(resmgr, WCD9XXX_BANDGAP_AUDIO_MODE);
+
+	while (old_bg_mbhc_users && --old_bg_mbhc_users)
+		wcd9xxx_resmgr_get_bandgap(resmgr, WCD9XXX_BANDGAP_MBHC_MODE);
+}
+
 /*
  * wcd9xxx_resmgr_get_bandgap : Vote for bandgap ref
  * choice : WCD9XXX_BANDGAP_AUDIO_MODE, WCD9XXX_BANDGAP_MBHC_MODE
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.h b/sound/soc/codecs/wcd9xxx-resmgr.h
index 2d04102..6c30eeb 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.h
+++ b/sound/soc/codecs/wcd9xxx-resmgr.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -158,6 +158,7 @@
 			      enum wcd9xxx_cfilt_sel cfilt_sel);
 
 void wcd9xxx_resmgr_bcl_lock(struct wcd9xxx_resmgr *resmgr);
+void wcd9xxx_resmgr_post_ssr(struct wcd9xxx_resmgr *resmgr);
 #define WCD9XXX_BCL_LOCK(resmgr)			\
 {							\
 	pr_debug("%s: Acquiring BCL\n", __func__);	\
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index 4c8d2e3..e5f0208 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -55,8 +55,7 @@
 # for MSM 8960 sound card driver
 
 obj-$(CONFIG_SND_SOC_MSM_QDSP6_INTF) += qdsp6/
-
-snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-multi-ch-pcm-q6.o msm-lowlatency-pcm-q6.o msm-pcm-routing.o msm-dai-fe.o msm-compr-q6.o msm-dai-stub.o
+snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-multi-ch-pcm-q6.o msm-lowlatency-pcm-q6.o msm-pcm-loopback.o msm-pcm-routing.o msm-dai-fe.o msm-compr-q6.o msm-dai-stub.o
 obj-$(CONFIG_SND_SOC_MSM_QDSP6_HDMI_AUDIO) += msm-dai-q6-hdmi.o
 obj-$(CONFIG_SND_SOC_VOICE) += msm-pcm-voice.o msm-pcm-voip.o msm-pcm-dtmf.o
 snd-soc-qdsp6-objs += msm-pcm-lpa.o msm-pcm-afe.o
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index cf0d4cd..784b650 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -229,6 +229,17 @@
 			.rate_min =	8000,
 			.rate_max = 48000,
 		},
+		.capture = {
+			.stream_name = "MultiMedia6 Capture",
+			.aif_name = "MM_UL6",
+			.rates = (SNDRV_PCM_RATE_8000_48000|
+					SNDRV_PCM_RATE_KNOT),
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 8,
+			.rate_min =     8000,
+			.rate_max =	48000,
+		},
 		.ops = &msm_fe_Multimedia_dai_ops,
 		.name = "MultiMedia6",
 	},
diff --git a/sound/soc/msm/msm-pcm-loopback.c b/sound/soc/msm/msm-pcm-loopback.c
new file mode 100644
index 0000000..55f29a5
--- /dev/null
+++ b/sound/soc/msm/msm-pcm-loopback.c
@@ -0,0 +1,327 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 and
+* only version 2 as published by the Free Software Foundation.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*/
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/apr_audio.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/q6asm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+
+#include "msm-pcm-routing.h"
+
+struct msm_pcm {
+	struct snd_pcm_substream *playback_substream;
+	struct snd_pcm_substream *capture_substream;
+
+	int instance;
+
+	struct mutex lock;
+
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+
+	int playback_start;
+	int capture_start;
+	int session_id;
+	struct audio_client *audio_client;
+};
+
+static void stop_pcm(struct msm_pcm *pcm);
+
+static struct msm_pcm pcm_info;
+
+static const struct snd_pcm_hardware dummy_pcm_hardware = {
+	.formats                = 0xffffffff,
+	.channels_min           = 1,
+	.channels_max           = UINT_MAX,
+
+	/* Random values to keep userspace happy when checking constraints */
+	.info                   = SNDRV_PCM_INFO_INTERLEAVED |
+				  SNDRV_PCM_INFO_BLOCK_TRANSFER,
+	.buffer_bytes_max       = 128*1024,
+	.period_bytes_min       = PAGE_SIZE,
+	.period_bytes_max       = PAGE_SIZE*2,
+	.periods_min            = 2,
+	.periods_max            = 128,
+};
+
+static void event_handler(uint32_t opcode,
+		uint32_t token, uint32_t *payload, void *priv)
+{
+	pr_debug("%s\n", __func__);
+	switch (opcode) {
+	case APR_BASIC_RSP_RESULT:
+		pr_debug("%s: opcode[0x%x]\n", __func__, opcode);
+		break;
+	default:
+		pr_err("Not Supported Event opcode[0x%x]\n", opcode);
+		break;
+	}
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_pcm *pcm = &pcm_info;
+	int ret = 0;
+
+	mutex_lock(&pcm->lock);
+
+	snd_soc_set_runtime_hwparams(substream, &dummy_pcm_hardware);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		pcm->playback_substream = substream;
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		pcm->capture_substream = substream;
+
+	pcm->instance++;
+	pr_debug("%s: pcm out open: %d,%d\n", __func__,
+			pcm->instance, substream->stream);
+	if (pcm->instance == 2) {
+		struct snd_soc_pcm_runtime *soc_pcm_rx =
+				pcm->playback_substream->private_data;
+		struct snd_soc_pcm_runtime *soc_pcm_tx =
+				pcm->capture_substream->private_data;
+		if (pcm->audio_client != NULL)
+			stop_pcm(pcm);
+
+		pcm->audio_client = q6asm_audio_client_alloc(
+				(app_cb)event_handler, pcm);
+		if (!pcm->audio_client) {
+			pr_err("%s: Could not allocate memory\n", __func__);
+			mutex_unlock(&pcm->lock);
+			return -ENOMEM;
+		}
+		pcm->session_id = pcm->audio_client->session;
+		pcm->audio_client->perf_mode = false;
+		ret = q6asm_open_loopack(pcm->audio_client);
+		if (ret < 0) {
+			pr_err("%s: pcm out open failed\n", __func__);
+			q6asm_audio_client_free(pcm->audio_client);
+			mutex_unlock(&pcm->lock);
+			return -ENOMEM;
+		}
+		msm_pcm_routing_reg_phy_stream(soc_pcm_tx->dai_link->be_id,
+			pcm->audio_client->perf_mode,
+			pcm->session_id, pcm->capture_substream->stream);
+		msm_pcm_routing_reg_phy_stream(soc_pcm_rx->dai_link->be_id,
+			pcm->audio_client->perf_mode,
+			pcm->session_id, pcm->playback_substream->stream);
+	}
+	pr_debug("%s: Instance = %d, Stream ID = %s\n",
+			__func__ , pcm->instance, substream->pcm->id);
+	runtime->private_data = pcm;
+
+	mutex_unlock(&pcm->lock);
+
+	return 0;
+}
+
+int msm_set_lb_volume(unsigned volume)
+{
+	int rc = 0;
+	if (pcm_info.audio_client != NULL) {
+		pr_debug("%s: apply loopback vol:%d\n", __func__, volume);
+		rc = q6asm_set_volume(pcm_info.audio_client, volume);
+		if (rc < 0) {
+			pr_err("%s: Send Volume command failed" \
+					" rc=%d\n", __func__, rc);
+		}
+	}
+	return rc;
+}
+
+static void stop_pcm(struct msm_pcm *pcm)
+{
+	struct snd_soc_pcm_runtime *soc_pcm_rx =
+		pcm->playback_substream->private_data;
+	struct snd_soc_pcm_runtime *soc_pcm_tx =
+		pcm->capture_substream->private_data;
+
+	if (pcm->audio_client == NULL)
+		return;
+	q6asm_cmd(pcm->audio_client, CMD_CLOSE);
+
+	msm_pcm_routing_dereg_phy_stream(soc_pcm_rx->dai_link->be_id,
+			SNDRV_PCM_STREAM_PLAYBACK);
+	msm_pcm_routing_dereg_phy_stream(soc_pcm_tx->dai_link->be_id,
+			SNDRV_PCM_STREAM_CAPTURE);
+	q6asm_audio_client_free(pcm->audio_client);
+	pcm->audio_client = NULL;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_pcm *pcm = runtime->private_data;
+	int ret = 0;
+
+	mutex_lock(&pcm->lock);
+
+	pr_debug("%s: end pcm call:%d\n", __func__, substream->stream);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		pcm->playback_start = 0;
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		pcm->capture_start = 0;
+
+	pcm->instance--;
+	if (!pcm->playback_start || !pcm->capture_start) {
+		pr_debug("%s: end pcm call\n", __func__);
+		stop_pcm(pcm);
+	}
+
+	mutex_unlock(&pcm->lock);
+	return ret;
+}
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_pcm *pcm = runtime->private_data;
+
+	mutex_lock(&pcm->lock);
+
+	pr_debug("%s: ASM loopback stream:%d\n", __func__, substream->stream);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (!pcm->playback_start)
+			pcm->playback_start = 1;
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		if (!pcm->capture_start)
+			pcm->capture_start = 1;
+	}
+	mutex_unlock(&pcm->lock);
+
+	return ret;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_pcm *pcm = runtime->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		pr_debug("%s: playback_start:%d,capture_start:%d\n", __func__,
+				pcm->playback_start, pcm->capture_start);
+		if (pcm->playback_start && pcm->capture_start)
+			q6asm_run_nowait(pcm->audio_client, 0, 0, 0);
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_STOP:
+		pr_debug("%s:Pause/Stop - playback_start:%d,capture_start:%d\n",
+			__func__, pcm->playback_start, pcm->capture_start);
+		if (pcm->playback_start && pcm->capture_start)
+			q6asm_cmd_nowait(pcm->audio_client, CMD_PAUSE);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+
+	pr_debug("%s: ASM loopback\n", __func__);
+
+	return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+		params_buffer_bytes(params));
+}
+
+static int msm_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+	.open           = msm_pcm_open,
+	.hw_params	= msm_pcm_hw_params,
+	.hw_free	= msm_pcm_hw_free,
+	.close          = msm_pcm_close,
+	.prepare        = msm_pcm_prepare,
+	.trigger        = msm_pcm_trigger,
+};
+
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	int ret = 0;
+
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+	return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+	.ops		= &msm_pcm_ops,
+	.pcm_new	= msm_asoc_pcm_new,
+};
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+	pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+	return snd_soc_register_platform(&pdev->dev,
+				   &msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_pcm_driver = {
+	.driver = {
+		.name = "msm-pcm-loopback",
+		.owner = THIS_MODULE,
+	},
+	.probe = msm_pcm_probe,
+	.remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+	memset(&pcm_info, 0, sizeof(struct msm_pcm));
+	mutex_init(&pcm_info.lock);
+
+	return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	mutex_destroy(&pcm_info.lock);
+	platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("ASM loopback module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 6cf74d5..aaae373 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -1608,6 +1608,9 @@
 	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT_BT_SCO_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = {
@@ -1644,6 +1647,9 @@
 	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AFE_PCM_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_AFE_PCM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = {
@@ -1662,6 +1668,9 @@
 	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AUXPCM_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_AUXPCM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = {
@@ -1758,6 +1767,12 @@
 	msm_routing_put_audio_mixer),
 };
 
+static const struct snd_kcontrol_new mmul6_mixer_controls[] = {
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
 static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
 	SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX,
 	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -2549,6 +2564,7 @@
 	SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("VoLTE_DL", "VoLTE Playback", 0, 0, 0, 0),
@@ -2656,6 +2672,8 @@
 	mmul4_mixer_controls, ARRAY_SIZE(mmul4_mixer_controls)),
 	SND_SOC_DAPM_MIXER("MultiMedia5 Mixer", SND_SOC_NOPM, 0, 0,
 	mmul5_mixer_controls, ARRAY_SIZE(mmul5_mixer_controls)),
+	SND_SOC_DAPM_MIXER("MultiMedia6 Mixer", SND_SOC_NOPM, 0, 0,
+	mmul6_mixer_controls, ARRAY_SIZE(mmul6_mixer_controls)),
 	SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
 	auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
 	SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -2830,6 +2848,7 @@
 	{"MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
 	{"MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+	{"MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
 	{"MI2S_RX", NULL, "MI2S_RX Audio Mixer"},
 
 	{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
@@ -2848,6 +2867,7 @@
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
 	{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Audio Mixer"},
 
 	{"INTERNAL_FM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -2862,12 +2882,14 @@
 	{"AFE_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"AFE_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
 	{"AFE_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+	{"AFE_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
 	{"PCM_RX", NULL, "AFE_PCM_RX Audio Mixer"},
 
 	{"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
 	{"MultiMedia5 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
 	{"MultiMedia1 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 	{"MultiMedia5 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+	{"MultiMedia6 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 
 	{"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"},
 	{"MultiMedia5 Mixer", "AFE_PCM_TX", "PCM_TX"},
@@ -2876,12 +2898,14 @@
 	{"MM_UL2", NULL, "MultiMedia2 Mixer"},
 	{"MM_UL4", NULL, "MultiMedia4 Mixer"},
 	{"MM_UL5", NULL, "MultiMedia5 Mixer"},
+	{"MM_UL6", NULL, "MultiMedia6 Mixer"},
 
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+	{"AUX_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
 	{"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"},
 
 	{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index b571483..202e7ea 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -145,6 +145,8 @@
 
 int lpa_set_volume(unsigned volume);
 
+int msm_set_lb_volume(unsigned volume);
+
 int msm_routing_check_backend_enabled(int fedai_id);
 
 int multi_ch_pcm_set_volume(unsigned volume);
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 8fd5840..8ec2e94 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -1,6 +1,6 @@
 
 /*
- * Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -912,6 +912,7 @@
 		case ASM_STREAM_CMD_OPEN_WRITE:
 		case ASM_STREAM_CMD_OPEN_WRITE_V2_1:
 		case ASM_STREAM_CMD_OPEN_READWRITE:
+		case ASM_STREAM_CMD_OPEN_LOOPBACK:
 		case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
 		case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
 		case ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED:
@@ -1848,6 +1849,45 @@
 	return -EINVAL;
 }
 
+int q6asm_open_loopack(struct audio_client *ac)
+{
+	int rc = 0x00;
+	struct asm_stream_cmd_open_loopback open;
+
+	if ((ac == NULL) || (ac->apr == NULL)) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	pr_debug("%s: session[%d]", __func__, ac->session);
+
+	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+	open.hdr.opcode = ASM_STREAM_CMD_OPEN_LOOPBACK;
+
+	open.mode_flags = 0;
+	open.src_endpointype = 0;
+	open.sink_endpointype = 0;
+	/* source endpoint : matrix */
+	open.postprocopo_id = get_asm_topology();
+	if (open.postprocopo_id == 0)
+		open.postprocopo_id = DEFAULT_POPP_TOPOLOGY;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+	if (rc < 0) {
+		pr_err("open failed op[0x%x]rc[%d]\n", \
+						open.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout. waited for OPEN_LOOPBACK rc[%d]\n", rc);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
 int q6asm_run(struct audio_client *ac, uint32_t flags,
 		uint32_t msw_ts, uint32_t lsw_ts)
 {