Merge "HID: uhid: forward raw output reports to user-space"
diff --git a/Documentation/devicetree/bindings/arm/msm/ipc-spinlock.txt b/Documentation/devicetree/bindings/arm/msm/ipc-spinlock.txt
index c71b190..24dbb4b 100644
--- a/Documentation/devicetree/bindings/arm/msm/ipc-spinlock.txt
+++ b/Documentation/devicetree/bindings/arm/msm/ipc-spinlock.txt
@@ -1,14 +1,27 @@
 Qualcomm Interprocessor Communication Spinlock
 
+--Dedicated Hardware Implementation--
 Required properties:
-- compatible : should be "qcom,ipc-spinlock"
+- compatible : should be "qcom,ipc-spinlock-sfpb"
 - reg : the location and size of the spinlock hardware
 - qcom,num-locks : the number of locks supported
 
 Example:
 
 	qcom,ipc-spinlock@fd484000 {
-		compatible = "qcom,ipc-spinlock";
+		compatible = "qcom,ipc-spinlock-sfpb";
 		reg = <0xfd484000 0x1000>;
 		qcom,num-locks = <32>;
 	};
+
+--LDREX Implementation--
+Required properties:
+- compatible : should be "qcom,ipc-spinlock-ldrex"
+- reg : the location and size of the shared lock memory
+
+Example:
+
+	qcom,ipc-spinlock@fa00000 {
+		compatible = "qcom,ipc-spinlock-ldrex";
+		reg = <0xfa00000 0x200000>;
+	};
diff --git a/Documentation/devicetree/bindings/bif/bif.txt b/Documentation/devicetree/bindings/bif/bif.txt
new file mode 100644
index 0000000..c4ff08b
--- /dev/null
+++ b/Documentation/devicetree/bindings/bif/bif.txt
@@ -0,0 +1,22 @@
+BIF (Battery Interface) Controllers
+
+Optional properties:
+- qcom,known-device-addresses:  Specifies a list of integers which correspond to
+                                the 8-bit BIF bus device addresses of BIF slaves
+                                found on the target.
+
+BIF Consumers
+
+Optional properties:
+- qcom,bif-ctrl:                phandle of parent BIF controller device node
+
+Example:
+	foo_ctrl: foo-controller {
+		...
+		qcom,known-device-addresses = <0x80, 0x81>;
+	};
+
+	bar-consumer {
+		...
+		qcom,bif-ctrl = <&foo_ctrl>;
+	};
diff --git a/Documentation/devicetree/bindings/bif/qpnp-bsi.txt b/Documentation/devicetree/bindings/bif/qpnp-bsi.txt
new file mode 100644
index 0000000..29267dd
--- /dev/null
+++ b/Documentation/devicetree/bindings/bif/qpnp-bsi.txt
@@ -0,0 +1,91 @@
+Qualcomm QPNP BSI - battery serial interface devices
+
+qpnp-bsi is a BIF driver which supports the BSI peripheral inside of PMICs
+that utilize the MSM SPMI implementation.
+
+Required properties:
+- compatible:      Must be "qcom,qpnp-bsi".
+- reg:             Specifies the SPMI address and size for this BSI device as
+                    well as the address of the BATT_ID status register.
+- reg-names:       A list of strings identifying the reg property entries.  The
+                    list must contain both "bsi-base" and "batt-id-status".
+- label:           A string used as a descriptive name for this BIF controller.
+- interrupts:      Specifies a list of four interrupts corresponding to
+                    IRQ ERR, IRQ RX, IRQ TX, and IRQ BATT_PRESENT in any order.
+- interrupt-names: Must be a list of strings containing all three of these
+                    strings: "err", "rx", "tx", "batt-present".  The ordering of
+                    these strings must match the ordering of the interrupts in
+                    the "interrupts" property.
+
+Required structure:
+- A qcom,qpnp-bsi node must be a child of an SPMI node that has specified the
+	spmi-slave-container property.
+
+Optional properties:
+- qcom,min-clock-period:  This property specifies a minimum clock period for the
+                           Tau BIF reference in nanoseconds.  It can be used to
+                           impose a minimum period which is higher (i.e. more
+                           restrictive) than that supported by the hardware.
+                           The BSI module supports 8 possible periods between
+                           2080 ns and 150420 ns.
+- qcom,max-clock-period:  This property specifies a maximum clock period for the
+                           Tau BIF reference in nanoseconds.  It can be used to
+                           impose a maximum period which is lower (i.e. more
+                           restrictive) than that supported by the hardware.
+                           The BSI module supports 8 possible periods between
+                           2080 ns and 150420 ns.
+- qcom,sample-rate:       Specifies the rate at which the BIF BCL should be
+                           sampled during communication with respect to the Tau
+                           BIF reference rate.  Supported values are 4 and 8
+                           which represent 4x and 8x sampling rates
+                           respectively.  If this property is not specified,
+                           then 4x sampling is assumed.
+- qcom,channel-num:       VADC channel number associated PMIC BATT_ID pin.  If
+                           no channel is specified, then it will not be
+                           possible to measure the slave Rid.
+- qcom,pullup-ohms:       Host side pull-up resistance present on BCL in ohms.
+                           If no value is specified, then 100000 ohms is
+                           assumed.
+- qcom,vref-microvolts:   Reference voltage used for BCL divider circuit in
+                           microvolts.  If no value is specified, then
+                           1800000 uV is assumed.
+
+All properties specified within for the BIF framework can also be used. These
+properties can be found in bif.txt.
+
+Example:
+	qcom,spmi@fc4c0000 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		interrupt-controller;
+		#interrupt-cells = <3>;
+
+		qcom,pm8941@1 {
+			spmi-slave-container;
+			reg = <0x1>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			qcom,bsi@1b00 {
+				compatible = "qcom,qpnp-bsi";
+				reg = <0x1b00 0x100>,
+				      <0x1208 0x1>;
+				reg-names = "bsi-base", "batt-id-status";
+				label = "pm8941-bsi";
+				interrupts = <0x0 0x1b 0x0>,
+					     <0x0 0x1b 0x1>,
+					     <0x0 0x1b 0x2>,
+					     <0x0 0x12 0x0>;
+				interrupt-names = "err",
+						  "rx",
+						  "tx",
+						  "batt-present";
+				qcom,sample-rate = <8>;
+				qcom,min-clock-period = <15830>;
+				qcom,max-clock-period = <122080>;
+				qcom,channel-num = <0x31>;
+				qcom,pullup-ohms = <100000>;
+				qcom,vref-microvolts = <1800000>;
+			};
+		};
+	};
diff --git a/Documentation/devicetree/bindings/coresight/coresight.txt b/Documentation/devicetree/bindings/coresight/coresight.txt
index 48f25de..c830bc4 100644
--- a/Documentation/devicetree/bindings/coresight/coresight.txt
+++ b/Documentation/devicetree/bindings/coresight/coresight.txt
@@ -10,9 +10,68 @@
 
 Required properties:
 
-- compatible : name of the component used for driver matching
+- compatible : name of the component used for driver matching, should be one of
+	the following:
+	"arm,coresight-tmc" for coresight tmc-etr or tmc-etf device,
+	"arm,coresight-tpiu" for coresight tpiu device,
+	"qcom,coresight-replicator" for coresight replicator device,
+	"arm,coresight-funnel" for coresight funnel devices,
+	"arm,coresight-stm" for coresight stm trace device,
+	"arm,coresight-etm" for coresight etm trace devices,
+	"qcom,coresight-csr" for coresight csr device,
+	"arm,coresight-cti" for coresight cti devices
 - reg : physical base address and length of the register set(s) of the component
-- reg-names: names corresponding to each reg property value
+- reg-names : names corresponding to each reg property value. The reg-names that
+	need to be used with corresponding compatible string for a coresight device
+	are:
+	- for coresight tmc-etr device:
+		compatible : should be "arm,coresight-tmc"
+		reg-names  : should be:
+			"tmc-etr-base" - physical base address of tmc-etr registers
+			"tmc-etr-bam-base" - physical base address of tmc-etr bam
+				 registers
+	- for coresight tmc-etf device:
+		compatible : should be "arm,coresight-tmc"
+		reg-names  : should be:
+			"tmc-etf-base" - physical base address of tmc-etf registers
+	- for coresight tpiu device:
+		compatible : should be "arm,coresight-tpiu"
+		reg-names  : should be:
+			"tpiu-base" - physical base address of tpiu registers
+	- for coresight replicator device
+		compatible : should be "qcom,coresight-replicator"
+		reg-names  : should be:
+			"replicator-base" - physical base address of replicator registers
+	- for coresight funnel devices
+		compatible : should be "arm,coresight-funnel"
+		reg-names  : should be:
+			"funnel-<val>-base" - physical base address of funnel registers
+				where <val> can be "merg", "in0", "in1", "kpss", "a7ss" or
+				"mmss"
+	- for coresight stm trace device
+		compatible : should be "arm,coresight-stm"
+		reg-names  : should be:
+			"stm-base" - physical base address of stm registers
+			"stm-data-base" - physical base address of stm data registers
+	- for coresight etm trace devices
+		compatible : should be "arm,coresight-etm"
+		reg-names  : should be:
+			"etm<num>-base" - physical base address of etm registers in
+				general where <num> is the number of etm components or cores
+				present for more than one cpu core
+	- for coresight csr device:
+		compatible : should be "qcom,coresight-csr"
+		reg-names  : should be:
+			"csr-base" - physical base address of csr registers
+	- for coresight cti devices:
+		compatible : should be "arm,coresight-cti"
+		reg-names  : should be:
+			"cti<num>-base" - physical base address of cti registers in general
+				 where <num> is the cti component number for more than one
+				 cti components
+			"cti-cpu<num>-base" - physical base address of cti cpu registers
+				 where <num> is the component number for more than one cpu core
+			"cti-l2" - physical base address of L2 cti registers
 - coresight-id : unique integer identifier for the component
 - coresight-name : unique descriptive name of the component
 - coresight-nr-inports : number of input ports on the component
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index 0f31a38..17b878c 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -43,6 +43,11 @@
 				previous property, the amount of fetch ids
 				defined should match the number of offsets
 				defined in property: qcom,mdss-pipe-dma-off
+- qcom,mdss-smp-data:		Array of shared memory pool data. There should
+				be only two values in this property. The first
+				value corresponds to the number of smp blocks
+				and the second is the size of each block
+				present in the mdss hardware.
 - qcom,mdss-ctl-off:		Array of offset addresses for the available ctl
 				hw blocks within MDP, these offsets are
 				calculated from register "mdp_phys" defined in
@@ -123,6 +128,7 @@
 		qcom,mdss-pipe-vig-fetch-id = <1 4 7>;
 		qcom,mdss-pipe-rgb-fetch-id = <16 17 18>;
 		qcom,mdss-pipe-dma-fetch-id = <10 13>;
+		qcom,mdss-smp-data = <22 4096>;
 
 		qcom,mdss-ctl-off = <0x00000600 0x00000700 0x00000800
 				     0x00000900 0x0000A00>;
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
index bb66e7b..8de8bdd 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
@@ -30,7 +30,16 @@
 		    2 : 2K
 		    3 : 4K
 - qcom,pre-div-channel-scaling : Pre-div used for the channel before the signal
-				 is being measured.
+				 is being measured. Some of the AMUX channels
+				 support dividing the signal from a predetermined
+				 ratio. The configuration for this node is to know
+				 the pre-determined ratio and use it for post scaling.
+				 Select from the following unsinged int.
+				 0 : {1, 1}
+				 1 : {1, 3}
+				 2 : {1, 4}
+				 3 : {1, 6}
+				 4 : {1, 20}
 - qcom,calibration-type : Reference voltage to use for channel calibration.
 			  Channel calibration is dependendent on the channel.
 			  Certain channels like XO_THERM, BATT_THERM use ratiometric
@@ -96,10 +105,39 @@
                                 label = "usb_in";
                                 reg = <0>;
                                 qcom,decimation = <0>;
-                                qcom,pre-div-channel-scaling = <20>;
+                                qcom,pre-div-channel-scaling = <4>;
                                 qcom,calibration-type = "absolute";
                                 qcom,scale-function = <0>;
                                 qcom,hw-settle-time = <0>;
                                 qcom,fast-avg-setup = <0>;
                         };
 	};
+
+/* Clients have an option of measuring an analog signal through an MPP.
+   MPP block is not part of the VADC block but is an individual PMIC
+   block that has an option to support clients to configure an MPP as
+   an analog input which can be routed through one of the VADC pre-mux
+   inputs. Here is an example of how to configure an MPP as an analog
+   input */
+
+/* Configure MPP4 as an Analog input to AMUX8 and read from channel 0x23 */
+/* MPP DT configuration in the platform DT file*/
+	mpp@a300 { /* MPP 4 */
+		qcom,mode = <4>; /* AIN input */
+		qcom,invert = <1>; /* Enable MPP */
+		qcom,ain-route = <3>; /* AMUX 8 */
+		qcom,master-en = <1>;
+		qcom,src-sel = <0>; /* Function constant */
+	};
+
+/* VADC Channel configuration */
+	chan@23 {
+		label = "mpp4_div3";
+		reg = <0x23>;
+		qcom,decimation = <0>;
+		qcom,pre-div-channel-scaling = <1>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,fast-avg-setup = <0>;
+	};
diff --git a/Documentation/devicetree/bindings/i2c/i2c-qup.txt b/Documentation/devicetree/bindings/i2c/i2c-qup.txt
index 60de396..a7976e8 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-qup.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-qup.txt
@@ -24,6 +24,11 @@
 		      desired I2C bus frequency. If this value is not
 		      provided, the source clock is assumed to be running
 		      at 19.2 MHz.
+ - qcom,scl-gpio     : I2C clock GPIO number. Required for execution of bus
+		      recovery procedure.
+ - qcom,sda-gpio     : I2C data  GPIO number. Required for execution of bus
+		      recovery procedure.
+
 Example:
 	i2c@f9966000 {
 		cell-index = <0>;
@@ -34,4 +39,6 @@
 		interrupt-names = "qup_err_intr";
 		qcom,i2c-bus-freq = <100000>;
 		qcom,i2c-src-freq = <24000000>;
+		qcom,scl-gpio = <&msmgpio 7 0>;
+		qcom,sda-gpio = <&msmgpio 6 0>;
 	};
diff --git a/Documentation/devicetree/bindings/media/video/msm-cpp.txt b/Documentation/devicetree/bindings/media/video/msm-cpp.txt
index 9d176d8..c345d38 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cpp.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cpp.txt
@@ -7,8 +7,9 @@
 - reg : offset and length of the register set for the device
     for the cpp operating in compatible mode.
 - reg-names : should specify relevant names to each reg property defined.
-  - cpp - has CPP hardware register set.
+  - cpp - has CPP MICRO register set.
   - cpp_vbif - has VBIF core register set used by CPP.
+  - cpp_hw - has CPP hardware register set.
 - interrupts : should contain the cpp interrupt.
 - interrupt-names : should specify relevant names to each interrupts
   property defined.
@@ -21,7 +22,8 @@
        compatible = "qcom,cpp";
        reg = <0xfda04000 0x100>;
              <0xfda40000 0x200>;
-       reg-names = "cpp", "cpp_vbif";
+             <0xfd180000 0x008>;
+       reg-names = "cpp", "cpp_vbif", "cpp_hw";
        interrupts = <0 49 0>;
        interrupt-names = "cpp";
        vdd-supply = <&gdsc_vfe>;
diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
index cd14056..f97e063 100644
--- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
@@ -31,6 +31,14 @@
   request by different video encoder usecases.
 - qcom,dec-ddr-ab-ib : list of bus vectors(ab, ib pair) for ddr bandwidth
   request by different video decoder usecases.
+- qcom,iommu-groups : list of IOMMU groups to be used.  Groups are defined as
+  phandles in <target>-iommu-domains.dtsi (e.g msm8974-v1-iommu-domains.dtsi)
+- qcom,iommu-group-buffer-types : bitmap of buffer types that can be mapped into
+  the corresponding IOMMU group. Buffer types are defined within the vidc driver
+  by "enum hal_buffer" in msm_smem.h
+- qcom,buffer-type-tz-usage-table : a key-value pair, mapping a buffer type
+  (enum hal_buffer) to its corresponding TZ usage. The TZ usages are defined
+  as "enum cp_mem_usage" in include/linux/msm_ion.h
 
 Example:
 
@@ -59,4 +67,8 @@
 			<60000 664950>;
 		qcom,dec-ddr-ab-ib = <0 0>,
 			<110000 909000>;
+		qcom,iommu-groups = <&venus_domain_ns &venus_domain_cp>;
+		qcom,iommu-group-buffer-types = <0xfff 0x1ff>;
+		qcom,buffer-type-tz-usage-table = <0x1 0x1>,
+						<0x1fe 0x2>;
 	};
diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
new file mode 100644
index 0000000..e98ee05
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory.txt
@@ -0,0 +1,106 @@
+* Memory binding
+
+The /memory node provides basic information about the address and size
+of the physical memory. This node is usually filled or updated by the
+bootloader, depending on the actual memory configuration of the given
+hardware.
+
+The memory layout is described by the folllowing node:
+
+memory {
+	reg =  <(baseaddr1) (size1)
+		(baseaddr2) (size2)
+		...
+		(baseaddrN) (sizeN)>;
+};
+
+baseaddrX:	the base address of the defined memory bank
+sizeX:		the size of the defined memory bank
+
+More than one memory bank can be defined.
+
+
+* Memory regions
+
+In /memory node one can create additional nodes describing particular
+memory regions, usually for the special usage by various device drivers.
+A good example are contiguous memory allocations or memory sharing with
+other operating system on the same hardware board. Those special memory
+regions might depend on the board configuration and devices used on the
+target system.
+
+Parameters for each memory region can be encoded into the device tree
+wit the following convention:
+
+(name): region@(base-address) {
+	reg = <(baseaddr) (size)>;
+	(linux,contiguous-region);
+	(linux,default-contiguous-region);
+        label = (unique_name);
+};
+
+name:		an name given to the defined region.
+base-address:	the base address of the defined region.
+size:		the size of the memory region.
+linux,contiguous-region: property indicating that the defined memory
+		region is used for contiguous memory allocations,
+		Linux specific (optional)
+linux,default-contiguous-region: property indicating that the region
+		is the default region for all contiguous memory
+		allocations, Linux specific (optional)
+label:		an internal name used for automatically associating the
+		cma region with a given device. The label is optional;
+		if the label is not given the client is responsible for
+		calling the appropriate functions to associate the region
+		with a device.
+
+* Device nodes
+
+Once the regions in the /memory node are defined, they can be assigned
+to device some device nodes for their special use. The following
+properties are defined:
+
+linux,contiguous-region = <&phandle>;
+	This property indicates that the device driver should use the
+	memory region pointed by the given phandle.
+
+
+* Example:
+
+This example defines a memory consisting of 4 memory banks. 2 contiguous
+regions are defined for Linux kernel, one default of all device drivers
+(named contig_mem, placed at 0x72000000, 64MiB) and one dedicated to the
+framebuffer device (named display_mem, placed at 0x78000000, 16MiB). The
+display_mem region is then assigned to fb@12300000 device for contiguous
+memory allocation with Linux kernel drivers.
+
+The reason for creating a separate region for framebuffer device is to
+match the framebuffer address of from configuration done by bootloader,
+so once Linux kernel drivers starts, no glitches on the displayed boot
+logo appears.
+
+/ {
+	/* ... */
+	memory {
+		reg =  <0x40000000 0x10000000
+			0x50000000 0x10000000
+			0x60000000 0x10000000
+			0x70000000 0x10000000>;
+
+		contig_mem: region@72000000 {
+			linux,contiguous-region;
+			linux,default-contiguous-region;
+			reg = <0x72000000 0x4000000>;
+		};
+
+		display_mem: region@78000000 {
+			linux,contiguous-region;
+			reg = <0x78000000 0x1000000>;
+		};
+	};
+
+	fb@12300000 {
+		linux,contiguous-region = <&display_mem>;
+		status = "okay";
+	};
+};
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
new file mode 100644
index 0000000..24b6b36
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -0,0 +1,107 @@
+Qualcomm Standard Secure Digital Host Controller (SDHC)
+
+Secure Digital Host Controller provides standard host interface to SD/MMC/SDIO cards.
+
+Required properties:
+  - compatible : should be "qcom,sdhci-msm"
+  - reg : should contain SDHC, SD Core register map.
+  - reg-names : indicates various resources passed to driver (via reg proptery) by name.
+		Required "reg-names" are "hc_mem" and "core_mem"
+  - interrupts : should contain SDHC interrupts.
+  - interrupt-names : indicates interrupts passed to driver (via interrupts property) by name.
+		      Required "interrupt-names" are "hc_irq" and "pwr_irq".
+  - <supply-name>-supply: phandle to the regulator device tree node
+			  Required "supply-name" are "vdd" and "vdd-io".
+
+Required alias:
+- The slot number is specified via an alias with the following format
+	'sdhc{n}' where n is the slot number.
+
+Optional Properties:
+	- interrupt-names - "status_irq". This status_irq will be used for card
+			     detection.
+	- qcom,bus-width - defines the bus I/O width that controller supports.
+			   Units - number of bits. The valid bus-width values are
+			   1, 4 and 8.
+	- qcom,nonremovable - specifies whether the card in slot is
+			      hot pluggable or hard wired.
+	- qcom,bus-speed-mode - specifies supported bus speed modes by host.
+				The supported bus speed modes are :
+				"HS200_1p8v" - indicates that host can support HS200 at 1.8v.
+				"HS200_1p2v" - indicates that host can support HS200 at 1.2v.
+				"DDR_1p8v" - indicates that host can support DDR mode at 1.8v.
+				"DDR_1p2v" - indicates that host can support DDR mode at 1.2v.
+
+In the following, <supply> can be vdd (flash core voltage) or vdd-io (I/O voltage).
+	- qcom,<supply>-always-on - specifies whether supply should be kept "on" always.
+	- qcom,<supply>-lpm_sup - specifies whether supply can be kept in low power mode (lpm).
+	- qcom,<supply>-voltage_level - specifies voltage levels for supply. Should be
+					specified in pairs (min, max), units uV.
+	- qcom,<supply>-current_level - specifies load levels for supply in lpm or
+					high power mode (hpm). Should be specified in
+					pairs (lpm, hpm), units uA.
+
+	- gpios - specifies gpios assigned for sdhc slot.
+	- qcom,gpio-names -  a list of strings that map in order to the list of gpios
+
+	A slot has either gpios or dedicated tlmm pins as represented below.
+	- qcom,pad-pull-on - Active pull configuration for sdc tlmm pins
+	- qcom,pad-pull-off - Suspend pull configuration for sdc tlmm pins.
+	- qcom,pad-drv-on - Active drive strength configuration for sdc tlmm pins.
+	- qcom,pad-drv-off - Suspend drive strength configuration for sdc tlmm pins.
+	Tlmm pins are specified as <clk cmd data>
+
+Example:
+
+	aliases {
+		sdhc1 = &sdhc_1;
+		sdhc2 = &sdhc_2;
+	};
+
+	sdhc_1: qcom,sdhc@f9824900 {
+		compatible = "qcom,sdhci-msm";
+                reg = <0xf9824900 0x11c>, <0xf9824000 0x800>;
+                reg-names = "hc_mem", "core_mem";
+                interrupts = <0 123 0>, <0 138 0>;
+                interrupt-names = "hc_irq", "pwr_irq";
+
+		vdd-supply = <&pm8941_l21>;
+		vdd-io-supply = <&pm8941_l13>;
+		qcom,vdd-voltage-level = <2950000 2950000>;
+		qcom,vdd-current-level = <9000 800000>;
+
+		qcom,vdd-io-always-on;
+		qcom,vdd-io-lpm-sup;
+		qcom,vdd-io-voltage-level = <1800000 2950000>;
+		qcom,vdd-io-current-level = <6 22000>;
+
+                qcom,bus-width = <4>;
+		qcom,nonremovable;
+		qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+
+		gpios = <&msmgpio 40 0>, /* CLK */
+			<&msmgpio 39 0>, /* CMD */
+			<&msmgpio 38 0>, /* DATA0 */
+			<&msmgpio 37 0>, /* DATA1 */
+			<&msmgpio 36 0>, /* DATA2 */
+			<&msmgpio 35 0>; /* DATA3 */
+		qcom,gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
+	};
+
+	sdhc_2: qcom,sdhc@f98a4900 {
+		compatible = "qcom,sdhci-msm";
+                reg = <0xf9824900 0x11c>, <0xf9824000 0x800>;
+                reg-names = "hc_mem", "core_mem";
+                interrupts = <0 123 0>, <0 138 0>;
+                interrupt-names = "hc_irq", "pwr_irq";
+
+		vdd-supply = <&pm8941_l21>;
+		vdd-io-supply = <&pm8941_l13>;
+
+                qcom,bus-width = <4>;
+
+		qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+		qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+		qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+		qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+	};
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index a868b75..4590227 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -54,7 +54,7 @@
 	each should be their own subnode.
 
 Sub node required properties:
-- compatible:		Must be "qcom,charger".
+- compatible:		Must be "qcom,qpnp-charger".
 - reg:			Specifies the SPMI address and size for this peripheral.
 - interrupts:		Specifies the interrupt associated with the peripheral.
 - interrupt-names:	Specifies the interrupt names for the peripheral. Every
@@ -125,7 +125,7 @@
 Example:
 	pm8941-chg {
 		spmi-dev-container;
-		compatible = "qcom,charger";
+		compatible = "qcom,qpnp-charger";
 		#address-cells = <1>;
 		#size-cells = <1>;
 
diff --git a/Documentation/devicetree/bindings/regulator/krait-regulator.txt b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
index f057834..aaa731e 100644
--- a/Documentation/devicetree/bindings/regulator/krait-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
@@ -1,5 +1,24 @@
 Krait Voltage regulators
 
+The cpus are powered using a single supply powered by PMIC ganged regulators operating in
+different phases. Individual kraits further can draw power from the single supply via
+a LDO or a head switch (BHS).  The first level node represents the PMIC ganged regulator
+and its properties and encompasses second level nodes that represent the individual
+krait LDO/BHS control regulator.
+
+[First Level Nodes]
+Required properties:
+- compatible:			Must be "qcom,krait-pdn"
+- reg:				Specifies the physical address of the APCS GCC
+				register base
+- reg-names:			"apcs_gcc" -string to identify the area where
+				the APCS GCC registers reside.
+
+Optional properties:
+- qcom,use-phase-switching	indicates whether the driver should add/shed phases on the PMIC
+				ganged regulator as cpus are hotplugged.
+
+[Second Level Nodes]
 Required properties:
 - compatible:			Must be "qcom,krait-regulator"
 - reg:				Specifies the address and size for this regulator device,
@@ -27,19 +46,28 @@
 binding, defined in regulator.txt, can also be used.
 
 Example:
-	krait0_vreg: regulator@f9088000 {
-		compatible = "qcom,krait-regulator";
-		regulator-name = "krait0";
-		reg = <0xf9088000 0x1000>, /* APCS_ALIAS0_KPSS_ACS */
-			<0xf908a800 0x1000>; /* APCS_ALIAS0_KPSS_MDD */
-		reg-names = "acs", "mdd";
-		regulator-min-microvolt = <500000>;
-		regulator-max-microvolt = <1100000>;
-		qcom,headroom-voltage = <150000>;
-		qcom,retention-voltage = <745000>;
-		qcom,ldo-default-voltage = <745000>;
-		qcom,ldo-threshold-voltage = <750000>;
-		qcom,ldo-delta-voltage = <50000>;
-		qcom,cpu-num = 0;
-	};
+	krait_pdn: krait-pdn@f9011000 {
+		reg = <0xf9011000 0x1000>;
+		reg-names = "apcs_gcc";
+		compatible = "qcom,krait-pdn";
+		qcom,use-phase-switching;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
 
+		krait0_vreg: regulator@f9088000 {
+			compatible = "qcom,krait-regulator";
+			regulator-name = "krait0";
+			reg = <0xf9088000 0x1000>, /* APCS_ALIAS0_KPSS_ACS */
+				<0xf908a800 0x1000>; /* APCS_ALIAS0_KPSS_MDD */
+			reg-names = "acs", "mdd";
+			regulator-min-microvolt = <500000>;
+			regulator-max-microvolt = <1100000>;
+			qcom,headroom-voltage = <150000>;
+			qcom,retention-voltage = <675000>;
+			qcom,ldo-default-voltage = <750000>;
+			qcom,ldo-threshold-voltage = <850000>;
+			qcom,ldo-delta-voltage = <50000>;
+			qcom,cpu-num = <0>;
+		};
+	};
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index fed8cb4..4cd9f99 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -434,6 +434,7 @@
 - prim-auxpcm-gpio-sync : GPIO on which AUXPCM SYNC signal is coming.
 - prim-auxpcm-gpio-din : GPIO on which AUXPCM DIN signal is coming.
 - prim-auxpcm-gpio-dout : GPIO on which AUXPCM DOUT signal is coming.
+- qcom,us-euro-gpios : GPIO on which gnd/mic swap signal is coming.
 
 Optional properties:
 - qcom,hdmi-audio-rx: specifies if HDMI audio support is enabled or not.
@@ -476,6 +477,7 @@
 	qcom,cdc-mclk-gpios = <&pm8941_gpios 15 0>;
 	taiko-mclk-clk = <&pm8941_clkdiv1>;
 	qcom,taiko-mclk-clk-freq = <9600000>;
+	qcom,us-euro-gpios = <&pm8941_gpios 20 0>;
 
 	qcom,hdmi-audio-rx;
 
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 9d0b0a5..6915827 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -52,6 +52,15 @@
 - qcom,hsusb-otg-clk-always-on-workaround: If present then USB core clocks
 	    remain active upon receiving bus suspend and USB cable is connected.
 	    Used for allowing USB to respond for remote wakup.
+- qcom,hsusb-otg-delay-lpm: If present then USB core will wait one second
+	after disconnect before entering low power mode.
+- <supply-name>-supply: handle to the regulator device tree node
+         Required "supply-name" is "HSUSB_VDDCX" (when voting for VDDCX) or
+         "hsusb_vdd_dig" (when voting for VDDCX Corner voltage),
+         "HSUSB_1p8-supply" and "HSUSB_3p3-supply".
+- qcom,vdd-voltage-level: This property must be a list of three integer
+	values (no, min, max) where each value represents either a voltage
+	in microvolts or a value corresponding to voltage corner.
 
 Example HSUSB OTG controller device node :
 	usb@f9690000 {
@@ -72,6 +81,10 @@
 		qcom,hsusb-otg-pmic-id-irq = <47>
 		qcom,hsusb-otg-lpm-on-dev-suspend;
 		qcom,hsusb-otg-clk-always-on-workaround;
+		hsusb_vdd_dig-supply = <&pm8226_s1_corner>;
+                HSUSB_1p8-supply = <&pm8226_l10>;
+                HSUSB_3p3-supply = <&pm8226_l20>;
+		qcom,vdd-voltage-level = <1 5 7>;
 
 		qcom,msm_bus,name = "usb2";
 		qcom,msm_bus,num_cases = <2>;
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 2f686fa..4678337 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1885,18 +1885,9 @@
 config ENABLE_DMM
 	def_bool n
 
-config FIX_MOVABLE_ZONE
-	def_bool n
-
 config DONT_MAP_HOLE_AFTER_MEMBANK0
 	def_bool n
 
-config ARCH_ENABLE_MEMORY_HOTPLUG
-	def_bool n
-
-config ARCH_ENABLE_MEMORY_HOTREMOVE
-	def_bool n
-
 config HOLES_IN_ZONE
 	def_bool n
 	depends on SPARSEMEM
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index ed18cae..3a9b770 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -63,27 +63,6 @@
 	      8 - SIGSEGV faults
 	     16 - SIGBUS faults
 
-config DEBUG_RODATA
-	bool "Write protect kernel text section"
-	default n
-	depends on DEBUG_KERNEL && MMU
-	---help---
-	  Mark the kernel text section as write-protected in the pagetables,
-	  in order to catch accidental (and incorrect) writes to such const
-	  data. This will cause the size of the kernel, plus up to 4MB, to
-	  be mapped as pages instead of sections, which will increase TLB
-	  pressure.
-	  If in doubt, say "N".
-
-config DEBUG_RODATA_TEST
-	bool "Testcase for the DEBUG_RODATA feature"
-	depends on DEBUG_RODATA
-	default n
-	---help---
-	  This option enables a testcase for the DEBUG_RODATA
-	  feature.
-	  If in doubt, say "N"
-
 # These options are only for real kernel hackers who want to get their hands dirty.
 config DEBUG_LL
 	bool "Kernel low-level debugging functions (read help!)"
diff --git a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
index 1c3cf29..42f6033 100644
--- a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
@@ -25,7 +25,7 @@
 		qcom,mdss-pan-porch-values = <32 12 144 3 4 9>;
 		qcom,mdss-pan-underflow-clr = <0xff>;
 		qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
-		qcom,mdss-pan-bl-levels = <1 255>;
+		qcom,mdss-pan-bl-levels = <1 4095>;
 		qcom,mdss-pan-dsi-mode = <0>;
 		qcom,mdss-pan-dsi-h-pulse-mode = <0>;
 		qcom,mdss-pan-dsi-h-power-stop = <0 0 0>;
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index de23f4c..44ece9e 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -22,6 +22,136 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 
+		qcom,power-on@800 {
+			compatible = "qcom,qpnp-power-on";
+			reg = <0x800 0x100>;
+			interrupts = <0x0 0x8 0x0>,
+				     <0x0 0x8 0x1>,
+				     <0x0 0x8 0x4>;
+			interrupt-names = "kpdpwr", "resin", "resin-bark";
+			qcom,pon-dbc-delay = <15625>;
+			qcom,system-reset;
+
+			qcom,pon_1 {
+				qcom,pon-type = <0>;
+				qcom,pull-up = <1>;
+				linux,code = <116>;
+			};
+
+			qcom,pon_2 {
+				qcom,pon-type = <1>;
+				qcom,support-reset = <1>;
+				qcom,pull-up = <1>;
+				qcom,s1-timer = <0>;
+				qcom,s2-timer = <2000>;
+				qcom,s2-type = <1>;
+				linux,code = <114>;
+			};
+		};
+
+		pm8226_chg: qcom,charger {
+			spmi-dev-container;
+			compatible = "qcom,qpnp-charger";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			status = "disabled";
+
+			qcom,chg-vddmax-mv = <4200>;
+			qcom,chg-vddsafe-mv = <4200>;
+			qcom,chg-vinmin-mv = <4200>;
+			qcom,chg-vbatdet-mv = <4100>;
+			qcom,chg-ibatmax-ma = <1500>;
+			qcom,chg-ibatterm-ma = <200>;
+			qcom,chg-ibatsafe-ma = <1500>;
+			qcom,chg-thermal-mitigation = <1500 700 600 325>;
+
+			qcom,chg-chgr@1000 {
+				status = "disabled";
+				reg = <0x1000 0x100>;
+				interrupts =	<0x0 0x10 0x0>,
+						<0x0 0x10 0x1>,
+						<0x0 0x10 0x2>,
+						<0x0 0x10 0x3>,
+						<0x0 0x10 0x4>,
+						<0x0 0x10 0x5>,
+						<0x0 0x10 0x6>,
+						<0x0 0x10 0x7>;
+
+				interrupt-names =	"vbat-det-lo",
+							"vbat-det-hi",
+							"chgwdog",
+							"state-change",
+							"trkl-chg-on",
+							"fast-chg-on",
+							"chg-failed",
+							"chg-done";
+			};
+
+			qcom,chg-buck@1100 {
+				status = "disabled";
+				reg = <0x1100 0x100>;
+				interrupts =	<0x0 0x11 0x0>,
+						<0x0 0x11 0x1>,
+						<0x0 0x11 0x2>,
+						<0x0 0x11 0x3>,
+						<0x0 0x11 0x4>,
+						<0x0 0x11 0x5>,
+						<0x0 0x11 0x6>;
+
+				interrupt-names =	"vbat-ov",
+							"vreg-ov",
+							"overtemp",
+							"vchg-loop",
+							"ichg-loop",
+							"ibat-loop",
+							"vdd-loop";
+			};
+
+			qcom,chg-bat-if@1200 {
+				status = "disabled";
+				reg = <0x1200 0x100>;
+				interrupts =	<0x0 0x12 0x0>,
+						<0x0 0x12 0x1>,
+						<0x0 0x12 0x2>,
+						<0x0 0x12 0x3>,
+						<0x0 0x12 0x4>;
+
+				interrupt-names =	"batt-pres",
+							"bat-temp-ok",
+							"bat-fet-on",
+							"vcp-on",
+							"psi";
+
+			};
+
+			qcom,chg-usb-chgpth@1300 {
+				status = "disabled";
+				reg = <0x1300 0x100>;
+				interrupts =	<0 0x13 0x0>,
+						<0 0x13 0x1>,
+						<0x0 0x13 0x2>;
+
+				interrupt-names =	"coarse-det-usb",
+							"usbin-valid",
+							"chg-gone";
+			};
+
+			qcom,chg-boost@1500 {
+				status = "disabled";
+				reg = <0x1500 0x100>;
+				interrupts =	<0x0 0x15 0x0>,
+						<0x0 0x15 0x1>;
+
+				interrupt-names =	"boost-pwr-ok",
+							"limit-error";
+			};
+
+			qcom,chg-misc@1600 {
+				status = "disabled";
+				reg = <0x1600 0x100>;
+			};
+		};
+
 		pm8226_gpios: gpios {
 			spmi-dev-container;
 			compatible = "qcom,qpnp-pin";
@@ -471,6 +601,12 @@
 			status = "disabled";
 		};
 
+		qcom,leds@d800 {
+			compatible = "qcom,leds-qpnp";
+			reg = <0xd800 0x100>;
+			label = "wled";
+		};
+
 		regulator@8000 {
 			regulator-name = "8226_lvs1";
 			reg = <0x8000 0x100>;
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 54f603d..892afbb 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -58,6 +58,28 @@
 			};
 		};
 
+		bif_ctrl: qcom,bsi@1b00 {
+			compatible = "qcom,qpnp-bsi";
+			reg = <0x1b00 0x100>,
+			      <0x1208 0x1>;
+			reg-names = "bsi-base", "batt-id-status";
+			label = "pm8941-bsi";
+			interrupts = <0x0 0x1b 0x0>,
+				     <0x0 0x1b 0x1>,
+				     <0x0 0x1b 0x2>,
+				     <0x0 0x12 0x0>;
+			interrupt-names = "err",
+					  "rx",
+					  "tx",
+					  "batt-present";
+			qcom,channel-num = <0x31>;
+			qcom,pullup-ohms = <100000>;
+			qcom,vref-microvolts = <1800000>;
+			qcom,min-clock-period = <1000>;
+			qcom,max-clock-period = <160000>;
+			qcom,sample-rate = <4>;
+		};
+
 		pm8941_bms: qcom,bms {
 			spmi-dev-container;
 			compatible = "qcom,qpnp-bms";
diff --git a/arch/arm/boot/dts/msm8226-bus.dtsi b/arch/arm/boot/dts/msm8226-bus.dtsi
index 28d0840..750e591 100644
--- a/arch/arm/boot/dts/msm8226-bus.dtsi
+++ b/arch/arm/boot/dts/msm8226-bus.dtsi
@@ -1049,6 +1049,8 @@
 			qcom,ws = <10000>;
 			qcom,mas-hw-id = <3>;
 			qcom,slv-hw-id = <2>;
+			qcom,mode = "Bypass";
+			qcom,hw-sel = "RPM";
 		};
 
 		slv-ebi-ch0 {
diff --git a/arch/arm/boot/dts/msm8226-cdp.dts b/arch/arm/boot/dts/msm8226-cdp.dts
index 1c431e8..a2707ee 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-cdp.dts
@@ -22,3 +22,142 @@
 		status = "ok";
 	};
 };
+
+&sdcc1 {
+	vdd-supply = <&pm8226_l17>;
+	qcom,vdd-always-on;
+	qcom,vdd-lpm-sup;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <800 500000>;
+
+	vdd-io-supply = <&pm8226_l6>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <250 154000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 16mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+	qcom,sup-voltages = <2950 2950>;
+
+	qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+	qcom,nonremovable;
+
+	status = "ok";
+};
+
+&sdcc2 {
+	vdd-supply = <&pm8226_l18>;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <9000 800000>;
+
+	vdd-io-supply = <&pm8226_l21>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <6 22000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 16mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+	qcom,sup-voltages = <2950 2950>;
+
+	qcom,xpc;
+	qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+	qcom,current-limit = <600>;
+
+	#address-cells = <0>;
+	interrupt-parent = <&sdcc2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+			1 &intc 0 220 0
+			2 &msmgpio 38 0x3>;
+	interrupt-names = "core_irq", "bam_irq", "status_irq";
+	cd-gpios = <&msmgpio 38 0x1>;
+
+	status = "ok";
+};
+
+&spmi_bus {
+	qcom,pm8226@1 {
+		qcom,leds@d800 {
+			status = "okay";
+			qcom,wled_0 {
+				label = "wled";
+				linux,name = "wled:backlight";
+				linux,default-trigger = "bkl-trigger";
+				qcom,cs-out-en;
+				qcom,op-fdbck;
+				qcom,default-state = "on";
+				qcom,max-current = <25>;
+				qcom,ctrl-delay-us = <0>;
+				qcom,boost-curr-lim = <3>;
+				qcom,cp-sel = <0>;
+				qcom,switch-freq = <2>;
+				qcom,ovp-val = <2>;
+				qcom,num-strings = <1>;
+				qcom,id = <0>;
+			};
+		};
+	};
+};
+
+&pm8226_gpios {
+	gpio@c000 { /* GPIO 1 */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+	};
+
+	gpio@c200 { /* GPIO 3 */
+	};
+
+	gpio@c300 { /* GPIO 4 */
+	};
+
+	gpio@c400 { /* GPIO 5 */
+	};
+
+	gpio@c500 { /* GPIO 6 */
+	};
+
+	gpio@c600 { /* GPIO 7 */
+	};
+
+	gpio@c700 { /* GPIO 8 */
+	};
+};
+
+&pm8226_mpps {
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+
+	mpp@a400 { /* MPP 5 */
+	};
+
+	mpp@a500 { /* MPP 6 */
+	};
+
+	mpp@a600 { /* MPP 7 */
+	};
+
+	mpp@a700 { /* MPP 8 */
+	};
+};
diff --git a/arch/arm/boot/dts/msm8226-coresight.dtsi b/arch/arm/boot/dts/msm8226-coresight.dtsi
new file mode 100644
index 0000000..8d5d23c
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-coresight.dtsi
@@ -0,0 +1,156 @@
+/* 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.
+ */
+
+/ {
+	tmc_etr: tmc@fc322000 {
+		compatible = "arm,coresight-tmc";
+		reg = <0xfc322000 0x1000>,
+		      <0xfc37c000 0x3000>;
+		reg-names = "tmc-etr-base", "tmc-etr-bam-base";
+
+		qcom,memory-reservation-type = "EBI1";
+		qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
+
+		coresight-id = <0>;
+		coresight-name = "coresight-tmc-etr";
+		coresight-nr-inports = <1>;
+	};
+
+	tpiu: tpiu@fc318000 {
+		compatible = "arm,coresight-tpiu";
+		reg = <0xfc318000 0x1000>;
+		reg-names = "tpiu-base";
+
+		coresight-id = <1>;
+		coresight-name = "coresight-tpiu";
+		coresight-nr-inports = <1>;
+	};
+
+	replicator: replicator@fc31c000 {
+		compatible = "qcom,coresight-replicator";
+		reg = <0xfc31c000 0x1000>;
+		reg-names = "replicator-base";
+
+		coresight-id = <2>;
+		coresight-name = "coresight-replicator";
+		coresight-nr-inports = <1>;
+		coresight-outports = <0 1>;
+		coresight-child-list = <&tmc_etr &tpiu>;
+		coresight-child-ports = <0 0>;
+	};
+
+	tmc_etf: tmc@fc307000 {
+		compatible = "arm,coresight-tmc";
+		reg = <0xfc307000 0x1000>;
+		reg-names = "tmc-etf-base";
+
+		coresight-id = <3>;
+		coresight-name = "coresight-tmc-etf";
+		coresight-nr-inports = <1>;
+		coresight-outports = <0>;
+		coresight-child-list = <&replicator>;
+		coresight-child-ports = <0>;
+		coresight-default-sink;
+	};
+
+	funnel_merg: funnel@fc31b000 {
+		compatible = "arm,coresight-funnel";
+		reg = <0xfc31b000 0x1000>;
+		reg-names = "funnel-merg-base";
+
+		coresight-id = <4>;
+		coresight-name = "coresight-funnel-merg";
+		coresight-nr-inports = <2>;
+		coresight-outports = <0>;
+		coresight-child-list = <&tmc_etf>;
+		coresight-child-ports = <0>;
+	};
+
+	funnel_in0: funnel@fc319000 {
+		compatible = "arm,coresight-funnel";
+		reg = <0xfc319000 0x1000>;
+		reg-names = "funnel-in0-base";
+
+		coresight-id = <5>;
+		coresight-name = "coresight-funnel-in0";
+		coresight-nr-inports = <8>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_merg>;
+		coresight-child-ports = <0>;
+	};
+
+	funnel_in1: funnel@fc31a000 {
+		compatible = "arm,coresight-funnel";
+		reg = <0xfc31a000 0x1000>;
+		reg-names = "funnel-in1-base";
+
+		coresight-id = <6>;
+		coresight-name = "coresight-funnel-in1";
+		coresight-nr-inports = <8>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_merg>;
+		coresight-child-ports = <1>;
+	};
+
+	funnel_a7ss: funnel@fc345000 {
+		compatible = "arm,coresight-funnel";
+		reg = <0xfc345000 0x1000>;
+		reg-names = "funnel-a7ss-base";
+
+		coresight-id = <7>;
+		coresight-name = "coresight-funnel-a7ss";
+		coresight-nr-inports = <4>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in1>;
+		coresight-child-ports = <5>;
+	};
+
+	funnel_mmss: funnel@fc364000 {
+		compatible = "arm,coresight-funnel";
+		reg = <0xfc364000 0x1000>;
+		reg-names = "funnel-mmss-base";
+
+
+		coresight-id = <8>;
+		coresight-name = "coresight-funnel-mmss";
+		coresight-nr-inports = <8>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in1>;
+		coresight-child-ports = <1>;
+	};
+
+	stm: stm@fc321000 {
+		compatible = "arm,coresight-stm";
+		reg = <0xfc321000 0x1000>,
+		      <0xfa280000 0x180000>;
+		reg-names = "stm-base", "stm-data-base";
+
+		coresight-id = <9>;
+		coresight-name = "coresight-stm";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in1>;
+		coresight-child-ports = <7>;
+	};
+
+	csr: csr@fc302000 {
+		compatible = "qcom,coresight-csr";
+		reg = <0xfc302000 0x1000>;
+		reg-names = "csr-base";
+
+		coresight-id = <10>;
+		coresight-name = "coresight-csr";
+		coresight-nr-inports = <0>;
+
+		qcom,blk-size = <3>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8226-iommu.dtsi b/arch/arm/boot/dts/msm8226-iommu.dtsi
index 51c2f38..20e1444 100644
--- a/arch/arm/boot/dts/msm8226-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8226-iommu.dtsi
@@ -15,21 +15,21 @@
 &jpeg_iommu {
 	status = "ok";
 
-	qcom,iommu-bfb-regs =  <0x604c
-				0x6050
-				0x6514
-				0x6540
-				0x656c
-				0x6314
-				0x6394
-				0x6414
-				0x60ac
-				0x615c
-				0x620c
-				0x6008
-				0x600c
-				0x6010
-				0x6014>;
+	qcom,iommu-bfb-regs =  <0x204c
+				0x2050
+				0x2514
+				0x2540
+				0x256c
+				0x2314
+				0x2394
+				0x2414
+				0x20ac
+				0x215c
+				0x220c
+				0x2008
+				0x200c
+				0x2010
+				0x2014>;
 
 	qcom,iommu-bfb-data =  <0x0000ffff
 				0x00000000
@@ -53,24 +53,24 @@
 	/* HACK: set to -1 during pre-si due to lack of TZ */
 	qcom,iommu-secure-id = <0xFFFFFFFF>;
 
-	qcom,iommu-bfb-regs =  <0x604c
-				0x6050
-				0x6514
-				0x6540
-				0x656c
-				0x60ac
-				0x615c
-				0x620c
-				0x6314
-				0x6394
-				0x6414
-				0x6008
-				0x600c
-				0x6010
-				0x6014
-				0x6018
-				0x601c
-				0x6020>;
+	qcom,iommu-bfb-regs =  <0x204c
+				0x2050
+				0x2514
+				0x2540
+				0x256c
+				0x20ac
+				0x215c
+				0x220c
+				0x2314
+				0x2394
+				0x2414
+				0x2008
+				0x200c
+				0x2010
+				0x2014
+				0x2018
+				0x201c
+				0x2020>;
 
 	qcom,iommu-bfb-data =  <0xffffffff
 				0x00000000
@@ -97,30 +97,30 @@
 	/* HACK: set to -1 during pre-si due to lack of TZ */
 	qcom,iommu-secure-id = <0xFFFFFFFF>;
 
-	qcom,iommu-bfb-regs =  <0x604c
-				0x6050
-				0x6514
-				0x6540
-				0x656c
-				0x60ac
-				0x615c
-				0x620c
-				0x6314
-				0x6394
-				0x6414
-				0x6008
-				0x600c
-				0x6010
-				0x6014
-				0x6018
-				0x601c
-				0x6020
-				0x6024
-				0x6028
-				0x602c
-				0x6030
-				0x6034
-				0x6038>;
+	qcom,iommu-bfb-regs =  <0x204c
+				0x2050
+				0x2514
+				0x2540
+				0x256c
+				0x20ac
+				0x215c
+				0x220c
+				0x2314
+				0x2394
+				0x2414
+				0x2008
+				0x200c
+				0x2010
+				0x2014
+				0x2018
+				0x201c
+				0x2020
+				0x2024
+				0x2028
+				0x202c
+				0x2030
+				0x2034
+				0x2038>;
 
 	qcom,iommu-bfb-data =  <0xffffffff
 				0xffffffff
@@ -159,18 +159,18 @@
 &kgsl_iommu {
 	status = "ok";
 
-	qcom,iommu-bfb-regs =  <0x604c
-				0x6050
-				0x6514
-				0x6540
-				0x656c
-				0x60ac
-				0x615c
-				0x620c
-				0x6314
-				0x6394
-				0x6414
-				0x6008>;
+	qcom,iommu-bfb-regs =  <0x204c
+				0x2050
+				0x2514
+				0x2540
+				0x256c
+				0x20ac
+				0x215c
+				0x220c
+				0x2314
+				0x2394
+				0x2414
+				0x2008>;
 
 	qcom,iommu-bfb-data =  <0x00000003
 				0x0
@@ -189,24 +189,24 @@
 &vfe_iommu {
 	status = "ok";
 
-	qcom,iommu-bfb-regs =  <0x604c
-				0x6050
-				0x6514
-				0x6540
-				0x656c
-				0x6314
-				0x6394
-				0x6414
-				0x60ac
-				0x615c
-				0x620c
-				0x6008
-				0x600c
-				0x6010
-				0x6014
-				0x6018
-				0x601c
-				0x6020>;
+	qcom,iommu-bfb-regs =  <0x204c
+				0x2050
+				0x2514
+				0x2540
+				0x256c
+				0x2314
+				0x2394
+				0x2414
+				0x20ac
+				0x215c
+				0x220c
+				0x2008
+				0x200c
+				0x2010
+				0x2014
+				0x2018
+				0x201c
+				0x2020>;
 
 	qcom,iommu-bfb-data =  <0xffffffff
 				0x00000000
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
new file mode 100644
index 0000000..1691743
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -0,0 +1,62 @@
+/* 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.
+ */
+
+/ {
+	qcom,mdss_mdp@fd900000 {
+		compatible = "qcom,mdss_mdp";
+		reg = <0xfd900000 0x22100>,
+			<0xfd924000 0x1000>;
+		reg-names = "mdp_phys", "vbif_phys";
+		interrupts = <0 72 0>;
+		vdd-supply = <&gdsc_mdss>;
+
+		qcom,mdss-pipe-vig-off = <0x00001200>;
+		qcom,mdss-pipe-rgb-off = <0x00001E00>;
+		qcom,mdss-pipe-dma-off = <0x00002A00>;
+		qcom,mdss-pipe-vig-fetch-id = <1>;
+		qcom,mdss-pipe-rgb-fetch-id = <7>;
+		qcom,mdss-pipe-dma-fetch-id = <4>;
+		qcom,mdss-smp-data = <7 4096>;
+
+		qcom,mdss-ctl-off = <0x00000600 0x00000700>;
+		qcom,mdss-mixer-intf-off = <0x00003200>;
+		qcom,mdss-mixer-wb-off = <0x00003E00>;
+		qcom,mdss-dspp-off = <0x00004600>;
+		qcom,mdss-wb-off = <0x00011100 0x00013100>;
+		qcom,mdss-intf-off = <0x00000000 0x00021300>;
+
+		qcom,vbif-settings = <0x004 0x00000001>,
+				     <0x0D8 0x00000707>,
+				     <0x124 0x00000003>;
+		qcom,mdp-settings = <0x02E0 0x000000A9>,
+				    <0x02E4 0x00000055>;
+
+		mdss_fb0: qcom,mdss_fb_primary {
+			cell-index = <0>;
+			compatible = "qcom,mdss-fb";
+			qcom,memory-reservation-type = "EBI1";
+			qcom,memory-reservation-size = <0x800000>;
+		};
+
+		mdss_fb1: qcom,mdss_fb_wfd {
+			cell-index = <1>;
+			compatible = "qcom,mdss-fb";
+		};
+	};
+
+	qcom,mdss_wb_panel {
+		compatible = "qcom,mdss_wb";
+		qcom,mdss_pan_res = <1280 720>;
+		qcom,mdss_pan_bpp = <24>;
+		qcom,mdss-fb-map = <&mdss_fb1>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8226-mtp.dts b/arch/arm/boot/dts/msm8226-mtp.dts
index ef0fdc0..43f6685 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-mtp.dts
@@ -22,3 +22,139 @@
 		status = "ok";
 	};
 };
+
+&sdcc1 {
+	vdd-supply = <&pm8226_l17>;
+	qcom,vdd-always-on;
+	qcom,vdd-lpm-sup;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <800 500000>;
+
+	vdd-io-supply = <&pm8226_l6>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <250 154000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 16mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+	qcom,sup-voltages = <2950 2950>;
+
+	qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+	qcom,nonremovable;
+
+	status = "ok";
+};
+
+&sdcc2 {
+	vdd-supply = <&pm8226_l18>;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <9000 800000>;
+
+	vdd-io-supply = <&pm8226_l21>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <6 22000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 16mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+	qcom,sup-voltages = <2950 2950>;
+
+	qcom,xpc;
+	qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+	qcom,current-limit = <600>; #address-cells = <0>; interrupt-parent = <&sdcc2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+			1 &intc 0 220 0
+			2 &msmgpio 38 0x3>;
+	interrupt-names = "core_irq", "bam_irq", "status_irq";
+	cd-gpios = <&msmgpio 38 0x1>;
+
+	status = "ok";
+};
+
+&spmi_bus {
+	qcom,pm8226@1 {
+		qcom,leds@d800 {
+			status = "okay";
+			qcom,wled_0 {
+				label = "wled";
+				linux,name = "wled:backlight";
+				linux,default-trigger = "bkl-trigger";
+				qcom,cs-out-en;
+				qcom,op-fdbck;
+				qcom,default-state = "on";
+				qcom,max-current = <25>;
+				qcom,ctrl-delay-us = <0>;
+				qcom,boost-curr-lim = <3>;
+				qcom,cp-sel = <0>;
+				qcom,switch-freq = <2>;
+				qcom,ovp-val = <2>;
+				qcom,num-strings = <1>;
+				qcom,id = <0>;
+			};
+		};
+	};
+};
+
+&pm8226_gpios {
+	gpio@c000 { /* GPIO 1 */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+	};
+
+	gpio@c200 { /* GPIO 3 */
+	};
+
+	gpio@c300 { /* GPIO 4 */
+	};
+
+	gpio@c400 { /* GPIO 5 */
+	};
+
+	gpio@c500 { /* GPIO 6 */
+	};
+
+	gpio@c600 { /* GPIO 7 */
+	};
+
+	gpio@c700 { /* GPIO 8 */
+	};
+};
+
+&pm8226_mpps {
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+
+	mpp@a400 { /* MPP 5 */
+	};
+
+	mpp@a500 { /* MPP 6 */
+	};
+
+	mpp@a600 { /* MPP 7 */
+	};
+
+	mpp@a700 { /* MPP 8 */
+	};
+};
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-pm.dtsi
index 4937efe..6348f5a 100644
--- a/arch/arm/boot/dts/msm8226-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-pm.dtsi
@@ -309,10 +309,12 @@
 		qcom,gic-map = <47 172>, /* usb2_hsic_async_wakeup_irq */
 			<53 104>, /* mdss_irq */
 			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+			<0xff 56>,  /* q6_wdog_expired_irq */
 			<0xff 57>,  /* mss_to_apps_irq(0) */
 			<0xff 58>,  /* mss_to_apps_irq(1) */
 			<0xff 59>,  /* mss_to_apps_irq(2) */
 			<0xff 60>,  /* mss_to_apps_irq(3) */
+			<0xff 61>,  /* mss_a2_bam_irq */
 			<0xff 173>, /* o_wcss_apss_smd_hi */
 			<0xff 174>, /* o_wcss_apss_smd_med */
 			<0xff 175>, /* o_wcss_apss_smd_low */
@@ -320,17 +322,15 @@
 			<0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
 			<0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
 			<0xff 179>, /* o_wcss_apss_asic_intr
-
+			<0xff 181>, /* o_wcss_apss_wdog_bite_and_reset_rdy */
 			<0xff 188>, /* lpass_irq_out_apcs(0) */
 			<0xff 189>, /* lpass_irq_out_apcs(1) */
 			<0xff 190>, /* lpass_irq_out_apcs(2) */
 			<0xff 191>, /* lpass_irq_out_apcs(3) */
 			<0xff 192>, /* lpass_irq_out_apcs(4) */
-			<0xff 193>, /* lpass_irq_out_apcs(5) */
-			<0xff 194>, /* lpass_irq_out_apcs(6) */
-			<0xff 195>, /* lpass_irq_out_apcs(7) */
-			<0xff 196>, /* lpass_irq_out_apcs(8) */
-			<0xff 197>, /* lpass_irq_out_apcs(9) */
+			<0xff 194>, /* lpass_irq_out_apcs[6] */
+			<0xff 195>, /* lpass_irq_out_apcs[7] */
+			<0xff 196>, /* lpass_irq_out_apcs[8] */
 			<0xff 200>, /* rpm_ipc(4) */
 			<0xff 201>, /* rpm_ipc(5) */
 			<0xff 202>, /* rpm_ipc(6) */
@@ -339,47 +339,54 @@
 			<0xff 205>, /* rpm_ipc(25) */
 			<0xff 206>, /* rpm_ipc(26) */
 			<0xff 207>, /* rpm_ipc(27) */
+			<0xff 258>, /* rpm_ipc(28) */
+			<0xff 259>, /* rpm_ipc(29) */
+			<0xff 275>, /* rpm_ipc(30) */
+			<0xff 276>, /* rpm_ipc(31) */
+			<0xff 269>, /* rpm_wdog_expired_irq */
 			<0xff 240>; /* summary_irq_kpss */
 
 		qcom,gpio-parent = <&msmgpio>;
-		qcom,gpio-map = <3  102>,
-			<4  1 >,
+		qcom,gpio-map = <3  1>,
+			<4  4 >,
 			<5  5 >,
 			<6  9 >,
-			<7  18>,
-			<8  20>,
-			<9  24>,
+			<7  13>,
+			<8  17>,
+			<9  21>,
 			<10  27>,
-			<11  28>,
-			<12  34>,
-			<13  35>,
-			<14  37>,
-			<15  42>,
-			<16  44>,
-			<17  46>,
-			<18  50>,
-			<19  54>,
-			<20  59>,
-			<21  61>,
-			<22  62>,
-			<23  64>,
-			<24  65>,
-			<25  66>,
-			<26  67>,
-			<27  68>,
-			<28  71>,
-			<29  72>,
-			<30  73>,
-			<31  74>,
-			<32  75>,
-			<33  77>,
-			<34  79>,
-			<35  80>,
-			<36  82>,
-			<37  86>,
-			<38  92>,
-			<39  93>,
-			<40  95>;
+			<11  29>,
+			<12  31>,
+			<13  33>,
+			<14  35>,
+			<15  37>,
+			<16  38>,
+			<17  39>,
+			<18  41>,
+			<19  46>,
+			<20  48>,
+			<21  49>,
+			<22  50>,
+			<23  51>,
+			<24  52>,
+			<25  54>,
+			<26  62>,
+			<27  63>,
+			<28  64>,
+			<29  65>,
+			<30  66>,
+			<31  67>,
+			<32  68>,
+			<33  69>,
+			<34  71>,
+			<35  72>,
+			<36  106>,
+			<37  107>,
+			<38  108>,
+			<39  109>,
+			<40  110>,
+			<54  111>,
+			<55  113>;
 	};
 
 	qcom,pm-8x60@fe805664 {
diff --git a/arch/arm/boot/dts/msm8226-qrd.dts b/arch/arm/boot/dts/msm8226-qrd.dts
index 7909435..482a5da 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-qrd.dts
@@ -22,3 +22,142 @@
 		status = "ok";
 	};
 };
+
+&sdcc1 {
+	vdd-supply = <&pm8226_l17>;
+	qcom,vdd-always-on;
+	qcom,vdd-lpm-sup;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <800 500000>;
+
+	vdd-io-supply = <&pm8226_l6>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <250 154000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 16mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+	qcom,sup-voltages = <2950 2950>;
+
+	qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+	qcom,nonremovable;
+
+	status = "ok";
+};
+
+&sdcc2 {
+	vdd-supply = <&pm8226_l18>;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <9000 800000>;
+
+	vdd-io-supply = <&pm8226_l21>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <6 22000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 16mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+	qcom,sup-voltages = <2950 2950>;
+
+	qcom,xpc;
+	qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+	qcom,current-limit = <600>;
+
+	#address-cells = <0>;
+	interrupt-parent = <&sdcc2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+			1 &intc 0 220 0
+			2 &msmgpio 38 0x3>;
+	interrupt-names = "core_irq", "bam_irq", "status_irq";
+	cd-gpios = <&msmgpio 38 0x1>;
+
+	status = "ok";
+};
+
+&spmi_bus {
+	qcom,pm8226@1 {
+		qcom,leds@d800 {
+			status = "okay";
+			qcom,wled_0 {
+				label = "wled";
+				linux,name = "wled:backlight";
+				linux,default-trigger = "bkl-trigger";
+				qcom,cs-out-en;
+				qcom,op-fdbck;
+				qcom,default-state = "on";
+				qcom,max-current = <25>;
+				qcom,ctrl-delay-us = <0>;
+				qcom,boost-curr-lim = <3>;
+				qcom,cp-sel = <0>;
+				qcom,switch-freq = <2>;
+				qcom,ovp-val = <2>;
+				qcom,num-strings = <1>;
+				qcom,id = <0>;
+			};
+		};
+	};
+};
+
+&pm8226_gpios {
+	gpio@c000 { /* GPIO 1 */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+	};
+
+	gpio@c200 { /* GPIO 3 */
+	};
+
+	gpio@c300 { /* GPIO 4 */
+	};
+
+	gpio@c400 { /* GPIO 5 */
+	};
+
+	gpio@c500 { /* GPIO 6 */
+	};
+
+	gpio@c600 { /* GPIO 7 */
+	};
+
+	gpio@c700 { /* GPIO 8 */
+	};
+};
+
+&pm8226_mpps {
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+
+	mpp@a400 { /* MPP 5 */
+	};
+
+	mpp@a500 { /* MPP 6 */
+	};
+
+	mpp@a600 { /* MPP 7 */
+	};
+
+	mpp@a700 { /* MPP 8 */
+	};
+};
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 3533d19..8111b40 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -18,6 +18,8 @@
 /include/ "msm8226-smp2p.dtsi"
 /include/ "msm8226-gpu.dtsi"
 /include/ "msm8226-bus.dtsi"
+/include/ "msm8226-mdss.dtsi"
+/include/ "msm8226-coresight.dtsi"
 
 / {
 	model = "Qualcomm MSM 8226";
@@ -85,14 +87,23 @@
 		reg = <0xf9a55000 0x400>;
 		interrupts = <0 134 0>, <0 140 0>;
 		interrupt-names = "core_irq", "async_irq";
-		HSUSB_VDDCX-supply = <&pm8226_s1>;
+		hsusb_vdd_dig-supply = <&pm8226_s1_corner>;
 		HSUSB_1p8-supply = <&pm8226_l10>;
 		HSUSB_3p3-supply = <&pm8226_l20>;
+		qcom,vdd-voltage-level = <1 5 7>;
 
 		qcom,hsusb-otg-phy-type = <2>;
 		qcom,hsusb-otg-mode = <1>;
-		qcom,hsusb-otg-otg-control = <1>;
+		qcom,hsusb-otg-otg-control = <2>;
 		qcom,hsusb-otg-disable-reset;
+
+		qcom,msm-bus,name = "usb2";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,active-only = <0>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<87 512 0 0>,
+				<87 512 60000 960000>;
 	};
 
 	android_usb@fe8050c8 {
@@ -337,7 +348,7 @@
 	qcom,smem@fa00000 {
 		compatible = "qcom,smem";
 		reg = <0xfa00000 0x200000>,
-			<0xfa006000 0x1000>,
+			<0xf9011000 0x1000>,
 			<0xfc428000 0x4000>;
 		reg-names = "smem", "irq-reg-base", "aux-mem1";
 
@@ -541,8 +552,8 @@
 		      <0xfc4b8000 0x1000>;
 		reg-names = "tsens_physical", "tsens_eeprom_physical";
 		interrupts = <0 184 0>;
-		qcom,sensors = <6>;
-		qcom,slope = <3200 3200 3200 3200 3200 3200>;
+		qcom,sensors = <4>;
+		qcom,slope = <2901 2846 3038 2955>;
 		qcom,calib-mode = "fuse_map2";
 	};
 
@@ -578,6 +589,17 @@
 		qcom,bam-producer-pipe-index = <13>;
 	};
 
+	qcom,bam_dmux@fc834000 {
+		compatible = "qcom,bam_dmux";
+		reg = <0xfc834000 0x7000>;
+		interrupts = <0 29 1>;
+	};
+
+	qcom,msm-rtb {
+		compatible = "qcom,msm-rtb";
+		qcom,memory-reservation-type = "EBI1";
+		qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
+	};
 };
 
 &gdsc_venus {
@@ -695,4 +717,32 @@
 		qcom,hw-settle-time = <2>;
 		qcom,fast-avg-setup = <0>;
 	};
+
+};
+
+&pm8226_chg {
+	status = "ok";
+
+	qcom,chg-charging-disabled;
+	qcom,chg-use-default-batt-values;
+
+	qcom,chg-chgr@1000 {
+		status = "ok";
+	};
+
+	qcom,chg-buck@1100 {
+		status = "ok";
+	};
+
+	qcom,chg-usb-chgpth@1300 {
+		status = "ok";
+	};
+
+	qcom,chg-boost@1500 {
+		status = "ok";
+	};
+
+	qcom,chg-misc@1600 {
+		status = "ok";
+	};
 };
diff --git a/arch/arm/boot/dts/msm8610-ion.dtsi b/arch/arm/boot/dts/msm8610-ion.dtsi
index 0abaca5..107961d 100644
--- a/arch/arm/boot/dts/msm8610-ion.dtsi
+++ b/arch/arm/boot/dts/msm8610-ion.dtsi
@@ -20,14 +20,6 @@
 			reg = <30>;
 		};
 
-		qcom,ion-heap@8 { /* CP_MM HEAP */
-			compatible = "qcom,msm-ion-reserve";
-			reg = <8>;
-			qcom,heap-align = <0x1000>;
-			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
-			qcom,memory-reservation-size = <0x3800000>;
-		};
-
 		qcom,ion-heap@25 { /* IOMMU HEAP */
 			reg = <25>;
 		};
@@ -37,7 +29,7 @@
 			reg = <27>;
 			qcom,heap-align = <0x1000>;
 			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
-			qcom,memory-reservation-size = <0x780000>;
+			qcom,memory-reservation-size = <0x100000>;
 		};
 
 		qcom,ion-heap@28 { /* AUDIO HEAP */
@@ -47,16 +39,6 @@
 			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
 			qcom,memory-reservation-size = <0x314000>;
 		};
-
-		qcom,ion-heap@29 { /* FIRMWARE HEAP */
-			compatible = "qcom,msm-ion-reserve";
-			reg = <29>;
-			qcom,heap-align = <0x20000>;
-			qcom,heap-adjacent = <8>;
-			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
-			qcom,memory-reservation-size = <0xA00000>;
-		};
-
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index ce6011b..2dff4c7 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -166,7 +166,7 @@
 	qcom,smem@d600000 {
 		compatible = "qcom,smem";
 		reg = <0xd600000 0x200000>,
-			<0xfa006000 0x1000>,
+			<0xf9011000 0x1000>,
 			<0xfc428000 0x4000>;
 		reg-names = "smem", "irq-reg-base", "aux-mem1";
 
diff --git a/arch/arm/boot/dts/msm8974-bus.dtsi b/arch/arm/boot/dts/msm8974-bus.dtsi
index ba4a14e8..8f58c3e 100644
--- a/arch/arm/boot/dts/msm8974-bus.dtsi
+++ b/arch/arm/boot/dts/msm8974-bus.dtsi
@@ -1217,6 +1217,8 @@
 			qcom,ws = <10000>;
 			qcom,mas-hw-id = <3>;
 			qcom,slv-hw-id = <2>;
+			qcom,mode = "Bypass";
+			qcom,hw-sel = "RPM";
 		};
 
 		slv-ebi-ch0 {
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index ea99aa3..ebb3912 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -159,8 +159,9 @@
 		cell-index = <0>;
 		compatible = "qcom,cpp";
 		reg = <0xfda04000 0x100>,
-		      <0xfda40000 0x200>;
-		reg-names = "cpp", "cpp_vbif";
+		      <0xfda40000 0x200>,
+		      <0xfda18000 0x008>;
+		reg-names = "cpp", "cpp_vbif", "cpp_hw";
 		interrupts = <0 49 0>;
 		interrupt-names = "cpp";
 		vdd-supply = <&gdsc_vfe>;
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 0acfaf6..ad26061 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -294,8 +294,49 @@
 	wp-gpios = <&pm8941_gpios 29 0x1>;
 };
 
+&sdhc_1 {
+	vdd-supply = <&pm8941_l20>;
+	vdd-io-supply = <&pm8941_s3>;
+
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <800 500000>;
+
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <250 154000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+	qcom,nonremovable;
+};
+
+&sdhc_2 {
+	vdd-supply = <&pm8941_l21>;
+	vdd-io-supply = <&pm8941_l13>;
+
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <9000 800000>;
+
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <6 22000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+};
+
 &uart7 {
 	status = "ok";
+	qcom,tx-gpio = <&msmgpio 41 0x00>;
+	qcom,rx-gpio = <&msmgpio 42 0x00>;
+	qcom,cts-gpio = <&msmgpio 43 0x00>;
+	qcom,rfr-gpio = <&msmgpio 44 0x00>;
 };
 
 &usb3 {
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index 92a6e01..dbb8958 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -291,6 +291,43 @@
 	cd-gpios = <&msmgpio 62 0x1>;
 };
 
+&sdhc_1 {
+	vdd-supply = <&pm8941_l20>;
+	vdd-io-supply = <&pm8941_s3>;
+
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <800 500000>;
+
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <250 154000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+	qcom,nonremovable;
+};
+
+&sdhc_2 {
+	vdd-supply = <&pm8941_l21>;
+	vdd-io-supply = <&pm8941_l13>;
+
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <9000 800000>;
+
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <6 22000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+};
+
 &usb3 {
 	qcom,otg-capability;
 };
diff --git a/arch/arm/boot/dts/msm8974-ion.dtsi b/arch/arm/boot/dts/msm8974-ion.dtsi
index f55cff2..dfa22c1 100644
--- a/arch/arm/boot/dts/msm8974-ion.dtsi
+++ b/arch/arm/boot/dts/msm8974-ion.dtsi
@@ -24,8 +24,7 @@
 			compatible = "qcom,msm-ion-reserve";
 			reg = <8>;
 			qcom,heap-align = <0x1000>;
-			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
-			qcom,memory-reservation-size = <0x7800000>;
+			linux,contiguous-region = <&secure_mem>;
 		};
 
 		qcom,ion-heap@25 { /* IOMMU HEAP */
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 68fed68..4dd92b98 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -380,7 +380,7 @@
 };
 
 &usb3 {
-	qcom,charging-disabled;
+	qcom,otg-capability;
 };
 
 &pm8941_mvs1 {
@@ -708,3 +708,70 @@
 		};
 	};
 };
+
+&pm8941_chg {
+	status = "ok";
+
+	qcom,chg-charging-disabled;
+
+	qcom,chg-chgr@1000 {
+		status = "ok";
+	};
+
+	qcom,chg-buck@1100 {
+		status = "ok";
+	};
+
+	qcom,chg-usb-chgpth@1300 {
+		status = "ok";
+	};
+
+	qcom,chg-dc-chgpth@1400 {
+		status = "ok";
+	};
+
+	qcom,chg-boost@1500 {
+		status = "ok";
+	};
+
+	qcom,chg-misc@1600 {
+		status = "ok";
+	};
+};
+
+&sdhc_1 {
+	vdd-supply = <&pm8941_l20>;
+	vdd-io-supply = <&pm8941_s3>;
+
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <800 500000>;
+
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <250 154000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+	qcom,nonremovable;
+};
+
+&sdhc_2 {
+	vdd-supply = <&pm8941_l21>;
+	vdd-io-supply = <&pm8941_l13>;
+
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <9000 800000>;
+
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <6 22000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+};
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index 0b95419..f382c3e 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -27,6 +27,7 @@
 		qcom,mdss-pipe-vig-fetch-id = <1 4 7>;
 		qcom,mdss-pipe-rgb-fetch-id = <16 17 18>;
 		qcom,mdss-pipe-dma-fetch-id = <10 13>;
+		qcom,mdss-smp-data = <22 4096>;
 
 		qcom,mdss-ctl-off = <0x00000600 0x00000700 0x00000800
 				     0x00000900 0x0000A00>;
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index c6935f4..d3d53dd 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -262,6 +262,43 @@
 	cd-gpios = <&msmgpio 62 0x1>;
 };
 
+&sdhc_1 {
+	vdd-supply = <&pm8941_l20>;
+	vdd-io-supply = <&pm8941_s3>;
+
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <800 500000>;
+
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <250 154000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+	qcom,nonremovable;
+};
+
+&sdhc_2 {
+	vdd-supply = <&pm8941_l21>;
+	vdd-io-supply = <&pm8941_l13>;
+
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <9000 800000>;
+
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <6 22000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+};
+
 &usb_otg {
 	qcom,hsusb-otg-otg-control = <2>;
 };
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index 1a6d9ba..5eff79c 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -423,68 +423,77 @@
 };
 
 / {
-	krait0_vreg: regulator@f9088000 {
-		compatible = "qcom,krait-regulator";
-		regulator-name = "krait0";
-		reg = <0xf9088000 0x1000>, /* APCS_ALIAS0_KPSS_ACS */
-			<0xf908a800 0x1000>; /* APCS_ALIAS0_KPSS_MDD */
-		reg-names = "acs", "mdd";
-		regulator-min-microvolt = <500000>;
-		regulator-max-microvolt = <1100000>;
-		qcom,headroom-voltage = <150000>;
-		qcom,retention-voltage = <675000>;
-		qcom,ldo-default-voltage = <750000>;
-		qcom,ldo-threshold-voltage = <850000>;
-		qcom,ldo-delta-voltage = <50000>;
-		qcom,cpu-num = <0>;
-	};
+	krait_pdn: krait-pdn@f9011000 {
+		reg = <0xf9011000 0x1000>;
+		reg-names = "apcs_gcc";
+		compatible = "qcom,krait-pdn";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
 
-	krait1_vreg: regulator@f9098000 {
-		compatible = "qcom,krait-regulator";
-		regulator-name = "krait1";
-		reg = <0xf9098000 0x1000>, /* APCS_ALIAS1_KPSS_ACS */
-			<0xf909a800 0x1000>; /* APCS_ALIAS1_KPSS_MDD */
-		reg-names = "acs", "mdd";
-		regulator-min-microvolt = <500000>;
-		regulator-max-microvolt = <1100000>;
-		qcom,headroom-voltage = <150000>;
-		qcom,retention-voltage = <675000>;
-		qcom,ldo-default-voltage = <750000>;
-		qcom,ldo-threshold-voltage = <850000>;
-		qcom,ldo-delta-voltage = <50000>;
-		qcom,cpu-num = <1>;
-	};
+		krait0_vreg: regulator@f9088000 {
+			compatible = "qcom,krait-regulator";
+			regulator-name = "krait0";
+			reg = <0xf9088000 0x1000>, /* APCS_ALIAS0_KPSS_ACS */
+				<0xf908a800 0x1000>; /* APCS_ALIAS0_KPSS_MDD */
+			reg-names = "acs", "mdd";
+			regulator-min-microvolt = <500000>;
+			regulator-max-microvolt = <1100000>;
+			qcom,headroom-voltage = <150000>;
+			qcom,retention-voltage = <675000>;
+			qcom,ldo-default-voltage = <750000>;
+			qcom,ldo-threshold-voltage = <850000>;
+			qcom,ldo-delta-voltage = <50000>;
+			qcom,cpu-num = <0>;
+		};
 
-	krait2_vreg: regulator@f90a8000 {
-		compatible = "qcom,krait-regulator";
-		regulator-name = "krait2";
-		reg = <0xf90a8000 0x1000>, /* APCS_ALIAS2_KPSS_ACS */
-			<0xf90aa800 0x1000>; /* APCS_ALIAS2_KPSS_MDD */
-		reg-names = "acs", "mdd";
-		regulator-min-microvolt = <500000>;
-		regulator-max-microvolt = <1100000>;
-		qcom,headroom-voltage = <150000>;
-		qcom,retention-voltage = <675000>;
-		qcom,ldo-default-voltage = <750000>;
-		qcom,ldo-threshold-voltage = <850000>;
-		qcom,ldo-delta-voltage = <50000>;
-		qcom,cpu-num = <2>;
-	};
+		krait1_vreg: regulator@f9098000 {
+			compatible = "qcom,krait-regulator";
+			regulator-name = "krait1";
+			reg = <0xf9098000 0x1000>, /* APCS_ALIAS1_KPSS_ACS */
+				<0xf909a800 0x1000>; /* APCS_ALIAS1_KPSS_MDD */
+			reg-names = "acs", "mdd";
+			regulator-min-microvolt = <500000>;
+			regulator-max-microvolt = <1100000>;
+			qcom,headroom-voltage = <150000>;
+			qcom,retention-voltage = <675000>;
+			qcom,ldo-default-voltage = <750000>;
+			qcom,ldo-threshold-voltage = <850000>;
+			qcom,ldo-delta-voltage = <50000>;
+			qcom,cpu-num = <1>;
+		};
 
-	krait3_vreg: regulator@f90b8000 {
-		compatible = "qcom,krait-regulator";
-		regulator-name = "krait3";
-		reg = <0xf90b8000 0x1000>, /* APCS_ALIAS3_KPSS_ACS */
-			<0xf90ba800 0x1000>; /* APCS_ALIAS3_KPSS_MDD */
-		reg-names = "acs", "mdd";
-		regulator-min-microvolt = <500000>;
-		regulator-max-microvolt = <1100000>;
-		qcom,headroom-voltage = <150000>;
-		qcom,retention-voltage = <675000>;
-		qcom,ldo-default-voltage = <750000>;
-		qcom,ldo-threshold-voltage = <850000>;
-		qcom,ldo-delta-voltage = <50000>;
-		qcom,cpu-num = <3>;
+		krait2_vreg: regulator@f90a8000 {
+			compatible = "qcom,krait-regulator";
+			regulator-name = "krait2";
+			reg = <0xf90a8000 0x1000>, /* APCS_ALIAS2_KPSS_ACS */
+				<0xf90aa800 0x1000>; /* APCS_ALIAS2_KPSS_MDD */
+			reg-names = "acs", "mdd";
+			regulator-min-microvolt = <500000>;
+			regulator-max-microvolt = <1100000>;
+			qcom,headroom-voltage = <150000>;
+			qcom,retention-voltage = <675000>;
+			qcom,ldo-default-voltage = <750000>;
+			qcom,ldo-threshold-voltage = <850000>;
+			qcom,ldo-delta-voltage = <50000>;
+			qcom,cpu-num = <2>;
+		};
+
+		krait3_vreg: regulator@f90b8000 {
+			compatible = "qcom,krait-regulator";
+			regulator-name = "krait3";
+			reg = <0xf90b8000 0x1000>, /* APCS_ALIAS3_KPSS_ACS */
+				<0xf90ba800 0x1000>; /* APCS_ALIAS3_KPSS_MDD */
+			reg-names = "acs", "mdd";
+			regulator-min-microvolt = <500000>;
+			regulator-max-microvolt = <1100000>;
+			qcom,headroom-voltage = <150000>;
+			qcom,retention-voltage = <675000>;
+			qcom,ldo-default-voltage = <750000>;
+			qcom,ldo-threshold-voltage = <850000>;
+			qcom,ldo-delta-voltage = <50000>;
+			qcom,cpu-num = <3>;
+		};
 	};
 
 	spi_eth_vreg: spi_eth_phy_vreg {
diff --git a/arch/arm/boot/dts/msm8974-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
similarity index 100%
rename from arch/arm/boot/dts/msm8974-pm.dtsi
rename to arch/arm/boot/dts/msm8974-v1-pm.dtsi
diff --git a/arch/arm/boot/dts/msm8974-v1.dtsi b/arch/arm/boot/dts/msm8974-v1.dtsi
index aed4daf..bccf0fe 100644
--- a/arch/arm/boot/dts/msm8974-v1.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1.dtsi
@@ -19,6 +19,7 @@
 /include/ "msm8974.dtsi"
 /include/ "msm8974-v1-iommu.dtsi"
 /include/ "msm8974-v1-iommu-domains.dtsi"
+/include/ "msm8974-v1-pm.dtsi"
 
 / {
 	android_usb@fc42b0c8 {
@@ -110,4 +111,16 @@
 		<1010000 1818000>,
 		<1616000 2908800>,
 		<2020000 6400000>;
+	qcom,iommu-groups = <&venus_domain_ns &venus_domain_cp>;
+	qcom,iommu-group-buffer-types = <0xfff 0x1ff>;
+	qcom,buffer-type-tz-usage-table = <0x1 0x1>,
+					<0x1fe 0x2>;
+};
+
+&sfpb_spinlock {
+	status = "disable";
+};
+
+&ldrex_spinlock {
+	status = "ok";
 };
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
new file mode 100644
index 0000000..4d98a1d
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -0,0 +1,426 @@
+/* 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/ "skeleton.dtsi"
+
+/ {
+	qcom,spm@f9089000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf9089000 0x1000>;
+		qcom,core-id = <0>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x3C102800>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
+				E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+		qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
+				E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+	};
+
+	qcom,spm@f9099000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf9099000 0x1000>;
+		qcom,core-id = <1>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x3C102800>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
+				E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+		qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
+				E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+	};
+
+	qcom,spm@f90a9000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf90a9000 0x1000>;
+		qcom,core-id = <2>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x3C102800>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
+				E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+		qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
+				E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+	};
+
+	qcom,spm@f90b9000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf90b9000 0x1000>;
+		qcom,core-id = <3>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x3C102800>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
+				E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+		qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
+				E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+	};
+
+	qcom,spm@f9012000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf9012000 0x1000>;
+		qcom,core-id = <0xffff>; /* L2/APCS SAW */
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x14>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x3C102800>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-pmic-data0 = <0x02030080>;
+		qcom,saw2-pmic-data1 = <0x00030000>;
+		qcom,vctl-timeout-us = <50>;
+		qcom,vctl-port = <0x0>;
+		qcom,phase-port = <0x1>;
+		qcom,pfm-port = <0x2>;
+		qcom,saw2-spm-cmd-ret = [1f 00 20 03 22 00 0f];
+		qcom,saw2-spm-cmd-gdhs = [00 20 32 60 70 80 42 07 78 80 44 22 50
+				3b 60 02 32 50 0f];
+		qcom,saw2-spm-cmd-pc = [00 10 32 60 70 80 b0 11 42 07 01 b0 78
+				80 12 44 50 3b 60 02 32 50 0f];
+	};
+
+	qcom,lpm-resources {
+		compatible = "qcom,lpm-resources";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,lpm-resources@0 {
+			reg = <0x0>;
+			qcom,name = "vdd-dig";
+			qcom,resource-type = <0>;
+			qcom,type = <0x62706d73>;	/* "smpb" */
+			qcom,id = <0x02>;
+			qcom,key = <0x6e726f63>;	/* "corn" */
+			qcom,init-value = <5>;		/* Super Turbo */
+		};
+
+		qcom,lpm-resources@1 {
+			reg = <0x1>;
+			qcom,name = "vdd-mem";
+			qcom,resource-type = <0>;
+			qcom,type = <0x62706d73>;	/* "smpb" */
+			qcom,id = <0x01>;
+			qcom,key = <0x7675>;		/* "uv" */
+			qcom,init-value = <1050000>;	/* Super Turbo */
+		};
+
+		qcom,lpm-resources@2 {
+			reg = <0x2>;
+			qcom,name = "pxo";
+			qcom,resource-type = <0>;
+			qcom,type = <0x306b6c63>;	/* "clk0" */
+			qcom,id = <0x00>;
+			qcom,key = <0x62616e45>;	/* "Enab" */
+			qcom,init-value = <1>;		/* On */
+		};
+
+		qcom,lpm-resources@3 {
+			reg = <0x3>;
+			qcom,name = "l2";
+			qcom,resource-type = <1>;
+			qcom,init-value = <2>;		/* Retention */
+		};
+	};
+
+	qcom,lpm-levels {
+		compatible = "qcom,lpm-levels";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,lpm-level@0 {
+			reg = <0x0>;
+			qcom,mode = <0>;        /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
+			qcom,xo = <1>;          /* ON */
+			qcom,l2 = <2>;          /* Retention */
+			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
+			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
+			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
+			qcom,irqs-detectable;
+			qcom.gpios-detectable;
+			qcom,latency-us = <1>;
+			qcom,ss-power = <784>;
+			qcom,energy-overhead = <190000>;
+			qcom,time-overhead = <100>;
+		};
+
+		qcom,lpm-level@1 {
+			reg = <0x1>;
+			qcom,mode = <4>;        /* MSM_PM_SLEEP_MODE_RETENTION*/
+			qcom,xo = <1>;          /* ON */
+			qcom,l2 = <2>;          /* Retention */
+			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
+			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
+			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
+			qcom,irqs-detectable;
+			qcom.gpios-detectable;
+			qcom,latency-us = <75>;
+			qcom,ss-power = <735>;
+			qcom,energy-overhead = <77341>;
+			qcom,time-overhead = <105>;
+		};
+
+		qcom,lpm-level@2 {
+			reg = <0x2>;
+			qcom,mode = <2>;        /* MSM_PM_SLEEP_MODE_STANDALONE_POWER_COLLAPSE */
+			qcom,xo = <1>;          /* ON */
+			qcom,l2 = <2>;          /* Retention */
+			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
+			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
+			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
+			qcom,irqs-detectable;
+			qcom.gpios-detectable;
+			qcom,latency-us = <95>;
+			qcom,ss-power = <725>;
+			qcom,energy-overhead = <99500>;
+			qcom,time-overhead = <130>;
+		};
+
+		qcom,lpm-level@3 {
+			reg = <0x3>;
+			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+			qcom,xo = <1>;          /* ON */
+			qcom,l2 = <1>;          /* GDHS */
+			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
+			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
+			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
+			qcom,irqs-detectable;
+			qcom.gpios-detectable;
+			qcom,latency-us = <2000>;
+			qcom,ss-power = <138>;
+			qcom,energy-overhead = <1208400>;
+			qcom,time-overhead = <3200>;
+		};
+
+		qcom,lpm-level@4 {
+			reg = <0x4>;
+			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+			qcom,xo = <1>;          /* ON */
+			qcom,l2 = <1>;          /* GDHS */
+			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
+			qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
+			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO  */
+			qcom,vdd-dig-lower-bound = <3>;  /* SVS SOC */
+			qcom,irqs-detectable;
+			qcom.gpios-detectable;
+			qcom,latency-us = <3000>;
+			qcom,ss-power = <110>;
+			qcom,energy-overhead = <1250300>;
+			qcom,time-overhead = <3500>;
+		};
+
+		qcom,lpm-level@5 {
+			reg = <0x5>;
+			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+			qcom,xo = <0>;          /* OFF */
+			qcom,l2 = <1>;          /* GDHS */
+			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
+			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
+			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
+			qcom,latency-us = <3000>;
+			qcom,ss-power = <68>;
+			qcom,energy-overhead = <1350200>;
+			qcom,time-overhead = <4000>;
+		};
+
+		qcom,lpm-level@6 {
+			reg = <0x6>;
+			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+			qcom,xo = <0>;          /* OFF */
+			qcom,l2 = <1>;          /* GDHS */
+			qcom,vdd-mem-upper-bound = <950000>; /* NORMAL */
+			qcom,vdd-mem-lower-bound = <950000>;  /* SVS SOC */
+			qcom,vdd-dig-upper-bound = <4>;  /* NORMAL */
+			qcom,vdd-dig-lower-bound = <3>;  /* SVS SOC */
+			qcom,latency-us = <18000>;
+			qcom,ss-power = <10>;
+			qcom,energy-overhead = <3202600>;
+			qcom,time-overhead = <27000>;
+		};
+
+		qcom,lpm-level@7 {
+			reg = <0x7>;
+			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+			qcom,xo = <0>;          /* OFF */
+			qcom,l2 = <0>;          /* OFF */
+			qcom,vdd-mem-upper-bound = <950000>; /* SVS SOC */
+			qcom,vdd-mem-lower-bound = <675000>; /* RETENTION */
+			qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
+			qcom,vdd-dig-lower-bound = <1>; /* RETENTION */
+			qcom,latency-us = <20000>;
+			qcom,ss-power = <2>;
+			qcom,energy-overhead = <4252000>;
+			qcom,time-overhead = <32000>;
+		};
+	};
+
+	qcom,pm-boot {
+		compatible = "qcom,pm-boot";
+		qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
+	};
+
+	qcom,mpm@fc4281d0 {
+		compatible = "qcom,mpm-v2";
+		reg = <0xfc4281d0 0x1000>, /* MSM_RPM_MPM_BASE 4K */
+		    <0xf9011008 0x4>;   /* MSM_APCS_GCC_BASE 4K */
+		reg-names = "vmpm", "ipc";
+		interrupts = <0 171 1>;
+
+		qcom,ipc-bit-offset = <1>;
+
+		qcom,gic-parent = <&intc>;
+		qcom,gic-map = <47 172>, /* usb2_hsic_async_wakeup_irq */
+			<53 104>, /* mdss_irq */
+			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+			<0xff 57>,  /* mss_to_apps_irq(0) */
+			<0xff 58>,  /* mss_to_apps_irq(1) */
+			<0xff 59>,  /* mss_to_apps_irq(2) */
+			<0xff 60>,  /* mss_to_apps_irq(3) */
+			<0xff 173>, /* o_wcss_apss_smd_hi */
+			<0xff 174>, /* o_wcss_apss_smd_med */
+			<0xff 175>, /* o_wcss_apss_smd_low */
+			<0xff 176>, /* o_wcss_apss_smsm_irq */
+			<0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
+			<0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
+			<0xff 179>, /* o_wcss_apss_asic_intr
+
+			<0xff 188>, /* lpass_irq_out_apcs(0) */
+			<0xff 189>, /* lpass_irq_out_apcs(1) */
+			<0xff 190>, /* lpass_irq_out_apcs(2) */
+			<0xff 191>, /* lpass_irq_out_apcs(3) */
+			<0xff 192>, /* lpass_irq_out_apcs(4) */
+			<0xff 193>, /* lpass_irq_out_apcs(5) */
+			<0xff 194>, /* lpass_irq_out_apcs(6) */
+			<0xff 195>, /* lpass_irq_out_apcs(7) */
+			<0xff 196>, /* lpass_irq_out_apcs(8) */
+			<0xff 197>, /* lpass_irq_out_apcs(9) */
+			<0xff 200>, /* rpm_ipc(4) */
+			<0xff 201>, /* rpm_ipc(5) */
+			<0xff 202>, /* rpm_ipc(6) */
+			<0xff 203>, /* rpm_ipc(7) */
+			<0xff 204>, /* rpm_ipc(24) */
+			<0xff 205>, /* rpm_ipc(25) */
+			<0xff 206>, /* rpm_ipc(26) */
+			<0xff 207>, /* rpm_ipc(27) */
+			<0xff 240>; /* summary_irq_kpss */
+
+		qcom,gpio-parent = <&msmgpio>;
+		qcom,gpio-map = <3  102>,
+			<4  1 >,
+			<5  5 >,
+			<6  9 >,
+			<7  18>,
+			<8  20>,
+			<9  24>,
+			<10  27>,
+			<11  28>,
+			<12  34>,
+			<13  35>,
+			<14  37>,
+			<15  42>,
+			<16  44>,
+			<17  46>,
+			<18  50>,
+			<19  54>,
+			<20  59>,
+			<21  61>,
+			<22  62>,
+			<23  64>,
+			<24  65>,
+			<25  66>,
+			<26  67>,
+			<27  68>,
+			<28  71>,
+			<29  72>,
+			<30  73>,
+			<31  74>,
+			<32  75>,
+			<33  77>,
+			<34  79>,
+			<35  80>,
+			<36  82>,
+			<37  86>,
+			<38  92>,
+			<39  93>,
+			<40  95>;
+	};
+
+	qcom,pm-8x60@fe805664 {
+		compatible = "qcom,pm-8x60";
+		reg = <0xfe805664 0x40>;
+		qcom,pc-mode = <0>; /*MSM_PC_TZ_L2_INT */
+		qcom,use-sync-timer;
+		qcom,saw-turns-off-pll;
+	};
+
+	qcom,rpm-log@fc19dc00 {
+		compatible = "qcom,rpm-log";
+		reg = <0xfc19dc00 0x4000>;
+		qcom,rpm-addr-phys = <0xfc000000>;
+		qcom,offset-version = <4>;
+		qcom,offset-page-buffer-addr = <36>;
+		qcom,offset-log-len = <40>;
+		qcom,offset-log-len-mask = <44>;
+		qcom,offset-page-indices = <56>;
+	};
+
+	qcom,rpm-stats@0xfc19dbd0{
+		compatible = "qcom,rpm-stats";
+		reg = <0xfc19dbd0 0x1000>;
+		reg-names = "phys_addr_base";
+		qcom,sleep-stats-version = <2>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 1a7c628..16cdeb1 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -19,6 +19,7 @@
 /include/ "msm8974.dtsi"
 /include/ "msm8974-v2-iommu.dtsi"
 /include/ "msm8974-v2-iommu-domains.dtsi"
+/include/ "msm8974-v2-pm.dtsi"
 
 / {
 	android_usb@fe8050c8 {
@@ -110,4 +111,14 @@
 		<1620000 970000>,
 		<2024000 1212000>,
 		<2132000 1279000>;
+	qcom,iommu-groups = <&venus_domain_ns &venus_domain_sec_bitstream
+			&venus_domain_sec_pixel &venus_domain_sec_non_pixel>;
+	qcom,iommu-group-buffer-types = <0xfff 0x91 0x42 0x120>;
+	qcom,buffer-type-tz-usage-table = <0x91 0x1>,
+					<0x42 0x2>,
+					<0x120 0x3>;
+};
+
+&krait_pdn {
+	qcom,use-phase-switching;
 };
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index b0b7677..ab6b7c8 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -11,7 +11,6 @@
  */
 
 /include/ "skeleton.dtsi"
-/include/ "msm8974-pm.dtsi"
 /include/ "msm8974-camera.dtsi"
 /include/ "msm8974-coresight.dtsi"
 /include/ "msm-gdsc.dtsi"
@@ -29,6 +28,19 @@
 	aliases {
 		spi0 = &spi_0;
 		spi7 = &spi_7;
+		sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
+		sdhc2 = &sdhc_2; /* SDC2 SD card slot */
+		sdhc3 = &sdhc_3; /* SDC3 SDIO slot */
+		sdhc4 = &sdhc_4; /* SDC4 SDIO slot */
+	};
+
+	memory {
+
+		secure_mem: region@0 {
+			linux,contiguous-region;
+			reg = <0 0x7800000>;
+			label = "secure_mem";
+		};
 	};
 
 	intc: interrupt-controller@F9000000 {
@@ -324,6 +336,64 @@
 		status = "disable";
 	};
 
+	sdhc_1: sdhci@f9824900 {
+		qcom,bus-width = <8>;
+		compatible = "qcom,sdhci-msm";
+		reg = <0xf9824900 0x11c>, <0xf9824000 0x800>;
+		reg-names = "hc_mem", "core_mem";
+		interrupts = <0 123 0>, <0 138 0>;
+		interrupt-names = "hc_irq", "pwr_irq";
+		qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+		status = "disable";
+	};
+
+	sdhc_2: sdhci@f98a4900 {
+		compatible = "qcom,sdhci-msm";
+		reg = <0xf98a4900 0x11c>, <0xf98a4000 0x800>;
+		reg-names = "hc_mem", "core_mem";
+		interrupts = <0 125 0>, <0 221 0>;
+		interrupt-names = "hc_irq", "pwr_irq";
+
+		qcom,bus-width = <4>;
+		status = "disable";
+	};
+
+	sdhc_3: sdhci@f9864900 {
+		compatible = "qcom,sdhci-msm";
+		reg = <0xf9864900 0x11c>, <0xf9864000 0x800>;
+		reg-names = "hc_mem", "core_mem";
+		interrupts = <0 127 0>, <0 224 0>;
+		interrupt-names = "hc_irq", "pwr_irq";
+		gpios = <&msmgpio 40 0>, /* CLK */
+			<&msmgpio 39 0>, /* CMD */
+			<&msmgpio 38 0>, /* DATA0 */
+			<&msmgpio 37 0>, /* DATA1 */
+			<&msmgpio 36 0>, /* DATA2 */
+			<&msmgpio 35 0>; /* DATA3 */
+		qcom,gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
+
+		qcom,bus-width = <4>;
+		status = "disable";
+	};
+
+	sdhc_4: sdhci@f98e4900 {
+		compatible = "qcom,sdhci-msm";
+		reg = <0xf98e4900 0x11c>, <0xf98e4000 0x800>;
+		reg-names = "hc_mem", "core_mem";
+		interrupts = <0 129 0>, <0 227 0>;
+		interrupt-names = "hc_irq", "pwr_irq";
+		gpios = <&msmgpio 93 0>, /* CLK */
+			<&msmgpio 91 0>, /* CMD */
+			<&msmgpio 96 0>, /* DATA0 */
+			<&msmgpio 95 0>, /* DATA1 */
+			<&msmgpio 94 0>, /* DATA2 */
+			<&msmgpio 92 0>; /* DATA3 */
+		qcom,gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
+
+		qcom,bus-width = <4>;
+		status = "disable";
+	};
+
 	qcom,sps@f9980000 {
 		compatible = "qcom,msm_sps";
 		reg = <0xf9984000 0x15000>,
@@ -1161,7 +1231,7 @@
 	qcom,smem@fa00000 {
 		compatible = "qcom,smem";
 		reg = <0xfa00000 0x200000>,
-			<0xfa006000 0x1000>,
+			<0xf9011000 0x1000>,
 			<0xfc428000 0x4000>;
 		reg-names = "smem", "irq-reg-base", "aux-mem1";
 
@@ -1234,6 +1304,18 @@
 		compatible = "qcom,ssm";
 		qcom,channel-name = "SSM_RTR";
 	};
+
+	sfpb_spinlock: qcom,ipc-spinlock@fd484000 {
+		compatible = "qcom,ipc-spinlock-sfpb";
+		reg = <0xfd484000 0x1000>;
+		qcom,num-locks = <32>;
+	};
+
+	ldrex_spinlock: qcom,ipc-spinlock@fa00000 {
+		compatible = "qcom,ipc-spinlock-ldrex";
+		reg = <0xfa00000 0x200000>;
+		status = "disable";
+	};
 };
 
 &gdsc_venus {
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index 1880965..e881977 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -162,6 +162,22 @@
 			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
 			qcom,xo = <0>;          /* OFF */
 			qcom,l2 = <0>;          /* OFF */
+			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
+			qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
+			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+			qcom,vdd-dig-lower-bound = <3>;  /* SVS SOC */
+			qcom,irqs-detectable;
+			qcom,latency-us = <8000>;
+			qcom,ss-power = <1800>;
+			qcom,energy-overhead = <71950000>;
+			qcom,time-overhead = <15300>;
+		};
+
+		qcom,lpm-level@6 {
+			reg = <0x6>;
+			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+			qcom,xo = <0>;          /* OFF */
+			qcom,l2 = <0>;          /* OFF */
 			qcom,vdd-mem-upper-bound = <950000>; /* SVS SOC */
 			qcom,vdd-mem-lower-bound = <675000>; /* RETENTION */
 			qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
diff --git a/arch/arm/boot/dts/msm9625-v1.dtsi b/arch/arm/boot/dts/msm9625-v1.dtsi
index 54fe443..54aa02a 100644
--- a/arch/arm/boot/dts/msm9625-v1.dtsi
+++ b/arch/arm/boot/dts/msm9625-v1.dtsi
@@ -49,3 +49,11 @@
 &stm {
 	qcom,write-64bit;
 };
+
+&sfpb_spinlock {
+	status = "disable";
+};
+
+&ldrex_spinlock {
+	status = "ok";
+};
diff --git a/arch/arm/boot/dts/msm9625-v2.dtsi b/arch/arm/boot/dts/msm9625-v2.dtsi
index c3c2c49..3ce6844 100644
--- a/arch/arm/boot/dts/msm9625-v2.dtsi
+++ b/arch/arm/boot/dts/msm9625-v2.dtsi
@@ -34,3 +34,11 @@
 &ipa_hw {
 	qcom,ipa-hw-ver = <2>; /* IPA h-w revision */
 };
+
+&sfpb_spinlock {
+	status = "disable";
+};
+
+&ldrex_spinlock {
+	status = "ok";
+};
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index f22fc28..03eaaf3 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -104,8 +104,8 @@
 	hsic@f9a15000 {
 		compatible = "qcom,hsic-host";
 		reg = <0xf9a15000 0x400>;
-		interrupts = <0 136 0>;
-		interrupt-names = "core_irq";
+		interrupts = <0 136 0>, <0 148 0>;
+		interrupt-names = "core_irq", "async_irq";
 		HSIC_VDDCX-supply = <&pm8019_l12>;
 		HSIC_GDSC-supply = <&gdsc_usb_hsic>;
 
@@ -515,6 +515,7 @@
 
 	qcom,msm-pcm {
 		compatible = "qcom,msm-pcm-dsp";
+		qcom,msm-pcm-dsp-id = <0>;
 	};
 
 	qcom,msm-pcm-routing {
@@ -633,7 +634,7 @@
 	qcom,smem@fa00000 {
 		compatible = "qcom,smem";
 		reg = <0xfa00000 0x200000>,
-			<0xfa006000 0x1000>,
+			<0xf9011000 0x1000>,
 			<0xfc428000 0x4000>;
 		reg-names = "smem", "irq-reg-base", "aux-mem1";
 
@@ -717,6 +718,18 @@
                 qcom,memblock-remove = <0x1f00000 0x5700000>; /* Address and Size of Hole */
         };
 
+	sfpb_spinlock: qcom,ipc-spinlock@fd484000 {
+		compatible = "qcom,ipc-spinlock-sfpb";
+		reg = <0xfd484000 0x1000>;
+		qcom,num-locks = <32>;
+	};
+
+	ldrex_spinlock: qcom,ipc-spinlock@fa00000 {
+		compatible = "qcom,ipc-spinlock-ldrex";
+		reg = <0xfa00000 0x200000>;
+		status = "disable";
+	};
+
 };
 
 /include/ "msm-pm8019-rpm-regulator.dtsi"
diff --git a/arch/arm/boot/dts/skeleton.dtsi b/arch/arm/boot/dts/skeleton.dtsi
index b41d241..f9988cd 100644
--- a/arch/arm/boot/dts/skeleton.dtsi
+++ b/arch/arm/boot/dts/skeleton.dtsi
@@ -9,5 +9,10 @@
 	#size-cells = <1>;
 	chosen { };
 	aliases { };
-	memory { device_type = "memory"; reg = <0 0>; };
+	memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		device_type = "memory";
+		reg = <0 0>;
+	};
 };
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index 8e948c2..8eac20f 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -374,7 +374,6 @@
 CONFIG_PRINTK_TIME=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_SHIRQ=y
-# CONFIG_SCHED_DEBUG is not set
 CONFIG_TIMER_STATS=y
 CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/msm7630-perf_defconfig b/arch/arm/configs/msm7630-perf_defconfig
index f2d25ac..e46b835 100644
--- a/arch/arm/configs/msm7630-perf_defconfig
+++ b/arch/arm/configs/msm7630-perf_defconfig
@@ -372,7 +372,6 @@
 CONFIG_PRINTK_TIME=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
-# CONFIG_SCHED_DEBUG is not set
 CONFIG_TIMER_STATS=y
 # CONFIG_DEBUG_PREEMPT is not set
 CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 2e4f84d..14bd1b4 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -45,6 +45,7 @@
 CONFIG_MSM_SMD=y
 CONFIG_MSM_SMD_PKG4=y
 CONFIG_MSM_IPC_LOGGING=y
+CONFIG_MSM_BAM_DMUX=y
 CONFIG_MSM_SMP2P=y
 CONFIG_MSM_SMP2P_TEST=y
 CONFIG_MSM_IPC_ROUTER=y
@@ -63,6 +64,7 @@
 CONFIG_MSM_WATCHDOG_V2=y
 CONFIG_MSM_DLOAD_MODE=y
 CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_OCMEM_POWER_DISABLE=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
@@ -108,6 +110,12 @@
 CONFIG_BRIDGE_NF_EBTABLES=y
 CONFIG_BRIDGE_EBT_BROUTE=y
 CONFIG_BRIDGE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_CLS_FW=y
+CONFIG_SYNC=y
+CONFIG_SW_SYNC=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_MD=y
@@ -115,6 +123,8 @@
 CONFIG_DM_CRYPT=y
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=y
+# CONFIG_MSM_RMNET is not set
+CONFIG_MSM_RMNET_BAM=y
 CONFIG_WCNSS_CORE=y
 CONFIG_WCNSS_CORE_PRONTO=y
 CONFIG_WCNSS_MEM_PRE_ALLOC=y
@@ -142,6 +152,9 @@
 CONFIG_I2C_QUP=y
 CONFIG_WCD9306_CODEC=y
 CONFIG_GPIO_QPNP_PIN=y
+CONFIG_HWMON=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_QPNP_CHARGER=y
 # CONFIG_HWMON is not set
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_SENSORS_QPNP_ADC_CURRENT=y
@@ -152,7 +165,14 @@
 CONFIG_ION_MSM=y
 CONFIG_MSM_KGSL=y
 CONFIG_FB=y
-CONFIG_FB_VIRTUAL=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_SOC=y
@@ -177,11 +197,15 @@
 CONFIG_ANDROID_RAM_CONSOLE=y
 CONFIG_ANDROID_TIMED_GPIO=y
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_QPNP_PWM=y
 CONFIG_MSM_IOMMU=y
 CONFIG_MSM_IOMMU_PMON=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
 CONFIG_MMC_MSM_SPS_SUPPORT=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_QPNP=y
 CONFIG_RTC_CLASS=y
 # CONFIG_RTC_DRV_MSM is not set
 CONFIG_RTC_DRV_QPNP=y
@@ -213,6 +237,7 @@
 CONFIG_CRYPTO_TWOFISH=y
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC_CCITT=y
+CONFIG_QPNP_POWER_ON=y
 CONFIG_LIBCRC32C=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_MEDIA_CAMERA_SUPPORT=y
@@ -229,3 +254,12 @@
 CONFIG_THERMAL=y
 CONFIG_THERMAL_TSENS8974=y
 CONFIG_THERMAL_MONITOR=y
+CONFIG_MSM_RTB=y
+CONFIG_MSM_RTB_SEPARATE_CPUS=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_TMC=y
+CONFIG_CORESIGHT_TPIU=y
+CONFIG_CORESIGHT_FUNNEL=y
+CONFIG_CORESIGHT_REPLICATOR=y
+CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_EVENT=m
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index 828484a..baefac5 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -438,7 +438,6 @@
 CONFIG_NLS_ISO8859_1=y
 CONFIG_PRINTK_TIME=y
 CONFIG_MAGIC_SYSRQ=y
-# CONFIG_SCHED_DEBUG is not set
 CONFIG_TIMER_STATS=y
 # CONFIG_DEBUG_PREEMPT is not set
 CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 7362ea0..8232a8d 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -510,7 +510,6 @@
 CONFIG_NLS_ISO8859_1=y
 CONFIG_PRINTK_TIME=y
 CONFIG_MAGIC_SYSRQ=y
-# CONFIG_SCHED_DEBUG is not set
 CONFIG_TIMER_STATS=y
 # CONFIG_DEBUG_PREEMPT is not set
 CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 5c03630..c6be3c5 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -234,6 +234,7 @@
 CONFIG_GENLOCK_MISCDEVICE=y
 CONFIG_SYNC=y
 CONFIG_SW_SYNC=y
+CONFIG_CMA=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_HAPTIC_ISA1200=y
@@ -392,6 +393,7 @@
 CONFIG_MMC_BLOCK_TEST=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_MSM=y
 CONFIG_MMC_MSM=y
 CONFIG_MMC_MSM_SPS_SUPPORT=y
 CONFIG_LEDS_QPNP=y
@@ -428,6 +430,8 @@
 CONFIG_CORESIGHT_ETM=y
 CONFIG_CORESIGHT_ETM_PCSAVE_DEFAULT_ENABLE=y
 CONFIG_CORESIGHT_EVENT=m
+CONFIG_BIF=y
+CONFIG_BIF_QPNP=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
@@ -441,7 +445,6 @@
 CONFIG_NLS_ISO8859_1=y
 CONFIG_PRINTK_TIME=y
 CONFIG_MAGIC_SYSRQ=y
-# CONFIG_SCHED_DEBUG is not set
 CONFIG_TIMER_STATS=y
 # CONFIG_DEBUG_PREEMPT is not set
 CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index faa0471..f77f04f 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -238,6 +238,7 @@
 CONFIG_GENLOCK_MISCDEVICE=y
 CONFIG_SYNC=y
 CONFIG_SW_SYNC=y
+CONFIG_CMA=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_TSPP=m
@@ -400,6 +401,7 @@
 CONFIG_MMC_BLOCK_TEST=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_MSM=y
 CONFIG_MMC_MSM=y
 CONFIG_MMC_MSM_SPS_SUPPORT=y
 CONFIG_LEDS_QPNP=y
@@ -437,6 +439,8 @@
 CONFIG_CORESIGHT_ETM=y
 CONFIG_CORESIGHT_ETM_PCSAVE_DEFAULT_ENABLE=y
 CONFIG_CORESIGHT_EVENT=m
+CONFIG_BIF=y
+CONFIG_BIF_QPNP=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
diff --git a/arch/arm/configs/msm9625-perf_defconfig b/arch/arm/configs/msm9625-perf_defconfig
index 2070f46..1fe528a 100644
--- a/arch/arm/configs/msm9625-perf_defconfig
+++ b/arch/arm/configs/msm9625-perf_defconfig
@@ -172,7 +172,8 @@
 CONFIG_KS8851=y
 # CONFIG_NET_VENDOR_MICROCHIP is not set
 # CONFIG_MSM_RMNET is not set
-CONFIG_MSM_RMNET_BAM=y
+# CONFIG_MSM_RMNET_BAM is not set
+CONFIG_MSM_RMNET_WWAN=y
 # CONFIG_NET_VENDOR_NATSEMI is not set
 # CONFIG_NET_VENDOR_SEEQ is not set
 # CONFIG_NET_VENDOR_SMSC is not set
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 9a1f872..aa18209 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -172,7 +172,8 @@
 CONFIG_KS8851=y
 # CONFIG_NET_VENDOR_MICROCHIP is not set
 # CONFIG_MSM_RMNET is not set
-CONFIG_MSM_RMNET_BAM=y
+# CONFIG_MSM_RMNET_BAM is not set
+CONFIG_MSM_RMNET_WWAN=y
 # CONFIG_NET_VENDOR_NATSEMI is not set
 # CONFIG_NET_VENDOR_SEEQ is not set
 # CONFIG_NET_VENDOR_SMSC is not set
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index d021905..584fe0b 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -16,7 +16,6 @@
 #include <asm/shmparam.h>
 #include <asm/cachetype.h>
 #include <asm/outercache.h>
-#include <asm/rodata.h>
 
 #define CACHE_COLOUR(vaddr)	((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT)
 
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 938be62..c1295c4 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -68,15 +68,18 @@
 #define __raw_writeb_no_log(v, a)	(__chk_io_ptr(a), *(volatile unsigned char __force  *)(a) = (v))
 #define __raw_writew_no_log(v, a)	(__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v))
 #define __raw_writel_no_log(v, a)	(__chk_io_ptr(a), *(volatile unsigned int __force *)(a) = (v))
+#define __raw_writell_no_log(v, a)	(__chk_io_ptr(a), *(volatile unsigned long long __force *)(a) = (v))
 
 
 #define __raw_writeb(v, a)	__raw_write_logged((v), (a), b)
 #define __raw_writew(v, a)	__raw_write_logged((v), (a), w)
 #define __raw_writel(v, a)	__raw_write_logged((v), (a), l)
+#define __raw_writell(v, a)	__raw_write_logged((v), (a), ll)
 
 #define __raw_readb_no_log(a)		(__chk_io_ptr(a), *(volatile unsigned char __force  *)(a))
 #define __raw_readw_no_log(a)		(__chk_io_ptr(a), *(volatile unsigned short __force *)(a))
 #define __raw_readl_no_log(a)		(__chk_io_ptr(a), *(volatile unsigned int __force *)(a))
+#define __raw_readll_no_log(a)		(__chk_io_ptr(a), *(volatile unsigned long long __force *)(a))
 
 #define __raw_read_logged(a, _l, _t)		({ \
 	unsigned _t __a; \
@@ -94,6 +97,7 @@
 #define __raw_readb(a)		__raw_read_logged((a), b, char)
 #define __raw_readw(a)		__raw_read_logged((a), w, short)
 #define __raw_readl(a)		__raw_read_logged((a), l, int)
+#define __raw_readll(a)		__raw_read_logged((a), ll, long long)
 
 /*
  * Architecture ioremap implementation.
@@ -268,8 +272,12 @@
 					__raw_readw(c)); __r; })
 #define readl_relaxed(c) ({ u32 __r = le32_to_cpu((__force __le32) \
 					__raw_readl(c)); __r; })
+#define readll_relaxed(c) ({ u64 __r = le64_to_cpu((__force __le64) \
+					__raw_readll(c)); __r; })
 #define readl_relaxed_no_log(c) ({ u32 __r = le32_to_cpu((__force __le32) \
 					__raw_readl_no_log(c)); __r; })
+#define readll_relaxed_no_log(c) ({ u64 __r = le64_to_cpu((__force __le64) \
+					__raw_readll_no_log(c)); __r; })
 
 
 #define writeb_relaxed(v,c)	((void)__raw_writeb(v,c))
@@ -277,16 +285,22 @@
 					cpu_to_le16(v),c))
 #define writel_relaxed(v,c)	((void)__raw_writel((__force u32) \
 					cpu_to_le32(v),c))
+#define writell_relaxed(v, c)	((void)__raw_writell((__force u64) \
+					cpu_to_le64(v), c))
 #define writel_relaxed_no_log(v, c)  ((void)__raw_writel_no_log((__force u32) \
 					cpu_to_le32(v), c))
+#define writell_relaxed_no_log(v, c)  ((void)__raw_writell_no_log((__force u64) \
+					cpu_to_le64(v), c))
 
 #define readb(c)		({ u8  __v = readb_relaxed(c); __iormb(); __v; })
 #define readw(c)		({ u16 __v = readw_relaxed(c); __iormb(); __v; })
 #define readl(c)		({ u32 __v = readl_relaxed(c); __iormb(); __v; })
+#define readll(c)		({ u64 __v = readll_relaxed(c); __iormb(); __v; })
 
 #define writeb(v,c)		({ __iowmb(); writeb_relaxed(v,c); })
 #define writew(v,c)		({ __iowmb(); writew_relaxed(v,c); })
 #define writel(v,c)		({ __iowmb(); writel_relaxed(v,c); })
+#define writell(v, c)		({ __iowmb(); writell_relaxed(v, c); })
 
 #define readsb(p,d,l)		__raw_readsb(p,d,l)
 #define readsw(p,d,l)		__raw_readsw(p,d,l)
@@ -316,22 +330,26 @@
 #define iounmap				__arm_iounmap
 
 /*
- * io{read,write}{8,16,32} macros
+ * io{read,write}{8,16,32,64} macros
  */
 #ifndef ioread8
 #define ioread8(p)	({ unsigned int __v = __raw_readb(p); __iormb(); __v; })
 #define ioread16(p)	({ unsigned int __v = le16_to_cpu((__force __le16)__raw_readw(p)); __iormb(); __v; })
 #define ioread32(p)	({ unsigned int __v = le32_to_cpu((__force __le32)__raw_readl(p)); __iormb(); __v; })
+#define ioread64(p)	({ unsigned int __v = le64_to_cpu((__force __le64)__raw_readll(p)); __iormb(); __v; })
 
 #define ioread16be(p)	({ unsigned int __v = be16_to_cpu((__force __be16)__raw_readw(p)); __iormb(); __v; })
 #define ioread32be(p)	({ unsigned int __v = be32_to_cpu((__force __be32)__raw_readl(p)); __iormb(); __v; })
+#define ioread64be(p)	({ unsigned int __v = be64_to_cpu((__force __be64)__raw_readll(p)); __iormb(); __v; })
 
 #define iowrite8(v,p)	({ __iowmb(); (void)__raw_writeb(v, p); })
 #define iowrite16(v,p)	({ __iowmb(); (void)__raw_writew((__force __u16)cpu_to_le16(v), p); })
 #define iowrite32(v,p)	({ __iowmb(); (void)__raw_writel((__force __u32)cpu_to_le32(v), p); })
+#define iowrite64(v, p)	({ __iowmb(); (void)__raw_writell((__force __u64)cpu_to_le64(v), p); })
 
 #define iowrite16be(v,p) ({ __iowmb(); (void)__raw_writew((__force __u16)cpu_to_be16(v), p); })
 #define iowrite32be(v,p) ({ __iowmb(); (void)__raw_writel((__force __u32)cpu_to_be32(v), p); })
+#define iowrite64be(v, p) ({ __iowmb(); (void)__raw_writell((__force __u64)cpu_to_be64(v), p); })
 
 #define ioread8_rep(p,d,c)	__raw_readsb(p,d,c)
 #define ioread16_rep(p,d,c)	__raw_readsw(p,d,c)
diff --git a/arch/arm/include/asm/rodata.h b/arch/arm/include/asm/rodata.h
deleted file mode 100644
index 8c8add8..0000000
--- a/arch/arm/include/asm/rodata.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- *  arch/arm/include/asm/rodata.h
- *
- *  Copyright (C) 2011 Google, Inc.
- *
- *  Author: Colin Cross <ccross@android.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#ifndef _ASMARM_RODATA_H
-#define _ASMARM_RODATA_H
-
-#ifndef __ASSEMBLY__
-
-#ifdef CONFIG_DEBUG_RODATA
-
-int set_memory_rw(unsigned long virt, int numpages);
-int set_memory_ro(unsigned long virt, int numpages);
-
-void mark_rodata_ro(void);
-void set_kernel_text_rw(void);
-void set_kernel_text_ro(void);
-#else
-static inline void set_kernel_text_rw(void) { }
-static inline void set_kernel_text_ro(void) { }
-#endif
-
-#endif
-
-#endif
diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c
index bf17145..df0bf0c 100644
--- a/arch/arm/kernel/ftrace.c
+++ b/arch/arm/kernel/ftrace.c
@@ -13,7 +13,6 @@
  */
 
 #include <linux/ftrace.h>
-#include <linux/module.h>
 #include <linux/uaccess.h>
 
 #include <asm/cacheflush.h>
@@ -64,20 +63,6 @@
 }
 #endif
 
-int ftrace_arch_code_modify_prepare(void)
-{
-	set_kernel_text_rw();
-	set_all_modules_text_rw();
-	return 0;
-}
-
-int ftrace_arch_code_modify_post_process(void)
-{
-	set_all_modules_text_ro();
-	set_kernel_text_ro();
-	return 0;
-}
-
 static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr)
 {
 	return arm_gen_branch_link(pc, addr);
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 42ed059..1b36410 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -50,13 +50,7 @@
 	select MSM_REMOTE_SPINLOCK_DEKKERS
 	select ARCH_SPARSEMEM_ENABLE
 	select ARCH_HAS_HOLES_MEMORYMODEL
-	select MEMORY_HOTPLUG
-	select MEMORY_HOTREMOVE
-	select ARCH_ENABLE_MEMORY_HOTPLUG
-	select ARCH_ENABLE_MEMORY_HOTREMOVE
 	select MIGRATION
-	select ARCH_MEMORY_PROBE
-	select ARCH_MEMORY_REMOVE
 	select MSM_GPIOMUX
 	select RESERVE_FIRST_PAGE
 	select MSM_DALRPC
@@ -412,6 +406,7 @@
 	select CPU_FREQ_GOV_ONDEMAND
 	select MSM_PIL
 	select MSM_RUN_QUEUE_STATS
+	select ARM_HAS_SG_CHAIN
 
 config ARCH_MSM8226
 	bool "MSM8226"
@@ -438,6 +433,7 @@
 	select MEMORY_HOLE_CARVEOUT
 	select DONT_MAP_HOLE_AFTER_MEMBANK0
 	select MSM_BUS_SCALING
+	select ARM_HAS_SG_CHAIN
 endmenu
 
 choice
@@ -1037,8 +1033,8 @@
 	default "0x80200000" if ARCH_MSM8930
 	default "0x00000000" if ARCH_MSM8974
 	default "0x00000000" if ARCH_MPQ8092
-	default "0x00100000" if ARCH_MSM8226
-	default "0x00100000" if ARCH_MSM8610
+	default "0x00000000" if ARCH_MSM8226
+	default "0x00000000" if ARCH_MSM8610
 	default "0x10000000" if ARCH_FSM9XXX
 	default "0x00200000" if ARCH_MSM9625
 	default "0x00200000" if !MSM_STACKED_MEMORY
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index f683b33..02d0b46 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -72,7 +72,7 @@
 	dtb-$(CONFIG_ARCH_MSM9625)      += msm9625-v2-1-cdp.dtb
 
 # MSM8226
-   zreladdr-$(CONFIG_ARCH_MSM8226)	:= 0x00108000
+   zreladdr-$(CONFIG_ARCH_MSM8226)	:= 0x00008000
         dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-sim.dtb
         dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-cdp.dtb
         dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-mtp.dtb
@@ -87,6 +87,6 @@
    zreladdr-$(CONFIG_ARCH_MPQ8092)	:= 0x00008000
 
 # MSM8610
-   zreladdr-$(CONFIG_ARCH_MSM8610)	:= 0x00108000
+   zreladdr-$(CONFIG_ARCH_MSM8610)	:= 0x00008000
         dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-rumi.dtb
         dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-sim.dtb
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index 7dc3a0e..8ba1b39 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -53,13 +53,13 @@
  * 3) Depending on Frodo version, may need minimum of LVL_NOM
  */
 static struct clkctl_acpu_speed acpu_freq_tbl[] = {
-	{ 0,   19200, CXO,     0, 0,   LVL_LOW,    950000, 0 },
-	{ 1,  300000, PLL0,    4, 2,   LVL_LOW,    950000, 4 },
-	{ 1,  384000, ACPUPLL, 5, 0,   LVL_LOW,    950000, 4 },
-	{ 1,  600000, PLL0,    4, 0,   LVL_NOM,    950000, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   LVL_NOM,   1050000, 6 },
-	{ 1,  998400, ACPUPLL, 5, 0,   LVL_HIGH,  1050000, 7 },
-	{ 1, 1190400, ACPUPLL, 5, 0,   LVL_HIGH,  1050000, 7 },
+	{ 0,   19200, CXO,     0, 0,   1150000,   1150000, 0 },
+	{ 1,  300000, PLL0,    4, 2,   1150000,   1150000, 4 },
+	{ 1,  384000, ACPUPLL, 5, 0,   1150000,   1150000, 4 },
+	{ 1,  600000, PLL0,    4, 0,   1150000,   1150000, 6 },
+	{ 1,  787200, ACPUPLL, 5, 0,   1150000,   1150000, 6 },
+	{ 0,  998400, ACPUPLL, 5, 0,   1150000,   1150000, 7 },
+	{ 0, 1190400, ACPUPLL, 5, 0,   1150000,   1150000, 7 },
 	{ 0 }
 };
 
@@ -68,7 +68,7 @@
 	.current_speed = &(struct clkctl_acpu_speed){ 0 },
 	.bus_scale = &bus_client_pdata,
 	/* FIXME regulator doesn't support corners yet */
-	.vdd_max_cpu = 1050000,
+	.vdd_max_cpu = 1150000,
 	.vdd_max_mem = 1150000,
 	.src_clocks = {
 		[PLL0].name = "gpll0",
diff --git a/arch/arm/mach-msm/acpuclock-cortex.c b/arch/arm/mach-msm/acpuclock-cortex.c
index 4ac1408..9104f98 100644
--- a/arch/arm/mach-msm/acpuclock-cortex.c
+++ b/arch/arm/mach-msm/acpuclock-cortex.c
@@ -133,7 +133,12 @@
 		pr_warn("acpu rcg didn't update its configuration\n");
 }
 
-static int set_speed(struct clkctl_acpu_speed *tgt_s)
+/*
+ * This function can be called in both atomic and nonatomic context.
+ * Since regulator APIS can sleep, we cannot always use the clk prepare
+ * unprepare API.
+ */
+static int set_speed(struct clkctl_acpu_speed *tgt_s, bool atomic)
 {
 	int rc = 0;
 	unsigned int tgt_freq_hz = tgt_s->khz * 1000;
@@ -147,11 +152,19 @@
 		select_clk_source_div(acpuclk_init_data, cxo_s);
 
 		/* Re-program acpu pll */
-		clk_disable(tgt);
+		if (atomic)
+			clk_disable(tgt);
+		else
+			clk_disable_unprepare(tgt);
+
 		rc = clk_set_rate(tgt, tgt_freq_hz);
 		if (rc)
 			pr_err("Failed to set ACPU PLL to %u\n", tgt_freq_hz);
-		BUG_ON(clk_enable(tgt));
+
+		if (atomic)
+			BUG_ON(clk_enable(tgt));
+		else
+			BUG_ON(clk_prepare_enable(tgt));
 
 		/* Switch back to acpu pll */
 		select_clk_source_div(acpuclk_init_data, tgt_s);
@@ -163,7 +176,11 @@
 			return rc;
 		}
 
-		rc = clk_enable(tgt);
+		if (atomic)
+			clk_enable(tgt);
+		else
+			clk_prepare_enable(tgt);
+
 		if (rc) {
 			pr_err("ACPU PLL enable failed\n");
 			return rc;
@@ -171,9 +188,17 @@
 
 		select_clk_source_div(acpuclk_init_data, tgt_s);
 
-		clk_disable(strt);
+		if (atomic)
+			clk_disable(strt);
+		else
+			clk_disable_unprepare(strt);
+
 	} else {
-		rc = clk_enable(tgt);
+		if (atomic)
+			clk_enable(tgt);
+		else
+			clk_prepare_enable(tgt);
+
 		if (rc) {
 			pr_err("%s enable failed\n",
 				acpuclk_init_data->src_clocks[tgt_s->src].name);
@@ -182,7 +207,11 @@
 
 		select_clk_source_div(acpuclk_init_data, tgt_s);
 
-		clk_disable(strt);
+		if (atomic)
+			clk_disable(strt);
+		else
+			clk_disable_unprepare(strt);
+
 	}
 
 	return rc;
@@ -223,8 +252,12 @@
 	pr_debug("Switching from CPU rate %u KHz -> %u KHz\n",
 		strt_s->khz, tgt_s->khz);
 
-	/* Switch CPU speed. */
-	rc = set_speed(tgt_s);
+	/* Switch CPU speed. Flag indicates atomic context */
+	if (reason == SETRATE_CPUFREQ || reason == SETRATE_INIT)
+		rc = set_speed(tgt_s, false);
+	else
+		rc = set_speed(tgt_s, true);
+
 	if (rc)
 		goto out;
 
@@ -316,11 +349,6 @@
 			clk_get(&pdev->dev,
 				acpuclk_init_data->src_clocks[i].name);
 		BUG_ON(IS_ERR(acpuclk_init_data->src_clocks[i].clk));
-		/*
-		 * Prepare the PLLs because we enable/disable them
-		 * in atomic context during power collapse/restore.
-		 */
-		BUG_ON(clk_prepare(acpuclk_init_data->src_clocks[i].clk));
 	}
 
 	/* Improve boot time by ramping up CPU immediately */
@@ -329,8 +357,8 @@
 			max_cpu_khz = acpuclk_init_data->freq_tbl[i].khz;
 
 	/* Initialize regulators */
-	rc = increase_vdd(acpuclk_init_data->freq_tbl[i].vdd_cpu,
-		acpuclk_init_data->freq_tbl[i].vdd_mem);
+	rc = increase_vdd(acpuclk_init_data->vdd_max_cpu,
+		acpuclk_init_data->vdd_max_mem);
 	if (rc)
 		goto err_vdd;
 
@@ -368,7 +396,6 @@
 	for (i = 0; i < NUM_SRC; i++) {
 		if (!acpuclk_init_data->src_clocks[i].name)
 			continue;
-		clk_unprepare(acpuclk_init_data->src_clocks[i].clk);
 		clk_put(acpuclk_init_data->src_clocks[i].clk);
 	}
 	return rc;
diff --git a/arch/arm/mach-msm/avs.c b/arch/arm/mach-msm/avs.c
index aa257ef..b2185e3 100644
--- a/arch/arm/mach-msm/avs.c
+++ b/arch/arm/mach-msm/avs.c
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -16,6 +16,7 @@
 #include <asm/mach-types.h>
 #include <asm/cputype.h>
 #include "avs.h"
+#include "spm.h"
 
 u32 avs_get_avscsr(void)
 {
@@ -72,7 +73,10 @@
 
 static void avs_disable_local(void *data)
 {
+	int cpu = smp_processor_id();
+
 	avs_set_avscsr(0);
+	msm_spm_set_vdd(cpu, msm_spm_get_vdd(cpu));
 }
 
 void avs_enable(int cpu, u32 avsdscr)
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 7c2c463..833b213 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -302,81 +302,56 @@
 #define bam_ch_is_in_reset(x)			\
 	(bam_ch[(x)].status & BAM_CH_IN_RESET)
 
-#define LOG_MESSAGE_MAX_SIZE 80
 struct kfifo bam_dmux_state_log;
-static uint32_t bam_dmux_state_logging_disabled;
 static int bam_dmux_uplink_vote;
 static int bam_dmux_power_state;
 
-static void bam_dmux_log(const char *fmt, ...)
-					__printf(1, 2);
-
-
-#define DMUX_LOG_KERR(fmt...) \
-do { \
-	bam_dmux_log(fmt); \
-	pr_err(fmt); \
-} while (0)
-
 static void *bam_ipc_log_txt;
 
 #define BAM_IPC_LOG_PAGES 5
 
 /**
  * Log a state change along with a small message.
- *
  * Complete size of messsage is limited to @todo.
+ * Logging is done using IPC Logging infrastructure.
+ *
+ * States
+ * D: 1 = Power collapse disabled
+ * R: 1 = in global reset
+ * P: 1 = BAM is powered up
+ * A: 1 = BAM initialized and ready for data
+ * V: 1 = Uplink vote for power
+ * U: 1 = Uplink active
+ * W: 1 = Uplink Wait-for-ack
+ * A: 1 = Uplink ACK received
+ * #: >=1 On-demand uplink vote
+ * D: 1 = Disconnect ACK active
  */
-static void bam_dmux_log(const char *fmt, ...)
-{
-	char buff[LOG_MESSAGE_MAX_SIZE];
-	va_list arg_list;
-	unsigned long long t_now;
-	unsigned long nanosec_rem;
-	int len = 0;
 
-	if (bam_dmux_state_logging_disabled)
-		return;
+#define BAM_DMUX_LOG(fmt, args...) \
+do { \
+	if (bam_ipc_log_txt) { \
+		ipc_log_string(bam_ipc_log_txt, \
+		"<DMUX> %c%c%c%c %c%c%c%c%d%c " fmt, \
+		a2_pc_disabled ? 'D' : 'd', \
+		in_global_reset ? 'R' : 'r', \
+		bam_dmux_power_state ? 'P' : 'p', \
+		bam_connection_is_active ? 'A' : 'a', \
+		bam_dmux_uplink_vote ? 'V' : 'v', \
+		bam_is_connected ?  'U' : 'u', \
+		wait_for_ack ? 'W' : 'w', \
+		ul_wakeup_ack_completion.done ? 'A' : 'a', \
+		atomic_read(&ul_ondemand_vote), \
+		disconnect_ack ? 'D' : 'd', \
+		args); \
+	} \
+} while (0)
 
-	t_now = sched_clock();
-	nanosec_rem = do_div(t_now, 1000000000U);
-
-	/*
-	 * States
-	 * D: 1 = Power collapse disabled
-	 * R: 1 = in global reset
-	 * P: 1 = BAM is powered up
-	 * A: 1 = BAM initialized and ready for data
-	 *
-	 * V: 1 = Uplink vote for power
-	 * U: 1 = Uplink active
-	 * W: 1 = Uplink Wait-for-ack
-	 * A: 1 = Uplink ACK received
-	 * #: >=1 On-demand uplink vote
-	 * D: 1 = Disconnect ACK active
-	 */
-	len += scnprintf(buff, sizeof(buff),
-		"<DMUX> %u.%09lu %c%c%c%c %c%c%c%c%d%c ",
-		(unsigned)t_now, nanosec_rem,
-		a2_pc_disabled ? 'D' : 'd',
-		in_global_reset ? 'R' : 'r',
-		bam_dmux_power_state ? 'P' : 'p',
-		bam_connection_is_active ? 'A' : 'a',
-		bam_dmux_uplink_vote ? 'V' : 'v',
-		bam_is_connected ?  'U' : 'u',
-		wait_for_ack ? 'W' : 'w',
-		ul_wakeup_ack_completion.done ? 'A' : 'a',
-		atomic_read(&ul_ondemand_vote),
-		disconnect_ack ? 'D' : 'd'
-		);
-
-	va_start(arg_list, fmt);
-	len += vscnprintf(buff + len, sizeof(buff) - len, fmt, arg_list);
-	va_end(arg_list);
-	memset(buff + len, 0x0, sizeof(buff) - len);
-	if (bam_ipc_log_txt)
-		ipc_log_string(bam_ipc_log_txt, buff);
-}
+#define DMUX_LOG_KERR(fmt, args...) \
+do { \
+	BAM_DMUX_LOG(fmt, args); \
+	pr_err(fmt, args); \
+} while (0)
 
 static inline void set_tx_timestamp(struct tx_pkt_info *pkt)
 {
@@ -396,12 +371,12 @@
 	spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
 	list_for_each_entry(info, &bam_tx_pool, list_node) {
 		if (!reported) {
-			bam_dmux_log("%s: tx pool not empty\n", func);
+			BAM_DMUX_LOG("%s: tx pool not empty\n", func);
 			if (!in_global_reset)
 				pr_err("%s: tx pool not empty\n", func);
 			reported = 1;
 		}
-		bam_dmux_log("%s: node=%p ts=%u.%09lu\n", __func__,
+		BAM_DMUX_LOG("%s: node=%p ts=%u.%09lu\n", __func__,
 			&info->list_node, info->ts_sec, info->ts_nsec);
 		if (!in_global_reset)
 			pr_err("%s: node=%p ts=%u.%09lu\n", __func__,
@@ -529,7 +504,7 @@
 
 	mutex_lock(&bam_pdev_mutexlock);
 	if (in_global_reset) {
-		bam_dmux_log("%s: open cid %d aborted due to ssr\n",
+		BAM_DMUX_LOG("%s: open cid %d aborted due to ssr\n",
 				__func__, rx_hdr->ch_id);
 		mutex_unlock(&bam_pdev_mutexlock);
 		queue_rx();
@@ -593,18 +568,18 @@
 		bam_mux_process_data(rx_skb);
 		break;
 	case BAM_MUX_HDR_CMD_OPEN:
-		bam_dmux_log("%s: opening cid %d PC enabled\n", __func__,
+		BAM_DMUX_LOG("%s: opening cid %d PC enabled\n", __func__,
 				rx_hdr->ch_id);
 		handle_bam_mux_cmd_open(rx_hdr);
 		if (!(rx_hdr->reserved & ENABLE_DISCONNECT_ACK)) {
-			bam_dmux_log("%s: deactivating disconnect ack\n",
+			BAM_DMUX_LOG("%s: deactivating disconnect ack\n",
 								__func__);
 			disconnect_ack = 0;
 		}
 		dev_kfree_skb_any(rx_skb);
 		break;
 	case BAM_MUX_HDR_CMD_OPEN_NO_A2_PC:
-		bam_dmux_log("%s: opening cid %d PC disabled\n", __func__,
+		BAM_DMUX_LOG("%s: opening cid %d PC disabled\n", __func__,
 				rx_hdr->ch_id);
 
 		if (!a2_pc_disabled) {
@@ -617,11 +592,11 @@
 		break;
 	case BAM_MUX_HDR_CMD_CLOSE:
 		/* probably should drop pending write */
-		bam_dmux_log("%s: closing cid %d\n", __func__,
+		BAM_DMUX_LOG("%s: closing cid %d\n", __func__,
 				rx_hdr->ch_id);
 		mutex_lock(&bam_pdev_mutexlock);
 		if (in_global_reset) {
-			bam_dmux_log("%s: close cid %d aborted due to ssr\n",
+			BAM_DMUX_LOG("%s: close cid %d aborted due to ssr\n",
 					__func__, rx_hdr->ch_id);
 			mutex_unlock(&bam_pdev_mutexlock);
 			break;
@@ -1412,7 +1387,7 @@
 	for (i = 0; i < BAM_DMUX_NUM_CHANNELS; ++i) {
 		if (bam_ch_is_open(i)) {
 			bam_ch[i].notify(bam_ch[i].priv, event, data);
-			bam_dmux_log("%s: cid=%d, event=%d, data=%lu\n",
+			BAM_DMUX_LOG("%s: cid=%d, event=%d, data=%lu\n",
 					__func__, i, event, data);
 		}
 	}
@@ -1455,11 +1430,11 @@
 
 static void power_vote(int vote)
 {
-	bam_dmux_log("%s: curr=%d, vote=%d\n", __func__,
+	BAM_DMUX_LOG("%s: curr=%d, vote=%d\n", __func__,
 			bam_dmux_uplink_vote, vote);
 
 	if (bam_dmux_uplink_vote == vote)
-		bam_dmux_log("%s: warning - duplicate power vote\n", __func__);
+		BAM_DMUX_LOG("%s: warning - duplicate power vote\n", __func__);
 
 	bam_dmux_uplink_vote = vote;
 	if (vote)
@@ -1473,7 +1448,7 @@
  */
 static inline void ul_powerdown(void)
 {
-	bam_dmux_log("%s: powerdown\n", __func__);
+	BAM_DMUX_LOG("%s: powerdown\n", __func__);
 	verify_tx_queue_is_empty(__func__);
 
 	if (a2_pc_disabled) {
@@ -1585,7 +1560,7 @@
 		}
 
 		if (ul_packet_written || atomic_read(&ul_ondemand_vote)) {
-			bam_dmux_log("%s: pkt written %d\n",
+			BAM_DMUX_LOG("%s: pkt written %d\n",
 				__func__, ul_packet_written);
 			ul_packet_written = 0;
 			schedule_delayed_work(&ul_timeout_work,
@@ -1614,7 +1589,7 @@
 
 	mutex_lock(&wakeup_lock);
 	if (bam_is_connected) { /* bam got connected before lock grabbed */
-		bam_dmux_log("%s Already awake\n", __func__);
+		BAM_DMUX_LOG("%s Already awake\n", __func__);
 		mutex_unlock(&wakeup_lock);
 		return;
 	}
@@ -1677,35 +1652,35 @@
 	 * instead of waiting
 	 */
 	if (wait_for_ack) {
-		bam_dmux_log("%s waiting for previous ack\n", __func__);
+		BAM_DMUX_LOG("%s waiting for previous ack\n", __func__);
 		ret = wait_for_completion_timeout(
 					&ul_wakeup_ack_completion, HZ);
 		wait_for_ack = 0;
 		if (unlikely(ret == 0) && ssrestart_check()) {
 			mutex_unlock(&wakeup_lock);
-			bam_dmux_log("%s timeout previous ack\n", __func__);
+			BAM_DMUX_LOG("%s timeout previous ack\n", __func__);
 			return;
 		}
 	}
 	INIT_COMPLETION(ul_wakeup_ack_completion);
 	power_vote(1);
-	bam_dmux_log("%s waiting for wakeup ack\n", __func__);
+	BAM_DMUX_LOG("%s waiting for wakeup ack\n", __func__);
 	ret = wait_for_completion_timeout(&ul_wakeup_ack_completion, HZ);
 	if (unlikely(ret == 0) && ssrestart_check()) {
 		mutex_unlock(&wakeup_lock);
-		bam_dmux_log("%s timeout wakeup ack\n", __func__);
+		BAM_DMUX_LOG("%s timeout wakeup ack\n", __func__);
 		return;
 	}
-	bam_dmux_log("%s waiting completion\n", __func__);
+	BAM_DMUX_LOG("%s waiting completion\n", __func__);
 	ret = wait_for_completion_timeout(&bam_connection_completion, HZ);
 	if (unlikely(ret == 0) && ssrestart_check()) {
 		mutex_unlock(&wakeup_lock);
-		bam_dmux_log("%s timeout power on\n", __func__);
+		BAM_DMUX_LOG("%s timeout power on\n", __func__);
 		return;
 	}
 
 	bam_is_connected = 1;
-	bam_dmux_log("%s complete\n", __func__);
+	BAM_DMUX_LOG("%s complete\n", __func__);
 	schedule_delayed_work(&ul_timeout_work,
 				msecs_to_jiffies(UL_TIMEOUT_DELAY));
 	mutex_unlock(&wakeup_lock);
@@ -1771,7 +1746,7 @@
 	/* handle disconnect during active UL */
 	write_lock_irqsave(&ul_wakeup_lock, flags);
 	if (bam_is_connected) {
-		bam_dmux_log("%s: UL active - forcing powerdown\n", __func__);
+		BAM_DMUX_LOG("%s: UL active - forcing powerdown\n", __func__);
 		ul_powerdown();
 	}
 	write_unlock_irqrestore(&ul_wakeup_lock, flags);
@@ -1817,10 +1792,10 @@
 {
 	int rc;
 
-	bam_dmux_log("%s\n", __func__);
+	BAM_DMUX_LOG("%s\n", __func__);
 	mutex_lock(&dfab_status_lock);
 	if (dfab_is_on) {
-		bam_dmux_log("%s: dfab is already on\n", __func__);
+		BAM_DMUX_LOG("%s: dfab is already on\n", __func__);
 		mutex_unlock(&dfab_status_lock);
 		return;
 	}
@@ -1842,7 +1817,7 @@
 
 static void unvote_dfab(void)
 {
-	bam_dmux_log("%s\n", __func__);
+	BAM_DMUX_LOG("%s\n", __func__);
 	mutex_lock(&dfab_status_lock);
 	if (!dfab_is_on) {
 		DMUX_LOG_KERR("%s: dfab is already off\n", __func__);
@@ -1864,7 +1839,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&wakelock_reference_lock, flags);
-	bam_dmux_log("%s: ref count = %d\n", __func__,
+	BAM_DMUX_LOG("%s: ref count = %d\n", __func__,
 						wakelock_reference_count);
 	if (wakelock_reference_count == 0)
 		wake_lock(&bam_wakelock);
@@ -1883,7 +1858,7 @@
 		spin_unlock_irqrestore(&wakelock_reference_lock, flags);
 		return;
 	}
-	bam_dmux_log("%s: ref count = %d\n", __func__,
+	BAM_DMUX_LOG("%s: ref count = %d\n", __func__,
 						wakelock_reference_count);
 	--wakelock_reference_count;
 	if (wakelock_reference_count == 0)
@@ -1917,7 +1892,7 @@
 	if (code == SUBSYS_BEFORE_SHUTDOWN) {
 		in_global_reset = 1;
 		in_ssr = 1;
-		bam_dmux_log("%s: begin\n", __func__);
+		BAM_DMUX_LOG("%s: begin\n", __func__);
 		flush_workqueue(bam_mux_rx_workqueue);
 	}
 	if (code != SUBSYS_AFTER_SHUTDOWN)
@@ -1978,7 +1953,7 @@
 	}
 	spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
 
-	bam_dmux_log("%s: complete\n", __func__);
+	BAM_DMUX_LOG("%s: complete\n", __func__);
 	return NOTIFY_DONE;
 }
 
@@ -2225,7 +2200,7 @@
 {
 	static unsigned int clear_bit; /* 0 = set the bit, else clear bit */
 
-	bam_dmux_log("%s: apps ack %d->%d\n", __func__,
+	BAM_DMUX_LOG("%s: apps ack %d->%d\n", __func__,
 			clear_bit & 0x1, ~clear_bit & 0x1);
 	smsm_change_state(SMSM_APPS_STATE,
 				clear_bit & SMSM_A2_POWER_CONTROL_ACK,
@@ -2241,10 +2216,10 @@
 	mutex_lock(&smsm_cb_lock);
 	bam_dmux_power_state = new_state & SMSM_A2_POWER_CONTROL ? 1 : 0;
 	DBG_INC_A2_POWER_CONTROL_IN_CNT();
-	bam_dmux_log("%s: 0x%08x -> 0x%08x\n", __func__, old_state,
+	BAM_DMUX_LOG("%s: 0x%08x -> 0x%08x\n", __func__, old_state,
 			new_state);
 	if (last_processed_state == (new_state & SMSM_A2_POWER_CONTROL)) {
-		bam_dmux_log("%s: already processed this state\n", __func__);
+		BAM_DMUX_LOG("%s: already processed this state\n", __func__);
 		mutex_unlock(&smsm_cb_lock);
 		return;
 	}
@@ -2252,23 +2227,23 @@
 	last_processed_state = new_state & SMSM_A2_POWER_CONTROL;
 
 	if (bam_mux_initialized && new_state & SMSM_A2_POWER_CONTROL) {
-		bam_dmux_log("%s: reconnect\n", __func__);
+		BAM_DMUX_LOG("%s: reconnect\n", __func__);
 		grab_wakelock();
 		reconnect_to_bam();
 	} else if (bam_mux_initialized &&
 					!(new_state & SMSM_A2_POWER_CONTROL)) {
-		bam_dmux_log("%s: disconnect\n", __func__);
+		BAM_DMUX_LOG("%s: disconnect\n", __func__);
 		disconnect_to_bam();
 		release_wakelock();
 	} else if (new_state & SMSM_A2_POWER_CONTROL) {
-		bam_dmux_log("%s: init\n", __func__);
+		BAM_DMUX_LOG("%s: init\n", __func__);
 		grab_wakelock();
 		if (cpu_is_msm9615())
 			msm9615_bam_init();
 		else
 			bam_init();
 	} else {
-		bam_dmux_log("%s: bad state change\n", __func__);
+		BAM_DMUX_LOG("%s: bad state change\n", __func__);
 		pr_err("%s: unsupported state change\n", __func__);
 	}
 	mutex_unlock(&smsm_cb_lock);
@@ -2279,7 +2254,7 @@
 						uint32_t new_state)
 {
 	DBG_INC_ACK_IN_CNT();
-	bam_dmux_log("%s: 0x%08x -> 0x%08x\n", __func__, old_state,
+	BAM_DMUX_LOG("%s: 0x%08x -> 0x%08x\n", __func__, old_state,
 			new_state);
 	complete_all(&ul_wakeup_ack_completion);
 }
@@ -2322,12 +2297,12 @@
 
 	xo_clk = clk_get(&pdev->dev, "xo");
 	if (IS_ERR(xo_clk)) {
-		bam_dmux_log("%s: did not get xo clock\n", __func__);
+		BAM_DMUX_LOG("%s: did not get xo clock\n", __func__);
 		xo_clk = NULL;
 	}
 	dfab_clk = clk_get(&pdev->dev, "bus_clk");
 	if (IS_ERR(dfab_clk)) {
-		bam_dmux_log("%s: did not get dfab clock\n", __func__);
+		BAM_DMUX_LOG("%s: did not get dfab clock\n", __func__);
 		dfab_clk = NULL;
 	} else {
 		rc = clk_set_rate(dfab_clk, 64000000);
@@ -2434,7 +2409,6 @@
 	bam_ipc_log_txt = ipc_log_context_create(BAM_IPC_LOG_PAGES, "bam_dmux");
 	if (!bam_ipc_log_txt) {
 		pr_err("%s : unable to create IPC Logging Context", __func__);
-		bam_dmux_state_logging_disabled = 1;
 	}
 
 	rx_timer_interval = DEFAULT_POLLING_MIN_SLEEP;
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index 0dee8f5..0f88287 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -1729,13 +1729,6 @@
 	},
 };
 
-static struct gpiomux_setting fsm8064_ep_sync_drsync_cfg = {
-	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_2MA,
-	.pull = GPIOMUX_PULL_UP,
-	.dir = GPIOMUX_OUT_HIGH,
-};
-
 static struct gpiomux_setting fsm8064_ep_sync_input_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_4MA,
@@ -1746,7 +1739,7 @@
 	{
 		.gpio      = 6,		/* GPSPPSIN_DRSYNC */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &fsm8064_ep_sync_drsync_cfg,
+			[GPIOMUX_SUSPENDED] = &fsm8064_ep_sync_input_cfg,
 		},
 	},
 	{
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index a1ff607..a1ed251 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -137,7 +137,7 @@
 	PM8921_GPIO_OUTPUT_VIN(14, 1, PM_GPIO_VIN_VPH),
 	/* PPS_SRC_SEL_N, chooses between WGR7640 PPS source (high) or
 	 * CW GPS module PPS source (low) */
-	PM8921_GPIO_OUTPUT_VIN(19, 1, PM_GPIO_VIN_VPH),	/* PPS_SRC_SEL_N */
+	PM8921_GPIO_OUTPUT_VIN(19, 0, PM_GPIO_VIN_VPH),	/* PPS_SRC_SEL_N */
 
 	PM8921_GPIO_OUTPUT_VIN(13, 1, PM_GPIO_VIN_VPH),	/* PCIE_CLK_PWR_EN */
 	PM8921_GPIO_OUTPUT_VIN(37, 1, PM_GPIO_VIN_VPH),	/* PCIE_RST_N */
@@ -557,4 +557,7 @@
 
 	if (!machine_is_apq8064_mtp() && !machine_is_apq8064_liquid())
 		apq8064_pm8921_chg_pdata.battery_less_hardware = 1;
+
+	if (machine_is_mpq8064_hrd())
+		apq8064_pm8921_chg_pdata.disable_chg_rmvl_wrkarnd = 1;
 }
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 9ed71da..1d07356 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -683,53 +683,6 @@
 	.paddr_to_memtype = apq8064_paddr_to_memtype,
 };
 
-static int apq8064_memory_bank_size(void)
-{
-	return 1<<29;
-}
-
-static void __init locate_unstable_memory(void)
-{
-	struct membank *mb = &meminfo.bank[meminfo.nr_banks - 1];
-	unsigned long bank_size;
-	unsigned long low, high;
-
-	bank_size = apq8064_memory_bank_size();
-	low = meminfo.bank[0].start;
-	high = mb->start + mb->size;
-
-	/* Check if 32 bit overflow occured */
-	if (high < mb->start)
-		high = -PAGE_SIZE;
-
-	low &= ~(bank_size - 1);
-
-	if (high - low <= bank_size)
-		goto no_dmm;
-
-#ifdef CONFIG_ENABLE_DMM
-	apq8064_reserve_info.low_unstable_address = mb->start -
-					MIN_MEMORY_BLOCK_SIZE + mb->size;
-	apq8064_reserve_info.max_unstable_size = MIN_MEMORY_BLOCK_SIZE;
-
-	apq8064_reserve_info.bank_size = bank_size;
-	pr_info("low unstable address %lx max size %lx bank size %lx\n",
-		apq8064_reserve_info.low_unstable_address,
-		apq8064_reserve_info.max_unstable_size,
-		apq8064_reserve_info.bank_size);
-	return;
-#endif
-no_dmm:
-	apq8064_reserve_info.low_unstable_address = high;
-	apq8064_reserve_info.max_unstable_size = 0;
-}
-
-static int apq8064_change_memory_power(u64 start, u64 size,
-	int change_type)
-{
-	return soc_change_memory_power(start, size, change_type);
-}
-
 static char prim_panel_name[PANEL_NAME_MAX_LEN];
 static char ext_panel_name[PANEL_NAME_MAX_LEN];
 
@@ -766,22 +719,9 @@
 	msm_reserve();
 }
 
-static void __init place_movable_zone(void)
-{
-#ifdef CONFIG_ENABLE_DMM
-	movable_reserved_start = apq8064_reserve_info.low_unstable_address;
-	movable_reserved_size = apq8064_reserve_info.max_unstable_size;
-	pr_info("movable zone start %lx size %lx\n",
-		movable_reserved_start, movable_reserved_size);
-#endif
-}
-
 static void __init apq8064_early_reserve(void)
 {
 	reserve_info = &apq8064_reserve_info;
-	locate_unstable_memory();
-	place_movable_zone();
-
 }
 #ifdef CONFIG_USB_EHCI_MSM_HSIC
 /* Bandwidth requests (zero) if no vote placed */
@@ -3935,8 +3875,6 @@
 	if (machine_is_apq8064_mtp())
 		platform_device_register(&mtp_kp_pdev);
 
-	change_memory_power = &apq8064_change_memory_power;
-
 	if (machine_is_mpq8064_cdp()) {
 		platform_device_register(&mpq_gpio_keys_pdev);
 		platform_device_register(&mpq_keypad_device);
@@ -3979,7 +3917,6 @@
 #ifdef CONFIG_MSM_CAMERA
 	apq8064_init_cam();
 #endif
-	change_memory_power = &apq8064_change_memory_power;
 }
 
 MACHINE_START(APQ8064_CDP, "QCT APQ8064 CDP")
@@ -4005,6 +3942,7 @@
 	.init_early = apq8064_allocate_memory_regions,
 	.init_very_early = apq8064_early_reserve,
 	.restart = msm_restart,
+	.smp = &msm8960_smp_ops,
 MACHINE_END
 
 MACHINE_START(APQ8064_MTP, "QCT APQ8064 MTP")
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index 8be5525..c1971c1 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -93,6 +93,28 @@
 	},
 };
 
+static struct gpiomux_setting sd_card_det_active_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_IN,
+};
+
+static struct gpiomux_setting sd_card_det_sleep_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+	.dir = GPIOMUX_IN,
+};
+
+static struct msm_gpiomux_config sd_card_det __initdata = {
+	.gpio = 38,
+	.settings = {
+		[GPIOMUX_ACTIVE]    = &sd_card_det_active_config,
+		[GPIOMUX_SUSPENDED] = &sd_card_det_sleep_config,
+	},
+};
+
 void __init msm8226_init_gpiomux(void)
 {
 	int rc;
@@ -108,4 +130,6 @@
 #endif
 
 	msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
+
+	msm_gpiomux_install(&sd_card_det, 1);
 }
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index 2b331d0..79ab428 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -51,6 +51,7 @@
 #include "platsmp.h"
 #include "spm.h"
 #include "lpm_resources.h"
+#include "modem_notifier.h"
 
 static struct memtype_reserve msm8226_reserve_table[] __initdata = {
 	[MEMTYPE_SMI] = {
@@ -102,6 +103,8 @@
  */
 void __init msm8226_add_drivers(void)
 {
+	msm_init_modem_notifier_list();
+	msm_smd_init();
 	msm_rpm_driver_init();
 	msm_lpmrs_module_init();
 	msm_spm_device_init();
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index fbcc6f1..73b4eb7 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -714,64 +714,9 @@
 	.paddr_to_memtype = msm8930_paddr_to_memtype,
 };
 
-static int msm8930_memory_bank_size(void)
-{
-	return 1<<29;
-}
-
-static void __init locate_unstable_memory(void)
-{
-	struct membank *mb = &meminfo.bank[meminfo.nr_banks - 1];
-	unsigned long bank_size;
-	unsigned long low, high;
-
-	bank_size = msm8930_memory_bank_size();
-	low = meminfo.bank[0].start;
-	high = mb->start + mb->size;
-
-	/* Check if 32 bit overflow occured */
-	if (high < mb->start)
-		high -= PAGE_SIZE;
-
-	if (high < MAX_FIXED_AREA_SIZE + MSM8930_FIXED_AREA_START)
-		panic("fixed area extends beyond end of memory\n");
-
-	low &= ~(bank_size - 1);
-
-	if (high - low <= bank_size)
-		goto no_dmm;
-
-	msm8930_reserve_info.bank_size = bank_size;
-#ifdef CONFIG_ENABLE_DMM
-	msm8930_reserve_info.low_unstable_address = mb->start -
-					MIN_MEMORY_BLOCK_SIZE + mb->size;
-	msm8930_reserve_info.max_unstable_size = MIN_MEMORY_BLOCK_SIZE;
-	pr_info("low unstable address %lx max size %lx bank size %lx\n",
-		msm8930_reserve_info.low_unstable_address,
-		msm8930_reserve_info.max_unstable_size,
-		msm8930_reserve_info.bank_size);
-	return;
-#endif
-no_dmm:
-	msm8930_reserve_info.low_unstable_address = high;
-	msm8930_reserve_info.max_unstable_size = 0;
-}
-
-static void __init place_movable_zone(void)
-{
-#ifdef CONFIG_ENABLE_DMM
-	movable_reserved_start = msm8930_reserve_info.low_unstable_address;
-	movable_reserved_size = msm8930_reserve_info.max_unstable_size;
-	pr_info("movable zone start %lx size %lx\n",
-		movable_reserved_start, movable_reserved_size);
-#endif
-}
-
 static void __init msm8930_early_memory(void)
 {
 	reserve_info = &msm8930_reserve_info;
-	locate_unstable_memory();
-	place_movable_zone();
 }
 
 static char prim_panel_name[PANEL_NAME_MAX_LEN];
@@ -799,12 +744,6 @@
 	msm_reserve();
 }
 
-static int msm8930_change_memory_power(u64 start, u64 size,
-	int change_type)
-{
-	return soc_change_memory_power(start, size, change_type);
-}
-
 static void __init msm8930_allocate_memory_regions(void)
 {
 	msm8930_allocate_fb_region();
@@ -3022,7 +2961,6 @@
 	msm8930_init_fb();
 	slim_register_board_info(msm_slim_devices,
 		ARRAY_SIZE(msm_slim_devices));
-	change_memory_power = &msm8930_change_memory_power;
 	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 
 	if (PLATFORM_IS_CHARM25())
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 819ccc5..bd54756 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -806,65 +806,9 @@
 	.paddr_to_memtype = msm8960_paddr_to_memtype,
 };
 
-static int msm8960_memory_bank_size(void)
-{
-	return 1<<29;
-}
-
-static void __init locate_unstable_memory(void)
-{
-	struct membank *mb = &meminfo.bank[meminfo.nr_banks - 1];
-	unsigned long bank_size;
-	unsigned long low, high;
-
-	bank_size = msm8960_memory_bank_size();
-	msm8960_reserve_info.bank_size = bank_size;
-
-	low = meminfo.bank[0].start;
-	high = mb->start + mb->size;
-
-	/* Check if 32 bit overflow occured */
-	if (high < mb->start)
-		high = ~0UL;
-
-	if (high < MAX_FIXED_AREA_SIZE + MSM8960_FIXED_AREA_START)
-		panic("fixed area extends beyond end of memory\n");
-
-	low &= ~(bank_size - 1);
-
-	if (high - low <= bank_size)
-		goto no_dmm;
-
-#ifdef CONFIG_ENABLE_DMM
-	msm8960_reserve_info.low_unstable_address = mb->start -
-					MIN_MEMORY_BLOCK_SIZE + mb->size;
-	msm8960_reserve_info.max_unstable_size = MIN_MEMORY_BLOCK_SIZE;
-	pr_info("low unstable address %lx max size %lx bank size %lx\n",
-		msm8960_reserve_info.low_unstable_address,
-		msm8960_reserve_info.max_unstable_size,
-		msm8960_reserve_info.bank_size);
-	return;
-#endif
-no_dmm:
-	msm8960_reserve_info.low_unstable_address = high;
-	msm8960_reserve_info.max_unstable_size = 0;
-}
-
-static void __init place_movable_zone(void)
-{
-#ifdef CONFIG_ENABLE_DMM
-	movable_reserved_start = msm8960_reserve_info.low_unstable_address;
-	movable_reserved_size = msm8960_reserve_info.max_unstable_size;
-	pr_info("movable zone start %lx size %lx\n",
-		movable_reserved_start, movable_reserved_size);
-#endif
-}
-
 static void __init msm8960_early_memory(void)
 {
 	reserve_info = &msm8960_reserve_info;
-	locate_unstable_memory();
-	place_movable_zone();
 }
 
 static char prim_panel_name[PANEL_NAME_MAX_LEN];
@@ -891,12 +835,6 @@
 	msm_reserve();
 }
 
-static int msm8960_change_memory_power(u64 start, u64 size,
-	int change_type)
-{
-	return soc_change_memory_power(start, size, change_type);
-}
-
 static void __init msm8960_allocate_memory_regions(void)
 {
 	msm8960_allocate_fb_region();
@@ -3037,7 +2975,10 @@
 
 	/* Fixup data that needs to change based on GPU ID */
 	if (cpu_is_msm8960ab()) {
-		kgsl_3d0_pdata->chipid = ADRENO_CHIPID(3, 2, 1, 0);
+		if (SOCINFO_VERSION_MINOR(soc_platform_version) == 0)
+			kgsl_3d0_pdata->chipid = ADRENO_CHIPID(3, 2, 1, 0);
+		else
+			kgsl_3d0_pdata->chipid = ADRENO_CHIPID(3, 2, 1, 1);
 		/* 8960PRO nominal clock rate is 320Mhz */
 		kgsl_3d0_pdata->pwrlevel[1].gpu_freq = 320000000;
 #ifdef CONFIG_MSM_BUS_SCALING
@@ -3553,7 +3494,6 @@
 	slim_register_board_info(msm_slim_devices,
 		ARRAY_SIZE(msm_slim_devices));
 	msm8960_init_dsps();
-	change_memory_power = &msm8960_change_memory_power;
 	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 	bt_power_init();
 	if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 7038ab9..9c9ccaa 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -93,9 +93,9 @@
 		"qup_scl" },
 	{ GPIO_CFG(61, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
 		"qup_sda" },
-	{ GPIO_CFG(131, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+	{ GPIO_CFG(131, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
 		"qup_scl" },
-	{ GPIO_CFG(132, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+	{ GPIO_CFG(132, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
 		"qup_sda" },
 };
 
@@ -104,9 +104,9 @@
 		"qup_scl" },
 	{ GPIO_CFG(61, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
 		"qup_sda" },
-	{ GPIO_CFG(131, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+	{ GPIO_CFG(131, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
 		"qup_scl" },
-	{ GPIO_CFG(132, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+	{ GPIO_CFG(132, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
 		"qup_sda" },
 };
 
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index a963c19..b40617c 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -60,6 +60,8 @@
 #define gpll0_mm_source_val 5
 #define dsipll_750_mm_source_val 1
 #define dsipll_667_mm_source_val 1
+#define dsipll0_byte_mm_source_val 1
+#define dsipll0_pixel_mm_source_val 1
 
 #define gpll1_hsic_source_val 4
 
@@ -1334,17 +1336,6 @@
 	},
 };
 
-static struct branch_clk gcc_mmss_noc_cfg_ahb_clk = {
-	.cbcr_reg = MMSS_NOC_CFG_AHB_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[GCC_BASE],
-	.c = {
-		.dbg_name = "gcc_mmss_noc_cfg_ahb_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(gcc_mmss_noc_cfg_ahb_clk.c),
-	},
-};
-
 static struct branch_clk gcc_mss_cfg_ahb_clk = {
 	.cbcr_reg = MSS_CFG_AHB_CBCR,
 	.has_sibling = 1,
@@ -1592,7 +1583,6 @@
 static struct measure_mux_entry measure_mux_GCC[] = {
 	{ &gcc_periph_noc_ahb_clk.c,  GCC_BASE, 0x0010 },
 	{ &gcc_noc_conf_xpu_ahb_clk.c,  GCC_BASE, 0x0018 },
-	{ &gcc_mmss_noc_cfg_ahb_clk.c,  GCC_BASE, 0x002a },
 	{ &gcc_mss_cfg_ahb_clk.c,  GCC_BASE, 0x0030 },
 	{ &gcc_mss_q6_bimc_axi_clk.c,  GCC_BASE, 0x0031 },
 	{ &gcc_usb_hsic_ahb_clk.c,  GCC_BASE, 0x0058 },
@@ -1697,19 +1687,6 @@
 	},
 };
 
-static struct pll_clk mmpll2_pll = {
-	.mode_reg = (void __iomem *)MMPLL2_PLL_MODE,
-	.status_reg = (void __iomem *)MMPLL2_PLL_STATUS,
-	.base = &virt_bases[MMSS_BASE],
-	.c = {
-		.dbg_name = "mmpll2_pll",
-		.parent = &xo.c,
-		.rate = 900000000,
-		.ops = &clk_ops_local_pll,
-		CLK_INIT(mmpll2_pll.c),
-	},
-};
-
 static struct clk_freq_tbl ftbl_camss_csi0_1_clk[] = {
 	F_MMSS( 100000000,      gpll0,   6,    0,    0),
 	F_MMSS( 200000000, mmpll0_pll,   4,    0,    0),
@@ -1826,21 +1803,36 @@
 	},
 };
 
-static struct clk_freq_tbl ftbl_mdss_pclk0_clk[] = {
-	F_MDSS(  83000000, dsipll_667,   8,    0,    0),
-	F_MDSS( 166000000, dsipll_667,   4,    0,    0),
-	F_END
+static struct branch_clk mdss_ahb_clk;
+static struct clk dsipll0_byte_clk_src = {
+	.depends = &mdss_ahb_clk.c,
+	.parent = &xo.c,
+	.dbg_name = "dsipll0_byte_clk_src",
+	.ops = &clk_ops_dsi_byte_pll,
+	CLK_INIT(dsipll0_byte_clk_src),
+};
+
+static struct clk dsipll0_pixel_clk_src = {
+	.depends = &mdss_ahb_clk.c,
+	.parent = &xo.c,
+	.dbg_name = "dsipll0_pixel_clk_src",
+	.ops = &clk_ops_dsi_pixel_pll,
+	CLK_INIT(dsipll0_pixel_clk_src),
+};
+
+static struct clk_freq_tbl pixel_freq = {
+	.src_clk = &dsipll0_pixel_clk_src,
+	.div_src_val = BVAL(10, 8, dsipll0_pixel_mm_source_val),
 };
 
 static struct rcg_clk pclk0_clk_src = {
 	.cmd_rcgr_reg = PCLK0_CMD_RCGR,
-	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_mdss_pclk0_clk,
-	.current_freq = &rcg_dummy_freq,
+	.current_freq = &pixel_freq,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
+		.parent = &dsipll0_pixel_clk_src,
 		.dbg_name = "pclk0_clk_src",
-		.ops = &clk_ops_rcg_mnd,
+		.ops = &clk_ops_pixel,
 		VDD_DIG_FMAX_MAP2(LOW, 83330000, NOMINAL, 166670000),
 		CLK_INIT(pclk0_clk_src.c),
 	},
@@ -2015,21 +2007,19 @@
 	},
 };
 
-static struct clk_freq_tbl ftbl_mdss_byte0_clk[] = {
-	F_MDSS(  62500000, dsipll_750,  12,    0,    0),
-	F_MDSS( 125000000, dsipll_750,   6,    0,    0),
-	F_END
+static struct clk_freq_tbl byte_freq = {
+	.src_clk = &dsipll0_byte_clk_src,
+	.div_src_val = BVAL(10, 8, dsipll0_byte_mm_source_val),
 };
 
 static struct rcg_clk byte0_clk_src = {
 	.cmd_rcgr_reg = BYTE0_CMD_RCGR,
-	.set_rate = set_rate_hid,
-	.freq_tbl = ftbl_mdss_byte0_clk,
-	.current_freq = &rcg_dummy_freq,
+	.current_freq = &byte_freq,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
+		.parent = &dsipll0_byte_clk_src,
 		.dbg_name = "byte0_clk_src",
-		.ops = &clk_ops_rcg,
+		.ops = &clk_ops_byte,
 		VDD_DIG_FMAX_MAP2(LOW, 62500000, NOMINAL, 125000000),
 		CLK_INIT(byte0_clk_src.c),
 	},
@@ -2530,17 +2520,6 @@
 	},
 };
 
-static struct branch_clk mmss_mmssnoc_ahb_clk = {
-	.cbcr_reg = MMSS_MMSSNOC_AHB_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[MMSS_BASE],
-	.c = {
-		.dbg_name = "mmss_mmssnoc_ahb_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(mmss_mmssnoc_ahb_clk.c),
-	},
-};
-
 static struct branch_clk mmss_mmssnoc_bto_ahb_clk = {
 	.cbcr_reg = MMSS_MMSSNOC_BTO_AHB_CBCR,
 	.has_sibling = 1,
@@ -2650,7 +2629,6 @@
 };
 
 static struct measure_mux_entry measure_mux_MMSS[] = {
-	{ &mmss_mmssnoc_ahb_clk.c,  MMSS_BASE, 0x0001 },
 	{ &mmss_mmssnoc_bto_ahb_clk.c,  MMSS_BASE, 0x0002 },
 	{ &mmss_misc_ahb_clk.c,  MMSS_BASE, 0x0003 },
 	{ &mmss_mmssnoc_axi_clk.c,  MMSS_BASE, 0x0004 },
@@ -3100,7 +3078,6 @@
 	CLK_LOOKUP("ocmem_a_clk", ocmemgx_msmbus_a_clk.c, "msm_bus"),
 	CLK_LOOKUP("bus_clk",	mmss_s0_axi_clk.c,	"msm_mmss_noc"),
 	CLK_LOOKUP("bus_a_clk",	mmss_s0_axi_clk.c,	"msm_mmss_noc"),
-	CLK_LOOKUP("iface_clk", gcc_mmss_noc_cfg_ahb_clk.c, ""),
 
 	/* CoreSight clocks */
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc322000.tmc"),
@@ -3197,7 +3174,6 @@
 	CLK_LOOKUP("gpll1", gpll1.c, ""),
 	CLK_LOOKUP("mmpll0", mmpll0_pll.c, ""),
 	CLK_LOOKUP("mmpll1", mmpll1_pll.c, ""),
-	CLK_LOOKUP("mmpll2", mmpll2_pll.c, ""),
 
 	CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, ""),
@@ -3236,12 +3212,12 @@
 	CLK_LOOKUP("pixel_clk", mdss_pclk0_clk.c, "fd922800.qcom,mdss_dsi"),
 	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "mdss_dsi_clk_ctrl"),
 
-	CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "mdp.0"),
-	CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "mdp.0"),
-	CLK_LOOKUP("core_clk_src", mdp_clk_src.c, "mdp.0"),
-	CLK_LOOKUP("vsync_clk", mdss_vsync_clk.c, "mdp.0"),
-	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "mdp.0"),
-	CLK_LOOKUP("bus_clk", mdss_axi_clk.c, "mdp.0"),
+	CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "fd900000.qcom,mdss_mdp"),
+	CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "fd900000.qcom,mdss_mdp"),
+	CLK_LOOKUP("core_clk_src", mdp_clk_src.c, "fd900000.qcom,mdss_mdp"),
+	CLK_LOOKUP("vsync_clk", mdss_vsync_clk.c, "fd900000.qcom,mdss_mdp"),
+	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd900000.qcom,mdss_mdp"),
+	CLK_LOOKUP("bus_clk", mdss_axi_clk.c, "fd900000.qcom,mdss_mdp"),
 
 	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd928000.qcom,iommu"),
 	CLK_LOOKUP("core_clk", mdss_axi_clk.c, "fd928000.qcom,iommu"),
@@ -3368,7 +3344,6 @@
 	CLK_LOOKUP("cam_gp1_clk", camss_gp1_clk.c, ""),
 	CLK_LOOKUP("iface_clk", camss_micro_ahb_clk.c, ""),
 
-	CLK_LOOKUP("", mmss_mmssnoc_ahb_clk.c, ""),
 	CLK_LOOKUP("", mmss_mmssnoc_bto_ahb_clk.c, ""),
 	CLK_LOOKUP("", mmss_mmssnoc_axi_clk.c, ""),
 	CLK_LOOKUP("", mmss_s0_axi_clk.c, ""),
@@ -3392,166 +3367,23 @@
 	.size = ARRAY_SIZE(msm_clocks_8226_rumi),
 };
 
-static struct pll_config_regs gpll0_regs __initdata = {
-	.l_reg = (void __iomem *)GPLL0_L_VAL,
-	.m_reg = (void __iomem *)GPLL0_M_VAL,
-	.n_reg = (void __iomem *)GPLL0_N_VAL,
-	.config_reg = (void __iomem *)GPLL0_USER_CTL,
-	.mode_reg = (void __iomem *)GPLL0_MODE,
-	.base = &virt_bases[GCC_BASE],
-};
-
-/* GPLL0 at 600 MHz, main output enabled. */
-static struct pll_config gpll0_config __initdata = {
-	.l = 0x1f,
-	.m = 0x1,
-	.n = 0x4,
-	.vco_val = 0x0,
-	.vco_mask = BM(21, 20),
-	.pre_div_val = 0x0,
-	.pre_div_mask = BM(14, 12),
-	.post_div_val = 0x0,
-	.post_div_mask = BM(9, 8),
-	.mn_ena_val = BIT(24),
-	.mn_ena_mask = BIT(24),
-	.main_output_val = BIT(0),
-	.main_output_mask = BIT(0),
-};
-
-static struct pll_config_regs gpll1_regs __initdata = {
-	.l_reg = (void __iomem *)GPLL1_L_VAL,
-	.m_reg = (void __iomem *)GPLL1_M_VAL,
-	.n_reg = (void __iomem *)GPLL1_N_VAL,
-	.config_reg = (void __iomem *)GPLL1_USER_CTL,
-	.mode_reg = (void __iomem *)GPLL1_MODE,
-	.base = &virt_bases[GCC_BASE],
-};
-
-/* GPLL1 at 480 MHz, main output enabled. */
-static struct pll_config gpll1_config __initdata = {
-	.l = 0x19,
-	.m = 0x0,
-	.n = 0x1,
-	.vco_val = 0x0,
-	.vco_mask = BM(21, 20),
-	.pre_div_val = 0x0,
-	.pre_div_mask = BM(14, 12),
-	.post_div_val = 0x0,
-	.post_div_mask = BM(9, 8),
-	.main_output_val = BIT(0),
-	.main_output_mask = BIT(0),
-};
-
-static struct pll_config_regs mmpll0_regs __initdata = {
-	.l_reg = (void __iomem *)MMPLL0_PLL_L_VAL,
-	.m_reg = (void __iomem *)MMPLL0_PLL_M_VAL,
-	.n_reg = (void __iomem *)MMPLL0_PLL_N_VAL,
-	.config_reg = (void __iomem *)MMPLL0_PLL_USER_CTL,
-	.mode_reg = (void __iomem *)MMPLL0_PLL_MODE,
-	.base = &virt_bases[MMSS_BASE],
-};
-
-/* MMPLL0 at 800 MHz, main output enabled. */
-static struct pll_config mmpll0_config __initdata = {
-	.l = 0x29,
-	.m = 0x2,
-	.n = 0x3,
-	.vco_val = 0x0,
-	.vco_mask = BM(21, 20),
-	.pre_div_val = 0x0,
-	.pre_div_mask = BM(14, 12),
-	.post_div_val = 0x0,
-	.post_div_mask = BM(9, 8),
-	.mn_ena_val = BIT(24),
-	.mn_ena_mask = BIT(24),
-	.main_output_val = BIT(0),
-	.main_output_mask = BIT(0),
-};
-
-static struct pll_config_regs mmpll1_regs __initdata = {
-	.l_reg = (void __iomem *)MMPLL1_PLL_L_VAL,
-	.m_reg = (void __iomem *)MMPLL1_PLL_M_VAL,
-	.n_reg = (void __iomem *)MMPLL1_PLL_N_VAL,
-	.config_reg = (void __iomem *)MMPLL1_PLL_USER_CTL,
-	.mode_reg = (void __iomem *)MMPLL1_PLL_MODE,
-	.base = &virt_bases[MMSS_BASE],
-};
-
-/* MMPLL1 at 1000 MHz, main output enabled. */
-static struct pll_config mmpll1_config __initdata = {
-	.l = 0x2C,
-	.m = 0x1,
-	.n = 0x10,
-	.vco_val = 0x0,
-	.vco_mask = BM(21, 20),
-	.pre_div_val = 0x0,
-	.pre_div_mask = BM(14, 12),
-	.post_div_val = 0x0,
-	.post_div_mask = BM(9, 8),
-	.mn_ena_val = BIT(24),
-	.mn_ena_mask = BIT(24),
-	.main_output_val = BIT(0),
-	.main_output_mask = BIT(0),
-};
-
-#define PLL_AUX_OUTPUT_BIT 1
-#define PLL_AUX2_OUTPUT_BIT 2
-
-#define PWR_ON_MASK		BIT(31)
-#define EN_REST_WAIT_MASK	(0xF << 20)
-#define EN_FEW_WAIT_MASK	(0xF << 16)
-#define CLK_DIS_WAIT_MASK	(0xF << 12)
-#define SW_OVERRIDE_MASK	BIT(2)
-#define HW_CONTROL_MASK		BIT(1)
-#define SW_COLLAPSE_MASK	BIT(0)
-
-/* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */
-#define EN_REST_WAIT_VAL	(0x2 << 20)
-#define EN_FEW_WAIT_VAL		(0x2 << 16)
-#define CLK_DIS_WAIT_VAL	(0x2 << 12)
-#define GDSC_TIMEOUT_US		50000
-
-#define PLL_OUTCTRL BIT(0)
-#define PLL_BYPASSNL BIT(1)
-#define PLL_RESET_N BIT(2)
-#define PLL_LOCKED_BIT BIT(16)
-#define ENABLE_WAIT_MAX_LOOPS 200
-
 static void __init reg_init(void)
 {
 	u32 regval;
 
-	if (!(readl_relaxed(GCC_REG_BASE(GPLL0_STATUS))
-			& gpll0.status_mask))
-		configure_sr_hpm_lp_pll(&gpll0_config, &gpll0_regs, 1);
-
-	if (!(readl_relaxed(GCC_REG_BASE(GPLL1_STATUS))
-			& gpll1.status_mask))
-		configure_sr_hpm_lp_pll(&gpll1_config, &gpll1_regs, 1);
-
-	configure_sr_hpm_lp_pll(&mmpll0_config, &mmpll0_regs, 1);
-	configure_sr_hpm_lp_pll(&mmpll1_config, &mmpll1_regs, 1);
-
-	/* Enable GPLL0's aux outputs. */
-	regval = readl_relaxed(GCC_REG_BASE(GPLL0_USER_CTL));
-	regval |= BIT(PLL_AUX_OUTPUT_BIT) | BIT(PLL_AUX2_OUTPUT_BIT);
-	writel_relaxed(regval, GCC_REG_BASE(GPLL0_USER_CTL));
-
 	/* Vote for GPLL0 to turn on. Needed by acpuclock. */
 	regval = readl_relaxed(GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
 	regval |= BIT(0);
 	writel_relaxed(regval, GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
 
 	/*
-	 * TODO: Confirm that no clocks need to be voted on in this sleep vote
-	 * register.
+	 * No clocks need to be enabled during sleep.
 	 */
 	writel_relaxed(0x0, GCC_REG_BASE(APCS_CLOCK_SLEEP_ENA_VOTE));
 }
 
 static void __init msm8226_clock_post_init(void)
 {
-
 	/* Set rates for single-rate clocks. */
 	clk_set_rate(&usb_hs_system_clk_src.c,
 			usb_hs_system_clk_src.freq_tbl[0].freq_hz);
@@ -3620,18 +3452,12 @@
 		panic("clock-8226: Unable to get the sr2_pll regulator!");
 
 	/*
-	 * The SR2 PLL is used at boot. Vote to prevent its regulator from
-	 * being turned off while the PLL is still in use.
+	 * These regulators are used at boot. Ensure they stay on
+	 * while the clock framework comes online.
 	 */
 	regulator_set_voltage(vdd_sr2_reg, 1800000, 1800000);
 	regulator_enable(vdd_sr2_reg);
 
-	/*
-	 * TODO: Set a voltage and enable vdd_dig, leaving the voltage high
-	 * until late_init. This may not be necessary with clock handoff;
-	 * Investigate this code on a real non-simulator target to determine
-	 * its necessity.
-	 */
 	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
 	regulator_enable(vdd_dig_reg);
 
@@ -3642,7 +3468,6 @@
 	 * access mmss clock controller registers.
 	 */
 	clk_set_rate(&mmssnoc_ahb_a_clk.c, 40000000);
-	clk_prepare_enable(&mmssnoc_ahb_a_clk.c);
 
 	/*
 	 * Hold an active set vote for CXO; this is because CXO is expected
@@ -3653,18 +3478,12 @@
 	enable_rpm_scaling();
 
 	reg_init();
-	/*
-	 * FIXME remove after bus driver is in place
-	 * Requires gpll0 to be configured
-	 */
-	clk_set_rate(&axi_clk_src.c, 200000000);
-	clk_prepare_enable(&mmss_s0_axi_clk.c);
 
 	/*
-	 * TODO: Enable the gcc_bimc_clk smcbc, which is the parent of thhe
-	 * mss_gcc_q6_bimc_axi_clk
+	 * MDSS needs the ahb clock and needs to init before we register the
+	 * lookup table.
 	 */
-	writel_relaxed(0x1, GCC_REG_BASE(0x1118));
+	mdss_clk_ctrl_pre_init(&mdss_ahb_clk.c);
 }
 
 static int __init msm8226_clock_late_init(void)
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index bfa9ec0..3587df6 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -809,6 +809,7 @@
 static DEFINE_CLK_BRANCH_VOTER(cxo_wlan_clk, &cxo_clk_src.c);
 static DEFINE_CLK_BRANCH_VOTER(cxo_pil_pronto_clk, &cxo_clk_src.c);
 static DEFINE_CLK_BRANCH_VOTER(cxo_dwc3_clk, &cxo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_ehci_host_clk, &cxo_clk_src.c);
 
 static struct clk_freq_tbl ftbl_gcc_usb30_master_clk[] = {
 	F(125000000,  gpll0,   1,   5,  24),
@@ -3029,134 +3030,6 @@
 	.src_clk = &dsipll0_byte_clk_src,
 	.div_src_val = BVAL(10, 8, dsipll0_byte_mm_source_val),
 };
-static struct clk_freq_tbl pixel_freq = {
-	.src_clk = &dsipll0_pixel_clk_src,
-	.div_src_val = BVAL(10, 8, dsipll0_pixel_mm_source_val),
-};
-static struct clk_ops clk_ops_byte;
-static struct clk_ops clk_ops_pixel;
-
-#define CFG_RCGR_DIV_MASK		BM(4, 0)
-#define CMD_RCGR_REG(x)			(*(x)->base + (x)->cmd_rcgr_reg + 0x0)
-#define CFG_RCGR_REG(x)			(*(x)->base + (x)->cmd_rcgr_reg + 0x4)
-#define M_REG(x)			(*(x)->base + (x)->cmd_rcgr_reg + 0x8)
-#define N_REG(x)			(*(x)->base + (x)->cmd_rcgr_reg + 0xC)
-#define MND_MODE_MASK			BM(13, 12)
-#define MND_DUAL_EDGE_MODE_BVAL		BVAL(13, 12, 0x2)
-#define CFG_RCGR_SRC_SEL_MASK		BM(10, 8)
-#define CMD_RCGR_ROOT_STATUS_BIT	BIT(31)
-
-static enum handoff byte_rcg_handoff(struct clk *clk)
-{
-	struct rcg_clk *rcg = to_rcg_clk(clk);
-	u32 div_val;
-	unsigned long pre_div_rate, parent_rate = clk_get_rate(clk->parent);
-
-	/* If the pre-divider is used, find the rate after the division */
-	div_val = readl_relaxed(CFG_RCGR_REG(rcg)) & CFG_RCGR_DIV_MASK;
-	if (div_val > 1)
-		pre_div_rate = parent_rate / ((div_val + 1) >> 1);
-	else
-		pre_div_rate = parent_rate;
-
-	clk->rate = pre_div_rate;
-
-	if (readl_relaxed(CMD_RCGR_REG(rcg)) & CMD_RCGR_ROOT_STATUS_BIT)
-		return HANDOFF_DISABLED_CLK;
-
-	return HANDOFF_ENABLED_CLK;
-}
-
-static int set_rate_byte(struct clk *clk, unsigned long rate)
-{
-	struct rcg_clk *rcg = to_rcg_clk(clk);
-	struct clk *pll = clk->parent;
-	unsigned long source_rate, div;
-	int rc;
-
-	if (rate == 0)
-		return -EINVAL;
-
-	rc = clk_set_rate(pll, rate);
-	if (rc)
-		return rc;
-
-	source_rate = clk_round_rate(pll, rate);
-	if ((2 * source_rate) % rate)
-		return -EINVAL;
-
-	div = ((2 * source_rate)/rate) - 1;
-	if (div > CFG_RCGR_DIV_MASK)
-		return -EINVAL;
-
-	byte_freq.div_src_val &= ~CFG_RCGR_DIV_MASK;
-	byte_freq.div_src_val |= BVAL(4, 0, div);
-	set_rate_hid(rcg, &byte_freq);
-
-	return 0;
-}
-
-static enum handoff pixel_rcg_handoff(struct clk *clk)
-{
-	struct rcg_clk *rcg = to_rcg_clk(clk);
-	u32 div_val, mval, nval, cfg_regval;
-	unsigned long pre_div_rate, parent_rate = clk_get_rate(clk->parent);
-
-	cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg));
-
-	/* If the pre-divider is used, find the rate after the division */
-	div_val = cfg_regval & CFG_RCGR_DIV_MASK;
-	if (div_val > 1)
-		pre_div_rate = parent_rate / ((div_val + 1) >> 1);
-	else
-		pre_div_rate = parent_rate;
-
-	clk->rate = pre_div_rate;
-
-	/* If MND is used, find the rate after the MND division */
-	if ((cfg_regval & MND_MODE_MASK) == MND_DUAL_EDGE_MODE_BVAL) {
-		mval = readl_relaxed(M_REG(rcg));
-		nval = readl_relaxed(N_REG(rcg));
-		if (!nval)
-			return HANDOFF_DISABLED_CLK;
-		nval = (~nval) + mval;
-		clk->rate = (pre_div_rate * mval) / nval;
-	}
-
-	if (readl_relaxed(CMD_RCGR_REG(rcg)) & CMD_RCGR_ROOT_STATUS_BIT)
-		return HANDOFF_DISABLED_CLK;
-
-	return HANDOFF_ENABLED_CLK;
-}
-
-static int set_rate_pixel(struct clk *clk, unsigned long rate)
-{
-	struct rcg_clk *rcg = to_rcg_clk(clk);
-	struct clk *pll = clk->parent;
-	unsigned long source_rate, div;
-	int rc;
-
-	if (rate == 0)
-		return -EINVAL;
-
-	rc = clk_set_rate(pll, rate);
-	if (rc)
-		return rc;
-
-	source_rate = clk_round_rate(pll, rate);
-	if ((2 * source_rate) % rate)
-		return -EINVAL;
-
-	div = ((2 * source_rate)/rate) - 1;
-	if (div > CFG_RCGR_DIV_MASK)
-		return -EINVAL;
-
-	pixel_freq.div_src_val &= ~CFG_RCGR_DIV_MASK;
-	pixel_freq.div_src_val |= BVAL(4, 0, div);
-	set_rate_mnd(rcg, &pixel_freq);
-
-	return 0;
-}
 
 static struct rcg_clk byte0_clk_src = {
 	.cmd_rcgr_reg = BYTE0_CMD_RCGR,
@@ -3323,35 +3196,6 @@
 	F_END
 };
 
-/*
- * Unlike other clocks, the HDMI rate is adjusted through PLL
- * re-programming. It is also routed through an HID divider.
- */
-static int rcg_clk_set_rate_hdmi(struct clk *c, unsigned long rate)
-{
-	struct clk_freq_tbl *nf;
-	struct rcg_clk *rcg = to_rcg_clk(c);
-	int rc;
-
-	for (nf = rcg->freq_tbl; nf->freq_hz != rate; nf++)
-		if (nf->freq_hz == FREQ_END) {
-			rc = -EINVAL;
-			goto out;
-		}
-
-	rc = clk_set_rate(nf->src_clk, rate);
-	if (rc < 0)
-		goto out;
-	set_rate_hid(rcg, nf);
-
-	rcg->current_freq = nf;
-	c->parent = nf->src_clk;
-out:
-	return rc;
-}
-
-static struct clk_ops clk_ops_rcg_hdmi;
-
 static struct rcg_clk extpclk_clk_src = {
 	.cmd_rcgr_reg = EXTPCLK_CMD_RCGR,
 	.freq_tbl = ftbl_mdss_extpclk_clk,
@@ -3384,6 +3228,10 @@
 	},
 };
 
+static struct clk_freq_tbl pixel_freq = {
+	.src_clk = &dsipll0_pixel_clk_src,
+	.div_src_val = BVAL(10, 8, dsipll0_pixel_mm_source_val),
+};
 
 static struct rcg_clk pclk0_clk_src = {
 	.cmd_rcgr_reg = PCLK0_CMD_RCGR,
@@ -4893,6 +4741,7 @@
 	CLK_LOOKUP("xo",       cxo_wlan_clk.c, "fb000000.qcom,wcnss-wlan"),
 	CLK_LOOKUP("xo", cxo_pil_pronto_clk.c,     "fb21b000.qcom,pronto"),
 	CLK_LOOKUP("xo",       cxo_dwc3_clk.c,                 "msm_dwc3"),
+	CLK_LOOKUP("xo",  cxo_ehci_host_clk.c,            "msm_ehci_host"),
 
 	CLK_LOOKUP("measure",	measure_clk.c,	"debug"),
 
@@ -5033,9 +4882,11 @@
 
 	/* MM sensor clocks */
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6e.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "20.qcom,camera"),
 	CLK_LOOKUP("cam_src_clk", mclk2_clk_src.c, "6c.qcom,camera"),
 	CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "90.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6e.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "20.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk2_clk.c, "6c.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, "90.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, ""),
@@ -5521,28 +5372,6 @@
 	writel_relaxed(0x0, GCC_REG_BASE(APCS_CLOCK_SLEEP_ENA_VOTE));
 }
 
-static void __init mdss_clock_setup(void)
-{
-	clk_ops_byte = clk_ops_rcg;
-	clk_ops_byte.set_rate = set_rate_byte;
-	clk_ops_byte.handoff = byte_rcg_handoff;
-	clk_ops_byte.get_parent = NULL;
-
-	clk_ops_pixel = clk_ops_rcg_mnd;
-	clk_ops_pixel.set_rate = set_rate_pixel;
-	clk_ops_pixel.handoff = pixel_rcg_handoff;
-	clk_ops_pixel.get_parent = NULL;
-
-	clk_ops_rcg_hdmi = clk_ops_rcg;
-	clk_ops_rcg_hdmi.set_rate = rcg_clk_set_rate_hdmi;
-
-	/*
-	 * MDSS needs the ahb clock and needs to init before we register the
-	 * lookup table.
-	 */
-	mdss_clk_ctrl_pre_init(&mdss_ahb_clk.c);
-}
-
 static void __init msm8974_clock_post_init(void)
 {
 	if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2) {
@@ -5689,7 +5518,11 @@
 			qup_i2c_clks[i][0]->parent =  qup_i2c_clks[i][1];
 	}
 
-	mdss_clock_setup();
+	/*
+	 * MDSS needs the ahb clock and needs to init before we register the
+	 * lookup table.
+	 */
+	mdss_clk_ctrl_pre_init(&mdss_ahb_clk.c);
 }
 
 static int __init msm8974_clock_late_init(void)
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index dd78557..214d1b7 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -624,6 +624,148 @@
 	return HANDOFF_ENABLED_CLK;
 }
 
+static enum handoff byte_rcg_handoff(struct clk *clk)
+{
+	struct rcg_clk *rcg = to_rcg_clk(clk);
+	u32 div_val;
+	unsigned long pre_div_rate, parent_rate = clk_get_rate(clk->parent);
+
+	/* If the pre-divider is used, find the rate after the division */
+	div_val = readl_relaxed(CFG_RCGR_REG(rcg)) & CFG_RCGR_DIV_MASK;
+	if (div_val > 1)
+		pre_div_rate = parent_rate / ((div_val + 1) >> 1);
+	else
+		pre_div_rate = parent_rate;
+
+	clk->rate = pre_div_rate;
+
+	if (readl_relaxed(CMD_RCGR_REG(rcg)) & CMD_RCGR_ROOT_STATUS_BIT)
+		return HANDOFF_DISABLED_CLK;
+
+	return HANDOFF_ENABLED_CLK;
+}
+
+static int set_rate_byte(struct clk *clk, unsigned long rate)
+{
+	struct rcg_clk *rcg = to_rcg_clk(clk);
+	struct clk *pll = clk->parent;
+	unsigned long source_rate, div;
+	struct clk_freq_tbl *byte_freq = rcg->current_freq;
+	int rc;
+
+	if (rate == 0)
+		return -EINVAL;
+
+	rc = clk_set_rate(pll, rate);
+	if (rc)
+		return rc;
+
+	source_rate = clk_round_rate(pll, rate);
+	if ((2 * source_rate) % rate)
+		return -EINVAL;
+
+	div = ((2 * source_rate)/rate) - 1;
+	if (div > CFG_RCGR_DIV_MASK)
+		return -EINVAL;
+
+	byte_freq->div_src_val &= ~CFG_RCGR_DIV_MASK;
+	byte_freq->div_src_val |= BVAL(4, 0, div);
+	set_rate_hid(rcg, byte_freq);
+
+	return 0;
+}
+
+static enum handoff pixel_rcg_handoff(struct clk *clk)
+{
+	struct rcg_clk *rcg = to_rcg_clk(clk);
+	u32 div_val, mval, nval, cfg_regval;
+	unsigned long pre_div_rate, parent_rate = clk_get_rate(clk->parent);
+
+	cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg));
+
+	/* If the pre-divider is used, find the rate after the division */
+	div_val = cfg_regval & CFG_RCGR_DIV_MASK;
+	if (div_val > 1)
+		pre_div_rate = parent_rate / ((div_val + 1) >> 1);
+	else
+		pre_div_rate = parent_rate;
+
+	clk->rate = pre_div_rate;
+
+	/* If MND is used, find the rate after the MND division */
+	if ((cfg_regval & MND_MODE_MASK) == MND_DUAL_EDGE_MODE_BVAL) {
+		mval = readl_relaxed(M_REG(rcg));
+		nval = readl_relaxed(N_REG(rcg));
+		if (!nval)
+			return HANDOFF_DISABLED_CLK;
+		nval = (~nval) + mval;
+		clk->rate = (pre_div_rate * mval) / nval;
+	}
+
+	if (readl_relaxed(CMD_RCGR_REG(rcg)) & CMD_RCGR_ROOT_STATUS_BIT)
+		return HANDOFF_DISABLED_CLK;
+
+	return HANDOFF_ENABLED_CLK;
+}
+
+static int set_rate_pixel(struct clk *clk, unsigned long rate)
+{
+	struct rcg_clk *rcg = to_rcg_clk(clk);
+	struct clk *pll = clk->parent;
+	unsigned long source_rate, div;
+	struct clk_freq_tbl *pixel_freq = rcg->current_freq;
+	int rc;
+
+	if (rate == 0)
+		return -EINVAL;
+
+	rc = clk_set_rate(pll, rate);
+	if (rc)
+		return rc;
+
+	source_rate = clk_round_rate(pll, rate);
+	if ((2 * source_rate) % rate)
+		return -EINVAL;
+
+	div = ((2 * source_rate)/rate) - 1;
+	if (div > CFG_RCGR_DIV_MASK)
+		return -EINVAL;
+
+	pixel_freq->div_src_val &= ~CFG_RCGR_DIV_MASK;
+	pixel_freq->div_src_val |= BVAL(4, 0, div);
+	set_rate_mnd(rcg, pixel_freq);
+
+	return 0;
+}
+
+/*
+ * Unlike other clocks, the HDMI rate is adjusted through PLL
+ * re-programming. It is also routed through an HID divider.
+ */
+static int rcg_clk_set_rate_hdmi(struct clk *c, unsigned long rate)
+{
+	struct clk_freq_tbl *nf;
+	struct rcg_clk *rcg = to_rcg_clk(c);
+	int rc;
+
+	for (nf = rcg->freq_tbl; nf->freq_hz != rate; nf++)
+		if (nf->freq_hz == FREQ_END) {
+			rc = -EINVAL;
+			goto out;
+		}
+
+	rc = clk_set_rate(nf->src_clk, rate);
+	if (rc < 0)
+		goto out;
+	set_rate_hid(rcg, nf);
+
+	rcg->current_freq = nf;
+	c->parent = nf->src_clk;
+out:
+	return rc;
+}
+
+
 struct clk_ops clk_ops_empty;
 
 struct clk_ops clk_ops_rcg = {
@@ -644,6 +786,32 @@
 	.get_parent = rcg_mnd_clk_get_parent,
 };
 
+struct clk_ops clk_ops_pixel = {
+	.enable = rcg_clk_prepare,
+	.set_rate = set_rate_pixel,
+	.list_rate = rcg_clk_list_rate,
+	.round_rate = rcg_clk_round_rate,
+	.handoff = pixel_rcg_handoff,
+};
+
+struct clk_ops clk_ops_byte = {
+	.enable = rcg_clk_prepare,
+	.set_rate = set_rate_byte,
+	.list_rate = rcg_clk_list_rate,
+	.round_rate = rcg_clk_round_rate,
+	.handoff = byte_rcg_handoff,
+};
+
+struct clk_ops clk_ops_rcg_hdmi = {
+	.enable = rcg_clk_prepare,
+	.set_rate = rcg_clk_set_rate_hdmi,
+	.set_rate = rcg_clk_set_rate,
+	.list_rate = rcg_clk_list_rate,
+	.round_rate = rcg_clk_round_rate,
+	.handoff = rcg_clk_handoff,
+	.get_parent = rcg_clk_get_parent,
+};
+
 struct clk_ops clk_ops_branch = {
 	.enable = branch_clk_enable,
 	.disable = branch_clk_disable,
diff --git a/arch/arm/mach-msm/clock-local2.h b/arch/arm/mach-msm/clock-local2.h
index 2e1b8a9..7ac7bd3 100644
--- a/arch/arm/mach-msm/clock-local2.h
+++ b/arch/arm/mach-msm/clock-local2.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
@@ -173,6 +173,9 @@
 extern struct clk_ops clk_ops_rcg_mnd;
 extern struct clk_ops clk_ops_branch;
 extern struct clk_ops clk_ops_vote;
+extern struct clk_ops clk_ops_rcg_hdmi;
+extern struct clk_ops clk_ops_byte;
+extern struct clk_ops clk_ops_pixel;
 
 /*
  * Clock definition macros
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index c6e93de..c5c4988 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -96,6 +96,8 @@
  * @list:	List head to link all iommus together
  * @clk_reg_virt: Optional clock register virtual address.
  * @halt_enabled: Set to 1 if IOMMU halt is supported in the IOMMU, 0 otherwise.
+ * @asid:         List of ASID and their usage count (index is ASID value).
+ * @ctx_attach_count: Count of how many context are attached.
  *
  * A msm_iommu_drvdata holds the global driver data about a single piece
  * of an IOMMU hardware instance.
@@ -117,6 +119,8 @@
 	struct list_head list;
 	void __iomem *clk_reg_virt;
 	int halt_enabled;
+	int *asid;
+	unsigned int ctx_attach_count;
 };
 
 void msm_iommu_add_drv(struct msm_iommu_drvdata *drv);
diff --git a/arch/arm/mach-msm/include/mach/iommu_perfmon.h b/arch/arm/mach-msm/include/mach/iommu_perfmon.h
index 5a01bee..c03c752 100644
--- a/arch/arm/mach-msm/include/mach/iommu_perfmon.h
+++ b/arch/arm/mach-msm/include/mach/iommu_perfmon.h
@@ -12,6 +12,7 @@
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <linux/list.h>
+#include <linux/irqreturn.h>
 
 #ifndef MSM_IOMMU_PERFMON_H
 #define MSM_IOMMU_PERFMON_H
diff --git a/arch/arm/mach-msm/include/mach/ipa.h b/arch/arm/mach-msm/include/mach/ipa.h
index 5ccdf82..f2a4427 100644
--- a/arch/arm/mach-msm/include/mach/ipa.h
+++ b/arch/arm/mach-msm/include/mach/ipa.h
@@ -438,6 +438,9 @@
 	int (*release_resource)(void);
 };
 
+#define A2_MUX_HDR_NAME_V4_PREF "dmux_hdr_v4_"
+#define A2_MUX_HDR_NAME_V6_PREF "dmux_hdr_v6_"
+
 enum a2_mux_event_type {
 	A2_MUX_RECEIVE,
 	A2_MUX_WRITE_DONE
@@ -460,26 +463,28 @@
 		enum a2_mux_event_type event,
 		unsigned long data);
 
-#ifdef CONFIG_IPA
-
-/*
- * a2 service
+/**
+ * enum teth_tethering_mode - Tethering mode (Rmnet / MBIM)
  */
-int a2_mux_open_channel(enum a2_mux_logical_channel_id lcid,
-			void *user_data,
-			a2_mux_notify_cb notify_cb);
+enum teth_tethering_mode {
+	TETH_TETHERING_MODE_RMNET,
+	TETH_TETHERING_MODE_MBIM,
+	TETH_TETHERING_MODE_MAX,
+};
 
-int a2_mux_close_channel(enum a2_mux_logical_channel_id lcid);
+/**
+ * struct teth_bridge_connect_params - Parameters used in teth_bridge_connect()
+ * @ipa_usb_pipe_hdl:	IPA to USB pipe handle, returned from ipa_connect()
+ * @usb_ipa_pipe_hdl:	USB to IPA pipe handle, returned from ipa_connect()
+ * @tethering_mode:	Rmnet or MBIM
+ */
+struct teth_bridge_connect_params {
+	u32 ipa_usb_pipe_hdl;
+	u32 usb_ipa_pipe_hdl;
+	enum teth_tethering_mode tethering_mode;
+};
 
-int a2_mux_write(enum a2_mux_logical_channel_id lcid, struct sk_buff *skb);
-
-int a2_mux_is_ch_low(enum a2_mux_logical_channel_id lcid);
-
-int a2_mux_is_ch_full(enum a2_mux_logical_channel_id lcid);
-
-int a2_mux_get_tethered_client_handles(enum a2_mux_logical_channel_id lcid,
-		unsigned int *clnt_cons_handle,
-		unsigned int *clnt_prod_handle);
+#ifdef CONFIG_IPA
 
 /*
  * Connect / Disconnect
@@ -649,6 +654,34 @@
 int ipa_rm_inactivity_timer_release_resource(
 				enum ipa_rm_resource_name resource_name);
 
+/*
+ * a2 service
+ */
+int a2_mux_open_channel(enum a2_mux_logical_channel_id lcid,
+			void *user_data,
+			a2_mux_notify_cb notify_cb);
+
+int a2_mux_close_channel(enum a2_mux_logical_channel_id lcid);
+
+int a2_mux_write(enum a2_mux_logical_channel_id lcid, struct sk_buff *skb);
+
+int a2_mux_is_ch_low(enum a2_mux_logical_channel_id lcid);
+
+int a2_mux_is_ch_full(enum a2_mux_logical_channel_id lcid);
+
+int a2_mux_get_tethered_client_handles(enum a2_mux_logical_channel_id lcid,
+		unsigned int *clnt_cons_handle,
+		unsigned int *clnt_prod_handle);
+
+/*
+ * Tethering bridge (Rmnet / MBIM)
+ */
+int teth_bridge_init(ipa_notify_cb *usb_notify_cb_ptr, void **private_data_ptr);
+
+int teth_bridge_disconnect(void);
+
+int teth_bridge_connect(struct teth_bridge_connect_params *connect_params);
+
 #else /* CONFIG_IPA */
 
 static inline int a2_mux_open_channel(enum a2_mux_logical_channel_id lcid,
@@ -685,7 +718,6 @@
 	return -EPERM;
 }
 
-
 /*
  * Connect / Disconnect
  */
@@ -1051,6 +1083,26 @@
 	return -EPERM;
 }
 
+/*
+ * Tethering bridge (Rmnetm / MBIM)
+ */
+static inline int teth_bridge_init(ipa_notify_cb *usb_notify_cb_ptr,
+				   void **private_data_ptr)
+{
+	return -EPERM;
+}
+
+static inline int teth_bridge_disconnect(void)
+{
+	return -EPERM;
+}
+
+static inline int teth_bridge_connect(struct teth_bridge_connect_params
+				      *connect_params)
+{
+	return -EPERM;
+}
+
 #endif /* CONFIG_IPA*/
 
 #endif /* _IPA_H_ */
diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h
index cf68108..d3574c8 100644
--- a/arch/arm/mach-msm/include/mach/memory.h
+++ b/arch/arm/mach-msm/include/mach/memory.h
@@ -75,14 +75,9 @@
 void clean_and_invalidate_caches(unsigned long, unsigned long, unsigned long);
 void clean_caches(unsigned long, unsigned long, unsigned long);
 void invalidate_caches(unsigned long, unsigned long, unsigned long);
-int platform_physical_remove_pages(u64, u64);
-int platform_physical_active_pages(u64, u64);
-int platform_physical_low_power_pages(u64, u64);
 int msm_get_memory_type_from_name(const char *memtype_name);
 unsigned long get_ddr_size(void);
 
-extern int (*change_memory_power)(u64, u64, int);
-
 #if defined(CONFIG_ARCH_MSM_ARM11) || defined(CONFIG_ARCH_MSM_CORTEX_A5)
 void write_to_strongly_ordered_memory(void);
 void map_page_strongly_ordered(void);
diff --git a/arch/arm/mach-msm/include/mach/msm_memtypes.h b/arch/arm/mach-msm/include/mach/msm_memtypes.h
index a989059..264dad5 100644
--- a/arch/arm/mach-msm/include/mach/msm_memtypes.h
+++ b/arch/arm/mach-msm/include/mach/msm_memtypes.h
@@ -29,7 +29,6 @@
 unsigned int get_num_memory_banks(void);
 unsigned int get_memory_bank_size(unsigned int);
 unsigned int get_memory_bank_start(unsigned int);
-int soc_change_memory_power(u64, u64, int);
 
 enum {
 	MEMTYPE_NONE = -1,
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
index 2748636..a8c7bb7 100644
--- a/arch/arm/mach-msm/include/mach/msm_smd.h
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -1,7 +1,7 @@
 /* linux/include/asm-arm/arch-msm/msm_smd.h
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-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
@@ -141,8 +141,8 @@
  * @size: size of the region in bytes
  */
 struct smd_smem_regions {
-	void *phys_addr;
-	unsigned size;
+	phys_addr_t phys_addr;
+	resource_size_t size;
 };
 
 struct smd_platform {
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index 02272bc..eb44c40 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -19,15 +19,15 @@
 #include <linux/rbtree.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
 #include <asm/sizes.h>
 #include <asm/page.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
 #include <mach/socinfo.h>
 #include <mach/msm_subsystem_map.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
 
 struct msm_iova_data {
 	struct rb_node node;
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index 2cec5c5..a08e7de 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -20,6 +20,9 @@
 #include <linux/fcntl.h>
 #include <linux/gfp.h>
 #include <linux/msm_ipc.h>
+#include <linux/sched.h>
+#include <linux/thread_info.h>
+#include <linux/qmi_encdec.h>
 
 #include <asm/string.h>
 #include <asm/atomic.h>
@@ -27,16 +30,93 @@
 #include <net/sock.h>
 
 #include <mach/msm_ipc_router.h>
+#include <mach/msm_ipc_logging.h>
 
 #include "ipc_router.h"
 #include "msm_ipc_router_security.h"
 
 #define msm_ipc_sk(sk) ((struct msm_ipc_sock *)(sk))
 #define msm_ipc_sk_port(sk) ((struct msm_ipc_port *)(msm_ipc_sk(sk)->port))
+#define REQ_RESP_IPC_LOG_PAGES 5
+#define IND_IPC_LOG_PAGES 5
+#define IPC_SEND 1
+#define IPC_RECV 2
+#define IPC_REQ_RESP_LOG(level, buf...) \
+do { \
+	if (ipc_req_resp_log_txt) { \
+		ipc_log_string(ipc_req_resp_log_txt, buf); \
+	} \
+} while (0) \
+
+#define IPC_IND_LOG(level, buf...) \
+do { \
+	if (ipc_ind_log_txt) { \
+		ipc_log_string(ipc_ind_log_txt, buf); \
+	} \
+} while (0) \
 
 static int sockets_enabled;
 static struct proto msm_ipc_proto;
 static const struct proto_ops msm_ipc_proto_ops;
+static void *ipc_req_resp_log_txt;
+static void *ipc_ind_log_txt;
+
+/**
+ * msm_ipc_router_ipc_log() - Pass log data to IPC logging framework
+ * @tran:	Identifies the data to be a receive or send.
+ * @ipc_buf:	Buffer to extract the log data.
+ * @port_ptr:	IPC Router port corresponding to the current log data.
+ *
+ * This function builds the data the would be passed on to the IPC logging
+ * framework. The data that would be passed corresponds to the information
+ * that is exchanged between the IPC Router and user space modules during
+ * request/response/indication transactions.
+ */
+
+static void msm_ipc_router_ipc_log(uint8_t tran,
+			struct sk_buff *ipc_buf, struct msm_ipc_port *port_ptr)
+{
+	struct qmi_header *hdr = (struct qmi_header *)ipc_buf->data;
+
+	/*
+	 * IPC Logging format is as below:-
+	 * <Name>(Name of the User Space Process):
+	 * <PID> (PID of the user space process) :
+	 * <TID> (TID of the user space thread)  :
+	 * <User Space Module>(CLNT or  SERV)    :
+	 * <Opertaion Type> (Transmit)		 :
+	 * <Control Flag> (Req/Resp/Ind)	 :
+	 * <Transaction ID>			 :
+	 * <Message ID>				 :
+	 * <Message Length>			 :
+	 */
+	if (ipc_req_resp_log_txt &&
+		(((uint8_t) hdr->cntl_flag == QMI_REQUEST_CONTROL_FLAG) ||
+		((uint8_t) hdr->cntl_flag == QMI_RESPONSE_CONTROL_FLAG)) &&
+		(port_ptr->type == CLIENT_PORT ||
+					port_ptr->type == SERVER_PORT)) {
+		IPC_REQ_RESP_LOG(KERN_DEBUG,
+			"%s %d %d %s %s CF:%x TI:%x MI:%x ML:%x",
+			current->comm, current->tgid, current->pid,
+			(port_ptr->type == CLIENT_PORT ? "QCCI" : "QCSI"),
+			(tran == IPC_RECV ? "RX" :
+			(tran == IPC_SEND ? "TX" : "ERR")),
+			(uint8_t)hdr->cntl_flag, hdr->txn_id, hdr->msg_id,
+			hdr->msg_len);
+	} else if (ipc_ind_log_txt &&
+		((uint8_t)hdr->cntl_flag == QMI_INDICATION_CONTROL_FLAG) &&
+		(port_ptr->type == CLIENT_PORT ||
+					port_ptr->type == SERVER_PORT)) {
+		IPC_IND_LOG(KERN_DEBUG,
+			"%s %d %d %s %s CF:%x TI:%x MI:%x ML:%x",
+			current->comm, current->tgid, current->pid,
+			(port_ptr->type == CLIENT_PORT ? "QCCI" : "QCSI"),
+			(tran == IPC_RECV ? "RX" :
+			(tran == IPC_SEND ? "TX" : "ERR")),
+			(uint8_t)hdr->cntl_flag, hdr->txn_id, hdr->msg_id,
+			hdr->msg_len);
+	}
+}
 
 static struct sk_buff_head *msm_ipc_router_build_msg(unsigned int num_sect,
 					  struct iovec const *msg_sect,
@@ -263,6 +343,7 @@
 	struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
 	struct sockaddr_msm_ipc *dest = (struct sockaddr_msm_ipc *)m->msg_name;
 	struct sk_buff_head *msg;
+	struct sk_buff *ipc_buf;
 	int ret;
 
 	if (!dest)
@@ -284,7 +365,8 @@
 
 	if (port_ptr->type == CLIENT_PORT)
 		wait_for_irsc_completion();
-
+	ipc_buf = skb_peek(msg);
+	msm_ipc_router_ipc_log(IPC_SEND, ipc_buf, port_ptr);
 	ret = msm_ipc_router_send_to(port_ptr, msg, &dest->address);
 	if (ret == (IPC_ROUTER_HDR_SIZE + total_len))
 		ret = total_len;
@@ -300,6 +382,7 @@
 	struct sock *sk = sock->sk;
 	struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
 	struct sk_buff_head *msg;
+	struct sk_buff *ipc_buf;
 	long timeout;
 	int ret;
 
@@ -344,6 +427,8 @@
 	}
 
 	ret = msm_ipc_router_extract_msg(m, msg);
+	ipc_buf = skb_peek(msg);
+	msm_ipc_router_ipc_log(IPC_RECV, ipc_buf, port_ptr);
 	msm_ipc_router_release_msg(msg);
 	msg = NULL;
 	release_sock(sk);
@@ -518,6 +603,29 @@
 	.obj_size       = sizeof(struct msm_ipc_sock),
 };
 
+/**
+ * msm_ipc_router_ipc_log_init() - Init function for IPC Logging
+ *
+ * Initialize the buffers to be used to provide the log information
+ * pertaining to the request, response and indication data flow that
+ * happens between user and kernel spaces.
+ */
+void msm_ipc_router_ipc_log_init(void)
+{
+	ipc_req_resp_log_txt =
+		ipc_log_context_create(REQ_RESP_IPC_LOG_PAGES, "req_resp");
+	if (!ipc_req_resp_log_txt) {
+		pr_err("%s: Unable to create IPC logging for Req/Resp",
+			__func__);
+	}
+	ipc_ind_log_txt =
+		ipc_log_context_create(IND_IPC_LOG_PAGES, "indication");
+	if (!ipc_ind_log_txt) {
+		pr_err("%s: Unable to create IPC logging for Indications",
+			__func__);
+	}
+}
+
 int msm_ipc_router_init_sockets(void)
 {
 	int ret;
@@ -536,6 +644,7 @@
 	}
 
 	sockets_enabled = 1;
+	msm_ipc_router_ipc_log_init();
 out_init_sockets:
 	return ret;
 }
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 0c1e279..8fe69d9 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -145,6 +145,7 @@
  *				regulator's callback functions to prevent
  *				simultaneous updates to the pmic's phase
  *				voltage.
+ * @apcs_gcc_base		virtual address of the APCS GCC registers
  */
 struct pmic_gang_vreg {
 	const char		*name;
@@ -155,6 +156,8 @@
 	bool			pfm_mode;
 	int			pmic_min_uV_for_retention;
 	bool			retention_enabled;
+	bool			use_phase_switching;
+	void __iomem		*apcs_gcc_base;
 };
 
 static struct pmic_gang_vreg *the_gang;
@@ -390,13 +393,17 @@
 	return 0;
 }
 
-static int set_pmic_gang_phases(int phase_count)
+static int set_pmic_gang_phases(struct pmic_gang_vreg *pvreg, int phase_count)
 {
-	/*
-	 * TODO : spm writes for phase control,
-	 * pmic phase control is not working yet
-	 */
-	return 0;
+	pr_debug("programming phase_count = %d\n", phase_count);
+	if (pvreg->use_phase_switching)
+		/*
+		 * note the PMIC sets the phase count to one more than
+		 * the value in the register - hence subtract 1 from it
+		 */
+		return msm_spm_apcs_set_phase(phase_count - 1);
+	else
+		return 0;
 }
 
 static int set_pmic_gang_voltage(struct pmic_gang_vreg *pvreg, int uV)
@@ -547,14 +554,19 @@
 				int load_uA)
 {
 	struct pmic_gang_vreg *pvreg = from->pvreg;
-	int phase_count = DIV_ROUND_UP(load_uA, LOAD_PER_PHASE) - 1;
+	int phase_count = DIV_ROUND_UP(load_uA, LOAD_PER_PHASE);
 	int rc = 0;
 
-	if (phase_count < 0)
-		phase_count = 0;
+	if (phase_count <= 0)
+		phase_count = 1;
+
+	 /* Increase phases if it is less than the number of cpus online */
+	if (phase_count < num_online_cpus()) {
+		phase_count = num_online_cpus();
+	}
 
 	if (phase_count != pvreg->pmic_phase_count) {
-		rc = set_pmic_gang_phases(phase_count);
+		rc = set_pmic_gang_phases(pvreg, phase_count);
 		if (rc < 0) {
 			dev_err(&from->rdev->dev,
 				"%s failed set phase %d rc = %d\n",
@@ -577,32 +589,6 @@
 	return rc;
 }
 
-static int __devinit pvreg_init(struct platform_device *pdev)
-{
-	struct pmic_gang_vreg *pvreg;
-
-	pvreg = devm_kzalloc(&pdev->dev,
-			sizeof(struct pmic_gang_vreg), GFP_KERNEL);
-	if (!pvreg) {
-		pr_err("kzalloc failed.\n");
-		return -ENOMEM;
-	}
-
-	pvreg->name = "pmic_gang";
-	pvreg->pmic_vmax_uV = PMIC_VOLTAGE_MIN;
-	pvreg->pmic_phase_count = 1;
-	pvreg->retention_enabled = true;
-	pvreg->pmic_min_uV_for_retention = INT_MAX;
-
-	mutex_init(&pvreg->krait_power_vregs_lock);
-	INIT_LIST_HEAD(&pvreg->krait_power_vregs);
-	the_gang = pvreg;
-
-	pr_debug("name=%s inited\n", pvreg->name);
-
-	return 0;
-}
-
 static int krait_power_get_voltage(struct regulator_dev *rdev)
 {
 	struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev);
@@ -906,12 +892,12 @@
 	mb();
 }
 
-static void glb_init(struct platform_device *pdev)
+static void glb_init(void __iomem *apcs_gcc_base)
 {
 	/* configure bi-modal switch */
-	writel_relaxed(0x0008736E, MSM_APCS_GCC_BASE + PWR_GATE_CONFIG);
+	writel_relaxed(0x0008736E, apcs_gcc_base + PWR_GATE_CONFIG);
 	/* read kpss version */
-	version = readl_relaxed(MSM_APCS_GCC_BASE + VERSION);
+	version = readl_relaxed(apcs_gcc_base + VERSION);
 	pr_debug("version= 0x%x\n", version);
 }
 
@@ -925,24 +911,6 @@
 	int ldo_delta_uV;
 	int cpu_num;
 
-	/* Initialize the pmic gang if it hasn't been initialized already */
-	if (the_gang == NULL) {
-		rc = pvreg_init(pdev);
-		if (rc < 0) {
-			dev_err(&pdev->dev,
-				"failed to init pmic gang rc = %d\n", rc);
-			return rc;
-		}
-		/* global initializtion */
-		glb_init(pdev);
-	}
-
-	if (dent == NULL) {
-		dent = debugfs_create_dir(KRAIT_REGULATOR_DRIVER_NAME, NULL);
-		debugfs_create_file("retention_uV",
-				0644, dent, the_gang, &retention_fops);
-	}
-
 	if (pdev->dev.of_node) {
 		/* Get init_data from device tree. */
 		init_data = of_get_regulator_init_data(&pdev->dev,
@@ -1139,14 +1107,106 @@
 	},
 };
 
+static struct of_device_id krait_pdn_match_table[] = {
+	{ .compatible = "qcom,krait-pdn", },
+	{}
+};
+
+static int __devinit krait_pdn_probe(struct platform_device *pdev)
+{
+	int rc;
+	bool use_phase_switching = false;
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node;
+	struct pmic_gang_vreg *pvreg;
+	struct resource *res;
+
+	if (!dev->of_node) {
+		dev_err(dev, "device tree information missing\n");
+		return -ENODEV;
+	}
+
+	use_phase_switching = of_property_read_bool(node,
+						"qcom,use-phase-switching");
+	pvreg = devm_kzalloc(&pdev->dev,
+			sizeof(struct pmic_gang_vreg), GFP_KERNEL);
+	if (!pvreg) {
+		pr_err("kzalloc failed.\n");
+		return 0;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apcs_gcc");
+	if (!res) {
+		dev_err(&pdev->dev, "missing apcs gcc base addresses\n");
+		return -EINVAL;
+	}
+
+	pvreg->apcs_gcc_base = devm_ioremap(&pdev->dev, res->start,
+					    resource_size(res));
+
+	if (pvreg->apcs_gcc_base == NULL)
+		return -ENOMEM;
+
+	pvreg->name = "pmic_gang";
+	pvreg->pmic_vmax_uV = PMIC_VOLTAGE_MIN;
+	pvreg->pmic_phase_count = -EINVAL;
+	pvreg->retention_enabled = true;
+	pvreg->pmic_min_uV_for_retention = INT_MAX;
+	pvreg->use_phase_switching = use_phase_switching;
+
+	mutex_init(&pvreg->krait_power_vregs_lock);
+	INIT_LIST_HEAD(&pvreg->krait_power_vregs);
+	the_gang = pvreg;
+
+	pr_debug("name=%s inited\n", pvreg->name);
+
+	/* global initializtion */
+	glb_init(pvreg->apcs_gcc_base);
+
+	rc = of_platform_populate(node, NULL, NULL, dev);
+	if (rc) {
+		dev_err(dev, "failed to add child nodes, rc=%d\n", rc);
+		return rc;
+	}
+
+	dent = debugfs_create_dir(KRAIT_REGULATOR_DRIVER_NAME, NULL);
+	debugfs_create_file("retention_uV",
+			0644, dent, the_gang, &retention_fops);
+	return 0;
+}
+
+static int __devexit krait_pdn_remove(struct platform_device *pdev)
+{
+	the_gang = NULL;
+	debugfs_remove_recursive(dent);
+	return 0;
+}
+
+static struct platform_driver krait_pdn_driver = {
+	.probe	= krait_pdn_probe,
+	.remove	= __devexit_p(krait_pdn_remove),
+	.driver	= {
+		.name		= KRAIT_PDN_DRIVER_NAME,
+		.of_match_table	= krait_pdn_match_table,
+		.owner		= THIS_MODULE,
+	},
+};
+
 int __init krait_power_init(void)
 {
-	return platform_driver_register(&krait_power_driver);
+	int rc = platform_driver_register(&krait_power_driver);
+	if (rc) {
+		pr_err("failed to add %s driver rc = %d\n",
+				KRAIT_REGULATOR_DRIVER_NAME, rc);
+		return rc;
+	}
+	return platform_driver_register(&krait_pdn_driver);
 }
 
 static void __exit krait_power_exit(void)
 {
 	platform_driver_unregister(&krait_power_driver);
+	platform_driver_unregister(&krait_pdn_driver);
 }
 module_exit(krait_power_exit);
 
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index 806581d..f3bd34a 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -135,29 +135,6 @@
 	return (void *)addr;
 }
 
-int (*change_memory_power)(u64, u64, int);
-
-int platform_physical_remove_pages(u64 start, u64 size)
-{
-	if (!change_memory_power)
-		return 0;
-	return change_memory_power(start, size, MEMORY_DEEP_POWERDOWN);
-}
-
-int platform_physical_active_pages(u64 start, u64 size)
-{
-	if (!change_memory_power)
-		return 0;
-	return change_memory_power(start, size, MEMORY_ACTIVE);
-}
-
-int platform_physical_low_power_pages(u64 start, u64 size)
-{
-	if (!change_memory_power)
-		return 0;
-	return change_memory_power(start, size, MEMORY_SELF_REFRESH);
-}
-
 char *memtype_name[] = {
 	"SMI_KERNEL",
 	"SMI",
diff --git a/arch/arm/mach-msm/memory_topology.c b/arch/arm/mach-msm/memory_topology.c
index 772e63e..781cd69 100644
--- a/arch/arm/mach-msm/memory_topology.c
+++ b/arch/arm/mach-msm/memory_topology.c
@@ -66,136 +66,6 @@
 }
 #endif
 
-#if (defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_MSM8930)) \
-	&& defined(CONFIG_ENABLE_DMM)
-static int rpm_change_memory_state(int retention_mask,
-					int active_mask)
-{
-	int ret;
-	struct msm_rpm_iv_pair cmd[2];
-	struct msm_rpm_iv_pair status[2];
-
-	cmd[0].id = MSM_RPM_ID_DDR_DMM_0;
-	cmd[1].id = MSM_RPM_ID_DDR_DMM_1;
-
-	status[0].id = MSM_RPM_STATUS_ID_DDR_DMM_0;
-	status[1].id = MSM_RPM_STATUS_ID_DDR_DMM_1;
-
-	cmd[0].value = retention_mask;
-	cmd[1].value = active_mask;
-
-	ret = msm_rpm_set(MSM_RPM_CTX_SET_0, cmd, 2);
-	if (ret < 0) {
-		pr_err("rpm set failed");
-		return -EINVAL;
-	}
-
-	ret = msm_rpm_get_status(status, 2);
-	if (ret < 0) {
-		pr_err("rpm status failed");
-		return -EINVAL;
-	}
-	if (status[0].value == retention_mask &&
-		status[1].value == active_mask)
-		return 0;
-	else {
-		pr_err("rpm failed to change memory state");
-		return -EINVAL;
-	}
-}
-
-static int switch_memory_state(int mask, int new_state, int start_region,
-				int end_region)
-{
-	int final_mask = 0;
-	int i;
-
-	mutex_lock(&mem_regions_mutex);
-
-	for (i = start_region; i <= end_region; i++) {
-		if (new_state == mem_regions[i].state)
-			goto no_change;
-		/* All region states must be the same to change them */
-		if (mem_regions[i].state != mem_regions[start_region].state)
-			goto no_change;
-	}
-
-	if (new_state == STATE_POWER_DOWN)
-		final_mask = mem_regions_mask & mask;
-	else if (new_state == STATE_ACTIVE)
-		final_mask = mem_regions_mask | ~mask;
-	else
-		goto no_change;
-
-	pr_info("request memory %d to %d state switch (%d->%d)\n",
-		start_region, end_region, mem_regions[start_region].state,
-		new_state);
-	if (rpm_change_memory_state(final_mask, final_mask) == 0) {
-		for (i = start_region; i <= end_region; i++)
-			mem_regions[i].state = new_state;
-		mem_regions_mask = final_mask;
-
-		pr_info("completed memory %d to %d state switch to %d\n",
-			start_region, end_region, new_state);
-		mutex_unlock(&mem_regions_mutex);
-		return 0;
-	}
-
-	pr_err("failed memory %d to %d state switch (%d->%d)\n",
-		start_region, end_region, mem_regions[start_region].state,
-		new_state);
-
-no_change:
-	mutex_unlock(&mem_regions_mutex);
-	return -EINVAL;
-}
-#else
-
-static int switch_memory_state(int mask, int new_state, int start_region,
-				int end_region)
-{
-	return -EINVAL;
-}
-#endif
-
-/* The hotplug code expects the number of bytes that switched state successfully
- * as the return value, so a return value of zero indicates an error
-*/
-int soc_change_memory_power(u64 start, u64 size, int change)
-{
-	int i = 0;
-	int mask = default_mask;
-	u64 end = start + size;
-	int start_region = 0;
-	int end_region = 0;
-
-	if (change != STATE_ACTIVE && change != STATE_POWER_DOWN) {
-		pr_info("requested state transition invalid\n");
-		return 0;
-	}
-	/* Find the memory regions that fall within the range */
-	for (i = 0; i < nr_mem_regions; i++) {
-		if (mem_regions[i].start <= start &&
-			mem_regions[i].start >=
-			mem_regions[start_region].start) {
-			start_region = i;
-		}
-		if (end <= mem_regions[i].start + mem_regions[i].size) {
-			end_region = i;
-			break;
-		}
-	}
-
-	/* Set the bitmask for each region in the range */
-	for (i = start_region; i <= end_region; i++)
-		mask &= ~(0x1 << i);
-
-	if (!switch_memory_state(mask, change, start_region, end_region))
-		return size;
-	else
-		return 0;
-}
-
 unsigned int get_num_memory_banks(void)
 {
 	return nr_mem_regions;
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
index d416c19..3c8348d 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
@@ -1960,7 +1960,8 @@
 	struct msm_bus_bimc_info *binfo =
 		(struct msm_bus_bimc_info *)hw_data;
 
-	if (!IS_SLAVE(info->node_info->priv_id))
+	if (!IS_SLAVE(info->node_info->priv_id) &&
+		(info->node_info->hw_sel != MSM_BUS_RPM))
 		msm_bus_bimc_mas_init(binfo, info);
 }
 
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index cd6aaf4..aa42f5b 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -57,7 +57,7 @@
 #define RMB_PMI_CODE_LENGTH		0x18
 
 #define VDD_MSS_UV			1050000
-#define MAX_VDD_MX_UV			1050000
+#define MAX_VDD_MX_UV			1150000
 
 #define PROXY_TIMEOUT_MS		10000
 #define POLL_INTERVAL_US		50
diff --git a/arch/arm/mach-msm/qdsp5/audio_ac3.c b/arch/arm/mach-msm/qdsp5/audio_ac3.c
index 0363348..199b322 100644
--- a/arch/arm/mach-msm/qdsp5/audio_ac3.c
+++ b/arch/arm/mach-msm/qdsp5/audio_ac3.c
@@ -1,6 +1,6 @@
 /* arch/arm/mach-msm/audio_ac3.c
  *
- * Copyright (c) 2008-2009, 2011-2012 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2008-2009, 2011-2013 The Linux Foundation. All rights reserved.
  *
  * This code also borrows from audio_aac.c, which is
  * Copyright (C) 2008 Google, Inc.
@@ -186,8 +186,10 @@
 static void audac3_dsp_event(void *private, unsigned id, uint16_t *msg);
 static void audac3_config_hostpcm(struct audio *audio);
 static void audac3_buffer_refresh(struct audio *audio);
+#ifdef CONFIG_HAS_EARLYSUSPEND
 static void audac3_post_event(struct audio *audio, int type,
 		union msm_audio_event_payload payload);
+#endif
 
 static int rmt_put_resource(struct audio *audio)
 {
diff --git a/arch/arm/mach-msm/remote_spinlock.c b/arch/arm/mach-msm/remote_spinlock.c
index 4e09a9e..94923a0 100644
--- a/arch/arm/mach-msm/remote_spinlock.c
+++ b/arch/arm/mach-msm/remote_spinlock.c
@@ -196,6 +196,8 @@
 /* end swp implementation --------------------------------------------------- */
 
 /* ldrex implementation ----------------------------------------------------- */
+static char *ldrex_compatible_string = "qcom,ipc-spinlock-ldrex";
+
 static void __raw_remote_ex_spin_lock(raw_remote_spinlock_t *lock)
 {
 	unsigned long tmp;
@@ -267,7 +269,7 @@
 static void *hw_mutex_reg_base;
 static DEFINE_MUTEX(hw_map_init_lock);
 
-static char *compatible_string = "qcom,ipc-spinlock";
+static char *sfpb_compatible_string = "qcom,ipc-spinlock-sfpb";
 
 static int init_hw_mutex(struct device_node *node)
 {
@@ -294,7 +296,7 @@
 {
 	struct device_node *node;
 
-	node = of_find_compatible_node(NULL, NULL, compatible_string);
+	node = of_find_compatible_node(NULL, NULL, sfpb_compatible_string);
 	if (node) {
 		init_hw_mutex(node);
 	} else {
@@ -341,7 +343,9 @@
 
 static int __raw_remote_sfpb_spin_trylock(raw_remote_spinlock_t *lock)
 {
-	return 1;
+	writel_relaxed(SPINLOCK_PID_APPS, lock);
+	smp_mb();
+	return readl_relaxed(lock) == SPINLOCK_PID_APPS;
 }
 
 static void __raw_remote_sfpb_spin_unlock(raw_remote_spinlock_t *lock)
@@ -397,6 +401,23 @@
 }
 
 
+static int dt_node_is_valid(const struct device_node *node)
+{
+	const char *status;
+	int statlen;
+
+	status = of_get_property(node, "status", &statlen);
+	if (status == NULL)
+		return 1;
+
+	if (statlen > 0) {
+		if (!strcmp(status, "okay") || !strcmp(status, "ok"))
+			return 1;
+	}
+
+	return 0;
+}
+
 static void initialize_ops(void)
 {
 	struct device_node *node;
@@ -435,23 +456,42 @@
 		is_hw_lock_type = 1;
 		break;
 	case AUTO_MODE:
-		node = of_find_compatible_node(NULL, NULL, compatible_string);
-		if (node) {
+		/*
+		 * of_find_compatible_node() returns a valid pointer even if
+		 * the status property is "disabled", so the validity needs
+		 * to be checked
+		 */
+		node = of_find_compatible_node(NULL, NULL,
+						sfpb_compatible_string);
+		if (node && dt_node_is_valid(node)) {
 			current_ops.lock = __raw_remote_sfpb_spin_lock;
 			current_ops.unlock = __raw_remote_sfpb_spin_unlock;
 			current_ops.trylock = __raw_remote_sfpb_spin_trylock;
 			current_ops.release = __raw_remote_gen_spin_release;
 			current_ops.owner = __raw_remote_gen_spin_owner;
 			is_hw_lock_type = 1;
-		} else {
+			break;
+		}
+
+		node = of_find_compatible_node(NULL, NULL,
+						ldrex_compatible_string);
+		if (node && dt_node_is_valid(node)) {
 			current_ops.lock = __raw_remote_ex_spin_lock;
 			current_ops.unlock = __raw_remote_ex_spin_unlock;
 			current_ops.trylock = __raw_remote_ex_spin_trylock;
 			current_ops.release = __raw_remote_gen_spin_release;
 			current_ops.owner = __raw_remote_gen_spin_owner;
 			is_hw_lock_type = 0;
-			pr_warn("Falling back to LDREX remote spinlock implementation");
+			break;
 		}
+
+		current_ops.lock = __raw_remote_ex_spin_lock;
+		current_ops.unlock = __raw_remote_ex_spin_unlock;
+		current_ops.trylock = __raw_remote_ex_spin_trylock;
+		current_ops.release = __raw_remote_gen_spin_release;
+		current_ops.owner = __raw_remote_gen_spin_owner;
+		is_hw_lock_type = 0;
+		pr_warn("Falling back to LDREX remote spinlock implementation");
 		break;
 	default:
 		BUG();
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 10e40b4..cffb211 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -172,13 +172,13 @@
 };
 
 struct smem_area {
-	void *phys_addr;
-	unsigned size;
+	phys_addr_t phys_addr;
+	resource_size_t size;
 	void __iomem *virt_addr;
 };
 static uint32_t num_smem_areas;
 static struct smem_area *smem_areas;
-static void *smem_range_check(void *base, unsigned offset);
+static void *smem_range_check(phys_addr_t base, unsigned offset);
 
 struct interrupt_stat interrupt_stats[NUM_SMD_SUBSYSTEMS];
 
@@ -2365,11 +2365,11 @@
  * @base: physical base address to check
  * @offset: offset from the base to get the final address
  */
-static void *smem_range_check(void *base, unsigned offset)
+static void *smem_range_check(phys_addr_t base, unsigned offset)
 {
 	int i;
-	void *phys_addr;
-	unsigned size;
+	phys_addr_t phys_addr;
+	resource_size_t size;
 
 	for (i = 0; i < num_smem_areas; ++i) {
 		phys_addr = smem_areas[i].phys_addr;
@@ -2464,7 +2464,7 @@
 			ret = (void *) (MSM_SHARED_RAM_BASE + toc[id].offset);
 		else
 			ret = smem_range_check(
-				(void *)(toc[id].reserved & BASE_ADDR_MASK),
+				toc[id].reserved & BASE_ADDR_MASK,
 				toc[id].offset);
 	} else {
 		*size = 0;
@@ -3466,10 +3466,10 @@
 				(unsigned long)(smem_areas[smem_idx].phys_addr),
 				smem_areas[smem_idx].size);
 			if (!smem_areas[smem_idx].virt_addr) {
-				pr_err("%s: ioremap_nocache() of addr:%p"
-					" size: %x\n", __func__,
-					smem_areas[smem_idx].phys_addr,
-					smem_areas[smem_idx].size);
+				pr_err("%s: ioremap_nocache() of addr: %pa size: %pa\n",
+					__func__,
+					&smem_areas[smem_idx].phys_addr,
+					&smem_areas[smem_idx].size);
 				err_ret = -ENOMEM;
 				++smem_idx;
 				goto smem_failed;
@@ -3712,8 +3712,8 @@
 	char *key;
 	struct resource *r;
 	void *irq_out_base;
-	void *aux_mem_base;
-	uint32_t aux_mem_size;
+	phys_addr_t aux_mem_base;
+	resource_size_t aux_mem_size;
 	int temp_string_size = 11; /* max 3 digit count */
 	char temp_string[temp_string_size];
 	int count;
@@ -3721,6 +3721,7 @@
 	int ret;
 	const char *compatible;
 	int subnode_num = 0;
+	resource_size_t irq_out_size;
 
 	disable_smsm_reset_handshake = 1;
 
@@ -3730,7 +3731,13 @@
 		pr_err("%s: missing '%s'\n", __func__, key);
 		return -ENODEV;
 	}
-	irq_out_base = (void *)(r->start);
+	irq_out_size = resource_size(r);
+	irq_out_base = ioremap_nocache(r->start, irq_out_size);
+	if (!irq_out_base) {
+		pr_err("%s: ioremap_nocache() of irq_out_base addr:%pr size:%pr\n",
+				__func__, &r->start, &irq_out_size);
+		return -ENOMEM;
+	}
 	SMD_DBG("%s: %s = %p", __func__, key, irq_out_base);
 
 	count = 1;
@@ -3766,20 +3773,20 @@
 								temp_string);
 			if (!r)
 				break;
-			aux_mem_base = (void *)(r->start);
-			aux_mem_size = (uint32_t)(resource_size(r));
-			SMD_DBG("%s: %s = %p %x", __func__, temp_string,
-					aux_mem_base, aux_mem_size);
+			aux_mem_base = r->start;
+			aux_mem_size = resource_size(r);
+			SMD_DBG("%s: %s = %pa %pa", __func__, temp_string,
+					&aux_mem_base, &aux_mem_size);
 			smem_areas[count - 1].phys_addr = aux_mem_base;
 			smem_areas[count - 1].size = aux_mem_size;
 			smem_areas[count - 1].virt_addr = ioremap_nocache(
 				(unsigned long)(smem_areas[count-1].phys_addr),
 				smem_areas[count - 1].size);
 			if (!smem_areas[count - 1].virt_addr) {
-				pr_err("%s: ioremap_nocache() of addr:%p size: %x\n",
+				pr_err("%s: ioremap_nocache() of addr:%pa size: %pa\n",
 					__func__,
-					smem_areas[count - 1].phys_addr,
-					smem_areas[count - 1].size);
+					&smem_areas[count - 1].phys_addr,
+					&smem_areas[count - 1].size);
 				ret = -ENOMEM;
 				goto free_smem_areas;
 			}
diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c
index 1820b23..5969a3c 100644
--- a/arch/arm/mach-msm/smd_tty.c
+++ b/arch/arm/mach-msm/smd_tty.c
@@ -47,7 +47,7 @@
 
 struct smd_tty_info {
 	smd_channel_t *ch;
-	struct tty_struct *tty;
+	struct tty_port port;
 	struct wake_lock wake_lock;
 	int open_count;
 	struct tasklet_struct tty_tsklt;
@@ -125,7 +125,7 @@
 	unsigned char *ptr;
 	int avail;
 	struct smd_tty_info *info = (struct smd_tty_info *)param;
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty = tty_port_tty_get(&info->port);
 	unsigned long flags;
 
 	if (!tty)
@@ -156,6 +156,7 @@
 		if (avail <= 0) {
 			mod_timer(&info->buf_req_timer,
 					jiffies + msecs_to_jiffies(30));
+			tty_kref_put(tty);
 			return;
 		}
 
@@ -173,11 +174,13 @@
 
 	/* XXX only when writable and necessary */
 	tty_wakeup(tty);
+	tty_kref_put(tty);
 }
 
 static void smd_tty_notify(void *priv, unsigned event)
 {
 	struct smd_tty_info *info = priv;
+	struct tty_struct *tty;
 	unsigned long flags;
 
 	switch (event) {
@@ -195,8 +198,10 @@
 		 */
 		if (smd_write_avail(info->ch)) {
 			smd_disable_read_intr(info->ch);
-			if (info->tty)
-				wake_up_interruptible(&info->tty->write_wait);
+			tty = tty_port_tty_get(&info->port);
+			if (tty)
+				wake_up_interruptible(&tty->write_wait);
+			tty_kref_put(tty);
 		}
 		spin_lock_irqsave(&info->ra_lock, flags);
 		if (smd_read_avail(info->ch)) {
@@ -225,9 +230,11 @@
 		/* schedule task to send TTY_BREAK */
 		tasklet_hi_schedule(&info->tty_tsklt);
 
-		if (info->tty->index == LOOPBACK_IDX)
+		tty = tty_port_tty_get(&info->port);
+		if (tty->index == LOOPBACK_IDX)
 			schedule_delayed_work(&loopback_work,
 					msecs_to_jiffies(1000));
+		tty_kref_put(tty);
 		break;
 	}
 }
@@ -241,7 +248,8 @@
 	return (modem_state & ready_state) == ready_state;
 }
 
-static int smd_tty_open(struct tty_struct *tty, struct file *f)
+static int smd_tty_port_activate(struct tty_port *tport,
+				 struct tty_struct *tty)
 {
 	int res = 0;
 	unsigned int n = tty->index;
@@ -306,8 +314,6 @@
 			}
 		}
 
-
-		info->tty = tty;
 		tasklet_init(&info->tty_tsklt, smd_tty_read,
 			     (unsigned long)info);
 		wake_lock_init(&info->wake_lock, WAKE_LOCK_SUSPEND,
@@ -354,24 +360,27 @@
 	return res;
 }
 
-static void smd_tty_close(struct tty_struct *tty, struct file *f)
+static void smd_tty_port_shutdown(struct tty_port *tport)
 {
-	struct smd_tty_info *info = tty->driver_data;
+	struct smd_tty_info *info;
+	struct tty_struct *tty = tty_port_tty_get(tport);
 	unsigned long flags;
 
-	if (info == 0)
+	info = tty->driver_data;
+	if (info == 0) {
+		tty_kref_put(tty);
 		return;
+	}
 
 	mutex_lock(&smd_tty_lock);
 	if (--info->open_count == 0) {
 		spin_lock_irqsave(&info->reset_lock, flags);
 		info->is_open = 0;
 		spin_unlock_irqrestore(&info->reset_lock, flags);
-		if (info->tty) {
+		if (tty) {
 			tasklet_kill(&info->tty_tsklt);
 			wake_lock_destroy(&info->wake_lock);
 			wake_lock_destroy(&info->ra_wake_lock);
-			info->tty = 0;
 		}
 		tty->driver_data = 0;
 		del_timer(&info->buf_req_timer);
@@ -382,6 +391,21 @@
 		}
 	}
 	mutex_unlock(&smd_tty_lock);
+	tty_kref_put(tty);
+}
+
+static int smd_tty_open(struct tty_struct *tty, struct file *f)
+{
+	struct smd_tty_info *info = smd_tty + tty->index;
+
+	return tty_port_open(&info->port, tty, f);
+}
+
+static void smd_tty_close(struct tty_struct *tty, struct file *f)
+{
+	struct smd_tty_info *info = tty->driver_data;
+
+	tty_port_close(&info->port, tty, f);
 }
 
 static int smd_tty_write(struct tty_struct *tty, const unsigned char *buf, int len)
@@ -482,6 +506,11 @@
 			  0, SMSM_SMD_LOOPBACK);
 }
 
+static const struct tty_port_operations smd_tty_port_ops = {
+	.shutdown = smd_tty_port_shutdown,
+	.activate = smd_tty_port_activate,
+};
+
 static struct tty_operations smd_tty_ops = {
 	.open = smd_tty_open,
 	.close = smd_tty_close,
@@ -523,6 +552,7 @@
 	int ret;
 	int n;
 	int idx;
+	struct tty_port *port;
 
 	smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS);
 	if (smd_tty_driver == 0)
@@ -578,6 +608,10 @@
 				continue;
 		}
 
+		port = &smd_tty[idx].port;
+		tty_port_init(port);
+		port->ops = &smd_tty_port_ops;
+		/* TODO: For kernel >= 3.7 use tty_port_register_device */
 		tty_register_device(smd_tty_driver, idx, 0);
 		init_completion(&smd_tty[idx].ch_allocated);
 
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 97e1c17..c8e2dd3 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.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
@@ -36,6 +36,7 @@
 	struct msm_spm_driver_data reg_data;
 	struct msm_spm_power_modes *modes;
 	uint32_t num_modes;
+	uint32_t cpu_vdd;
 };
 
 struct msm_spm_vdd_info {
@@ -54,6 +55,7 @@
 	struct msm_spm_vdd_info *info = (struct msm_spm_vdd_info *)data;
 
 	dev = &per_cpu(msm_cpu_spm_device, info->cpu);
+	dev->cpu_vdd = info->vlevel;
 	info->err = msm_spm_drv_set_vdd(&dev->reg_data, info->vlevel);
 }
 
@@ -106,7 +108,7 @@
 	struct msm_spm_device *dev;
 
 	dev = &per_cpu(msm_cpu_spm_device, cpu);
-	return msm_spm_drv_get_sts_curr_pmic_data(&dev->reg_data);
+	return dev->cpu_vdd;
 }
 EXPORT_SYMBOL(msm_spm_get_vdd);
 
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 6314e94..d177b05 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -7,7 +7,6 @@
 
 obj-$(CONFIG_MMU)		+= fault-armv.o flush.o idmap.o ioremap.o \
 				   mmap.o pgd.o mmu.o vmregion.o
-obj-$(CONFIG_DEBUG_RODATA)	+= rodata.o
 
 ifneq ($(CONFIG_MMU),y)
 obj-y				+= nommu.o
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 0ebc2b9..38da432 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -224,7 +224,7 @@
  * allocations.  This must be the smallest DMA mask in the system,
  * so a successful GFP_DMA allocation will always satisfy this.
  */
-u32 arm_dma_limit;
+phys_addr_t arm_dma_limit;
 
 static void __init arm_adjust_dma_zone(unsigned long *size, unsigned long *hole,
 	unsigned long dma_size)
@@ -721,9 +721,6 @@
 	extern u32 dtcm_end;
 	extern u32 itcm_end;
 #endif
-#ifdef CONFIG_FIX_MOVABLE_ZONE
-	struct zone *zone;
-#endif
 
 	max_mapnr   = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map;
 
@@ -769,14 +766,6 @@
 #endif
 	}
 
-#ifdef CONFIG_FIX_MOVABLE_ZONE
-	for_each_zone(zone) {
-		if (zone_idx(zone) == ZONE_MOVABLE)
-			total_unmovable_pages = totalram_pages -
-							zone->spanned_pages;
-	}
-#endif
-
 	/*
 	 * Since our memory may not be contiguous, calculate the
 	 * real number of pages we have in this system
@@ -898,39 +887,9 @@
 					    __phys_to_pfn(__pa(__init_end)),
 					    "init");
 		totalram_pages += reclaimed_initmem;
-#ifdef CONFIG_FIX_MOVABLE_ZONE
-		total_unmovable_pages += reclaimed_initmem;
-#endif
 	}
 }
 
-#ifdef CONFIG_MEMORY_HOTPLUG
-int arch_add_memory(int nid, u64 start, u64 size)
-{
-	struct pglist_data *pgdata = NODE_DATA(nid);
-	struct zone *zone = pgdata->node_zones + ZONE_MOVABLE;
-	unsigned long start_pfn = start >> PAGE_SHIFT;
-	unsigned long nr_pages = size >> PAGE_SHIFT;
-
-	return __add_pages(nid, zone, start_pfn, nr_pages);
-}
-
-int arch_physical_active_memory(u64 start, u64 size)
-{
-	return platform_physical_active_pages(start, size);
-}
-
-int arch_physical_remove_memory(u64 start, u64 size)
-{
-	return platform_physical_remove_pages(start, size);
-}
-
-int arch_physical_low_power_memory(u64 start, u64 size)
-{
-	return platform_physical_low_power_pages(start, size);
-}
-#endif
-
 #ifdef CONFIG_BLK_DEV_INITRD
 
 static int keep_initrd;
@@ -945,9 +904,6 @@
 						 __phys_to_pfn(__pa(end)),
 						 "initrd");
 		totalram_pages += reclaimed_initrd_mem;
-#ifdef CONFIG_FIX_MOVABLE_ZONE
-		total_unmovable_pages += reclaimed_initrd_mem;
-#endif
 	}
 }
 
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h
index 8877ddd..21653f2 100644
--- a/arch/arm/mm/mm.h
+++ b/arch/arm/mm/mm.h
@@ -65,9 +65,9 @@
 #endif
 
 #ifdef CONFIG_ZONE_DMA
-extern u32 arm_dma_limit;
+extern phys_addr_t arm_dma_limit;
 #else
-#define arm_dma_limit ((u32)~0)
+#define arm_dma_limit ((phys_addr_t)~0)
 #endif
 
 struct map_desc;
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 8575f78..0e31910 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -604,53 +604,30 @@
 	return early_alloc_aligned(sz, sz);
 }
 
-static pte_t * __init early_pte_alloc(pmd_t *pmd)
-{
-	if (pmd_none(*pmd) || pmd_bad(*pmd))
-		return early_alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE);
-	return pmd_page_vaddr(*pmd);
-}
-
-static void __init early_pte_install(pmd_t *pmd, pte_t *pte, unsigned long prot)
-{
-	__pmd_populate(pmd, __pa(pte), prot);
-	BUG_ON(pmd_bad(*pmd));
-}
-
-#ifdef CONFIG_HIGHMEM
-static pte_t * __init early_pte_alloc_and_install(pmd_t *pmd,
-	unsigned long addr, unsigned long prot)
+static pte_t * __init early_pte_alloc(pmd_t *pmd, unsigned long addr, unsigned long prot)
 {
 	if (pmd_none(*pmd)) {
-		pte_t *pte = early_pte_alloc(pmd);
-		early_pte_install(pmd, pte, prot);
+		pte_t *pte = early_alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE);
+		__pmd_populate(pmd, __pa(pte), prot);
 	}
 	BUG_ON(pmd_bad(*pmd));
 	return pte_offset_kernel(pmd, addr);
 }
-#endif
 
 static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,
 				  unsigned long end, unsigned long pfn,
 				  const struct mem_type *type)
 {
-	pte_t *start_pte = early_pte_alloc(pmd);
-	pte_t *pte = start_pte + pte_index(addr);
-
-	/* If replacing a section mapping, the whole section must be replaced */
-	BUG_ON(pmd_bad(*pmd) && ((addr | end) & ~PMD_MASK));
-
+	pte_t *pte = early_pte_alloc(pmd, addr, type->prot_l1);
 	do {
 		set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)), 0);
 		pfn++;
 	} while (pte++, addr += PAGE_SIZE, addr != end);
-	early_pte_install(pmd, start_pte, type->prot_l1);
 }
 
 static void __init alloc_init_section(pud_t *pud, unsigned long addr,
 				      unsigned long end, phys_addr_t phys,
-				      const struct mem_type *type,
-				      bool force_pages)
+				      const struct mem_type *type)
 {
 	pmd_t *pmd = pmd_offset(pud, addr);
 
@@ -660,7 +637,7 @@
 	 * L1 entries, whereas PGDs refer to a group of L1 entries making
 	 * up one logical pointer to an L2 table.
 	 */
-	if (type->prot_sect && ((addr | end | phys) & ~SECTION_MASK) == 0 && !force_pages) {
+	if (type->prot_sect && ((addr | end | phys) & ~SECTION_MASK) == 0) {
 		pmd_t *p = pmd;
 
 #ifndef CONFIG_ARM_LPAE
@@ -684,15 +661,14 @@
 }
 
 static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
-	unsigned long end, unsigned long phys, const struct mem_type *type,
-	bool force_pages)
+	unsigned long end, unsigned long phys, const struct mem_type *type)
 {
 	pud_t *pud = pud_offset(pgd, addr);
 	unsigned long next;
 
 	do {
 		next = pud_addr_end(addr, end);
-		alloc_init_section(pud, addr, next, phys, type, force_pages);
+		alloc_init_section(pud, addr, next, phys, type);
 		phys += next - addr;
 	} while (pud++, addr = next, addr != end);
 }
@@ -766,7 +742,7 @@
  * offsets, and we take full advantage of sections and
  * supersections.
  */
-static void __init create_mapping(struct map_desc *md, bool force_pages)
+static void __init create_mapping(struct map_desc *md)
 {
 	unsigned long addr, length, end;
 	phys_addr_t phys;
@@ -818,7 +794,7 @@
 	do {
 		unsigned long next = pgd_addr_end(addr, end);
 
-		alloc_init_pud(pgd, addr, next, phys, type, force_pages);
+		alloc_init_pud(pgd, addr, next, phys, type);
 
 		phys += next - addr;
 		addr = next;
@@ -839,7 +815,7 @@
 	vm = early_alloc_aligned(sizeof(*vm) * nr, __alignof__(*vm));
 
 	for (md = io_desc; nr; md++, nr--) {
-		create_mapping(md, false);
+		create_mapping(md);
 		vm->addr = (void *)(md->virtual & PAGE_MASK);
 		vm->size = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
 		vm->phys_addr = __pfn_to_phys(md->pfn); 
@@ -964,10 +940,6 @@
 	find_memory_hole();
 #endif
 
-#if (defined CONFIG_HIGHMEM) && (defined CONFIG_FIX_MOVABLE_ZONE)
-	if (movable_reserved_size && __pa(vmalloc_min) > movable_reserved_start)
-		vmalloc_min = __va(movable_reserved_start);
-#endif
 	for (i = 0, j = 0; i < meminfo.nr_banks; i++) {
 		struct membank *bank = &meminfo.bank[j];
 		*bank = meminfo.bank[i];
@@ -1199,12 +1171,12 @@
 	map.virtual = 0xffff0000;
 	map.length = PAGE_SIZE;
 	map.type = MT_HIGH_VECTORS;
-	create_mapping(&map, false);
+	create_mapping(&map);
 
 	if (!vectors_high()) {
 		map.virtual = 0;
 		map.type = MT_LOW_VECTORS;
-		create_mapping(&map, false);
+		create_mapping(&map);
 	}
 
 	/*
@@ -1224,7 +1196,7 @@
 			map.virtual = CONFIG_ARM_USER_ACCESSIBLE_TIMER_BASE;
 			map.length = PAGE_SIZE;
 			map.type = MT_DEVICE_USER_ACCESSIBLE;
-			create_mapping(&map, false);
+			create_mapping(&map);
 		}
 	}
 
@@ -1241,7 +1213,7 @@
 static void __init kmap_init(void)
 {
 #ifdef CONFIG_HIGHMEM
-	pkmap_page_table = early_pte_alloc_and_install(pmd_off_k(PKMAP_BASE),
+	pkmap_page_table = early_pte_alloc(pmd_off_k(PKMAP_BASE),
 		PKMAP_BASE, _PAGE_KERNEL_TABLE);
 #endif
 }
@@ -1349,14 +1321,12 @@
 static void __init map_lowmem(void)
 {
 	struct memblock_region *reg;
-	phys_addr_t start;
-	phys_addr_t end;
-	struct map_desc map;
 
 	/* Map all the lowmem memory banks. */
 	for_each_memblock(memory, reg) {
-		start = reg->base;
-		end = start + reg->size;
+		phys_addr_t start = reg->base;
+		phys_addr_t end = start + reg->size;
+		struct map_desc map;
 
 		if (end > arm_lowmem_limit)
 			end = arm_lowmem_limit;
@@ -1370,28 +1340,28 @@
 			map.length = SECTION_SIZE;
 			map.type = MT_MEMORY;
 
-			create_mapping(&map, false);
+			create_mapping(&map);
 
 			map.pfn = __phys_to_pfn(start + SECTION_SIZE);
 			map.virtual = __phys_to_virt(start + SECTION_SIZE);
 			map.length = (unsigned long)RX_AREA_END - map.virtual;
 			map.type = MT_MEMORY_RX;
 
-			create_mapping(&map, false);
+			create_mapping(&map);
 
 			map.pfn = __phys_to_pfn(__pa(__start_rodata));
 			map.virtual = (unsigned long)__start_rodata;
 			map.length = __init_begin - __start_rodata;
 			map.type = MT_MEMORY_R;
 
-			create_mapping(&map, false);
+			create_mapping(&map);
 
 			map.pfn = __phys_to_pfn(__pa(__init_begin));
 			map.virtual = (unsigned long)__init_begin;
 			map.length = __init_data - __init_begin;
 			map.type = MT_MEMORY;
 
-			create_mapping(&map, false);
+			create_mapping(&map);
 
 			map.pfn = __phys_to_pfn(__pa(__init_data));
 			map.virtual = (unsigned long)__init_data;
@@ -1406,20 +1376,8 @@
 		map.type = MT_MEMORY;
 #endif
 
-		create_mapping(&map, false);
+		create_mapping(&map);
 	}
-
-#ifdef CONFIG_DEBUG_RODATA
-	start = __pa(_stext) & PMD_MASK;
-	end = ALIGN(__pa(__end_rodata), PMD_SIZE);
-
-	map.pfn = __phys_to_pfn(start);
-	map.virtual = __phys_to_virt(start);
-	map.length = end - start;
-	map.type = MT_MEMORY;
-
-	create_mapping(&map, true);
-#endif
 }
 
 /*
diff --git a/arch/arm/mm/rodata.c b/arch/arm/mm/rodata.c
deleted file mode 100644
index 9a8eb84..0000000
--- a/arch/arm/mm/rodata.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- *  linux/arch/arm/mm/rodata.c
- *
- *  Copyright (C) 2011 Google, Inc.
- *
- *  Author: Colin Cross <ccross@android.com>
- *
- *  Based on x86 implementation in arch/x86/mm/init_32.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-
-#include <asm/cache.h>
-#include <asm/pgtable.h>
-#include <asm/rodata.h>
-#include <asm/sections.h>
-#include <asm/tlbflush.h>
-
-#include "mm.h"
-
-static int kernel_set_to_readonly __read_mostly;
-
-#ifdef CONFIG_DEBUG_RODATA_TEST
-static const int rodata_test_data = 0xC3;
-
-static noinline void rodata_test(void)
-{
-	int result;
-
-	pr_info("%s: attempting to write to read-only section:\n", __func__);
-
-	if (*(volatile int *)&rodata_test_data != 0xC3) {
-		pr_err("read only data changed before test\n");
-		return;
-	}
-
-	/*
-	 * Attempt to to write to rodata_test_data, trapping the expected
-	 * data abort.  If the trap executed, result will be 1.  If it didn't,
-	 * result will be 0xFF.
-	 */
-	asm volatile(
-		"0:	str	%[zero], [%[rodata_test_data]]\n"
-		"	mov	%[result], #0xFF\n"
-		"	b	2f\n"
-		"1:	mov	%[result], #1\n"
-		"2:\n"
-
-		/* Exception fixup - if store at label 0 faults, jumps to 1 */
-		".pushsection __ex_table, \"a\"\n"
-		"	.long	0b, 1b\n"
-		".popsection\n"
-
-		: [result] "=r" (result)
-		: [rodata_test_data] "r" (&rodata_test_data), [zero] "r" (0)
-		: "memory"
-	);
-
-	if (result == 1)
-		pr_info("write to read-only section trapped, success\n");
-	else
-		pr_err("write to read-only section NOT trapped, test failed\n");
-
-	if (*(volatile int *)&rodata_test_data != 0xC3)
-		pr_err("read only data changed during write\n");
-}
-#else
-static inline void rodata_test(void) { }
-#endif
-
-static int set_page_attributes(unsigned long virt, int numpages,
-	pte_t (*f)(pte_t))
-{
-	pmd_t *pmd;
-	pte_t *pte;
-	unsigned long start = virt;
-	unsigned long end = virt + (numpages << PAGE_SHIFT);
-	unsigned long pmd_end;
-
-	while (virt < end) {
-		pmd = pmd_off_k(virt);
-		pmd_end = min(ALIGN(virt + 1, PMD_SIZE), end);
-
-		if ((pmd_val(*pmd) & PMD_TYPE_MASK) != PMD_TYPE_TABLE) {
-			pr_err("%s: pmd %p=%08lx for %08lx not page table\n",
-				__func__, pmd, pmd_val(*pmd), virt);
-			virt = pmd_end;
-			continue;
-		}
-
-		while (virt < pmd_end) {
-			pte = pte_offset_kernel(pmd, virt);
-			set_pte_ext(pte, f(*pte), 0);
-			virt += PAGE_SIZE;
-		}
-	}
-
-	flush_tlb_kernel_range(start, end);
-
-	return 0;
-}
-
-int set_memory_ro(unsigned long virt, int numpages)
-{
-	return set_page_attributes(virt, numpages, pte_wrprotect);
-}
-EXPORT_SYMBOL(set_memory_ro);
-
-int set_memory_rw(unsigned long virt, int numpages)
-{
-	return set_page_attributes(virt, numpages, pte_mkwrite);
-}
-EXPORT_SYMBOL(set_memory_rw);
-
-void set_kernel_text_rw(void)
-{
-	unsigned long start = PAGE_ALIGN((unsigned long)_text);
-	unsigned long size = PAGE_ALIGN((unsigned long)__end_rodata) - start;
-
-	if (!kernel_set_to_readonly)
-		return;
-
-	pr_debug("Set kernel text: %lx - %lx to read-write\n",
-		 start, start + size);
-
-	set_memory_rw(start, size >> PAGE_SHIFT);
-}
-
-void set_kernel_text_ro(void)
-{
-	unsigned long start = PAGE_ALIGN((unsigned long)_text);
-	unsigned long size = PAGE_ALIGN((unsigned long)__end_rodata) - start;
-
-	if (!kernel_set_to_readonly)
-		return;
-
-	pr_info_once("Write protecting the kernel text section %lx - %lx\n",
-		start, start + size);
-
-	pr_debug("Set kernel text: %lx - %lx to read only\n",
-		 start, start + size);
-
-	set_memory_ro(start, size >> PAGE_SHIFT);
-}
-
-void mark_rodata_ro(void)
-{
-	kernel_set_to_readonly = 1;
-
-	set_kernel_text_ro();
-
-	rodata_test();
-}
diff --git a/drivers/Kconfig b/drivers/Kconfig
index a73d713..adead10 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -150,4 +150,6 @@
 
 source "drivers/coresight/Kconfig"
 
+source "drivers/bif/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index f461e83..d55b035 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -142,3 +142,5 @@
 obj-$(CONFIG_MOBICORE_SUPPORT)  += gud/
 
 obj-$(CONFIG_CORESIGHT)		+= coresight/
+
+obj-$(CONFIG_BIF)		+= bif/
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 1937db8..3a8bbc5 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -9,6 +9,9 @@
  * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License or (at your optional) any later version of the license.
+ *
+ * The Linux Foundation chooses to take subject only to the GPLv2 license
+ * terms, and distributes only under these terms.
  */
 
 #define pr_fmt(fmt) "cma: " fmt
@@ -24,6 +27,9 @@
 
 #include <linux/memblock.h>
 #include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
 #include <linux/mm.h>
 #include <linux/mutex.h>
 #include <linux/page-isolation.h>
@@ -52,8 +58,9 @@
 	phys_addr_t base;
 	unsigned long size;
 	struct cma *cma;
-} cma_areas[MAX_CMA_AREAS] __initdata;
-static unsigned cma_area_count __initdata;
+	const char *name;
+} cma_areas[MAX_CMA_AREAS];
+static unsigned cma_area_count;
 
 
 static struct cma_map {
@@ -71,6 +78,20 @@
 	return NULL;
 }
 
+static struct cma *cma_get_area_by_name(const char *name)
+{
+	int i;
+	if (!name)
+		return NULL;
+
+	for (i = 0; i < cma_area_count; i++)
+		if (cma_areas[i].name && strcmp(cma_areas[i].name, name) == 0)
+			return cma_areas[i].cma;
+	return NULL;
+}
+
+
+
 #ifdef CONFIG_CMA_SIZE_MBYTES
 #define CMA_SIZE_MBYTES CONFIG_CMA_SIZE_MBYTES
 #else
@@ -181,6 +202,38 @@
 	return ERR_PTR(ret);
 }
 
+/*****************************************************************************/
+
+#ifdef CONFIG_OF
+int __init cma_fdt_scan(unsigned long node, const char *uname,
+				int depth, void *data)
+{
+	phys_addr_t base, size;
+	unsigned long len;
+	__be32 *prop;
+	char *name;
+
+	if (strncmp(uname, "region@", 7) != 0 || depth != 2 ||
+	    !of_get_flat_dt_prop(node, "linux,contiguous-region", NULL))
+		return 0;
+
+	prop = of_get_flat_dt_prop(node, "reg", &len);
+	if (!prop || (len != 2 * sizeof(unsigned long)))
+		return 0;
+
+	base = be32_to_cpu(prop[0]);
+	size = be32_to_cpu(prop[1]);
+
+	name = of_get_flat_dt_prop(node, "label", NULL);
+
+	pr_info("Found %s, memory base %lx, size %ld MiB\n", uname,
+		(unsigned long)base, (unsigned long)size / SZ_1M);
+	dma_contiguous_reserve_area(size, &base, 0, name);
+
+	return 0;
+}
+#endif
+
 /**
  * dma_contiguous_reserve() - reserve area for contiguous memory handling
  * @limit: End address of the reserved memory (optional, 0 for any).
@@ -216,9 +269,13 @@
 		pr_debug("%s: reserving %ld MiB for global area\n", __func__,
 			 (unsigned long)sel_size / SZ_1M);
 
-		if (dma_contiguous_reserve_area(sel_size, &base, limit) == 0)
+		if (dma_contiguous_reserve_area(sel_size, &base, limit, NULL)
+		    == 0)
 			dma_contiguous_def_base = base;
 	}
+#ifdef CONFIG_OF
+	of_scan_flat_dt(cma_fdt_scan, NULL);
+#endif
 };
 
 /**
@@ -236,7 +293,7 @@
  * devices.
  */
 int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t *res_base,
-				       phys_addr_t limit)
+				       phys_addr_t limit, const char *name)
 {
 	phys_addr_t base = *res_base;
 	phys_addr_t alignment;
@@ -288,6 +345,7 @@
 	 */
 	cma_areas[cma_area_count].base = base;
 	cma_areas[cma_area_count].size = size;
+	cma_areas[cma_area_count].name = name;
 	cma_area_count++;
 	*res_base = base;
 
@@ -323,6 +381,45 @@
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static void cma_assign_device_from_dt(struct device *dev)
+{
+	struct device_node *node;
+	struct cma *cma;
+	const char *name;
+	u32 value;
+
+	node = of_parse_phandle(dev->of_node, "linux,contiguous-region", 0);
+	if (!node)
+		return;
+	if (of_property_read_u32(node, "reg", &value) && !value)
+		return;
+
+	if (of_property_read_string(node, "label", &name))
+		return;
+
+	cma = cma_get_area_by_name(name);
+	if (!cma)
+		return;
+
+	dev_set_cma_area(dev, cma);
+	pr_info("Assigned CMA region at %lx to %s device\n", (unsigned long)value, dev_name(dev));
+}
+
+static int cma_device_init_notifier_call(struct notifier_block *nb,
+					 unsigned long event, void *data)
+{
+	struct device *dev = data;
+	if (event == BUS_NOTIFY_ADD_DEVICE && dev->of_node)
+		cma_assign_device_from_dt(dev);
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block cma_dev_init_nb = {
+	.notifier_call = cma_device_init_notifier_call,
+};
+#endif
+
 static int __init cma_init_reserved_areas(void)
 {
 	struct cma *cma;
@@ -344,6 +441,9 @@
 		dev_set_cma_area(cma_maps[i].dev, cma);
 	}
 
+#ifdef CONFIG_OF
+	bus_register_notifier(&platform_bus_type, &cma_dev_init_nb);
+#endif
 	return 0;
 }
 core_initcall(cma_init_reserved_areas);
diff --git a/drivers/bif/Kconfig b/drivers/bif/Kconfig
new file mode 100644
index 0000000..d9828c5
--- /dev/null
+++ b/drivers/bif/Kconfig
@@ -0,0 +1,26 @@
+#
+# BIF framework and drivers
+#
+menuconfig BIF
+	bool "MIPI-BIF support"
+	select CRC_CCITT
+	select BITREVERSE
+	help
+	  MIPI-BIF (battery interface) is a one-wire serial interface between a
+	  host master device and one or more slave devices which are located in
+	  a battery pack or also on the host.  Enabling this option allows for
+	  BIF consumer drivers to issue transactions via BIF controller drivers.
+
+if BIF
+config BIF_QPNP
+	depends on SPMI
+	depends on OF_SPMI
+	tristate "Qualcomm QPNP BIF support"
+	help
+	  This driver supports the QPNP BSI peripheral found inside of Qualcomm
+	  QPNP PMIC devices.  The BSI peripheral is able to communicate using
+	  the BIF protocol.  The QPNP BSI driver hooks into the BIF framework.
+	  Enable this option in order to provide support for BIF communication
+	  on targets which have BSI PMIC peripherals.
+
+endif
diff --git a/drivers/bif/Makefile b/drivers/bif/Makefile
new file mode 100644
index 0000000..7604ca7
--- /dev/null
+++ b/drivers/bif/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for kernel BIF framework.
+#
+obj-$(CONFIG_BIF)			+= bif-core.o
+obj-$(CONFIG_BIF_QPNP)			+= qpnp-bsi.o
diff --git a/drivers/bif/bif-core.c b/drivers/bif/bif-core.c
new file mode 100644
index 0000000..e11e6ba4
--- /dev/null
+++ b/drivers/bif/bif-core.c
@@ -0,0 +1,2934 @@
+/* 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/bitrev.h>
+#include <linux/crc-ccitt.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/workqueue.h>
+#include <linux/bif/consumer.h>
+#include <linux/bif/driver.h>
+
+/**
+ * struct bif_ctrl_dev - holds controller device specific information
+ * @list:			Doubly-linked list parameter linking to other
+ *				BIF controllers registered in the system
+ * @desc:			Description structure for this BIF controller
+ * @mutex:			Mutex lock that is used to ensure mutual
+ *				exclusion between transactions performed on the
+ *				BIF bus for this controller
+ * @ctrl_dev:			Device pointer to the BIF controller device
+ * @driver_data:		Private data used by the BIF controller
+ * @selected_sdev:		Slave device that is currently selected on
+ *				the BIF bus of this controller
+ * @bus_change_notifier:	Head of a notifier list containing notifier
+ *				blocks that are notified when the battery
+ *				presence changes
+ * @enter_irq_mode_work:	Work task that is scheduled after a transaction
+ *				completes when there are consumers that are
+ *				actively monitoring BIF slave interrupts
+ * @irq_count:			This is a count of the total number of BIF slave
+ *				interrupts that are currently being monitored
+ *				for the BIF slaves connected to this BIF
+ *				controller
+ * @irq_mode_delay_jiffies:	Number of jiffies to wait before scheduling the
+ *				enter IRQ mode task.  Using a larger value
+ *				helps to improve the performance of BIF
+ *				consumers that perform many BIF transactions.
+ *				Using a smaller value reduces the latency of
+ *				BIF slave interrupts.
+ * @battery_present:		Cached value of the battery presence.  This is
+ *				used to filter out spurious presence update
+ *				calls when the battery presence state has not
+ *				changed.
+ */
+struct bif_ctrl_dev {
+	struct list_head		list;
+	struct bif_ctrl_desc		*desc;
+	struct mutex			mutex;
+	struct device			*ctrl_dev;
+	void				*driver_data;
+	struct bif_slave_dev		*selected_sdev;
+	struct blocking_notifier_head	bus_change_notifier;
+	struct delayed_work		enter_irq_mode_work;
+	int				irq_count;
+	int				irq_mode_delay_jiffies;
+	bool				battery_present;
+};
+
+/**
+ * struct bif_ctrl - handle used by BIF consumers for bus oriented BIF
+ *			operations
+ * @bdev:		Pointer to BIF controller device
+ * @exclusive_lock:	Flag which indicates that the BIF consumer responsible
+ *			for this handle has locked the BIF bus of this
+ *			controller.  BIF transactions from other consumers are
+ *			blocked until the bus is unlocked.
+ */
+struct bif_ctrl {
+	struct bif_ctrl_dev	*bdev;
+	bool			exclusive_lock;
+};
+
+/**
+ * struct bif_slave_dev - holds BIF slave device information
+ * @list:			Doubly-linked list parameter linking to other
+ *				BIF slaves that have been enumerated
+ * @bdev:			Pointer to the BIF controller device that this
+ *				slave is physically connected to
+ * @slave_addr:			8-bit BIF DEV_ADR assigned to this slave
+ * @unique_id:			80-bit BIF unique ID of the slave
+ * @unique_id_bits_known:	Number of bits of the UID that are currently
+ *				known.  This number starts is incremented during
+ *				a UID search and must end at 80 if the slave
+ *				responds to the search properly.
+ * @present:			Boolean value showing if this slave is
+*				physically present in the system at a given
+*				point in time.  The value is set to false if the
+*				battery pack containing the slave is
+*				disconnected.
+ * @l1_data:			BIF DDB L1 data of the slave as read from the
+ *				slave's memory
+ * @function_directory:		Pointer to the BIF DDB L2 function directory
+ *				list as read from the slave's memory
+ * @protocol_function:		Pointer to constant protocol function data as
+ *				well as software state information if the slave
+ *				has a protocol function
+ * @slave_ctrl_function:	Pointer to constant slave control function data
+ *				as well as software state information if the
+ *				slave has a slave control function
+ * @nvm_function:		Pointer to constant non-volatile memory function
+ *				data as well as software state information if
+ *				the slave has a non-volatile memory function
+ *
+ * bif_slave_dev objects are stored indefinitely after enumeration in order to
+ * speed up battery reinsertion.  Only a UID check is needed after inserting a
+ * battery assuming it has been enumerated before.
+ *
+ * unique_id bytes are stored such that unique_id[0] = MSB and
+ * unique_id[BIF_UNIQUE_ID_BYTE_LENGTH - 1] = LSB
+ */
+struct bif_slave_dev {
+	struct list_head			list;
+	struct bif_ctrl_dev			*bdev;
+	u8					slave_addr;
+	u8				unique_id[BIF_UNIQUE_ID_BYTE_LENGTH];
+	int					unique_id_bits_known;
+	bool					present;
+	struct bif_ddb_l1_data			l1_data;
+	struct bif_ddb_l2_data			*function_directory;
+	struct bif_protocol_function		*protocol_function;
+	struct bif_slave_control_function	*slave_ctrl_function;
+	struct bif_nvm_function			*nvm_function;
+};
+
+/**
+ * struct bif_slave - handle used by BIF consumers for slave oriented BIF
+ *			operations
+ * @ctrl:		Consumer BIF controller handle data
+ * @sdev:		Pointer to BIF slave device
+ */
+struct bif_slave {
+	struct bif_ctrl				ctrl;
+	struct bif_slave_dev			*sdev;
+};
+
+/* Number of times to retry a full BIF transaction before returning an error. */
+#define BIF_TRANSACTION_RETRY_COUNT	5
+
+static DEFINE_MUTEX(bif_ctrl_list_mutex);
+static LIST_HEAD(bif_ctrl_list);
+static DEFINE_MUTEX(bif_sdev_list_mutex);
+static LIST_HEAD(bif_sdev_list);
+
+static u8 next_dev_addr = 0x02;
+
+#define DEBUG_PRINT_BUFFER_SIZE 256
+static void fill_string(char *str, size_t str_len, u8 *buf, int buf_len)
+{
+	int pos = 0;
+	int i;
+
+	for (i = 0; i < buf_len; i++) {
+		pos += scnprintf(str + pos, str_len - pos, "0x%02X", buf[i]);
+		if (i < buf_len - 1)
+			pos += scnprintf(str + pos, str_len - pos, ", ");
+	}
+}
+
+static void bif_print_slave_data(struct bif_slave_dev *sdev)
+{
+	char str[DEBUG_PRINT_BUFFER_SIZE];
+	u8 *uid;
+	int i, j;
+	struct bif_object *object;
+
+	if (sdev->unique_id_bits_known != BIF_UNIQUE_ID_BIT_LENGTH)
+		return;
+
+	uid = sdev->unique_id;
+	pr_debug("BIF slave: 0x%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n",
+		uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6],
+		uid[7], uid[8], uid[9]);
+	pr_debug("  present=%d, dev_adr=0x%02X\n", sdev->present,
+		sdev->slave_addr);
+	pr_debug("  revision=0x%02X, level=0x%02X, device class=0x%04X\n",
+		sdev->l1_data.revision, sdev->l1_data.level,
+		sdev->l1_data.device_class);
+	pr_debug("  manufacturer ID=0x%04X, product ID=0x%04X\n",
+		sdev->l1_data.manufacturer_id, sdev->l1_data.product_id);
+	pr_debug("  function directory length=%d\n", sdev->l1_data.length);
+
+	for (i = 0; i < sdev->l1_data.length / 4; i++) {
+		pr_debug("  Function %d: type=0x%02X, version=0x%02X, pointer=0x%04X\n",
+			i, sdev->function_directory[i].function_type,
+			sdev->function_directory[i].function_version,
+			sdev->function_directory[i].function_pointer);
+	}
+
+	if (sdev->nvm_function) {
+		pr_debug("  NVM function: pointer=0x%04X, task=%d, wr_buf_size=%d, nvm_base=0x%04X, nvm_size=%d\n",
+			sdev->nvm_function->nvm_pointer,
+			sdev->nvm_function->slave_control_channel,
+			(sdev->nvm_function->write_buffer_size
+				? sdev->nvm_function->write_buffer_size : 0),
+			sdev->nvm_function->nvm_base_address,
+			sdev->nvm_function->nvm_size);
+		if (sdev->nvm_function->object_count)
+			pr_debug("  NVM objects:\n");
+		i = 0;
+		list_for_each_entry(object, &sdev->nvm_function->object_list,
+					list) {
+			pr_debug("    Object %d - addr=0x%04X, data len=%d, type=0x%02X, version=0x%02X, manufacturer ID=0x%04X, crc=0x%04X\n",
+				i, object->addr, object->length - 8,
+				object->type, object->version,
+				object->manufacturer_id, object->crc);
+			for (j = 0; j < DIV_ROUND_UP(object->length - 8, 16);
+					j++) {
+				fill_string(str, DEBUG_PRINT_BUFFER_SIZE,
+					object->data + j * 16,
+					min(16, object->length - 8 - (j * 16)));
+				pr_debug("      data(0x%04X): %s\n", j * 16,
+					str);
+			}
+			i++;
+		}
+	}
+}
+
+static void bif_print_slaves(void)
+{
+	struct bif_slave_dev *sdev;
+
+	mutex_lock(&bif_sdev_list_mutex);
+
+	list_for_each_entry(sdev, &bif_sdev_list, list) {
+		/* Skip slaves without fully known UIDs. */
+		if (sdev->unique_id_bits_known != BIF_UNIQUE_ID_BIT_LENGTH)
+			continue;
+		bif_print_slave_data(sdev);
+	}
+
+	mutex_unlock(&bif_sdev_list_mutex);
+}
+
+static struct bif_slave_dev *bif_add_slave(struct bif_ctrl_dev *bdev)
+{
+	struct bif_slave_dev *sdev;
+
+	sdev = kzalloc(sizeof(struct bif_slave_dev), GFP_KERNEL);
+	if (sdev == NULL) {
+		pr_err("Memory allocation failed for bif_slave_dev\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	sdev->bdev = bdev;
+	INIT_LIST_HEAD(&sdev->list);
+	list_add_tail(&sdev->list, &bif_sdev_list);
+
+	return sdev;
+}
+
+static void bif_remove_slave(struct bif_slave_dev *sdev)
+{
+	list_del(&sdev->list);
+	if (sdev->bdev->selected_sdev == sdev)
+		sdev->bdev->selected_sdev = NULL;
+
+	if (sdev->slave_ctrl_function)
+		kfree(sdev->slave_ctrl_function->irq_notifier_list);
+	kfree(sdev->slave_ctrl_function);
+	kfree(sdev->protocol_function);
+	kfree(sdev->function_directory);
+
+	kfree(sdev);
+}
+
+/* This function assumes that the uid array is all 0 to start with. */
+static void set_uid_bit(u8 uid[BIF_UNIQUE_ID_BYTE_LENGTH], unsigned int bit,
+			unsigned int value)
+{
+	u8 mask;
+
+	if (bit >= BIF_UNIQUE_ID_BIT_LENGTH)
+		return;
+
+	mask = 1 << (7 - (bit % 8));
+
+	uid[bit / 8] &= ~mask;
+	uid[bit / 8] |= value << (7 - (bit % 8));
+}
+
+static unsigned int get_uid_bit(u8 uid[BIF_UNIQUE_ID_BYTE_LENGTH],
+			unsigned int bit)
+{
+	if (bit >= BIF_UNIQUE_ID_BIT_LENGTH)
+		return 0;
+
+	return (uid[bit / 8] & (1 << (7 - (bit % 8)))) ? 1 : 0;
+}
+
+static void bif_enter_irq_mode_work(struct work_struct *work)
+{
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct bif_ctrl_dev *bdev
+		= container_of(dwork, struct bif_ctrl_dev, enter_irq_mode_work);
+	int rc, i;
+
+	mutex_lock(&bdev->mutex);
+	for (i = 0; i < BIF_TRANSACTION_RETRY_COUNT; i++) {
+		rc = bdev->desc->ops->set_bus_state(bdev,
+					BIF_BUS_STATE_INTERRUPT);
+		if (rc == 0)
+			break;
+	}
+	mutex_unlock(&bdev->mutex);
+
+	/* Reschedule the task if the transaction failed. */
+	if (rc) {
+		pr_err("Could not set BIF bus to interrupt mode, rc=%d\n", rc);
+		schedule_delayed_work(&bdev->enter_irq_mode_work,
+					bdev->irq_mode_delay_jiffies);
+	}
+}
+
+static void bif_cancel_irq_mode_work(struct bif_ctrl_dev *bdev)
+{
+	cancel_delayed_work(&bdev->enter_irq_mode_work);
+}
+
+static void bif_schedule_irq_mode_work(struct bif_ctrl_dev *bdev)
+{
+	if (bdev->irq_count > 0 &&
+	    bdev->desc->ops->get_bus_state(bdev) != BIF_BUS_STATE_INTERRUPT)
+		schedule_delayed_work(&bdev->enter_irq_mode_work,
+					bdev->irq_mode_delay_jiffies);
+}
+
+static int _bif_select_slave_no_retry(struct bif_slave_dev *sdev)
+{
+	struct bif_ctrl_dev *bdev = sdev->bdev;
+	int rc = 0;
+	int i;
+
+	/* Check if the slave is already selected. */
+	if (sdev->bdev->selected_sdev == sdev)
+		return 0;
+
+	if (sdev->slave_addr) {
+		/* Select using DEV_ADR. */
+		rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_SDA,
+							sdev->slave_addr);
+		if (!rc)
+			sdev->bdev->selected_sdev = sdev;
+	} else if (sdev->unique_id_bits_known == BIF_UNIQUE_ID_BIT_LENGTH) {
+		/* Select using full UID. */
+		for (i = 0; i < BIF_UNIQUE_ID_BYTE_LENGTH - 1; i++) {
+			rc = bdev->desc->ops->bus_transaction(bdev,
+				BIF_TRANS_EDA, sdev->unique_id[i]);
+			if (rc)
+				goto out;
+		}
+
+		rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_SDA,
+			sdev->unique_id[BIF_UNIQUE_ID_BYTE_LENGTH - 1]);
+		if (rc)
+			goto out;
+	} else {
+		pr_err("Cannot select slave because it has neither UID nor DEV_ADR.\n");
+		return -EINVAL;
+	}
+
+	sdev->bdev->selected_sdev = sdev;
+
+	return 0;
+out:
+	pr_err("bus_transaction failed, rc=%d\n", rc);
+	return rc;
+}
+
+static int bif_select_slave(struct bif_slave_dev *sdev)
+{
+	int rc = -EPERM;
+	int i;
+
+	for (i = 0; i < BIF_TRANSACTION_RETRY_COUNT; i++) {
+		rc = _bif_select_slave_no_retry(sdev);
+		if (rc == 0)
+			break;
+		/* Force slave reselection. */
+		sdev->bdev->selected_sdev = NULL;
+	}
+
+	return rc;
+}
+
+/*
+ * Returns 1 if slave is selected, 0 if slave is not selected, or errno if
+ * error.
+ */
+static int bif_is_slave_selected(struct bif_ctrl_dev *bdev)
+{
+	int rc = -EPERM;
+	int tack, i;
+
+	for (i = 0; i < BIF_TRANSACTION_RETRY_COUNT; i++) {
+		/* Attempt a transaction query. */
+		rc = bdev->desc->ops->bus_transaction_read(bdev, BIF_TRANS_BC,
+						BIF_CMD_TQ, &tack);
+		if (rc == 0 || rc == -ETIMEDOUT)
+			break;
+	}
+
+	if (rc == 0)
+		rc = 1;
+	else if (rc == -ETIMEDOUT)
+		rc = 0;
+	else
+		pr_err("BIF bus_transaction_read failed, rc=%d\n", rc);
+
+	return rc;
+}
+
+/* Read from a specified number of consecutive registers. */
+static int _bif_slave_read_no_retry(struct bif_slave_dev *sdev, u16 addr,
+			u8 *buf, int len)
+{
+	struct bif_ctrl_dev *bdev = sdev->bdev;
+	int rc = 0;
+	int i, response;
+
+	rc = bif_select_slave(sdev);
+	if (rc)
+		return rc;
+
+	if (bdev->desc->ops->read_slave_registers) {
+		/*
+		 * Use low level slave register read implementation in order to
+		 * receive the benefits of BIF burst reads.
+		 */
+		rc = bdev->desc->ops->read_slave_registers(bdev, addr, buf,
+							   len);
+		if (rc)
+			pr_err("read_slave_registers failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	for (i = 0; i < len; i++) {
+		rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_ERA,
+							addr >> 8);
+		if (rc) {
+			pr_err("bus_transaction failed, rc=%d\n", rc);
+			return rc;
+		}
+
+		rc = bdev->desc->ops->bus_transaction_read(bdev, BIF_TRANS_RRA,
+							addr & 0xFF, &response);
+		if (rc) {
+			pr_err("bus_transaction_read failed, rc=%d\n", rc);
+			return rc;
+		}
+
+		if (!(response & BIF_SLAVE_RD_ACK)) {
+			pr_err("BIF register read error=0x%02X\n",
+				response & BIF_SLAVE_RD_ERR);
+			return -EIO;
+		}
+
+		buf[i] = response & BIF_SLAVE_RD_DATA;
+		addr++;
+	}
+
+	return rc;
+}
+
+/*
+ * Read from a specified number of consecutive registers.  Retry the transaction
+ * several times in case of communcation failures.
+ */
+static int _bif_slave_read(struct bif_slave_dev *sdev, u16 addr, u8 *buf,
+			int len)
+{
+	int rc = -EPERM;
+	int i;
+
+	for (i = 0; i < BIF_TRANSACTION_RETRY_COUNT; i++) {
+		rc = _bif_slave_read_no_retry(sdev, addr, buf, len);
+		if (rc == 0)
+			break;
+		/* Force slave reselection. */
+		sdev->bdev->selected_sdev = NULL;
+	}
+
+	return rc;
+}
+
+/* Write to a specified number of consecutive registers. */
+static int _bif_slave_write_no_retry(struct bif_slave_dev *sdev, u16 addr,
+			u8 *buf, int len)
+{
+	struct bif_ctrl_dev *bdev = sdev->bdev;
+	int rc = 0;
+	int i;
+
+	rc = bif_select_slave(sdev);
+	if (rc)
+		return rc;
+
+	if (bdev->desc->ops->write_slave_registers) {
+		/*
+		 * Use low level slave register write implementation in order to
+		 * receive the benefits of BIF burst writes.
+		 */
+		rc = bdev->desc->ops->write_slave_registers(bdev, addr, buf,
+							    len);
+		if (rc)
+			pr_err("write_slave_registers failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_ERA, addr >> 8);
+	if (rc)
+		goto out;
+
+	rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_WRA, addr & 0xFF);
+	if (rc)
+		goto out;
+
+	for (i = 0; i < len; i++) {
+		rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_WD,
+							buf[i]);
+		if (rc)
+			goto out;
+	}
+
+	return 0;
+out:
+	pr_err("bus_transaction failed, rc=%d\n", rc);
+	return rc;
+}
+
+/*
+ * Write to a specified number of consecutive registers.  Retry the transaction
+ * several times in case of communcation failures.
+ */
+static int _bif_slave_write(struct bif_slave_dev *sdev, u16 addr, u8 *buf,
+			int len)
+{
+	int rc = -EPERM;
+	int i;
+
+	for (i = 0; i < BIF_TRANSACTION_RETRY_COUNT; i++) {
+		rc = _bif_slave_write_no_retry(sdev, addr, buf, len);
+		if (rc == 0)
+			break;
+		/* Force slave reselection. */
+		sdev->bdev->selected_sdev = NULL;
+	}
+
+	return rc;
+}
+
+/* Takes a mutex if this consumer is not an exclusive bus user. */
+static void bif_ctrl_lock(struct bif_ctrl *ctrl)
+{
+	if (!ctrl->exclusive_lock) {
+		mutex_lock(&ctrl->bdev->mutex);
+		bif_cancel_irq_mode_work(ctrl->bdev);
+	}
+}
+
+/* Releases a mutex if this consumer is not an exclusive bus user. */
+static void bif_ctrl_unlock(struct bif_ctrl *ctrl)
+{
+	if (!ctrl->exclusive_lock) {
+		bif_schedule_irq_mode_work(ctrl->bdev);
+		mutex_unlock(&ctrl->bdev->mutex);
+	}
+}
+
+static void bif_slave_ctrl_lock(struct bif_slave *slave)
+{
+	bif_ctrl_lock(&slave->ctrl);
+}
+
+static void bif_slave_ctrl_unlock(struct bif_slave *slave)
+{
+	bif_ctrl_unlock(&slave->ctrl);
+}
+
+static int bif_check_task(struct bif_slave *slave, unsigned int task)
+{
+	if (IS_ERR_OR_NULL(slave)) {
+		pr_err("Invalid slave handle.\n");
+		return -EINVAL;
+	} else if (!slave->sdev->bdev) {
+		pr_err("BIF controller has been removed.\n");
+		return -ENXIO;
+	} else if (!slave->sdev->slave_ctrl_function
+			|| slave->sdev->slave_ctrl_function->task_count == 0) {
+		pr_err("BIF slave does not support slave control.\n");
+		return -ENODEV;
+	} else if (task >= slave->sdev->slave_ctrl_function->task_count) {
+		pr_err("Requested task: %u greater than max: %u for this slave\n",
+			task, slave->sdev->slave_ctrl_function->task_count);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * bif_request_irq() - request a BIF slave IRQ by slave task number
+ * @slave:	BIF slave handle
+ * @task:	BIF task number of the IRQ inside of the slave.  This
+ *		corresponds to the slave control channel specified for a given
+ *		BIF function inside of the slave.
+ * @nb:		Notifier block to call when the IRQ fires
+ *
+ * This function registers a notifier block to call when the BIF slave interrupt
+ * is triggered and also enables the interrupt.  The interrupt is enabled inside
+ * of the BIF slave's slave control function and also the BIF bus is put into
+ * interrupt mode.
+ *
+ * Returns 0 for success or errno if an error occurred.
+ */
+int bif_request_irq(struct bif_slave *slave, unsigned int task,
+			struct notifier_block *nb)
+{
+	int rc;
+	u16 addr;
+	u8 reg, mask;
+
+	rc = bif_check_task(slave, task);
+	if (rc) {
+		pr_err("Invalid slave or task, rc=%d\n", rc);
+		return rc;
+	}
+
+	bif_slave_ctrl_lock(slave);
+
+	rc = blocking_notifier_chain_register(
+		&slave->sdev->slave_ctrl_function->irq_notifier_list[task], nb);
+	if (rc) {
+		pr_err("Notifier registration failed, rc=%d\n", rc);
+		goto done;
+	}
+
+	/* Enable the interrupt within the slave */
+	mask = BIT(task % SLAVE_CTRL_TASKS_PER_SET);
+	addr = SLAVE_CTRL_FUNC_IRQ_EN_ADDR(
+		slave->sdev->slave_ctrl_function->slave_ctrl_pointer, task);
+	if (task / SLAVE_CTRL_TASKS_PER_SET == 0) {
+		/* Set global interrupt enable. */
+		mask |= BIT(0);
+	}
+	rc = _bif_slave_read(slave->sdev, addr, &reg, 1);
+	if (rc) {
+		pr_err("BIF slave register read failed, rc=%d\n", rc);
+		goto notifier_unregister;
+	}
+	reg |= mask;
+	rc = _bif_slave_write(slave->sdev, addr, &reg, 1);
+	if (rc) {
+		pr_err("BIF slave register write failed, rc=%d\n", rc);
+		goto notifier_unregister;
+	}
+
+	/* Set global interrupt enable if task not in set 0. */
+	if (task / SLAVE_CTRL_TASKS_PER_SET != 0) {
+		mask = BIT(0);
+		addr = SLAVE_CTRL_FUNC_IRQ_EN_ADDR(
+		       slave->sdev->slave_ctrl_function->slave_ctrl_pointer, 0);
+		rc = _bif_slave_read(slave->sdev, addr, &reg, 1);
+		if (rc) {
+			pr_err("BIF slave register read failed, rc=%d\n", rc);
+			goto notifier_unregister;
+		}
+		reg |= mask;
+		rc = _bif_slave_write(slave->sdev, addr, &reg, 1);
+		if (rc) {
+			pr_err("BIF slave register write failed, rc=%d\n", rc);
+			goto notifier_unregister;
+		}
+	}
+
+	rc = slave->sdev->bdev->desc->ops->set_bus_state(slave->sdev->bdev,
+		BIF_BUS_STATE_INTERRUPT);
+	if (rc) {
+		pr_err("Could not set BIF bus to interrupt mode, rc=%d\n", rc);
+		goto notifier_unregister;
+	}
+
+	slave->sdev->bdev->irq_count++;
+done:
+	bif_slave_ctrl_unlock(slave);
+
+	return rc;
+
+notifier_unregister:
+	blocking_notifier_chain_unregister(
+		&slave->sdev->slave_ctrl_function->irq_notifier_list[task],
+		nb);
+	bif_slave_ctrl_unlock(slave);
+
+	return rc;
+
+}
+EXPORT_SYMBOL(bif_request_irq);
+
+/**
+ * bif_free_irq() - free a BIF slave IRQ by slave task number
+ * @slave:	BIF slave handle
+ * @task:	BIF task number of the IRQ inside of the slave.  This
+ *		corresponds to the slave control channel specified for a given
+ *		BIF function inside of the slave.
+ * @nb:		Notifier block previously registered with this interrupt
+ *
+ * This function unregisters a notifier block that was previously registered
+ * with bif_request_irq().
+ *
+ * Returns 0 for success or errno if an error occurred.
+ */
+int bif_free_irq(struct bif_slave *slave, unsigned int task,
+			struct notifier_block *nb)
+{
+	int rc;
+	u16 addr;
+	u8 reg;
+
+	rc = bif_check_task(slave, task);
+	if (rc) {
+		pr_err("Invalid slave or task, rc=%d\n", rc);
+		return rc;
+	}
+
+	bif_slave_ctrl_lock(slave);
+
+	/* Disable the interrupt within the slave */
+	reg = BIT(task % SLAVE_CTRL_TASKS_PER_SET);
+	addr = SLAVE_CTRL_FUNC_IRQ_CLEAR_ADDR(
+		slave->sdev->slave_ctrl_function->slave_ctrl_pointer, task);
+	rc = _bif_slave_write(slave->sdev, addr, &reg, 1);
+	if (rc) {
+		pr_err("BIF slave register write failed, rc=%d\n", rc);
+		goto done;
+	}
+
+	rc = blocking_notifier_chain_unregister(
+		&slave->sdev->slave_ctrl_function->irq_notifier_list[task], nb);
+	if (rc) {
+		pr_err("Notifier unregistration failed, rc=%d\n", rc);
+		goto done;
+	}
+
+	slave->sdev->bdev->irq_count--;
+
+	if (slave->sdev->bdev->irq_count == 0) {
+		bif_cancel_irq_mode_work(slave->sdev->bdev);
+	} else if (slave->sdev->bdev->irq_count < 0) {
+		pr_err("Unbalanced IRQ free.\n");
+		rc = -EINVAL;
+		slave->sdev->bdev->irq_count = 0;
+	}
+done:
+	bif_slave_ctrl_unlock(slave);
+
+	return rc;
+}
+EXPORT_SYMBOL(bif_free_irq);
+
+/**
+ * bif_trigger_task() - trigger a task within a BIF slave
+ * @slave:	BIF slave handle
+ * @task:	BIF task inside of the slave to trigger.  This corresponds to
+ *		the slave control channel specified for a given BIF function
+ *		inside of the slave.
+ *
+ * Returns 0 for success or errno if an error occurred.
+ */
+int bif_trigger_task(struct bif_slave *slave, unsigned int task)
+{
+	int rc;
+	u16 addr;
+	u8 reg;
+
+	rc = bif_check_task(slave, task);
+	if (rc) {
+		pr_err("Invalid slave or task, rc=%d\n", rc);
+		return rc;
+	}
+
+	bif_slave_ctrl_lock(slave);
+
+	/* Trigger the task within the slave. */
+	reg = BIT(task % SLAVE_CTRL_TASKS_PER_SET);
+	addr = SLAVE_CTRL_FUNC_TASK_TRIGGER_ADDR(
+		slave->sdev->slave_ctrl_function->slave_ctrl_pointer, task);
+	rc = _bif_slave_write(slave->sdev, addr, &reg, 1);
+	if (rc) {
+		pr_err("BIF slave register write failed, rc=%d\n", rc);
+		goto done;
+	}
+
+done:
+	bif_slave_ctrl_unlock(slave);
+
+	return rc;
+}
+EXPORT_SYMBOL(bif_trigger_task);
+
+/**
+ * bif_task_is_busy() - checks the state of a BIF slave task
+ * @slave:	BIF slave handle
+ * @task:	BIF task inside of the slave to trigger.  This corresponds to
+ *		the slave control channel specified for a given	BIF function
+ *		inside of the slave.
+ *
+ * Returns 1 if the task is busy, 0 if it is not busy, and errno on error.
+ */
+int bif_task_is_busy(struct bif_slave *slave, unsigned int task)
+{
+	int rc;
+	u16 addr;
+	u8 reg;
+
+	rc = bif_check_task(slave, task);
+	if (rc) {
+		pr_err("Invalid slave or task, rc=%d\n", rc);
+		return rc;
+	}
+
+	bif_slave_ctrl_lock(slave);
+
+	/* Check the task busy state. */
+	addr = SLAVE_CTRL_FUNC_TASK_BUSY_ADDR(
+		slave->sdev->slave_ctrl_function->slave_ctrl_pointer, task);
+	rc = _bif_slave_read(slave->sdev, addr, &reg, 1);
+	if (rc) {
+		pr_err("BIF slave register read failed, rc=%d\n", rc);
+		goto done;
+	}
+
+	rc = (reg & BIT(task % SLAVE_CTRL_TASKS_PER_SET)) ? 1 : 0;
+done:
+	bif_slave_ctrl_unlock(slave);
+
+	return rc;
+}
+EXPORT_SYMBOL(bif_task_is_busy);
+
+static int bif_slave_notify_irqs(struct bif_slave_dev *sdev, int set, u8 val)
+{
+	int rc = 0;
+	int i, task;
+
+	for (i = 0; i < SLAVE_CTRL_TASKS_PER_SET; i++) {
+		if (val & (1 << i)) {
+			task = set * SLAVE_CTRL_TASKS_PER_SET + i;
+
+			rc = blocking_notifier_call_chain(
+			    &sdev->slave_ctrl_function->irq_notifier_list[task],
+			    task, sdev->bdev);
+			rc = notifier_to_errno(rc);
+			if (rc)
+				pr_err("Notification failed for task %d\n",
+					task);
+		}
+	}
+
+	return rc;
+}
+
+static int bif_slave_handle_irq(struct bif_slave_dev *sdev)
+{
+	struct bif_ctrl_dev *bdev = sdev->bdev;
+	bool resp = false;
+	int rc = 0;
+	int i;
+	u16 addr;
+	u8 reg;
+
+	mutex_lock(&sdev->bdev->mutex);
+	bif_cancel_irq_mode_work(sdev->bdev);
+
+	rc = bif_select_slave(sdev);
+	if (rc) {
+		pr_err("Could not select slave, rc=%d\n", rc);
+		goto done;
+	}
+
+	/* Check overall slave interrupt status. */
+	rc = bdev->desc->ops->bus_transaction_query(bdev, BIF_TRANS_BC,
+						    BIF_CMD_ISTS, &resp);
+	if (rc) {
+		pr_err("Could not query slave interrupt status, rc=%d\n", rc);
+		goto done;
+	}
+
+	if (resp) {
+		for (i = 0; i < sdev->slave_ctrl_function->task_count
+					/ SLAVE_CTRL_TASKS_PER_SET; i++) {
+			addr = sdev->slave_ctrl_function->slave_ctrl_pointer
+				+ 4 * i + 1;
+			rc = _bif_slave_read(sdev, addr, &reg, 1);
+			if (rc) {
+				pr_err("BIF slave register read failed, rc=%d\n",
+					rc);
+				goto done;
+			}
+
+			/* Ensure that interrupts are pending in the set. */
+			if (reg != 0x00) {
+				/*
+				 * Release mutex before notifying consumers so
+				 * that they can use the bus.
+				 */
+				mutex_unlock(&sdev->bdev->mutex);
+				rc = bif_slave_notify_irqs(sdev, i, reg);
+				if (rc) {
+					pr_err("BIF slave irq notification failed, rc=%d\n",
+						rc);
+					goto notification_failed;
+				}
+				mutex_lock(&sdev->bdev->mutex);
+
+				rc = bif_select_slave(sdev);
+				if (rc) {
+					pr_err("Could not select slave, rc=%d\n",
+						rc);
+					goto done;
+				}
+
+				/* Clear all interrupts in this set. */
+				rc = _bif_slave_write(sdev, addr, &reg, 1);
+				if (rc) {
+					pr_err("BIF slave register write failed, rc=%d\n",
+						rc);
+					goto done;
+				}
+			}
+		}
+	}
+
+done:
+	bif_schedule_irq_mode_work(sdev->bdev);
+	mutex_unlock(&sdev->bdev->mutex);
+notification_failed:
+	if (rc == 0)
+		rc = resp;
+	return rc;
+}
+
+/**
+ * bif_ctrl_notify_slave_irq() - notify the BIF framework that a slave interrupt
+ *				was received by a BIF controller
+ * @bdev:	BIF controller device pointer
+ *
+ * This function should only be called from a BIF controller driver.
+ *
+ * Returns 0 for success or errno if an error occurred.
+ */
+int bif_ctrl_notify_slave_irq(struct bif_ctrl_dev *bdev)
+{
+	struct bif_slave_dev *sdev;
+	int rc = 0, handled = 0;
+
+	if (IS_ERR_OR_NULL(bdev))
+		return -EINVAL;
+
+	mutex_lock(&bif_sdev_list_mutex);
+
+	list_for_each_entry(sdev, &bif_sdev_list, list) {
+		if (sdev->bdev == bdev && sdev->present) {
+			rc = bif_slave_handle_irq(sdev);
+			if (rc < 0) {
+				pr_err("Could not handle BIF slave irq, rc=%d\n",
+					rc);
+				break;
+			}
+			handled += rc;
+		}
+	}
+
+	mutex_unlock(&bif_sdev_list_mutex);
+
+	if (handled == 0)
+		pr_info("Spurious BIF slave interrupt detected.\n");
+
+	if (rc > 0)
+		rc = 0;
+
+	return rc;
+}
+EXPORT_SYMBOL(bif_ctrl_notify_slave_irq);
+
+/**
+ * bif_ctrl_notify_battery_changed() - notify the BIF framework that a battery
+ *				pack has been inserted or removed
+ * @bdev:	BIF controller device pointer
+ *
+ * This function should only be called from a BIF controller driver.
+ *
+ * Returns 0 for success or errno if an error occurred.
+ */
+int bif_ctrl_notify_battery_changed(struct bif_ctrl_dev *bdev)
+{
+	int rc = 0;
+	int present;
+
+	if (IS_ERR_OR_NULL(bdev))
+		return -EINVAL;
+
+	if (bdev->desc->ops->get_battery_presence) {
+		present = bdev->desc->ops->get_battery_presence(bdev);
+		if (present < 0) {
+			pr_err("Could not determine battery presence, rc=%d\n",
+				rc);
+			return rc;
+		}
+
+		if (bdev->battery_present == !!present)
+			return 0;
+
+		bdev->battery_present = present;
+
+		rc = blocking_notifier_call_chain(&bdev->bus_change_notifier,
+			present ? BIF_BUS_EVENT_BATTERY_INSERTED
+				: BIF_BUS_EVENT_BATTERY_REMOVED, bdev);
+		if (rc)
+			pr_err("Call chain noification failed, rc=%d\n", rc);
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL(bif_ctrl_notify_battery_changed);
+
+/**
+ * bif_ctrl_signal_battery_changed() - notify the BIF framework that a battery
+ *				pack has been inserted or removed
+ * @ctrl:	BIF controller consumer handle
+ *
+ * This function should only be called by a BIF consumer driver on systems where
+ * the BIF controller driver is unable to determine when a battery is inserted
+ * or removed.
+ *
+ * Returns 0 for success or errno if an error occurred.
+ */
+int bif_ctrl_signal_battery_changed(struct bif_ctrl *ctrl)
+{
+	if (IS_ERR_OR_NULL(ctrl))
+		return -EINVAL;
+
+	return bif_ctrl_notify_battery_changed(ctrl->bdev);
+}
+EXPORT_SYMBOL(bif_ctrl_signal_battery_changed);
+
+/**
+ * bif_ctrl_notifier_register() - register a notifier block to be called when
+ *				a battery pack is inserted or removed
+ * @ctrl:	BIF controller consumer handle
+ *
+ * The value passed into the notifier when it is called is one of
+ * enum bif_bus_event.
+ *
+ * Returns 0 for success or errno if an error occurred.
+ */
+int bif_ctrl_notifier_register(struct bif_ctrl *ctrl, struct notifier_block *nb)
+{
+	int rc;
+
+	if (IS_ERR_OR_NULL(ctrl))
+		return -EINVAL;
+
+	rc = blocking_notifier_chain_register(&ctrl->bdev->bus_change_notifier,
+					      nb);
+	if (rc)
+		pr_err("Notifier registration failed, rc=%d\n", rc);
+
+	return rc;
+}
+EXPORT_SYMBOL(bif_ctrl_notifier_register);
+
+/**
+ * bif_ctrl_notifier_unregister() - unregister a battery status change notifier
+ *				block that was previously registered
+ * @ctrl:	BIF controller consumer handle
+ *
+ * Returns 0 for success or errno if an error occurred.
+ */
+int bif_ctrl_notifier_unregister(struct bif_ctrl *ctrl,
+				 struct notifier_block *nb)
+{
+	int rc;
+
+	if (IS_ERR_OR_NULL(ctrl))
+		return -EINVAL;
+
+	rc =
+	    blocking_notifier_chain_unregister(&ctrl->bdev->bus_change_notifier,
+						nb);
+	if (rc)
+		pr_err("Notifier unregistration failed, rc=%d\n", rc);
+
+	return rc;
+}
+EXPORT_SYMBOL(bif_ctrl_notifier_unregister);
+
+/**
+ * bif_get_bus_handle() - returns the BIF controller consumer handle associated
+ *			with a BIF slave handle
+ * @slave:	BIF slave handle
+ *
+ * Note, bif_ctrl_put() should never be called for the pointer output by
+ * bif_get_bus_handle().
+ */
+struct bif_ctrl *bif_get_bus_handle(struct bif_slave *slave)
+{
+	if (IS_ERR_OR_NULL(slave))
+		return ERR_PTR(-EINVAL);
+
+	return &slave->ctrl;
+}
+EXPORT_SYMBOL(bif_get_bus_handle);
+
+/**
+ * bif_ctrl_count() - returns the number of registered BIF controllers
+ */
+int bif_ctrl_count(void)
+{
+	struct bif_ctrl_dev *bdev;
+	int count = 0;
+
+	mutex_lock(&bif_ctrl_list_mutex);
+
+	list_for_each_entry(bdev, &bif_ctrl_list, list) {
+		count++;
+	}
+	mutex_unlock(&bif_ctrl_list_mutex);
+
+	return count;
+}
+EXPORT_SYMBOL(bif_ctrl_count);
+
+/**
+ * bif_ctrl_get_by_id() - get a handle for the id'th BIF controller registered
+ *			in the system
+ * @id:	Arbitrary number associated with the BIF bus in the system
+ *
+ * id must be in the range [0, bif_ctrl_count() - 1].  This function should only
+ * need to be called by a BIF consumer that is unable to link to a given BIF
+ * controller via a device tree binding.
+ *
+ * Returns a BIF controller consumer handle if successful or an ERR_PTR if not.
+ */
+struct bif_ctrl *bif_ctrl_get_by_id(unsigned int id)
+{
+	struct bif_ctrl_dev *bdev;
+	struct bif_ctrl_dev *bdev_found = NULL;
+	struct bif_ctrl *ctrl = ERR_PTR(-ENODEV);
+
+	mutex_lock(&bif_ctrl_list_mutex);
+
+	list_for_each_entry(bdev, &bif_ctrl_list, list) {
+		if (id == 0) {
+			bdev_found = bdev;
+			break;
+		}
+		id--;
+	}
+	mutex_unlock(&bif_ctrl_list_mutex);
+
+	if (bdev_found) {
+		ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
+		if (!ctrl) {
+			pr_err("Bus handle allocation failed\n");
+			ctrl = ERR_PTR(-ENOMEM);
+		} else {
+			ctrl->bdev = bdev_found;
+		}
+	}
+
+	return ctrl;
+}
+EXPORT_SYMBOL(bif_ctrl_get_by_id);
+
+/**
+ * bif_ctrl_get() - get a handle for the BIF controller that is linked to the
+ *			consumer device in the device tree
+ * @consumer_dev:	Pointer to the consumer's device
+ *
+ * In order to use this function, the BIF consumer's device must specify the
+ * "qcom,bif-ctrl" property in its device tree node which points to a BIF
+ * controller device node.
+ *
+ * Returns a BIF controller consumer handle if successful or an ERR_PTR if not.
+ * If the BIF controller linked to the consumer device has not yet probed, then
+ * ERR_PTR(-EPROBE_DEFER) is returned.
+ */
+struct bif_ctrl *bif_ctrl_get(struct device *consumer_dev)
+{
+	struct device_node *ctrl_node = NULL;
+	struct bif_ctrl_dev *bdev_found = NULL;
+	struct bif_ctrl *ctrl = ERR_PTR(-EPROBE_DEFER);
+	struct bif_ctrl_dev *bdev = NULL;
+
+	if (!consumer_dev || !consumer_dev->of_node) {
+		pr_err("Invalid device node\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	ctrl_node = of_parse_phandle(consumer_dev->of_node, "qcom,bif-ctrl", 0);
+	if (!ctrl_node) {
+		pr_err("Could not find qcom,bif-ctrl property in %s\n",
+			consumer_dev->of_node->full_name);
+		return ERR_PTR(-ENXIO);
+	}
+
+	mutex_lock(&bif_ctrl_list_mutex);
+	list_for_each_entry(bdev, &bif_ctrl_list, list) {
+		if (bdev->ctrl_dev && bdev->ctrl_dev->of_node == ctrl_node) {
+			bdev_found = bdev;
+			break;
+		}
+	}
+	mutex_unlock(&bif_ctrl_list_mutex);
+
+	if (bdev_found) {
+		ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
+		if (!ctrl) {
+			pr_err("Bus handle allocation failed\n");
+			ctrl = ERR_PTR(-ENOMEM);
+		} else {
+			ctrl->bdev = bdev_found;
+		}
+	}
+
+	return ctrl;
+}
+EXPORT_SYMBOL(bif_ctrl_get);
+
+/**
+ * bif_ctrl_put() - frees a BIF controller handle
+ * @ctrl:	BIF controller consumer handle
+ */
+void bif_ctrl_put(struct bif_ctrl *ctrl)
+{
+	if (!IS_ERR_OR_NULL(ctrl) && ctrl->exclusive_lock)
+		mutex_unlock(&ctrl->bdev->mutex);
+	kfree(ctrl);
+}
+EXPORT_SYMBOL(bif_ctrl_put);
+
+/*
+ * Returns true if all parameters are matched, otherwise false.
+ * function_type and function_version mean that their exists some function in
+ * the slave which has the specified type and subtype.  ctrl == NULL is treated
+ * as a wildcard.
+ */
+static bool bif_slave_match(const struct bif_ctrl *ctrl,
+	struct bif_slave_dev *sdev, const struct bif_match_criteria *criteria)
+{
+	int i, type, version;
+
+	if (ctrl && (ctrl->bdev != sdev->bdev))
+		return false;
+
+	if (!sdev->present
+	    && (!(criteria->match_mask & BIF_MATCH_IGNORE_PRESENCE)
+		|| ((criteria->match_mask & BIF_MATCH_IGNORE_PRESENCE)
+		    && !criteria->ignore_presence)))
+		return false;
+
+	if ((criteria->match_mask & BIF_MATCH_MANUFACTURER_ID)
+	    && sdev->l1_data.manufacturer_id != criteria->manufacturer_id)
+		return false;
+
+	if ((criteria->match_mask & BIF_MATCH_PRODUCT_ID)
+	    && sdev->l1_data.product_id != criteria->product_id)
+		return false;
+
+	if (criteria->match_mask & BIF_MATCH_FUNCTION_TYPE) {
+		if (!sdev->function_directory)
+			return false;
+		for (i = 0; i < sdev->l1_data.length / 4; i++) {
+			type = sdev->function_directory[i].function_type;
+			version = sdev->function_directory[i].function_version;
+			if (type == criteria->function_type &&
+				(version == criteria->function_version
+					|| !(criteria->match_mask
+						& BIF_MATCH_FUNCTION_VERSION)))
+				return true;
+		}
+		return false;
+	}
+
+	return true;
+}
+
+/**
+ * bif_slave_match_count() - returns the number of slaves associated with the
+ *			specified BIF controller which fit the matching
+ *			criteria
+ * @ctrl:		BIF controller consumer handle
+ * @match_criteria:	Matching criteria used to filter slaves
+ */
+int bif_slave_match_count(const struct bif_ctrl *ctrl,
+			const struct bif_match_criteria *match_criteria)
+{
+	struct bif_slave_dev *sdev;
+	int count = 0;
+
+	mutex_lock(&bif_sdev_list_mutex);
+
+	list_for_each_entry(sdev, &bif_sdev_list, list) {
+		if (bif_slave_match(ctrl, sdev, match_criteria))
+			count++;
+	}
+
+	mutex_unlock(&bif_sdev_list_mutex);
+
+	return count;
+}
+EXPORT_SYMBOL(bif_slave_match_count);
+
+/**
+ * bif_slave_match_get() - get a slave handle for the id'th slave associated
+ *			with the specified BIF controller which fits the
+ *			matching criteria
+ * @ctrl:		BIF controller consumer handle
+ * @id:			Index into the set of matching slaves
+ * @match_criteria:	Matching criteria used to filter slaves
+ *
+ * id must be in the range [0, bif_slave_match_count(ctrl, match_criteria) - 1].
+ *
+ * Returns a BIF slave handle if successful or an ERR_PTR if not.
+ */
+struct bif_slave *bif_slave_match_get(const struct bif_ctrl *ctrl,
+	unsigned int id, const struct bif_match_criteria *match_criteria)
+{
+	struct bif_slave_dev *sdev;
+	struct bif_slave *slave = ERR_PTR(-ENODEV);
+	struct bif_slave_dev *sdev_found = NULL;
+	int count = 0;
+
+	mutex_lock(&bif_sdev_list_mutex);
+
+	list_for_each_entry(sdev, &bif_sdev_list, list) {
+		if (bif_slave_match(ctrl, sdev, match_criteria))
+			count++;
+		if (count == id + 1) {
+			sdev_found = sdev;
+			break;
+		}
+	}
+
+	mutex_unlock(&bif_sdev_list_mutex);
+
+	if (sdev_found) {
+		slave = kzalloc(sizeof(*slave), GFP_KERNEL);
+		if (!slave) {
+			pr_err("Slave allocation failed\n");
+			slave = ERR_PTR(-ENOMEM);
+		} else {
+			slave->sdev = sdev_found;
+			slave->ctrl.bdev = sdev_found->bdev;
+		}
+	}
+
+	return slave;
+}
+EXPORT_SYMBOL(bif_slave_match_get);
+
+/**
+ * bif_slave_put() - frees a BIF slave handle
+ * @slave:	BIF slave handle
+ */
+void bif_slave_put(struct bif_slave *slave)
+{
+	if (!IS_ERR_OR_NULL(slave) && slave->ctrl.exclusive_lock)
+		mutex_unlock(&slave->sdev->bdev->mutex);
+	kfree(slave);
+}
+EXPORT_SYMBOL(bif_slave_put);
+
+/**
+ * bif_slave_find_function() - get the function pointer and version of a
+ *			BIF function if it is present on the specified slave
+ * @slave:		BIF slave handle
+ * @function:		BIF function to search for inside of the slave
+ * @version:		If the function is found, then 'version' is set to the
+ *			version value of the function
+ * @function_pointer:	If the function is found, then 'function_pointer' is set
+ *			to the BIF slave address of the function
+ *
+ * Returns 0 for success or errno if an error occurred.  If the function is not
+ * found in the slave, then -ENODEV is returned.
+ */
+int bif_slave_find_function(struct bif_slave *slave, u8 function, u8 *version,
+				u16 *function_pointer)
+{
+	int rc = -ENODEV;
+	struct bif_ddb_l2_data *func;
+	int i;
+
+	if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(version)
+	    || IS_ERR_OR_NULL(function_pointer)) {
+		pr_err("Invalid pointer input.\n");
+		return -EINVAL;
+	}
+
+	func = slave->sdev->function_directory;
+
+	for (i = 0; i < slave->sdev->l1_data.length / 4; i++) {
+		if (function == func[i].function_type) {
+			*version = func[i].function_version;
+			*function_pointer = func[i].function_pointer;
+			rc = 0;
+			break;
+		}
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL(bif_slave_find_function);
+
+/**
+ * bif_slave_read() - read contiguous memory values from a BIF slave
+ * @slave:	BIF slave handle
+ * @addr:	BIF slave address to begin reading at
+ * @buf:	Buffer to fill with memory values
+ * @len:	Number of byte to read
+ *
+ * Returns 0 for success or errno if an error occurred.
+ */
+int bif_slave_read(struct bif_slave *slave, u16 addr, u8 *buf, int len)
+{
+	int rc;
+
+	if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(buf)) {
+		pr_err("Invalid pointer input.\n");
+		return -EINVAL;
+	}
+
+	bif_slave_ctrl_lock(slave);
+
+	rc = _bif_slave_read(slave->sdev, addr, buf, len);
+	if (rc)
+		pr_err("BIF slave read failed, rc=%d\n", rc);
+
+	bif_slave_ctrl_unlock(slave);
+
+	return rc;
+}
+EXPORT_SYMBOL(bif_slave_read);
+
+/**
+ * bif_slave_write() - write contiguous memory values to a BIF slave
+ * @slave:	BIF slave handle
+ * @addr:	BIF slave address to begin writing at
+ * @buf:	Buffer containing values to write
+ * @len:	Number of byte to write
+ *
+ * Returns 0 for success or errno if an error occurred.
+ */
+int bif_slave_write(struct bif_slave *slave, u16 addr, u8 *buf, int len)
+{
+	int rc;
+
+	if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(buf)) {
+		pr_err("Invalid pointer input.\n");
+		return -EINVAL;
+	}
+
+	bif_slave_ctrl_lock(slave);
+
+	rc = _bif_slave_write(slave->sdev, addr, buf, len);
+	if (rc)
+		pr_err("BIF slave write failed, rc=%d\n", rc);
+
+	bif_slave_ctrl_unlock(slave);
+
+	return rc;
+}
+EXPORT_SYMBOL(bif_slave_write);
+
+/**
+ * bif_slave_is_present() - check if a slave is currently physically present
+ *		in the system
+ * @slave:	BIF slave handle
+ *
+ * Returns 1 if the slave is present, 0 if the slave is not present, or errno
+ * if an error occurred.
+ *
+ * This function can be used by BIF consumer drivers to check if their slave
+ * handles are still meaningful after battery reinsertion.
+ */
+int bif_slave_is_present(struct bif_slave *slave)
+{
+	if (IS_ERR_OR_NULL(slave)) {
+		pr_err("Invalid pointer input.\n");
+		return -EINVAL;
+	}
+
+	return slave->sdev->present;
+}
+EXPORT_SYMBOL(bif_slave_is_present);
+
+/**
+ * bif_slave_is_selected() - check if a slave is currently selected on the BIF
+ *		bus
+ * @slave:	BIF slave handle
+ *
+ * Returns 1 if the slave is selected, 0 if the slave is not selected, or errno
+ * if an error occurred.
+ *
+ * This function should not be required under normal circumstances since the
+ * bif-core framework ensures that slaves are always selected when needed.
+ * It would be most useful when used as a helper in conjunction with
+ * bif_ctrl_bus_lock() and the raw transaction functions.
+ */
+int bif_slave_is_selected(struct bif_slave *slave)
+{
+	int rc;
+
+	if (IS_ERR_OR_NULL(slave)) {
+		pr_err("Invalid pointer input.\n");
+		return -EINVAL;
+	}
+
+	if (slave->sdev->bdev->selected_sdev != slave->sdev)
+		return false;
+
+	bif_slave_ctrl_lock(slave);
+	rc = bif_is_slave_selected(slave->sdev->bdev);
+	bif_slave_ctrl_unlock(slave);
+
+	return rc;
+}
+EXPORT_SYMBOL(bif_slave_is_selected);
+
+/**
+ * bif_slave_select() - select a slave on the BIF bus
+ * @slave:	BIF slave handle
+ *
+ * Returns 0 on success or errno if an error occurred.
+ *
+ * This function should not be required under normal circumstances since the
+ * bif-core framework ensures that slaves are always selected when needed.
+ * It would be most useful when used as a helper in conjunction with
+ * bif_ctrl_bus_lock() and the raw transaction functions.
+ */
+int bif_slave_select(struct bif_slave *slave)
+{
+	int rc;
+
+	if (IS_ERR_OR_NULL(slave)) {
+		pr_err("Invalid pointer input.\n");
+		return -EINVAL;
+	}
+
+	bif_slave_ctrl_lock(slave);
+	slave->sdev->bdev->selected_sdev = NULL;
+	rc = bif_select_slave(slave->sdev);
+	bif_slave_ctrl_unlock(slave);
+
+	return rc;
+}
+EXPORT_SYMBOL(bif_slave_select);
+
+/**
+ * bif_ctrl_raw_transaction() - perform a raw BIF transaction on the bus which
+ *			expects no slave response
+ * @ctrl:		BIF controller consumer handle
+ * @transaction:	BIF transaction to carry out.  This should be one of the
+ *			values in enum bif_transaction.
+ * @data:		8-bit data to use in the transaction.  The meaning of
+ *			this data depends upon the transaction that is to be
+ *			performed.
+ *
+ * When performing a bus command (BC) transaction, values in enum
+ * bif_bus_command may be used for the data parameter.  Additional manufacturer
+ * specific values may also be used in a BC transaction.
+ *
+ * Returns 0 on success or errno if an error occurred.
+ *
+ * This function should only need to be used when BIF transactions are required
+ * that are not handled by the bif-core directly.
+ */
+int bif_ctrl_raw_transaction(struct bif_ctrl *ctrl, int transaction, u8 data)
+{
+	int rc;
+
+	if (IS_ERR_OR_NULL(ctrl)) {
+		pr_err("Invalid pointer input.\n");
+		return -EINVAL;
+	}
+
+	bif_ctrl_lock(ctrl);
+
+	rc = ctrl->bdev->desc->ops->bus_transaction(ctrl->bdev, transaction,
+							data);
+	if (rc)
+		pr_err("BIF bus transaction failed, rc=%d\n", rc);
+
+	bif_ctrl_unlock(ctrl);
+
+	return rc;
+}
+EXPORT_SYMBOL(bif_ctrl_raw_transaction);
+
+/**
+ * bif_ctrl_raw_transaction_read() - perform a raw BIF transaction on the bus
+ *			which expects an RD or TACK slave response word
+ * @ctrl:		BIF controller consumer handle
+ * @transaction:	BIF transaction to carry out.  This should be one of the
+ *			values in enum bif_transaction.
+ * @data:		8-bit data to use in the transaction.  The meaning of
+ *			this data depends upon the transaction that is to be
+ *			performed.
+ * @response:		Pointer to an integer which is filled with the 11-bit
+ *			slave response word upon success.  The 11-bit format is
+ *			(MSB to LSB) BCF, ACK, EOT, D7-D0.
+ *
+ * When performing a bus command (BC) transaction, values in enum
+ * bif_bus_command may be used for the data parameter.  Additional manufacturer
+ * specific values may also be used in a BC transaction.
+ *
+ * Returns 0 on success or errno if an error occurred.
+ *
+ * This function should only need to be used when BIF transactions are required
+ * that are not handled by the bif-core directly.
+ */
+int bif_ctrl_raw_transaction_read(struct bif_ctrl *ctrl, int transaction,
+					u8 data, int *response)
+{
+	int rc;
+
+	if (IS_ERR_OR_NULL(ctrl) || IS_ERR_OR_NULL(response)) {
+		pr_err("Invalid pointer input.\n");
+		return -EINVAL;
+	}
+
+	bif_ctrl_lock(ctrl);
+
+	rc = ctrl->bdev->desc->ops->bus_transaction_read(ctrl->bdev,
+					transaction, data, response);
+	if (rc)
+		pr_err("BIF bus transaction failed, rc=%d\n", rc);
+
+	bif_ctrl_unlock(ctrl);
+
+	return rc;
+}
+EXPORT_SYMBOL(bif_ctrl_raw_transaction_read);
+
+/**
+ * bif_ctrl_raw_transaction_query() - perform a raw BIF transaction on the bus
+ *			which expects a BQ slave response
+ * @ctrl:		BIF controller consumer handle
+ * @transaction:	BIF transaction to carry out.  This should be one of the
+ *			values in enum bif_transaction.
+ * @data:		8-bit data to use in the transaction.  The meaning of
+ *			this data depends upon the transaction that is to be
+ *			performed.
+ * @query_response:	Pointer to boolean which is set to true if a BQ pulse
+ *			is receieved, or false if no BQ pulse is received before
+ *			timing out.
+ *
+ * When performing a bus command (BC) transaction, values in enum
+ * bif_bus_command may be used for the data parameter.  Additional manufacturer
+ * specific values may also be used in a BC transaction.
+ *
+ * Returns 0 on success or errno if an error occurred.
+ *
+ * This function should only need to be used when BIF transactions are required
+ * that are not handled by the bif-core directly.
+ */
+int bif_ctrl_raw_transaction_query(struct bif_ctrl *ctrl, int transaction,
+		u8 data, bool *query_response)
+{
+	int rc;
+
+	if (IS_ERR_OR_NULL(ctrl) || IS_ERR_OR_NULL(query_response)) {
+		pr_err("Invalid pointer input.\n");
+		return -EINVAL;
+	}
+
+	bif_ctrl_lock(ctrl);
+
+	rc = ctrl->bdev->desc->ops->bus_transaction_query(ctrl->bdev,
+					transaction, data, query_response);
+	if (rc)
+		pr_err("BIF bus transaction failed, rc=%d\n", rc);
+
+	bif_ctrl_unlock(ctrl);
+
+	return rc;
+}
+EXPORT_SYMBOL(bif_ctrl_raw_transaction_query);
+
+/**
+ * bif_ctrl_bus_lock() - lock the BIF bus of a controller for exclusive access
+ * @ctrl:	BIF controller consumer handle
+ *
+ * This function should only need to be called in circumstances where a BIF
+ * consumer is issuing special BIF bus commands that have strict ordering
+ * requirements.
+ */
+void bif_ctrl_bus_lock(struct bif_ctrl *ctrl)
+{
+	if (IS_ERR_OR_NULL(ctrl)) {
+		pr_err("Invalid controller handle.\n");
+		return;
+	}
+
+	if (ctrl->exclusive_lock) {
+		pr_err("BIF bus exclusive lock already held\n");
+		return;
+	}
+
+	mutex_lock(&ctrl->bdev->mutex);
+	ctrl->exclusive_lock = true;
+	bif_cancel_irq_mode_work(ctrl->bdev);
+}
+EXPORT_SYMBOL(bif_ctrl_bus_lock);
+
+/**
+ * bif_ctrl_bus_unlock() - lock the BIF bus of a controller that was previously
+ *		locked for exclusive access
+ * @ctrl:	BIF controller consumer handle
+ *
+ * This function must only be called after first calling bif_ctrl_bus_lock().
+ */
+void bif_ctrl_bus_unlock(struct bif_ctrl *ctrl)
+{
+	if (IS_ERR_OR_NULL(ctrl)) {
+		pr_err("Invalid controller handle.\n");
+		return;
+	}
+
+	if (!ctrl->exclusive_lock) {
+		pr_err("BIF bus exclusive lock not already held\n");
+		return;
+	}
+
+	ctrl->exclusive_lock = false;
+	bif_schedule_irq_mode_work(ctrl->bdev);
+	mutex_unlock(&ctrl->bdev->mutex);
+}
+EXPORT_SYMBOL(bif_ctrl_bus_unlock);
+
+/**
+ * bif_ctrl_measure_rid() - measure the battery pack Rid pull-down resistance
+ *		in ohms
+ * @ctrl:	BIF controller consumer handle
+ *
+ * Returns the resistance of the Rid resistor in ohms if successful or errno
+ * if an error occurred.
+ */
+int bif_ctrl_measure_rid(struct bif_ctrl *ctrl)
+{
+	int rc;
+
+	if (IS_ERR_OR_NULL(ctrl)) {
+		pr_err("Invalid controller handle.\n");
+		return -ENODEV;
+	}
+
+	if (!ctrl->bdev->desc->ops->get_battery_rid) {
+		pr_err("Cannot measure Rid.\n");
+		return -ENXIO;
+	}
+
+	bif_ctrl_lock(ctrl);
+
+	rc = ctrl->bdev->desc->ops->get_battery_rid(ctrl->bdev);
+	if (rc < 0)
+		pr_err("Error during Rid measurement, rc=%d\n", rc);
+
+	bif_ctrl_unlock(ctrl);
+
+	return rc;
+}
+EXPORT_SYMBOL(bif_ctrl_measure_rid);
+
+/**
+ * bif_ctrl_get_bus_period() - get the BIF bus period (tau_bif) in nanoseconds
+ * @ctrl:	BIF controller consumer handle
+ *
+ * Returns the currently configured bus period in nanoseconds if successful or
+ * errno if an error occurred.
+ */
+int bif_ctrl_get_bus_period(struct bif_ctrl *ctrl)
+{
+	int rc;
+
+	if (IS_ERR_OR_NULL(ctrl)) {
+		pr_err("Invalid controller handle.\n");
+		return -ENODEV;
+	}
+
+	if (!ctrl->bdev->desc->ops->get_bus_period) {
+		pr_err("Cannot get the BIF bus period.\n");
+		return -ENXIO;
+	}
+
+	rc = ctrl->bdev->desc->ops->get_bus_period(ctrl->bdev);
+	if (rc < 0)
+		pr_err("Error during bus period retrieval, rc=%d\n", rc);
+
+	return rc;
+}
+EXPORT_SYMBOL(bif_ctrl_get_bus_period);
+
+/**
+ * bif_ctrl_set_bus_period() - set the BIF bus period (tau_bif) in nanoseconds
+ * @ctrl:	BIF controller consumer handle
+ * @period_ns:	BIF bus period in nanoseconds to use
+ *
+ * If the exact period is not supported by the BIF controller hardware, then the
+ * next larger supported period will be used.
+ *
+ * Returns 0 on success or errno if an error occurred.
+ */
+int bif_ctrl_set_bus_period(struct bif_ctrl *ctrl, int period_ns)
+{
+	int rc;
+
+	if (IS_ERR_OR_NULL(ctrl)) {
+		pr_err("Invalid controller handle.\n");
+		return -ENODEV;
+	}
+
+	if (!ctrl->bdev->desc->ops->set_bus_period) {
+		pr_err("Cannot set the BIF bus period.\n");
+		return -ENXIO;
+	}
+
+	bif_ctrl_lock(ctrl);
+	rc = ctrl->bdev->desc->ops->set_bus_period(ctrl->bdev, period_ns);
+	if (rc)
+		pr_err("Error during bus period configuration, rc=%d\n", rc);
+	bif_ctrl_unlock(ctrl);
+
+	return rc;
+}
+EXPORT_SYMBOL(bif_ctrl_set_bus_period);
+
+/**
+ * bif_ctrl_get_bus_state() - get the current state of the BIF bus
+ * @ctrl:	BIF controller consumer handle
+ *
+ * Returns a bus state from enum bif_bus_state if successful or errno if an
+ * error occurred.
+ */
+int bif_ctrl_get_bus_state(struct bif_ctrl *ctrl)
+{
+	int rc;
+
+	if (IS_ERR_OR_NULL(ctrl)) {
+		pr_err("Invalid controller handle.\n");
+		return -ENODEV;
+	}
+
+	rc = ctrl->bdev->desc->ops->get_bus_state(ctrl->bdev);
+	if (rc < 0)
+		pr_err("Error during bus state retrieval, rc=%d\n", rc);
+
+	return rc;
+}
+EXPORT_SYMBOL(bif_ctrl_get_bus_state);
+
+/**
+ * bif_ctrl_set_bus_state() - set the state of the BIF bus
+ * @ctrl:	BIF controller consumer handle
+ * @state:	State for the BIF bus to enter
+ *
+ * Returns 0 on success or errno if an error occurred.
+ */
+int bif_ctrl_set_bus_state(struct bif_ctrl *ctrl, enum bif_bus_state state)
+{
+	int rc;
+
+	if (IS_ERR_OR_NULL(ctrl)) {
+		pr_err("Invalid controller handle.\n");
+		return -ENODEV;
+	}
+
+	bif_ctrl_lock(ctrl);
+
+	rc = ctrl->bdev->desc->ops->set_bus_state(ctrl->bdev, state);
+	if (rc < 0)
+		pr_err("Error during bus state configuration, rc=%d\n", rc);
+
+	/*
+	 * Uncache the selected slave if the new bus state results in the slave
+	 * becoming unselected.
+	 */
+	if (state == BIF_BUS_STATE_MASTER_DISABLED
+	    || state == BIF_BUS_STATE_POWER_DOWN
+	    || state == BIF_BUS_STATE_STANDBY)
+		ctrl->bdev->selected_sdev = NULL;
+
+	bif_ctrl_unlock(ctrl);
+
+	return rc;
+}
+EXPORT_SYMBOL(bif_ctrl_set_bus_state);
+
+/*
+ * Check if the specified function is a protocol function and if it is, then
+ * instantiate protocol function data for the slave.
+ */
+static int bif_initialize_protocol_function(struct bif_slave_dev *sdev,
+		struct bif_ddb_l2_data *func)
+{
+	int rc = 0;
+	u8 buf[4];
+
+	/* Ensure that this is a protocol function. */
+	if (func->function_type != BIF_FUNC_PROTOCOL)
+		return 0;
+
+	if (sdev->protocol_function) {
+		pr_err("Duplicate protocol function found for BIF slave; DEV_ADR=0x%02X\n",
+			sdev->slave_addr);
+		return -EPERM;
+	}
+
+	sdev->protocol_function = kzalloc(sizeof(struct bif_protocol_function),
+						GFP_KERNEL);
+	if (!sdev->protocol_function) {
+		pr_err("out of memory\n");
+		return -ENOMEM;
+	}
+
+	rc = _bif_slave_read(sdev, func->function_pointer, buf, 4);
+	if (rc) {
+		pr_err("Protocol function data read failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	sdev->protocol_function->protocol_pointer  = buf[0] << 8 | buf[1];
+	sdev->protocol_function->device_id_pointer = buf[2] << 8 | buf[3];
+	sdev->protocol_function->l2_entry = func;
+
+	rc = _bif_slave_read(sdev, sdev->protocol_function->device_id_pointer,
+		sdev->protocol_function->device_id, BIF_DEVICE_ID_BYTE_LENGTH);
+	if (rc) {
+		pr_err("Device ID read failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	/* Check if this slave does not have a UID value stored. */
+	if (sdev->unique_id_bits_known == 0) {
+		sdev->unique_id_bits_known = BIF_UNIQUE_ID_BIT_LENGTH;
+		/* Fill in UID using manufacturer ID and device ID. */
+		sdev->unique_id[0] = sdev->l1_data.manufacturer_id >> 8;
+		sdev->unique_id[1] = sdev->l1_data.manufacturer_id;
+		memcpy(&sdev->unique_id[2],
+			sdev->protocol_function->device_id,
+			BIF_DEVICE_ID_BYTE_LENGTH);
+	}
+
+	return rc;
+}
+
+/*
+ * Check if the specified function is a slave control function and if it is,
+ * then instantiate slave control function data for the slave.
+ */
+static int bif_initialize_slave_control_function(struct bif_slave_dev *sdev,
+		struct bif_ddb_l2_data *func)
+{
+	int rc = 0;
+	int i;
+	u8 buf[3];
+
+	/* Ensure that this is a slave control function. */
+	if (func->function_type != BIF_FUNC_SLAVE_CONTROL)
+		return 0;
+
+	if (sdev->slave_ctrl_function) {
+		pr_err("Duplicate slave control function found for BIF slave; DEV_ADR=0x%02X\n",
+			sdev->slave_addr);
+		return -EPERM;
+	}
+
+	sdev->slave_ctrl_function
+		= kzalloc(sizeof(struct bif_protocol_function), GFP_KERNEL);
+	if (!sdev->slave_ctrl_function) {
+		pr_err("out of memory\n");
+		return -ENOMEM;
+	}
+
+	rc = _bif_slave_read(sdev, func->function_pointer, buf, 3);
+	if (rc) {
+		pr_err("Slave control function data read failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	sdev->slave_ctrl_function->slave_ctrl_pointer = buf[0] << 8 | buf[1];
+	sdev->slave_ctrl_function->task_count
+		= buf[2] * SLAVE_CTRL_TASKS_PER_SET;
+	sdev->slave_ctrl_function->l2_entry = func;
+
+	if (sdev->slave_ctrl_function->task_count > 0) {
+		sdev->slave_ctrl_function->irq_notifier_list =
+			kzalloc(sizeof(struct blocking_notifier_head)
+			    * sdev->slave_ctrl_function->task_count,
+			    GFP_KERNEL);
+		if (!sdev->slave_ctrl_function->irq_notifier_list) {
+			pr_err("out of memory\n");
+			kfree(sdev->slave_ctrl_function);
+			return -ENOMEM;
+		}
+
+		for (i = 0; i < sdev->slave_ctrl_function->task_count; i++) {
+			BLOCKING_INIT_NOTIFIER_HEAD(
+			    &sdev->slave_ctrl_function->irq_notifier_list[i]);
+		}
+	}
+
+	return rc;
+}
+
+/**
+ * bif_crc_ccitt() - calculate the CRC-CCITT CRC value of the data specified
+ * @buffer:	Data to calculate the CRC of
+ * @len:	Length of the data buffer in bytes
+ *
+ * MIPI-BIF specifies the usage of CRC-CCITT for BIF data objects.  This
+ * function performs the CRC calculation while taking into account the bit
+ * ordering used by BIF.
+ */
+u16 bif_crc_ccitt(const u8 *buffer, unsigned int len)
+{
+	u16 crc = 0xFFFF;
+
+	while (len--) {
+		crc = crc_ccitt_byte(crc, bitrev8(*buffer));
+		buffer++;
+	}
+	return bitrev16(crc);
+}
+EXPORT_SYMBOL(bif_crc_ccitt);
+
+static u16 bif_object_crc_ccitt(const struct bif_object *object)
+{
+	u16 crc = 0xFFFF;
+	int i;
+
+	crc = crc_ccitt_byte(crc, bitrev8(object->type));
+	crc = crc_ccitt_byte(crc, bitrev8(object->version));
+	crc = crc_ccitt_byte(crc, bitrev8(object->manufacturer_id >> 8));
+	crc = crc_ccitt_byte(crc, bitrev8(object->manufacturer_id));
+	crc = crc_ccitt_byte(crc, bitrev8(object->length >> 8));
+	crc = crc_ccitt_byte(crc, bitrev8(object->length));
+
+	for (i = 0; i < object->length - 8; i++)
+		crc = crc_ccitt_byte(crc, bitrev8(object->data[i]));
+
+	return bitrev16(crc);
+}
+
+/*
+ * Check if the specified function is an NVM function and if it is, then
+ * instantiate NVM function data for the slave and read all objects.
+ */
+static int bif_initialize_nvm_function(struct bif_slave_dev *sdev,
+		struct bif_ddb_l2_data *func)
+{
+	int rc = 0;
+	int data_len;
+	u8 buf[8], object_type;
+	struct bif_object *object;
+	struct bif_object *temp;
+	u16 addr;
+	u16 crc;
+
+	/* Ensure that this is an NVM function. */
+	if (func->function_type != BIF_FUNC_NVM)
+		return 0;
+
+	if (sdev->nvm_function) {
+		pr_err("Duplicate NVM function found for BIF slave; DEV_ADR=0x%02X\n",
+			sdev->slave_addr);
+		return -EPERM;
+	}
+
+	sdev->nvm_function
+		= kzalloc(sizeof(*sdev->nvm_function), GFP_KERNEL);
+	if (!sdev->nvm_function) {
+		pr_err("out of memory\n");
+		return -ENOMEM;
+	}
+
+	rc = _bif_slave_read(sdev, func->function_pointer, buf, 8);
+	if (rc) {
+		pr_err("NVM function data read failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	sdev->nvm_function->nvm_pointer		= buf[0] << 8 | buf[1];
+	sdev->nvm_function->slave_control_channel	= buf[2];
+	sdev->nvm_function->write_buffer_size		= buf[3];
+	sdev->nvm_function->nvm_base_address		= buf[4] << 8 | buf[5];
+	sdev->nvm_function->nvm_size			= buf[6] << 8 | buf[7];
+
+	INIT_LIST_HEAD(&sdev->nvm_function->object_list);
+
+	/* Read object list */
+	addr = sdev->nvm_function->nvm_base_address;
+	rc = _bif_slave_read(sdev, addr, &object_type, 1);
+	if (rc) {
+		pr_err("Slave memory read failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	/* Object type == 0x00 corresponds to the end of the object list. */
+	while (object_type != 0x00) {
+		object = kzalloc(sizeof(*object), GFP_KERNEL);
+		if (!object) {
+			pr_err("out of memory\n");
+			rc = -ENOMEM;
+			goto free_data;
+		}
+		list_add_tail(&object->list, &sdev->nvm_function->object_list);
+
+		rc = _bif_slave_read(sdev, addr + 1, buf + 1, 5);
+		if (rc) {
+			pr_err("Slave memory read of object header failed; addr=0x%04X, len=%d, rc=%d\n",
+				addr + 1, 5, rc);
+			goto free_data;
+		}
+
+		object->addr		= addr;
+		object->type		= object_type;
+		object->version		= buf[1];
+		object->manufacturer_id	= buf[2] << 8 | buf[3];
+		object->length		= buf[4] << 8 | buf[5];
+
+		if ((object->addr + object->length)
+		    > (sdev->nvm_function->nvm_base_address
+				+ sdev->nvm_function->nvm_size)) {
+			pr_warn("warning: BIF slave object is not formatted correctly; NVM base=0x%04X, NVM len=%d, object addr=0x%04X, object len=%d\n",
+				sdev->nvm_function->nvm_base_address,
+				sdev->nvm_function->nvm_size,
+				object->addr,
+				object->length);
+			/* Limit object size to remaining NVM size. */
+			object->length = sdev->nvm_function->nvm_size
+				+ sdev->nvm_function->nvm_base_address
+				- object->addr;
+		}
+
+		/* Object header + CRC takes up 8 bytes. */
+		data_len = object->length - 8;
+		object->data = kmalloc(data_len, GFP_KERNEL);
+		if (!object->data) {
+			pr_err("out of memory\n");
+			rc = -ENOMEM;
+			goto free_data;
+		}
+
+		rc = _bif_slave_read(sdev, addr + 6, object->data, data_len);
+		if (rc) {
+			pr_err("Slave memory read of object data failed; addr=0x%04X, len=%d, rc=%d\n",
+				addr + 6, data_len, rc);
+			goto free_data;
+		}
+
+		rc = _bif_slave_read(sdev, addr + 6 + data_len, buf, 3);
+		if (rc) {
+			pr_err("Slave memory read of object CRC failed; addr=0x%04X, len=%d, rc=%d\n",
+				addr + 6 + data_len, 3, rc);
+			goto free_data;
+		}
+
+		object->crc = buf[0] << 8 | buf[1];
+		object_type = buf[2];
+		sdev->nvm_function->object_count++;
+
+		crc = bif_object_crc_ccitt(object);
+		if (crc != object->crc)
+			pr_info("BIF object at addr=0x%04X has invalid CRC; crc calc=0x%04X, crc exp=0x%04X\n",
+				object->addr, crc, object->crc);
+
+		addr += object->length;
+	}
+
+	return rc;
+
+free_data:
+	list_for_each_entry_safe(object, temp,
+				&sdev->nvm_function->object_list, list) {
+		list_del(&object->list);
+		kfree(object->data);
+		kfree(object);
+	}
+	kfree(sdev->nvm_function);
+	sdev->nvm_function = NULL;
+	return rc;
+}
+
+static int bif_parse_slave_data(struct bif_slave_dev *sdev)
+{
+	int rc = 0;
+	u8 buf[10];
+	u8 *func_buf;
+	struct bif_ddb_l2_data *func;
+	int function_count, i;
+
+	rc = _bif_slave_read(sdev, BIF_DDB_L1_BASE_ADDR, buf, 10);
+	if (rc) {
+		pr_err("DDB L1 data read failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	sdev->l1_data.revision		= buf[0];
+	sdev->l1_data.level		= buf[1];
+	sdev->l1_data.device_class	= buf[2] << 8 | buf[3];
+	sdev->l1_data.manufacturer_id	= buf[4] << 8 | buf[5];
+	sdev->l1_data.product_id	= buf[6] << 8 | buf[7];
+	sdev->l1_data.length		= buf[8] << 8 | buf[9];
+
+	function_count = sdev->l1_data.length / 4;
+	if (sdev->l1_data.length % 4) {
+		pr_err("Function directory length=%d is invalid\n",
+				sdev->l1_data.length);
+		return -EPROTO;
+	}
+
+	/* No DDB L2 function directory */
+	if (function_count == 0)
+		return 0;
+
+	func_buf = kmalloc(sdev->l1_data.length, GFP_KERNEL);
+	if (!func_buf) {
+		pr_err("out of memory\n");
+		return -ENOMEM;
+	}
+
+	sdev->function_directory = kzalloc(
+		function_count * sizeof(struct bif_ddb_l2_data), GFP_KERNEL);
+	if (!sdev->function_directory) {
+		pr_err("out of memory\n");
+		return -ENOMEM;
+	}
+
+	rc = _bif_slave_read(sdev, BIF_DDB_L2_BASE_ADDR, func_buf,
+				sdev->l1_data.length);
+	if (rc) {
+		pr_err("DDB L2 data read failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	for (i = 0; i < function_count; i++) {
+		func = &sdev->function_directory[i];
+		func->function_type	= func_buf[i * 4];
+		func->function_version	= func_buf[i * 4 + 1];
+		func->function_pointer	= func_buf[i * 4 + 2] << 8
+					  | func_buf[i * 4 + 3];
+		rc = bif_initialize_protocol_function(sdev, func);
+		if (rc)
+			goto done;
+		rc = bif_initialize_slave_control_function(sdev, func);
+		if (rc)
+			goto done;
+		rc = bif_initialize_nvm_function(sdev, func);
+		if (rc)
+			goto done;
+	}
+done:
+	kfree(func_buf);
+	return rc;
+}
+
+static int bif_add_secondary_slaves(struct bif_slave_dev *primary_slave)
+{
+	int rc = 0;
+	int data_len, i;
+	u16 crc;
+	struct bif_slave_dev *sdev;
+	struct bif_object *object;
+
+	list_for_each_entry(object, &primary_slave->nvm_function->object_list,
+				list) {
+		if (object->type != BIF_OBJ_SEC_SLAVE)
+			continue;
+
+		data_len = object->length - 8;
+		if (data_len % BIF_UNIQUE_ID_BYTE_LENGTH) {
+			pr_info("Invalid secondary slave object found, addr=0x%04X, data len=%d\n",
+				object->addr, data_len);
+			continue;
+		}
+
+		crc = bif_object_crc_ccitt(object);
+		if (crc != object->crc) {
+			pr_info("BIF object at addr=0x%04X has invalid CRC; crc calc=0x%04X, crc exp=0x%04X\n",
+				object->addr, crc, object->crc);
+			continue;
+		}
+
+		for (i = 0; i < data_len / BIF_UNIQUE_ID_BYTE_LENGTH; i++) {
+			sdev = bif_add_slave(primary_slave->bdev);
+			if (IS_ERR(sdev)) {
+				rc = PTR_ERR(sdev);
+				pr_err("bif_add_slave failed, rc=%d\n", rc);
+				return rc;
+			}
+			memcpy(sdev->unique_id,
+				&object->data[i * BIF_UNIQUE_ID_BYTE_LENGTH],
+				BIF_UNIQUE_ID_BYTE_LENGTH);
+			sdev->unique_id_bits_known = BIF_UNIQUE_ID_BIT_LENGTH;
+
+			rc = bif_select_slave(sdev);
+			if (rc) {
+				pr_err("Could not select slave, rc=%d\n", rc);
+				goto free_slave;
+			}
+
+			rc = bif_is_slave_selected(sdev->bdev);
+			if (rc < 0) {
+				pr_err("Transaction failed, rc=%d\n", rc);
+				goto free_slave;
+			} else if (rc == 1) {
+				sdev->present = true;
+				sdev->bdev->selected_sdev = sdev;
+			} else {
+				sdev->present = false;
+				sdev->bdev->selected_sdev = NULL;
+			}
+		}
+	}
+
+	return rc;
+
+free_slave:
+	bif_remove_slave(sdev);
+	return rc;
+}
+
+/*
+ * Performs UID search to identify all slaves attached to the bus. Assumes that
+ * all necessary locks are held.
+ */
+static int bif_perform_uid_search(struct bif_ctrl_dev *bdev)
+{
+	struct bif_slave_dev *sdev;
+	struct bif_slave_dev *new_slave;
+	bool resp[2], resp_dilc;
+	int i;
+	int rc = 0;
+	u8 cmd_probe[2] = {BIF_CMD_DIP0, BIF_CMD_DIP1};
+	u8 cmd_enter[2] = {BIF_CMD_DIE0, BIF_CMD_DIE1};
+
+	/*
+	 * Iterate over all partially known UIDs adding new ones as they are
+	 * found.
+	 */
+	list_for_each_entry(sdev, &bif_sdev_list, list) {
+		/* Skip slaves with fully known UIDs. */
+		if (sdev->unique_id_bits_known == BIF_UNIQUE_ID_BIT_LENGTH
+		    || sdev->bdev != bdev)
+			continue;
+
+		/* Begin a new UID search. */
+		rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_BC,
+							BIF_CMD_DISS);
+		if (rc) {
+			pr_err("bus_transaction failed, rc=%d\n", rc);
+			return rc;
+		}
+
+		/* Step through all known UID bits (MSB to LSB). */
+		for (i = 0; i < sdev->unique_id_bits_known; i++) {
+			rc = bdev->desc->ops->bus_transaction(bdev,
+				BIF_TRANS_BC,
+				cmd_enter[get_uid_bit(sdev->unique_id, i)]);
+			if (rc) {
+				pr_err("bus_transaction failed, rc=%d\n", rc);
+				return rc;
+			}
+		}
+
+		/* Step through unknown UID bits. */
+		for (i = sdev->unique_id_bits_known;
+				i < BIF_UNIQUE_ID_BIT_LENGTH; i++) {
+			rc = bdev->desc->ops->bus_transaction_query(bdev,
+				BIF_TRANS_BC, cmd_probe[0], &resp[0]);
+			if (rc) {
+				pr_err("bus_transaction failed, rc=%d\n", rc);
+				return rc;
+			}
+
+			rc = bdev->desc->ops->bus_transaction_query(bdev,
+				BIF_TRANS_BC, cmd_probe[1], &resp[1]);
+			if (rc) {
+				pr_err("bus_transaction failed, rc=%d\n", rc);
+				return rc;
+			}
+
+			if (resp[0] && resp[1]) {
+				/* Create an entry for the new UID branch. */
+				new_slave = bif_add_slave(bdev);
+				if (IS_ERR(new_slave)) {
+					rc = PTR_ERR(sdev);
+					pr_err("bif_add_slave failed, rc=%d\n",
+						rc);
+					return rc;
+				}
+				memcpy(new_slave->unique_id, sdev->unique_id,
+					BIF_UNIQUE_ID_BYTE_LENGTH);
+				new_slave->bdev = sdev->bdev;
+
+				set_uid_bit(sdev->unique_id, i, 0);
+				sdev->unique_id_bits_known = i + 1;
+
+				set_uid_bit(new_slave->unique_id, i, 1);
+				new_slave->unique_id_bits_known = i + 1;
+			} else if (resp[0]) {
+				set_uid_bit(sdev->unique_id, i, 0);
+				sdev->unique_id_bits_known = i + 1;
+			} else if (resp[1]) {
+				set_uid_bit(sdev->unique_id, i, 1);
+				sdev->unique_id_bits_known = i + 1;
+			} else {
+				pr_debug("no bus query response received\n");
+				rc = -ENXIO;
+				return rc;
+			}
+
+			rc = bdev->desc->ops->bus_transaction(bdev,
+				BIF_TRANS_BC, cmd_enter[resp[0] ? 0 : 1]);
+			if (rc) {
+				pr_err("bus_transaction failed, rc=%d\n", rc);
+				return rc;
+			}
+		}
+
+		rc = bdev->desc->ops->bus_transaction_query(bdev,
+			BIF_TRANS_BC, BIF_CMD_DILC, &resp_dilc);
+		if (rc) {
+			pr_err("bus_transaction failed, rc=%d\n", rc);
+			return rc;
+		}
+
+		if (resp_dilc) {
+			sdev->present = true;
+			sdev->bdev->selected_sdev = sdev;
+			rc = bif_parse_slave_data(sdev);
+		} else {
+			pr_err("Slave failed to respond to DILC bus command; its UID is thus unverified.\n");
+			sdev->unique_id_bits_known = 0;
+			rc = -ENXIO;
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
+/*
+ * Removes slaves from the bif_sdev_list which have the same UID as previous
+ * slaves in the list.
+ */
+static int bif_remove_duplicate_slaves(struct bif_ctrl_dev *bdev)
+{
+	struct bif_slave_dev *sdev;
+	struct bif_slave_dev *last_slave;
+	struct bif_slave_dev *temp;
+
+	list_for_each_entry_safe(last_slave, temp, &bif_sdev_list, list) {
+		list_for_each_entry(sdev, &bif_sdev_list, list) {
+			if (last_slave == sdev) {
+				break;
+			} else if (memcmp(last_slave->unique_id,
+					sdev->unique_id,
+					BIF_UNIQUE_ID_BYTE_LENGTH) == 0) {
+				bif_remove_slave(last_slave);
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int bif_add_all_slaves(struct bif_ctrl_dev *bdev)
+{
+	struct bif_slave_dev *sdev;
+	int rc = 0;
+	int i;
+	bool has_slave = false, is_primary_slave = false;
+
+	mutex_lock(&bif_sdev_list_mutex);
+	mutex_lock(&bdev->mutex);
+
+	list_for_each_entry(sdev, &bif_sdev_list, list) {
+		if (sdev->bdev == bdev) {
+			has_slave = true;
+			break;
+		}
+	}
+
+	if (!has_slave) {
+		/* Create a single empty slave to start the search algorithm. */
+		sdev = bif_add_slave(bdev);
+		if (IS_ERR(sdev)) {
+			rc = PTR_ERR(sdev);
+			pr_err("bif_add_slave failed, rc=%d\n", rc);
+			goto out;
+		}
+
+		for (i = 0; i < BIF_TRANSACTION_RETRY_COUNT; i++) {
+			/* Attempt to select primary slave in battery pack. */
+			rc = bdev->desc->ops->bus_transaction(bdev,
+				BIF_TRANS_SDA, BIF_PRIMARY_SLAVE_DEV_ADR);
+			if (rc == 0)
+				break;
+		}
+		if (rc) {
+			pr_err("BIF bus_transaction failed, rc=%d\n", rc);
+			goto out;
+		}
+
+		/* Check if a slave is selected. */
+		rc = bif_is_slave_selected(bdev);
+		if (rc < 0) {
+			pr_err("BIF bus_transaction failed, rc=%d\n", rc);
+			goto out;
+		} else {
+			is_primary_slave = rc;
+		}
+	}
+
+	if (is_primary_slave) {
+		pr_debug("Using primary slave at DEV_ADR==0x%02X\n",
+			BIF_PRIMARY_SLAVE_DEV_ADR);
+		sdev->bdev->selected_sdev = sdev;
+		sdev->present = true;
+		sdev->slave_addr = BIF_PRIMARY_SLAVE_DEV_ADR;
+		rc = bif_parse_slave_data(sdev);
+		if (rc) {
+			pr_err("Failed to parse primary slave data, rc=%d\n",
+				rc);
+			goto out;
+		}
+		rc = bif_add_secondary_slaves(sdev);
+		if (rc) {
+			pr_err("Failed to add secondary slaves, rc=%d\n", rc);
+			goto out;
+		}
+	} else {
+		pr_debug("Falling back on full UID search.\n");
+		for (i = 0; i < BIF_TRANSACTION_RETRY_COUNT; i++) {
+			rc = bif_perform_uid_search(bdev);
+			if (rc == 0)
+				break;
+		}
+		if (rc) {
+			pr_debug("BIF UID search failed, rc=%d\n", rc);
+			goto out;
+		}
+	}
+
+	bif_remove_duplicate_slaves(bdev);
+
+	mutex_unlock(&bdev->mutex);
+	mutex_unlock(&bif_sdev_list_mutex);
+
+	return rc;
+
+out:
+	mutex_unlock(&bdev->mutex);
+	mutex_unlock(&bif_sdev_list_mutex);
+	pr_debug("BIF slave search failed, rc=%d\n", rc);
+	return rc;
+}
+
+static int bif_add_known_slave(struct bif_ctrl_dev *bdev, u8 slave_addr)
+{
+	struct bif_slave_dev *sdev;
+	int rc = 0;
+	int i;
+
+	for (i = 0; i < BIF_TRANSACTION_RETRY_COUNT; i++) {
+		/* Attempt to select the slave. */
+		rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_SDA,
+							slave_addr);
+		if (rc == 0)
+			break;
+	}
+	if (rc) {
+		pr_err("BIF bus_transaction failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	/* Check if a slave is selected. */
+	rc = bif_is_slave_selected(bdev);
+	if (rc < 0) {
+		pr_err("BIF bus_transaction failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	sdev = bif_add_slave(bdev);
+	if (IS_ERR(sdev)) {
+		rc = PTR_ERR(sdev);
+		pr_err("bif_add_slave failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	sdev->bdev->selected_sdev = sdev;
+	sdev->present = true;
+	sdev->slave_addr = slave_addr;
+	rc = bif_parse_slave_data(sdev);
+	if (rc) {
+		pr_err("Failed to parse slave data, addr=0x%02X, rc=%d\n",
+			slave_addr, rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int bif_add_known_slaves_from_dt(struct bif_ctrl_dev *bdev,
+					struct device_node *of_node)
+{
+	int len = 0;
+	int rc, i;
+	u32 addr;
+	const __be32 *val;
+
+	mutex_lock(&bif_sdev_list_mutex);
+	mutex_lock(&bdev->mutex);
+
+	val = of_get_property(of_node, "qcom,known-device-addresses", &len);
+	len /= sizeof(u32);
+	if (val && len == 0) {
+		pr_err("qcom,known-device-addresses property is invalid\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	for (i = 0; i < len; i++) {
+		addr = be32_to_cpup(val++);
+		if (addr == 0x00 || addr > 0xFF) {
+			rc = -EINVAL;
+			pr_err("qcom,known-device-addresses property contains invalid address=0x%X\n",
+				addr);
+			goto out;
+		}
+		rc = bif_add_known_slave(bdev, addr);
+		if (rc) {
+			pr_err("bif_add_known_slave() failed, rc=%d\n", rc);
+			goto out;
+		}
+	}
+
+out:
+	if (len > 0)
+		bif_remove_duplicate_slaves(bdev);
+
+	mutex_unlock(&bdev->mutex);
+	mutex_unlock(&bif_sdev_list_mutex);
+
+	return rc;
+}
+
+/*
+ * Programs a device address for the specified slave in order to simplify
+ * slave selection in the future.
+ */
+static int bif_assign_slave_dev_addr(struct bif_slave_dev *sdev, u8 dev_addr)
+{
+	int rc;
+	u16 addr;
+
+	if (!sdev->protocol_function) {
+		pr_err("Protocol function not present; cannot set device address.\n");
+		return -ENODEV;
+	}
+
+	addr = PROTOCOL_FUNC_DEV_ADR_ADDR(
+			sdev->protocol_function->protocol_pointer);
+
+	rc = _bif_slave_write(sdev, addr, &dev_addr, 1);
+	if (rc)
+		pr_err("Failed to set slave device address.\n");
+	else
+		sdev->slave_addr = dev_addr;
+
+	return rc;
+}
+
+/* Assigns a unique device address to all slaves which do not have one. */
+static int bif_assign_all_slaves_dev_addr(struct bif_ctrl_dev *bdev)
+{
+	struct bif_slave_dev *sdev;
+	struct bif_slave_dev *sibling;
+	bool duplicate;
+	int rc = 0;
+	u8 dev_addr, first_dev_addr;
+
+	mutex_lock(&bif_sdev_list_mutex);
+	mutex_lock(&bdev->mutex);
+
+	first_dev_addr = next_dev_addr;
+	/*
+	 * Iterate over all partially known UIDs adding new ones as they are
+	 * found.
+	 */
+	list_for_each_entry(sdev, &bif_sdev_list, list) {
+		/*
+		 * Skip slaves without known UIDs, which already have a device
+		 * address or which aren't present.
+		 */
+		if (sdev->unique_id_bits_known != BIF_UNIQUE_ID_BIT_LENGTH
+		    || sdev->slave_addr != 0x00 || !sdev->present)
+			continue;
+
+		do {
+			dev_addr = next_dev_addr;
+			duplicate = false;
+			list_for_each_entry(sibling, &bif_sdev_list, list) {
+				if (sibling->slave_addr == dev_addr) {
+					duplicate = true;
+					break;
+				}
+			}
+
+			next_dev_addr = dev_addr + 1;
+		} while (duplicate && (next_dev_addr != first_dev_addr));
+
+		if (next_dev_addr == first_dev_addr) {
+			pr_err("No more BIF slave device addresses available.\n");
+			rc = -ENODEV;
+			goto out;
+		}
+
+		rc =  bif_assign_slave_dev_addr(sdev, dev_addr);
+		if (rc) {
+			pr_err("Failed to set slave address.\n");
+			goto out;
+		}
+	}
+
+	mutex_unlock(&bdev->mutex);
+	mutex_unlock(&bif_sdev_list_mutex);
+
+	return rc;
+
+out:
+	mutex_unlock(&bdev->mutex);
+	mutex_unlock(&bif_sdev_list_mutex);
+	pr_err("BIF slave device address setting failed, rc=%d\n", rc);
+	return rc;
+}
+
+/**
+ * bdev_get_drvdata() - get the private BIF controller driver data
+ * @bdev:	BIF controller device pointer
+ */
+void *bdev_get_drvdata(struct bif_ctrl_dev *bdev)
+{
+	return bdev->driver_data;
+}
+EXPORT_SYMBOL(bdev_get_drvdata);
+
+static const char * const battery_label[] = {
+	"unknown",
+	"none",
+	"special 1",
+	"special 2",
+	"special 3",
+	"low cost",
+	"smart",
+};
+
+static const char *bif_get_battery_pack_type(int rid_ohm)
+{
+	const char *label = battery_label[0];
+
+	if (rid_ohm > BIF_BATT_RID_SMART_MAX)
+		label = battery_label[1];
+	else if (rid_ohm >= BIF_BATT_RID_SMART_MIN)
+		label = battery_label[6];
+	else if (rid_ohm >= BIF_BATT_RID_LOW_COST_MIN
+			&& rid_ohm <= BIF_BATT_RID_LOW_COST_MAX)
+		label = battery_label[5];
+	else if (rid_ohm >= BIF_BATT_RID_SPECIAL3_MIN
+			&& rid_ohm <= BIF_BATT_RID_SPECIAL3_MAX)
+		label = battery_label[4];
+	else if (rid_ohm >= BIF_BATT_RID_SPECIAL2_MIN
+			&& rid_ohm <= BIF_BATT_RID_SPECIAL2_MAX)
+		label = battery_label[3];
+	else if (rid_ohm >= BIF_BATT_RID_SPECIAL1_MIN
+			&& rid_ohm <= BIF_BATT_RID_SPECIAL1_MAX)
+		label = battery_label[2];
+
+	return label;
+}
+
+/**
+ * bif_ctrl_register() - register a BIF controller with the BIF framework
+ * @bif_desc:		Pointer to BIF controller descriptor
+ * @dev:		Device pointer of the BIF controller
+ * @driver_data:	Private driver data to associate with the BIF controller
+ * @of_node		Pointer to the device tree node of the BIF controller
+ *
+ * Returns a BIF controller device pointer for the controller if registration
+ * is successful or an ERR_PTR if an error occurred.
+ */
+struct bif_ctrl_dev *bif_ctrl_register(struct bif_ctrl_desc *bif_desc,
+	struct device *dev, void *driver_data, struct device_node *of_node)
+{
+	struct bif_ctrl_dev *bdev = ERR_PTR(-EINVAL);
+	struct bif_slave_dev *sdev;
+	bool battery_present = false;
+	int rc, rid_ohm;
+
+	if (!bif_desc) {
+		pr_err("Invalid bif_desc specified\n");
+		return bdev;
+	} else if (!bif_desc->name) {
+		pr_err("BIF name missing\n");
+		return bdev;
+	} else if (!bif_desc->ops) {
+		pr_err("BIF operations missing\n");
+		return bdev;
+	} else if (!bif_desc->ops->bus_transaction
+			|| !bif_desc->ops->bus_transaction_query
+			|| !bif_desc->ops->bus_transaction_read
+			|| !bif_desc->ops->get_bus_state
+			|| !bif_desc->ops->set_bus_state) {
+		pr_err("BIF operation callback function(s) missing\n");
+		return bdev;
+	}
+
+	bdev = kzalloc(sizeof(struct bif_ctrl_dev), GFP_KERNEL);
+	if (bdev == NULL) {
+		pr_err("Memory allocation failed for bif_ctrl_dev\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	mutex_init(&bdev->mutex);
+	INIT_LIST_HEAD(&bdev->list);
+	INIT_DELAYED_WORK(&bdev->enter_irq_mode_work, bif_enter_irq_mode_work);
+	bdev->desc			= bif_desc;
+	bdev->ctrl_dev			= dev;
+	bdev->driver_data		= driver_data;
+	bdev->irq_mode_delay_jiffies	= 2;
+
+	mutex_lock(&bif_ctrl_list_mutex);
+	list_add_tail(&bdev->list, &bif_ctrl_list);
+	mutex_unlock(&bif_ctrl_list_mutex);
+
+	rc = bif_add_all_slaves(bdev);
+	if (rc)
+		pr_debug("Search for all slaves failed, rc=%d\n", rc);
+	rc = bif_add_known_slaves_from_dt(bdev, of_node);
+	if (rc)
+		pr_err("Adding slaves based on device tree addressed failed, rc=%d.\n",
+			rc);
+	rc = bif_assign_all_slaves_dev_addr(bdev);
+	if (rc)
+		pr_err("Failed to set slave device address, rc=%d\n", rc);
+
+	bif_print_slaves();
+
+	if (bdev->desc->ops->get_battery_presence) {
+		rc = bdev->desc->ops->get_battery_presence(bdev);
+		if (rc < 0) {
+			pr_err("Could not determine battery presence, rc=%d\n",
+				rc);
+		} else {
+			battery_present = rc;
+			pr_info("Battery pack present = %c\n", rc ? 'Y' : 'N');
+		}
+	}
+
+	if (bdev->desc->ops->get_battery_rid) {
+		rid_ohm = bdev->desc->ops->get_battery_rid(bdev);
+		if (rid_ohm >= 0)
+			pr_info("Battery pack type = %s (Rid=%d ohm)\n",
+				bif_get_battery_pack_type(rid_ohm), rid_ohm);
+		else
+			pr_err("Could not read Rid, rc=%d\n", rid_ohm);
+	}
+
+	list_for_each_entry(sdev, &bif_sdev_list, list) {
+		if (sdev->present) {
+			battery_present = true;
+			break;
+		}
+	}
+
+	BLOCKING_INIT_NOTIFIER_HEAD(&bdev->bus_change_notifier);
+
+	if (battery_present) {
+		bdev->battery_present = true;
+		rc = blocking_notifier_call_chain(&bdev->bus_change_notifier,
+			BIF_BUS_EVENT_BATTERY_INSERTED, bdev);
+		if (rc)
+			pr_err("Call chain noification failed, rc=%d\n", rc);
+	}
+
+	return bdev;
+}
+EXPORT_SYMBOL(bif_ctrl_register);
+
+/**
+ * bif_ctrl_unregister() - unregisters a BIF controller
+ * @bdev:	BIF controller device pointer
+ */
+void bif_ctrl_unregister(struct bif_ctrl_dev *bdev)
+{
+	if (bdev) {
+		mutex_lock(&bif_ctrl_list_mutex);
+		list_del(&bdev->list);
+		mutex_unlock(&bif_ctrl_list_mutex);
+	}
+}
+EXPORT_SYMBOL(bif_ctrl_unregister);
diff --git a/drivers/bif/qpnp-bsi.c b/drivers/bif/qpnp-bsi.c
new file mode 100644
index 0000000..5068a21
--- /dev/null
+++ b/drivers/bif/qpnp-bsi.c
@@ -0,0 +1,1765 @@
+/* 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/atomic.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/spmi.h>
+#include <linux/workqueue.h>
+#include <linux/bif/driver.h>
+#include <linux/qpnp/qpnp-adc.h>
+
+enum qpnp_bsi_irq {
+	QPNP_BSI_IRQ_ERR,
+	QPNP_BSI_IRQ_RX,
+	QPNP_BSI_IRQ_TX,
+	QPNP_BSI_IRQ_COUNT,
+};
+
+enum qpnp_bsi_com_mode {
+	QPNP_BSI_COM_MODE_IRQ,
+	QPNP_BSI_COM_MODE_POLL,
+};
+
+struct qpnp_bsi_chip {
+	struct bif_ctrl_desc	bdesc;
+	struct spmi_device	*spmi_dev;
+	struct bif_ctrl_dev	*bdev;
+	struct work_struct	slave_irq_work;
+	u16			base_addr;
+	u16			batt_id_stat_addr;
+	int			r_pullup_ohm;
+	int			vid_ref_uV;
+	int			tau_index;
+	int			tau_sampling_mask;
+	enum bif_bus_state	state;
+	enum qpnp_bsi_com_mode	com_mode;
+	int			irq[QPNP_BSI_IRQ_COUNT];
+	atomic_t		irq_flag[QPNP_BSI_IRQ_COUNT];
+	int			batt_present_irq;
+	enum qpnp_vadc_channels	batt_id_adc_channel;
+};
+
+#define QPNP_BSI_DRIVER_NAME	"qcom,qpnp-bsi"
+
+enum qpnp_bsi_registers {
+	QPNP_BSI_REG_TYPE		= 0x04,
+	QPNP_BSI_REG_SUBTYPE		= 0x05,
+	QPNP_BSI_REG_STATUS		= 0x08,
+	QPNP_BSI_REG_ENABLE		= 0x46,
+	QPNP_BSI_REG_CLEAR_ERROR	= 0x4F,
+	QPNP_BSI_REG_FORCE_BCL_LOW	= 0x51,
+	QPNP_BSI_REG_TAU_CONFIG		= 0x52,
+	QPNP_BSI_REG_MODE		= 0x53,
+	QPNP_BSI_REG_RX_TX_ENABLE	= 0x54,
+	QPNP_BSI_REG_TX_DATA_LOW	= 0x5A,
+	QPNP_BSI_REG_TX_DATA_HIGH	= 0x5B,
+	QPNP_BSI_REG_TX_CTRL		= 0x5D,
+	QPNP_BSI_REG_RX_DATA_LOW	= 0x60,
+	QPNP_BSI_REG_RX_DATA_HIGH	= 0x61,
+	QPNP_BSI_REG_RX_SOURCE		= 0x62,
+	QPNP_BSI_REG_BSI_ERROR		= 0x70,
+};
+
+#define QPNP_BSI_TYPE			0x02
+#define QPNP_BSI_SUBTYPE		0x10
+
+#define QPNP_BSI_STATUS_ERROR		0x10
+#define QPNP_BSI_STATUS_TX_BUSY		0x08
+#define QPNP_BSI_STATUS_RX_BUSY		0x04
+#define QPNP_BSI_STATUS_TX_GO_BUSY	0x02
+#define QPNP_BSI_STATUS_RX_DATA_READY	0x01
+
+#define QPNP_BSI_ENABLE_MASK		0x80
+#define QPNP_BSI_ENABLE			0x80
+#define QPNP_BSI_DISABLE		0x00
+
+#define QPNP_BSI_TAU_CONFIG_SAMPLE_MASK	0x10
+#define QPNP_BSI_TAU_CONFIG_SAMPLE_8X	0x10
+#define QPNP_BSI_TAU_CONFIG_SAMPLE_4X	0x00
+#define QPNP_BSI_TAU_CONFIG_SPEED_MASK	0x07
+
+#define QPNP_BSI_MODE_TX_PULSE_MASK	0x10
+#define QPNP_BSI_MODE_TX_PULSE_INT	0x10
+#define QPNP_BSI_MODE_TX_PULSE_DATA	0x00
+#define QPNP_BSI_MODE_RX_PULSE_MASK	0x08
+#define QPNP_BSI_MODE_RX_PULSE_INT	0x08
+#define QPNP_BSI_MODE_RX_PULSE_DATA	0x00
+#define QPNP_BSI_MODE_TX_PULSE_T_MASK	0x04
+#define QPNP_BSI_MODE_TX_PULSE_T_WAKE	0x04
+#define QPNP_BSI_MODE_TX_PULSE_T_1_TAU	0x00
+#define QPNP_BSI_MODE_RX_FORMAT_MASK	0x02
+#define QPNP_BSI_MODE_RX_FORMAT_17_BIT	0x02
+#define QPNP_BSI_MODE_RX_FORMAT_11_BIT	0x00
+#define QPNP_BSI_MODE_TX_FORMAT_MASK	0x01
+#define QPNP_BSI_MODE_TX_FORMAT_17_BIT	0x01
+#define QPNP_BSI_MODE_TX_FORMAT_11_BIT	0x00
+
+#define QPNP_BSI_TX_ENABLE_MASK		0x80
+#define QPNP_BSI_TX_ENABLE		0x80
+#define QPNP_BSI_TX_DISABLE		0x00
+#define QPNP_BSI_RX_ENABLE_MASK		0x40
+#define QPNP_BSI_RX_ENABLE		0x40
+#define QPNP_BSI_RX_DISABLE		0x00
+
+#define QPNP_BSI_TX_DATA_HIGH_MASK	0x07
+
+#define QPNP_BSI_TX_CTRL_GO		0x01
+
+#define QPNP_BSI_RX_DATA_HIGH_MASK	0x07
+
+#define QPNP_BSI_RX_SRC_LOOPBACK_FLAG	0x10
+
+#define QPNP_BSI_BSI_ERROR_CLEAR	0x80
+
+#define QPNP_SMBB_BAT_IF_BATT_PRES_MASK	0x80
+#define QPNP_SMBB_BAT_IF_BATT_ID_MASK	0x01
+
+#define QPNP_BSI_NUM_CLOCK_PERIODS	8
+
+struct qpnp_bsi_tau {
+	int period_4x_ns[QPNP_BSI_NUM_CLOCK_PERIODS];
+	int period_8x_ns[QPNP_BSI_NUM_CLOCK_PERIODS];
+	int period_4x_us[QPNP_BSI_NUM_CLOCK_PERIODS];
+	int period_8x_us[QPNP_BSI_NUM_CLOCK_PERIODS];
+};
+
+/* Tau BIF clock periods in ns supported by BSI for either 4x or 8x sampling. */
+static const struct qpnp_bsi_tau qpnp_bsi_tau_period = {
+	.period_4x_ns = {
+		150420, 122080, 61040, 31670, 15830, 7920, 3960, 2080
+	},
+	.period_8x_ns = {
+		150420, 122080, 63330, 31670, 15830, 7920, 4170, 2080
+	},
+	.period_4x_us = {
+		151, 122, 61, 32, 16, 8, 4, 2
+	},
+	.period_8x_us = {
+		151, 122, 64, 32, 16, 8, 4, 2
+	},
+
+};
+#define QPNP_BSI_MIN_CLOCK_SPEED_NS	2080
+#define QPNP_BSI_MAX_CLOCK_SPEED_NS	150420
+
+#define QPNP_BSI_MIN_PULLUP_OHM		1000
+#define QPNP_BSI_MAX_PULLUP_OHM		500000
+#define QPNP_BSI_DEFAULT_PULLUP_OHM	100000
+#define QPNP_BSI_MIN_VID_REF_UV		500000
+#define QPNP_BSI_MAX_VID_REF_UV		5000000
+#define QPNP_BSI_DEFAULT_VID_REF_UV	1800000
+
+/* These have units of tau_bif. */
+#define QPNP_BSI_MAX_TRANSMIT_CYCLES	36
+#define QPNP_BSI_MIN_RECEIVE_CYCLES	24
+#define QPNP_BSI_MAX_BUS_QUERY_CYCLES	17
+
+/*
+ * Maximum time in microseconds for a slave to transition from suspend to active
+ * state.
+ */
+#define QPNP_BSI_MAX_SLAVE_ACTIVIATION_DELAY_US	50
+
+/*
+ * Maximum time in milliseconds for a slave to transition from power down to
+ * active state.
+ */
+#define QPNP_BSI_MAX_SLAVE_POWER_UP_DELAY_MS	10
+
+#define QPNP_BSI_POWER_UP_LOW_DELAY_US		240
+
+/*
+ * Latencies that are used when determining if polling or interrupts should be
+ * used for a given transaction.
+ */
+#define QPNP_BSI_MAX_IRQ_LATENCY_US		170
+#define QPNP_BSI_MAX_BSI_DATA_READ_LATENCY_US	16
+
+static int qpnp_bsi_set_bus_state(struct bif_ctrl_dev *bdev, int state);
+
+static inline int qpnp_bsi_read(struct qpnp_bsi_chip *chip, u16 addr, u8 *buf,
+				int len)
+{
+	int rc;
+
+	rc = spmi_ext_register_readl(chip->spmi_dev->ctrl,
+			chip->spmi_dev->sid, chip->base_addr + addr, buf, len);
+	if (rc)
+		dev_err(&chip->spmi_dev->dev, "%s: spmi_ext_register_readl() failed. sid=%d, addr=%04X, len=%d, rc=%d\n",
+			__func__, chip->spmi_dev->sid, chip->base_addr + addr,
+			len, rc);
+
+	return rc;
+}
+
+static inline int qpnp_bsi_write(struct qpnp_bsi_chip *chip, u16 addr, u8 *buf,
+				int len)
+{
+	int rc;
+
+	rc = spmi_ext_register_writel(chip->spmi_dev->ctrl,
+			chip->spmi_dev->sid, chip->base_addr + addr, buf, len);
+
+	if (rc)
+		dev_err(&chip->spmi_dev->dev, "%s: spmi_ext_register_writel() failed. sid=%d, addr=%04X, len=%d, rc=%d\n",
+			__func__, chip->spmi_dev->sid, chip->base_addr + addr,
+			len, rc);
+
+	return rc;
+}
+
+enum qpnp_bsi_rx_tx_state {
+	QPNP_BSI_RX_TX_STATE_RX_OFF_TX_OFF,
+	QPNP_BSI_RX_TX_STATE_RX_OFF_TX_DATA,
+	QPNP_BSI_RX_TX_STATE_RX_OFF_TX_INT,
+	QPNP_BSI_RX_TX_STATE_RX_INT_TX_DATA,
+	QPNP_BSI_RX_TX_STATE_RX_DATA_TX_DATA,
+	QPNP_BSI_RX_TX_STATE_RX_INT_TX_OFF,
+};
+
+static int qpnp_bsi_rx_tx_config(struct qpnp_bsi_chip *chip,
+				    enum qpnp_bsi_rx_tx_state state)
+{
+	u8 buf[2] = {0, 0};
+	int rc;
+
+	buf[0] = QPNP_BSI_MODE_TX_FORMAT_11_BIT
+		 | QPNP_BSI_MODE_RX_FORMAT_11_BIT;
+
+	switch (state) {
+	case QPNP_BSI_RX_TX_STATE_RX_OFF_TX_OFF:
+		buf[0] |= QPNP_BSI_MODE_TX_PULSE_DATA |
+			QPNP_BSI_MODE_RX_PULSE_DATA;
+		buf[1] = QPNP_BSI_TX_DISABLE | QPNP_BSI_RX_DISABLE;
+		break;
+	case QPNP_BSI_RX_TX_STATE_RX_OFF_TX_DATA:
+		buf[0] |= QPNP_BSI_MODE_TX_PULSE_DATA |
+			QPNP_BSI_MODE_RX_PULSE_DATA;
+		buf[1] = QPNP_BSI_TX_ENABLE | QPNP_BSI_RX_DISABLE;
+		break;
+	case QPNP_BSI_RX_TX_STATE_RX_OFF_TX_INT:
+		buf[0] |= QPNP_BSI_MODE_TX_PULSE_INT |
+			QPNP_BSI_MODE_RX_PULSE_DATA;
+		buf[1] = QPNP_BSI_TX_ENABLE | QPNP_BSI_RX_DISABLE;
+		break;
+	case QPNP_BSI_RX_TX_STATE_RX_INT_TX_DATA:
+		buf[0] |= QPNP_BSI_MODE_TX_PULSE_DATA |
+			QPNP_BSI_MODE_RX_PULSE_INT;
+		buf[1] = QPNP_BSI_TX_ENABLE | QPNP_BSI_RX_ENABLE;
+		break;
+	case QPNP_BSI_RX_TX_STATE_RX_DATA_TX_DATA:
+		buf[0] |= QPNP_BSI_MODE_TX_PULSE_DATA |
+			QPNP_BSI_MODE_RX_PULSE_DATA;
+		buf[1] = QPNP_BSI_TX_ENABLE | QPNP_BSI_RX_ENABLE;
+		break;
+	case QPNP_BSI_RX_TX_STATE_RX_INT_TX_OFF:
+		buf[0] |= QPNP_BSI_MODE_TX_PULSE_DATA |
+			QPNP_BSI_MODE_RX_PULSE_INT;
+		buf[1] = QPNP_BSI_TX_DISABLE | QPNP_BSI_RX_DISABLE;
+		break;
+	default:
+		dev_err(&chip->spmi_dev->dev, "%s: invalid state=%d\n",
+			__func__, state);
+		return -EINVAL;
+	}
+
+	rc = qpnp_bsi_write(chip, QPNP_BSI_REG_MODE, buf, 2);
+	if (rc)
+		dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
+			__func__, rc);
+
+	return rc;
+}
+
+static void qpnp_bsi_slave_irq_work(struct work_struct *work)
+{
+	struct qpnp_bsi_chip *chip
+		= container_of(work, struct qpnp_bsi_chip, slave_irq_work);
+	int rc;
+
+	rc = bif_ctrl_notify_slave_irq(chip->bdev);
+	if (rc)
+		pr_err("Could not notify BIF core about slave interrupt, rc=%d\n",
+			rc);
+}
+
+static irqreturn_t qpnp_bsi_isr(int irq, void *data)
+{
+	struct qpnp_bsi_chip *chip = data;
+	bool found = false;
+	int i;
+
+	for (i = 0; i < QPNP_BSI_IRQ_COUNT; i++) {
+		if (irq == chip->irq[i]) {
+			found = true;
+			atomic_cmpxchg(&chip->irq_flag[i], 0, 1);
+
+			/* Check if this is a slave interrupt. */
+			if (i == QPNP_BSI_IRQ_RX
+			    && chip->state == BIF_BUS_STATE_INTERRUPT) {
+				/* Slave IRQ makes the bus active. */
+				qpnp_bsi_rx_tx_config(chip,
+					QPNP_BSI_RX_TX_STATE_RX_OFF_TX_OFF);
+				chip->state = BIF_BUS_STATE_ACTIVE;
+				schedule_work(&chip->slave_irq_work);
+			}
+		}
+	}
+
+	if (!found)
+		pr_err("Unknown interrupt: %d\n", irq);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t qpnp_bsi_batt_present_isr(int irq, void *data)
+{
+	struct qpnp_bsi_chip *chip = data;
+	int rc;
+
+	if (!chip->bdev)
+		return IRQ_HANDLED;
+
+	rc = bif_ctrl_notify_battery_changed(chip->bdev);
+	if (rc)
+		pr_err("Could not notify about battery state change, rc=%d\n",
+			rc);
+
+	return IRQ_HANDLED;
+}
+
+static void qpnp_bsi_set_com_mode(struct qpnp_bsi_chip *chip,
+				enum qpnp_bsi_com_mode mode)
+{
+	int i;
+
+	if (chip->com_mode == mode)
+		return;
+
+	if (mode == QPNP_BSI_COM_MODE_IRQ)
+		for (i = 0; i < QPNP_BSI_IRQ_COUNT; i++)
+			enable_irq(chip->irq[i]);
+	else
+		for (i = 0; i < QPNP_BSI_IRQ_COUNT; i++)
+			disable_irq(chip->irq[i]);
+
+	chip->com_mode = mode;
+}
+
+static inline bool qpnp_bsi_check_irq(struct qpnp_bsi_chip *chip, int irq)
+{
+	return atomic_cmpxchg(&chip->irq_flag[irq], 1, 0);
+}
+
+static void qpnp_bsi_clear_irq_flags(struct qpnp_bsi_chip *chip)
+{
+	int i;
+
+	for (i = 0; i < QPNP_BSI_IRQ_COUNT; i++)
+		atomic_set(&chip->irq_flag[i], 0);
+}
+
+static inline int qpnp_bsi_get_tau_ns(struct qpnp_bsi_chip *chip)
+{
+	if (chip->tau_sampling_mask == QPNP_BSI_TAU_CONFIG_SAMPLE_4X)
+		return qpnp_bsi_tau_period.period_4x_ns[chip->tau_index];
+	else
+		return qpnp_bsi_tau_period.period_8x_ns[chip->tau_index];
+}
+
+static inline int qpnp_bsi_get_tau_us(struct qpnp_bsi_chip *chip)
+{
+	if (chip->tau_sampling_mask == QPNP_BSI_TAU_CONFIG_SAMPLE_4X)
+		return qpnp_bsi_tau_period.period_4x_us[chip->tau_index];
+	else
+		return qpnp_bsi_tau_period.period_8x_us[chip->tau_index];
+}
+
+/* Checks if BSI is in an error state and clears the error if it is. */
+static int qpnp_bsi_clear_bsi_error(struct qpnp_bsi_chip *chip)
+{
+	int rc, delay_us;
+	u8 reg;
+
+	rc = qpnp_bsi_read(chip, QPNP_BSI_REG_BSI_ERROR, &reg, 1);
+	if (rc) {
+		dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_read() failed, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	if (reg > 0) {
+		/*
+		 * Delay before clearing the BSI error in case a transaction is
+		 * still in flight.
+		 */
+		delay_us = QPNP_BSI_MAX_TRANSMIT_CYCLES
+				* qpnp_bsi_get_tau_us(chip);
+		udelay(delay_us);
+
+		pr_info("PMIC BSI module in error state, error=%d\n", reg);
+
+		reg = QPNP_BSI_BSI_ERROR_CLEAR;
+		rc = qpnp_bsi_write(chip, QPNP_BSI_REG_CLEAR_ERROR, &reg, 1);
+		if (rc)
+			dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
+				__func__, rc);
+	}
+
+	return rc;
+}
+
+static int qpnp_bsi_get_bsi_error(struct qpnp_bsi_chip *chip)
+{
+	int rc;
+	u8 reg;
+
+	rc = qpnp_bsi_read(chip, QPNP_BSI_REG_BSI_ERROR, &reg, 1);
+	if (rc) {
+		dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_read() failed, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	return reg;
+}
+
+static int qpnp_bsi_wait_for_tx(struct qpnp_bsi_chip *chip, int timeout)
+{
+	int rc = 0;
+
+	/* Wait for TX or ERR IRQ. */
+	while (timeout > 0) {
+		if (qpnp_bsi_check_irq(chip, QPNP_BSI_IRQ_ERR)) {
+			dev_err(&chip->spmi_dev->dev, "%s: transaction error occurred, BSI error=%d\n",
+				__func__, qpnp_bsi_get_bsi_error(chip));
+			return -EIO;
+		}
+
+		if (qpnp_bsi_check_irq(chip, QPNP_BSI_IRQ_TX))
+			break;
+
+		udelay(1);
+		timeout--;
+	}
+
+	if (timeout == 0) {
+		rc = -ETIMEDOUT;
+		dev_err(&chip->spmi_dev->dev, "%s: transaction timed out, no interrupts received, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int qpnp_bsi_issue_transaction(struct qpnp_bsi_chip *chip,
+		int transaction, u8 data)
+{
+	int rc;
+	u8 buf[4];
+
+	/* MIPI_BIF_DATA_TX_0 = BIF word bits 7 to 0 */
+	buf[0] = data;
+	/* MIPI_BIF_DATA_TX_1 = BIF word BCF, bits 9 to 8 */
+	buf[1] = transaction & QPNP_BSI_TX_DATA_HIGH_MASK;
+	/* MIPI_BIF_DATA_TX_2 ignored */
+	buf[2] = 0x00;
+	/* MIPI_BIF_TX_CTL bit 0 written to start the transaction. */
+	buf[3] = QPNP_BSI_TX_CTRL_GO;
+
+	/* Write the TX_DATA bytes and initiate the transaction. */
+	rc = qpnp_bsi_write(chip, QPNP_BSI_REG_TX_DATA_LOW, buf, 4);
+	if (rc)
+		dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
+			__func__, rc);
+	return rc;
+}
+
+static int qpnp_bsi_issue_transaction_wait_for_tx(struct qpnp_bsi_chip *chip,
+		int transaction, u8 data)
+{
+	int rc, timeout;
+
+	rc = qpnp_bsi_issue_transaction(chip, transaction, data);
+	if (rc)
+		return rc;
+
+	timeout = QPNP_BSI_MAX_TRANSMIT_CYCLES * qpnp_bsi_get_tau_us(chip)
+			+ QPNP_BSI_MAX_IRQ_LATENCY_US;
+
+	rc = qpnp_bsi_wait_for_tx(chip, timeout);
+
+	return rc;
+}
+
+static int qpnp_bsi_wait_for_rx(struct qpnp_bsi_chip *chip, int timeout)
+{
+	int rc = 0;
+
+	/* Wait for RX IRQ to indicate that data is ready to read. */
+	while (timeout > 0) {
+		if (qpnp_bsi_check_irq(chip, QPNP_BSI_IRQ_ERR)) {
+			dev_err(&chip->spmi_dev->dev, "%s: transaction error occurred, BSI error=%d\n",
+				__func__, qpnp_bsi_get_bsi_error(chip));
+			return -EIO;
+		}
+
+		if (qpnp_bsi_check_irq(chip, QPNP_BSI_IRQ_RX))
+			break;
+
+		udelay(1);
+		timeout--;
+	}
+
+	if (timeout == 0)
+		rc = -ETIMEDOUT;
+
+	return rc;
+}
+
+static int qpnp_bsi_bus_transaction(struct bif_ctrl_dev *bdev, int transaction,
+				u8 data)
+{
+	struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+	int rc;
+
+	rc = qpnp_bsi_clear_bsi_error(chip);
+	if (rc)
+		return rc;
+
+	qpnp_bsi_clear_irq_flags(chip);
+
+	qpnp_bsi_set_com_mode(chip, QPNP_BSI_COM_MODE_IRQ);
+
+	rc = qpnp_bsi_set_bus_state(bdev, BIF_BUS_STATE_ACTIVE);
+	if (rc) {
+		dev_err(&chip->spmi_dev->dev, "%s: failed to set bus state, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	rc = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_OFF_TX_DATA);
+	if (rc)
+		return rc;
+
+	rc = qpnp_bsi_issue_transaction_wait_for_tx(chip, transaction, data);
+	if (rc)
+		return rc;
+
+	rc = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_OFF_TX_OFF);
+
+	return rc;
+}
+
+static int qpnp_bsi_bus_transaction_query(struct bif_ctrl_dev *bdev,
+				int transaction, u8 data, bool *query_response)
+{
+	struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+	int rc, timeout;
+
+	rc = qpnp_bsi_clear_bsi_error(chip);
+	if (rc)
+		return rc;
+
+	qpnp_bsi_clear_irq_flags(chip);
+
+	qpnp_bsi_set_com_mode(chip, QPNP_BSI_COM_MODE_IRQ);
+
+	rc = qpnp_bsi_set_bus_state(bdev, BIF_BUS_STATE_ACTIVE);
+	if (rc) {
+		dev_err(&chip->spmi_dev->dev, "%s: failed to set bus state, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	rc = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_INT_TX_DATA);
+	if (rc)
+		return rc;
+
+	rc = qpnp_bsi_issue_transaction_wait_for_tx(chip, transaction, data);
+	if (rc)
+		return rc;
+
+	timeout = QPNP_BSI_MAX_BUS_QUERY_CYCLES * qpnp_bsi_get_tau_us(chip)
+				+ QPNP_BSI_MAX_IRQ_LATENCY_US;
+
+	rc = qpnp_bsi_wait_for_rx(chip, timeout);
+	if (rc == 0) {
+		*query_response = true;
+	} else if (rc == -ETIMEDOUT) {
+		*query_response = false;
+		rc = 0;
+	}
+
+	rc = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_OFF_TX_OFF);
+
+	return rc;
+}
+
+static int qpnp_bsi_bus_transaction_read(struct bif_ctrl_dev *bdev,
+				int transaction, u8 data, int *response)
+{
+	struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+	int rc, timeout;
+	u8 buf[3];
+
+	rc = qpnp_bsi_clear_bsi_error(chip);
+	if (rc)
+		return rc;
+
+	qpnp_bsi_clear_irq_flags(chip);
+
+	qpnp_bsi_set_com_mode(chip, QPNP_BSI_COM_MODE_IRQ);
+
+	rc = qpnp_bsi_set_bus_state(bdev, BIF_BUS_STATE_ACTIVE);
+	if (rc) {
+		dev_err(&chip->spmi_dev->dev, "%s: failed to set bus state, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	rc = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_DATA_TX_DATA);
+	if (rc)
+		return rc;
+
+	rc = qpnp_bsi_issue_transaction_wait_for_tx(chip, transaction, data);
+	if (rc)
+		return rc;
+
+	timeout = QPNP_BSI_MAX_TRANSMIT_CYCLES * qpnp_bsi_get_tau_us(chip)
+				+ QPNP_BSI_MAX_IRQ_LATENCY_US;
+
+	rc = qpnp_bsi_wait_for_rx(chip, timeout);
+	if (rc) {
+		if (rc == -ETIMEDOUT) {
+			/*
+			 * No error message is printed in this case in order
+			 * to provide silent operation when checking if a slave
+			 * is selected using the transaction query bus command.
+			 */
+			dev_dbg(&chip->spmi_dev->dev, "%s: transaction timed out, no interrupts received, rc=%d\n",
+					__func__, rc);
+		}
+		return rc;
+	}
+
+	/* Read the RX_DATA bytes. */
+	rc = qpnp_bsi_read(chip, QPNP_BSI_REG_RX_DATA_LOW, buf, 3);
+	if (rc) {
+		dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_read() failed, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	if (buf[2] & QPNP_BSI_RX_SRC_LOOPBACK_FLAG) {
+		rc = -EIO;
+		dev_err(&chip->spmi_dev->dev, "%s: unexpected loopback data read, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	*response = ((int)(buf[1] & QPNP_BSI_RX_DATA_HIGH_MASK) << 8) | buf[0];
+
+	rc = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_OFF_TX_OFF);
+
+	return 0;
+}
+
+/*
+ * Wait for RX_FLOW_STATUS to be set to 1 which indicates that another BIF word
+ * can be read from PMIC registers.
+ */
+static int qpnp_bsi_wait_for_rx_data(struct qpnp_bsi_chip *chip)
+{
+	int rc = 0;
+	int timeout;
+	u8 reg;
+
+	timeout = QPNP_BSI_MAX_TRANSMIT_CYCLES * qpnp_bsi_get_tau_us(chip);
+
+	/* Wait for RX_FLOW_STATUS == 1 or ERR_FLAG == 1. */
+	while (timeout > 0) {
+		rc = qpnp_bsi_read(chip, QPNP_BSI_REG_STATUS, &reg, 1);
+		if (rc) {
+			dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+
+		if (reg & QPNP_BSI_STATUS_ERROR) {
+			dev_err(&chip->spmi_dev->dev, "%s: transaction error occurred, BSI error=%d\n",
+				__func__, qpnp_bsi_get_bsi_error(chip));
+			return -EIO;
+		}
+
+		if (reg & QPNP_BSI_STATUS_RX_DATA_READY) {
+			/* BSI RX has data word latched. */
+			return 0;
+		}
+
+		udelay(1);
+		timeout--;
+	}
+
+	rc = -ETIMEDOUT;
+	dev_err(&chip->spmi_dev->dev, "%s: transaction timed out, RX_FLOW_STATUS never set to 1, rc=%d\n",
+		__func__, rc);
+
+	return rc;
+}
+
+/*
+ * Wait for TX_GO_STATUS to be set to 0 which indicates that another BIF word
+ * can be enqueued.
+ */
+static int qpnp_bsi_wait_for_tx_go(struct qpnp_bsi_chip *chip)
+{
+	int rc = 0;
+	int timeout;
+	u8 reg;
+
+	timeout = QPNP_BSI_MAX_TRANSMIT_CYCLES * qpnp_bsi_get_tau_us(chip);
+
+	/* Wait for TX_GO_STATUS == 0 or ERR_FLAG == 1. */
+	while (timeout > 0) {
+		rc = qpnp_bsi_read(chip, QPNP_BSI_REG_STATUS, &reg, 1);
+		if (rc) {
+			dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+
+		if (reg & QPNP_BSI_STATUS_ERROR) {
+			dev_err(&chip->spmi_dev->dev, "%s: transaction error occurred, BSI error=%d\n",
+				__func__, qpnp_bsi_get_bsi_error(chip));
+			return -EIO;
+		}
+
+		if (!(reg & QPNP_BSI_STATUS_TX_GO_BUSY)) {
+			/* BSI TX is ready to accept the next word. */
+			return 0;
+		}
+
+		udelay(1);
+		timeout--;
+	}
+
+	rc = -ETIMEDOUT;
+	dev_err(&chip->spmi_dev->dev, "%s: transaction timed out, TX_GO_STATUS never set to 0, rc=%d\n",
+		__func__, rc);
+
+	return rc;
+}
+
+/*
+ * Wait for TX_BUSY to be set to 0 which indicates that the TX data has been
+ * successfully transmitted.
+ */
+static int qpnp_bsi_wait_for_tx_idle(struct qpnp_bsi_chip *chip)
+{
+	int rc = 0;
+	int timeout;
+	u8 reg;
+
+	timeout = QPNP_BSI_MAX_TRANSMIT_CYCLES * qpnp_bsi_get_tau_us(chip);
+
+	/* Wait for TX_BUSY == 0 or ERR_FLAG == 1. */
+	while (timeout > 0) {
+		rc = qpnp_bsi_read(chip, QPNP_BSI_REG_STATUS, &reg, 1);
+		if (rc) {
+			dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+
+		if (reg & QPNP_BSI_STATUS_ERROR) {
+			dev_err(&chip->spmi_dev->dev, "%s: transaction error occurred, BSI error=%d\n",
+				__func__, qpnp_bsi_get_bsi_error(chip));
+			return -EIO;
+		}
+
+		if (!(reg & QPNP_BSI_STATUS_TX_BUSY)) {
+			/* BSI TX is idle. */
+			return 0;
+		}
+
+		udelay(1);
+		timeout--;
+	}
+
+	rc = -ETIMEDOUT;
+	dev_err(&chip->spmi_dev->dev, "%s: transaction timed out, TX_BUSY never set to 0, rc=%d\n",
+		__func__, rc);
+
+	return rc;
+}
+
+/*
+ * For burst read length greater than 1, send necessary RBL and RBE BIF bus
+ * commands.
+ */
+static int qpnp_bsi_send_burst_length(struct qpnp_bsi_chip *chip, int burst_len)
+{
+	int rc = 0;
+
+	/*
+	 * Send burst read length bus commands according to the following:
+	 *
+	 * 256                --> RBL0
+	 * 0-255 = 16 * y + x --> RBEy and RBLx
+	 *		RBE0 does not need to be sent
+	 *		RBL0 does not need to be sent
+	 */
+	if (burst_len == 256) {
+		rc = qpnp_bsi_issue_transaction(chip, BIF_TRANS_BC,
+						BIF_CMD_RBL);
+		if (rc)
+			return rc;
+
+		rc = qpnp_bsi_wait_for_tx_go(chip);
+		if (rc)
+			return rc;
+	} else if (burst_len >= 16) {
+		rc = qpnp_bsi_issue_transaction(chip, BIF_TRANS_BC,
+					BIF_CMD_RBE + (burst_len / 16));
+		if (rc)
+			return rc;
+
+		rc = qpnp_bsi_wait_for_tx_go(chip);
+		if (rc)
+			return rc;
+	}
+
+	if (burst_len % 16) {
+		rc = qpnp_bsi_issue_transaction(chip, BIF_TRANS_BC,
+					BIF_CMD_RBL + (burst_len % 16));
+		if (rc)
+			return rc;
+
+		rc = qpnp_bsi_wait_for_tx_go(chip);
+		if (rc)
+			return rc;
+	}
+
+	return rc;
+}
+
+/* Perform validation steps on received BIF data. */
+static int qpnp_bsi_validate_rx_data(struct qpnp_bsi_chip *chip, int response,
+					u8 rx2_data, bool last_word)
+{
+	int err = -EIO;
+
+	if (rx2_data & QPNP_BSI_RX_SRC_LOOPBACK_FLAG) {
+		dev_err(&chip->spmi_dev->dev, "%s: unexpected loopback data read, rc=%d\n",
+			__func__, err);
+		return err;
+	}
+
+	if (!(response & BIF_SLAVE_RD_ACK)) {
+		dev_err(&chip->spmi_dev->dev, "%s: BIF register read error=0x%02X\n",
+			__func__, response & BIF_SLAVE_RD_ERR);
+		return err;
+	}
+
+	if (last_word && !(response & BIF_SLAVE_RD_EOT)) {
+		dev_err(&chip->spmi_dev->dev, "%s: BIF register read error, last RD packet has EOT=0\n",
+			__func__);
+		return err;
+	} else if (!last_word && (response & BIF_SLAVE_RD_EOT)) {
+		dev_err(&chip->spmi_dev->dev, "%s: BIF register read error, RD packet other than last has EOT=1\n",
+			__func__);
+		return err;
+	}
+
+	return 0;
+}
+
+/* Performs all BIF transactions in order to utilize burst reads. */
+static int qpnp_bsi_read_slave_registers(struct bif_ctrl_dev *bdev, u16 addr,
+						u8 *data, int len)
+{
+	struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+	int response = 0;
+	unsigned long flags;
+	int rc, rc2, i, burst_len;
+	u8 buf[3];
+
+	rc = qpnp_bsi_clear_bsi_error(chip);
+	if (rc)
+		return rc;
+
+	qpnp_bsi_clear_irq_flags(chip);
+
+	qpnp_bsi_set_com_mode(chip, QPNP_BSI_COM_MODE_POLL);
+
+	rc = qpnp_bsi_set_bus_state(bdev, BIF_BUS_STATE_ACTIVE);
+	if (rc) {
+		dev_err(&chip->spmi_dev->dev, "%s: failed to set bus state, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	rc = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_DATA_TX_DATA);
+	if (rc)
+		return rc;
+
+	while (len > 0) {
+		burst_len = min(len, 256);
+
+		rc = qpnp_bsi_send_burst_length(chip, burst_len);
+		if (rc)
+			return rc;
+
+		rc = qpnp_bsi_issue_transaction(chip, BIF_TRANS_ERA, addr >> 8);
+		if (rc)
+			return rc;
+
+		rc = qpnp_bsi_wait_for_tx_go(chip);
+		if (rc)
+			return rc;
+
+		/* Perform burst read in atomic context. */
+		local_irq_save(flags);
+
+		rc = qpnp_bsi_issue_transaction(chip, BIF_TRANS_RRA,
+						addr & 0xFF);
+		if (rc)
+			goto burst_err;
+
+		for (i = 0; i < burst_len; i++) {
+			rc = qpnp_bsi_wait_for_rx_data(chip);
+			if (rc)
+				goto burst_err;
+
+			/* Read the RX_DATA bytes. */
+			rc = qpnp_bsi_read(chip, QPNP_BSI_REG_RX_DATA_LOW, buf,
+					   3);
+			if (rc) {
+				dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_read() failed, rc=%d\n",
+					__func__, rc);
+				goto burst_err;
+			}
+
+			response = ((buf[1] & QPNP_BSI_RX_DATA_HIGH_MASK) << 8)
+					| buf[0];
+
+			rc = qpnp_bsi_validate_rx_data(chip, response, buf[2],
+					i == burst_len - 1);
+			if (rc)
+				goto burst_err;
+
+			data[i] = buf[0];
+		}
+		local_irq_restore(flags);
+
+		addr += burst_len;
+		data += burst_len;
+		len -= burst_len;
+	}
+
+	rc = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_OFF_TX_OFF);
+
+	return rc;
+
+burst_err:
+	local_irq_restore(flags);
+
+	rc2 = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_OFF_TX_OFF);
+	if (rc2 < 0)
+		rc = rc2;
+
+	return rc;
+}
+
+/* Performs all BIF transactions in order to utilize burst writes. */
+static int qpnp_bsi_write_slave_registers(struct bif_ctrl_dev *bdev, u16 addr,
+						const u8 *data, int len)
+{
+	struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+	unsigned long flags;
+	int rc, rc2, i;
+
+	rc = qpnp_bsi_clear_bsi_error(chip);
+	if (rc)
+		return rc;
+
+	qpnp_bsi_clear_irq_flags(chip);
+
+	qpnp_bsi_set_com_mode(chip, QPNP_BSI_COM_MODE_POLL);
+
+	rc = qpnp_bsi_set_bus_state(bdev, BIF_BUS_STATE_ACTIVE);
+	if (rc) {
+		dev_err(&chip->spmi_dev->dev, "%s: failed to set bus state, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	rc = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_OFF_TX_DATA);
+	if (rc)
+		return rc;
+
+	rc = qpnp_bsi_issue_transaction(chip, BIF_TRANS_ERA, addr >> 8);
+	if (rc)
+		return rc;
+
+	rc = qpnp_bsi_wait_for_tx_go(chip);
+	if (rc)
+		return rc;
+
+	rc = qpnp_bsi_issue_transaction(chip, BIF_TRANS_WRA, addr & 0xFF);
+	if (rc)
+		return rc;
+
+	rc = qpnp_bsi_wait_for_tx_go(chip);
+	if (rc)
+		return rc;
+
+	/* Perform burst write in atomic context. */
+	local_irq_save(flags);
+
+	for (i = 0; i < len; i++) {
+		rc = qpnp_bsi_issue_transaction(chip, BIF_TRANS_WD, data[i]);
+		if (rc)
+			goto burst_err;
+
+		rc = qpnp_bsi_wait_for_tx_go(chip);
+		if (rc)
+			goto burst_err;
+	}
+
+	rc = qpnp_bsi_wait_for_tx_idle(chip);
+	if (rc)
+		goto burst_err;
+
+	local_irq_restore(flags);
+
+	rc = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_OFF_TX_OFF);
+
+	return rc;
+
+burst_err:
+	local_irq_restore(flags);
+
+	rc2 = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_OFF_TX_OFF);
+	if (rc2 < 0)
+		rc = rc2;
+
+	return rc;
+}
+
+
+static int qpnp_bsi_bus_set_interrupt_mode(struct bif_ctrl_dev *bdev)
+{
+	struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+	int rc;
+
+	rc = qpnp_bsi_clear_bsi_error(chip);
+	if (rc)
+		return rc;
+
+	qpnp_bsi_clear_irq_flags(chip);
+
+	qpnp_bsi_set_com_mode(chip, QPNP_BSI_COM_MODE_IRQ);
+
+	/*
+	 * Temporarily change the bus to active state so that the EINT command
+	 * can be issued.
+	 */
+	rc = qpnp_bsi_set_bus_state(bdev, BIF_BUS_STATE_ACTIVE);
+	if (rc) {
+		dev_err(&chip->spmi_dev->dev, "%s: failed to set bus state, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	rc = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_INT_TX_DATA);
+	if (rc)
+		return rc;
+
+	/*
+	 * Set the bus state to interrupt mode so that an RX interrupt which
+	 * occurs immediately after issuing the EINT command is handled
+	 * properly.
+	 */
+	chip->state = BIF_BUS_STATE_INTERRUPT;
+
+	/* Send EINT bus command. */
+	rc = qpnp_bsi_issue_transaction_wait_for_tx(chip, BIF_TRANS_BC,
+							BIF_CMD_EINT);
+	if (rc)
+		return rc;
+
+	rc = qpnp_bsi_rx_tx_config(chip, QPNP_BSI_RX_TX_STATE_RX_INT_TX_OFF);
+
+	return rc;
+}
+
+static int qpnp_bsi_bus_set_active_mode(struct bif_ctrl_dev *bdev,
+					int prev_state)
+{
+	struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+	int rc;
+	u8 buf[2];
+
+	rc = qpnp_bsi_clear_bsi_error(chip);
+	if (rc)
+		return rc;
+
+	buf[0] = QPNP_BSI_MODE_TX_PULSE_INT |
+		QPNP_BSI_MODE_RX_PULSE_DATA;
+	buf[1] = QPNP_BSI_TX_ENABLE | QPNP_BSI_RX_DISABLE;
+
+	if (prev_state == BIF_BUS_STATE_INTERRUPT)
+		buf[0] |= QPNP_BSI_MODE_TX_PULSE_T_1_TAU;
+	else
+		buf[0] |= QPNP_BSI_MODE_TX_PULSE_T_WAKE;
+
+	rc = qpnp_bsi_write(chip, QPNP_BSI_REG_MODE, buf, 2);
+	if (rc) {
+		dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	buf[0] = QPNP_BSI_TX_CTRL_GO;
+	/* Initiate BCL low pulse. */
+	rc = qpnp_bsi_write(chip, QPNP_BSI_REG_TX_CTRL, buf, 1);
+	if (rc) {
+		dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	switch (prev_state) {
+	case BIF_BUS_STATE_INTERRUPT:
+		udelay(qpnp_bsi_get_tau_us(chip) * 4);
+		break;
+	case BIF_BUS_STATE_STANDBY:
+		udelay(qpnp_bsi_get_tau_us(chip)
+			+ QPNP_BSI_MAX_SLAVE_ACTIVIATION_DELAY_US
+			+ QPNP_BSI_POWER_UP_LOW_DELAY_US);
+		break;
+	case BIF_BUS_STATE_POWER_DOWN:
+		msleep(QPNP_BSI_MAX_SLAVE_POWER_UP_DELAY_MS);
+		break;
+	}
+
+	return rc;
+}
+
+static int qpnp_bsi_get_bus_state(struct bif_ctrl_dev *bdev)
+{
+	struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+
+	return chip->state;
+}
+
+static int qpnp_bsi_set_bus_state(struct bif_ctrl_dev *bdev, int state)
+{
+	struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+	int rc = 0;
+
+	if (state == chip->state)
+		return 0;
+
+	switch (state) {
+	case BIF_BUS_STATE_MASTER_DISABLED:
+		pr_info("master disable not yet supported.\n");
+		break;
+	case BIF_BUS_STATE_POWER_DOWN:
+		rc = qpnp_bsi_bus_transaction(bdev, BIF_TRANS_BC, BIF_CMD_PDWN);
+		if (rc)
+			dev_err(&chip->spmi_dev->dev, "%s: failed to enable power down mode, rc=%d\n",
+				__func__, rc);
+		break;
+	case BIF_BUS_STATE_STANDBY:
+		rc = qpnp_bsi_bus_transaction(bdev, BIF_TRANS_BC, BIF_CMD_STBY);
+		if (rc)
+			dev_err(&chip->spmi_dev->dev, "%s: failed to enable standby mode, rc=%d\n",
+				__func__, rc);
+		break;
+	case BIF_BUS_STATE_ACTIVE:
+		rc = qpnp_bsi_bus_set_active_mode(bdev, chip->state);
+		if (rc)
+			dev_err(&chip->spmi_dev->dev, "%s: failed to enable active mode, rc=%d\n",
+				__func__, rc);
+		break;
+	case BIF_BUS_STATE_INTERRUPT:
+		/*
+		 * qpnp_bsi_bus_set_interrupt_mode() internally sets
+		 * chip->state = BIF_BUS_STATE_INTERRUPT immediately before
+		 * issuing the EINT command.
+		 */
+		rc = qpnp_bsi_bus_set_interrupt_mode(bdev);
+		if (rc) {
+			dev_err(&chip->spmi_dev->dev, "%s: failed to enable interrupt mode, rc=%d\n",
+				__func__, rc);
+		} else if (chip->state == BIF_BUS_STATE_ACTIVE) {
+			/*
+			 * A slave interrupt was received immediately after
+			 * issuing the EINT command.  Therefore, stay in active
+			 * communication mode.
+			 */
+			state = BIF_BUS_STATE_ACTIVE;
+		}
+		break;
+	default:
+		rc = -EINVAL;
+		dev_err(&chip->spmi_dev->dev, "%s: invalid state=%d\n",
+			__func__, state);
+	}
+
+	if (!rc)
+		chip->state = state;
+
+	return rc;
+}
+
+/* Returns the smallest tau_bif that is greater than or equal to period_ns. */
+static int qpnp_bsi_tau_bif_higher(int period_ns, int sample_mask)
+{
+	const int *supported_period_ns =
+			(sample_mask == QPNP_BSI_TAU_CONFIG_SAMPLE_4X ?
+				qpnp_bsi_tau_period.period_4x_ns :
+				qpnp_bsi_tau_period.period_8x_ns);
+	int smallest_tau_bif = INT_MAX;
+	int i;
+
+	for (i = QPNP_BSI_NUM_CLOCK_PERIODS - 1; i >= 0; i--) {
+		if (period_ns <= supported_period_ns[i]) {
+			smallest_tau_bif = supported_period_ns[i];
+			break;
+		}
+	}
+
+	return smallest_tau_bif;
+}
+
+/* Returns the largest tau_bif that is less than or equal to period_ns. */
+static int qpnp_bsi_tau_bif_lower(int period_ns, int sample_mask)
+{
+	const int *supported_period_ns =
+			(sample_mask == QPNP_BSI_TAU_CONFIG_SAMPLE_4X ?
+				qpnp_bsi_tau_period.period_4x_ns :
+				qpnp_bsi_tau_period.period_8x_ns);
+	int largest_tau_bif = 0;
+	int i;
+
+	for (i = 0; i < QPNP_BSI_NUM_CLOCK_PERIODS; i++) {
+		if (period_ns >= supported_period_ns[i]) {
+			largest_tau_bif = supported_period_ns[i];
+			break;
+		}
+	}
+
+	return largest_tau_bif;
+}
+
+/*
+ * Moves period_ns into allowed range and then sets tau bif to the period that
+ * is greater than or equal to period_ns.
+ */
+static int qpnp_bsi_set_tau_bif(struct qpnp_bsi_chip *chip, int period_ns)
+{
+	const int *supported_period_ns =
+		(chip->tau_sampling_mask == QPNP_BSI_TAU_CONFIG_SAMPLE_4X ?
+			qpnp_bsi_tau_period.period_4x_ns :
+			qpnp_bsi_tau_period.period_8x_ns);
+	int idx = 0;
+	int i, rc;
+	u8 reg;
+
+	if (period_ns < chip->bdesc.bus_clock_min_ns)
+		period_ns = chip->bdesc.bus_clock_min_ns;
+	else if (period_ns > chip->bdesc.bus_clock_max_ns)
+		period_ns = chip->bdesc.bus_clock_max_ns;
+
+	for (i = QPNP_BSI_NUM_CLOCK_PERIODS - 1; i >= 0; i--) {
+		if (period_ns <= supported_period_ns[i]) {
+			idx = i;
+			break;
+		}
+	}
+
+	/* Set the tau BIF clock period and sampling rate. */
+	reg = chip->tau_sampling_mask | idx;
+	rc = qpnp_bsi_write(chip, QPNP_BSI_REG_TAU_CONFIG, &reg, 1);
+	if (rc) {
+		dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	chip->tau_index = idx;
+
+	return 0;
+}
+
+static int qpnp_bsi_get_bus_period(struct bif_ctrl_dev *bdev)
+{
+	struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+
+	return qpnp_bsi_get_tau_ns(chip);
+}
+
+static int qpnp_bsi_set_bus_period(struct bif_ctrl_dev *bdev, int period_ns)
+{
+	struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+
+	return qpnp_bsi_set_tau_bif(chip, period_ns);
+}
+
+static int qpnp_bsi_get_battery_rid(struct bif_ctrl_dev *bdev)
+{
+	struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+	struct qpnp_vadc_result adc_result;
+	int rid_ohm, vid_uV, rc;
+	s64 temp;
+
+	if (chip->batt_id_adc_channel >= ADC_MAX_NUM) {
+		dev_err(&chip->spmi_dev->dev, "%s: no ADC channel specified for Rid measurement\n",
+			__func__);
+		return -ENXIO;
+	}
+
+	rc = qpnp_vadc_read(chip->batt_id_adc_channel, &adc_result);
+	if (!rc) {
+		vid_uV = adc_result.physical;
+
+		if (chip->vid_ref_uV - vid_uV <= 0) {
+			rid_ohm = INT_MAX;
+		} else {
+			temp = (s64)chip->r_pullup_ohm * (s64)vid_uV;
+			do_div(temp, chip->vid_ref_uV - vid_uV);
+			if (temp > INT_MAX)
+				rid_ohm = INT_MAX;
+			else
+				rid_ohm = temp;
+		}
+	} else {
+		dev_err(&chip->spmi_dev->dev, "%s: qpnp_vadc_read(%d) failed, rc=%d\n",
+			__func__, chip->batt_id_adc_channel, rc);
+		rid_ohm = rc;
+	}
+
+	return rid_ohm;
+}
+
+/*
+ * Returns 1 if a battery pack is present on the BIF bus, 0 if a battery pack
+ * is not present, or errno if detection fails.
+ *
+ * Battery detection is based upon the idle BCL voltage.
+ */
+static int qpnp_bsi_get_battery_presence(struct bif_ctrl_dev *bdev)
+{
+	struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
+	u8 reg = 0x00;
+	int rc;
+
+	rc = spmi_ext_register_readl(chip->spmi_dev->ctrl, chip->spmi_dev->sid,
+		chip->batt_id_stat_addr, &reg, 1);
+	if (rc) {
+		dev_err(&chip->spmi_dev->dev, "%s: spmi_ext_register_readl() failed, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	return !!(reg & QPNP_SMBB_BAT_IF_BATT_PRES_MASK);
+}
+
+static struct bif_ctrl_ops qpnp_bsi_ops = {
+	.bus_transaction	= qpnp_bsi_bus_transaction,
+	.bus_transaction_query	= qpnp_bsi_bus_transaction_query,
+	.bus_transaction_read	= qpnp_bsi_bus_transaction_read,
+	.get_bus_state		= qpnp_bsi_get_bus_state,
+	.set_bus_state		= qpnp_bsi_set_bus_state,
+	.get_bus_period		= qpnp_bsi_get_bus_period,
+	.set_bus_period		= qpnp_bsi_set_bus_period,
+	.read_slave_registers	= qpnp_bsi_read_slave_registers,
+	.write_slave_registers	= qpnp_bsi_write_slave_registers,
+	.get_battery_rid	= qpnp_bsi_get_battery_rid,
+	.get_battery_presence	= qpnp_bsi_get_battery_presence,
+};
+
+/* Load all BSI properties from device tree. */
+static int __devinit qpnp_bsi_parse_dt(struct qpnp_bsi_chip *chip,
+			struct spmi_device *spmi)
+{
+	struct device *dev = &spmi->dev;
+	struct device_node *node = spmi->dev.of_node;
+	struct resource *res;
+	int rc, temp;
+
+	chip->batt_id_adc_channel = ADC_MAX_NUM;
+	rc = of_property_read_u32(node, "qcom,channel-num",
+				  &chip->batt_id_adc_channel);
+	if (!rc && (chip->batt_id_adc_channel < 0
+			|| chip->batt_id_adc_channel >= ADC_MAX_NUM)) {
+		dev_err(dev, "%s: invalid qcom,channel-num=%d specified\n",
+			__func__, chip->batt_id_adc_channel);
+		return -EINVAL;
+	}
+
+	chip->r_pullup_ohm = QPNP_BSI_DEFAULT_PULLUP_OHM;
+	rc = of_property_read_u32(node, "qcom,pullup-ohms",
+					&chip->r_pullup_ohm);
+	if (!rc && (chip->r_pullup_ohm < QPNP_BSI_MIN_PULLUP_OHM ||
+			chip->r_pullup_ohm > QPNP_BSI_MAX_PULLUP_OHM)) {
+		dev_err(dev, "%s: invalid qcom,pullup-ohms=%d property value\n",
+			__func__, chip->r_pullup_ohm);
+		return -EINVAL;
+	}
+
+	chip->vid_ref_uV = QPNP_BSI_DEFAULT_VID_REF_UV;
+	rc = of_property_read_u32(node, "qcom,vref-microvolts",
+					&chip->vid_ref_uV);
+	if (!rc && (chip->vid_ref_uV < QPNP_BSI_MIN_VID_REF_UV ||
+			chip->vid_ref_uV > QPNP_BSI_MAX_VID_REF_UV)) {
+		dev_err(dev, "%s: invalid qcom,vref-microvolts=%d property value\n",
+			__func__, chip->vid_ref_uV);
+		return -EINVAL;
+	}
+
+	res = spmi_get_resource_byname(spmi, NULL, IORESOURCE_MEM, "bsi-base");
+	if (!res) {
+		dev_err(dev, "%s: node is missing BSI base address\n",
+			__func__);
+		return -EINVAL;
+	}
+	chip->base_addr = res->start;
+
+	res = spmi_get_resource_byname(spmi, NULL, IORESOURCE_MEM,
+		"batt-id-status");
+	if (!res) {
+		dev_err(dev, "%s: node is missing BATT_ID status address\n",
+			__func__);
+		return -EINVAL;
+	}
+	chip->batt_id_stat_addr = res->start;
+
+	chip->bdesc.name = spmi_get_primary_dev_name(spmi);
+	if (!chip->bdesc.name) {
+		dev_err(dev, "%s: label binding undefined for node %s\n",
+			__func__, spmi->dev.of_node->full_name);
+		return -EINVAL;
+	}
+
+	/* Use maximum range by default. */
+	chip->bdesc.bus_clock_min_ns	= QPNP_BSI_MIN_CLOCK_SPEED_NS;
+	chip->bdesc.bus_clock_max_ns	= QPNP_BSI_MAX_CLOCK_SPEED_NS;
+	chip->tau_sampling_mask		= QPNP_BSI_TAU_CONFIG_SAMPLE_4X;
+
+	rc = of_property_read_u32(node, "qcom,sample-rate", &temp);
+	if (rc == 0) {
+		if (temp == 4) {
+			chip->tau_sampling_mask = QPNP_BSI_TAU_CONFIG_SAMPLE_4X;
+		} else if (temp == 8) {
+			chip->tau_sampling_mask = QPNP_BSI_TAU_CONFIG_SAMPLE_8X;
+		} else {
+			dev_err(dev, "%s: invalid qcom,sample-rate=%d.  Only values of 4 and 8 are supported.\n",
+				__func__, temp);
+			return -EINVAL;
+		}
+	}
+
+	rc = of_property_read_u32(node, "qcom,min-clock-period", &temp);
+	if (rc == 0)
+		chip->bdesc.bus_clock_min_ns = qpnp_bsi_tau_bif_higher(temp,
+						chip->tau_sampling_mask);
+
+	rc = of_property_read_u32(node, "qcom,max-clock-period", &temp);
+	if (rc == 0)
+		chip->bdesc.bus_clock_max_ns = qpnp_bsi_tau_bif_lower(temp,
+						chip->tau_sampling_mask);
+
+	if (chip->bdesc.bus_clock_min_ns > chip->bdesc.bus_clock_max_ns) {
+		dev_err(dev, "%s: invalid qcom,min/max-clock-period.\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	chip->irq[QPNP_BSI_IRQ_ERR] = spmi_get_irq_byname(spmi, NULL, "err");
+	if (chip->irq[QPNP_BSI_IRQ_ERR] < 0) {
+		dev_err(dev, "%s: node is missing err irq\n", __func__);
+		return chip->irq[QPNP_BSI_IRQ_ERR];
+	}
+
+	chip->irq[QPNP_BSI_IRQ_RX] = spmi_get_irq_byname(spmi, NULL, "rx");
+	if (chip->irq[QPNP_BSI_IRQ_RX] < 0) {
+		dev_err(dev, "%s: node is missing rx irq\n", __func__);
+		return chip->irq[QPNP_BSI_IRQ_RX];
+	}
+
+	chip->irq[QPNP_BSI_IRQ_TX] = spmi_get_irq_byname(spmi, NULL, "tx");
+	if (chip->irq[QPNP_BSI_IRQ_TX] < 0) {
+		dev_err(dev, "%s: node is missing tx irq\n", __func__);
+		return chip->irq[QPNP_BSI_IRQ_TX];
+	}
+
+	chip->batt_present_irq = spmi_get_irq_byname(spmi, NULL,
+		"batt-present");
+	if (chip->batt_present_irq < 0) {
+		dev_err(dev, "%s: node is missing batt-present irq\n",
+			__func__);
+		return chip->batt_present_irq;
+	}
+
+	return rc;
+}
+
+/* Request all BSI and battery presence IRQs and set them as wakeable. */
+static int __devinit qpnp_bsi_init_irqs(struct qpnp_bsi_chip *chip,
+			struct device *dev)
+{
+	int rc;
+
+	rc = devm_request_irq(dev, chip->irq[QPNP_BSI_IRQ_ERR],
+			qpnp_bsi_isr, IRQF_TRIGGER_RISING, "bsi-err", chip);
+	if (rc < 0) {
+		dev_err(dev, "%s: request for bsi-err irq %d failed, rc=%d\n",
+			__func__, chip->irq[QPNP_BSI_IRQ_ERR], rc);
+		return rc;
+	}
+
+	rc = irq_set_irq_wake(chip->irq[QPNP_BSI_IRQ_ERR], 1);
+	if (rc < 0) {
+		dev_err(dev, "%s: unable to set bsi-err irq %d as wakeable, rc=%d\n",
+			__func__, chip->irq[QPNP_BSI_IRQ_ERR], rc);
+		return rc;
+	}
+
+	rc = devm_request_irq(dev, chip->irq[QPNP_BSI_IRQ_RX],
+			qpnp_bsi_isr, IRQF_TRIGGER_RISING, "bsi-rx", chip);
+	if (rc < 0) {
+		dev_err(dev, "%s: request for bsi-rx irq %d failed, rc=%d\n",
+			__func__, chip->irq[QPNP_BSI_IRQ_RX], rc);
+		goto set_unwakeable_irq_err;
+	}
+
+	rc = irq_set_irq_wake(chip->irq[QPNP_BSI_IRQ_RX], 1);
+	if (rc < 0) {
+		dev_err(dev, "%s: unable to set bsi-rx irq %d as wakeable, rc=%d\n",
+			__func__, chip->irq[QPNP_BSI_IRQ_RX], rc);
+		goto set_unwakeable_irq_err;
+	}
+
+	rc = devm_request_irq(dev, chip->irq[QPNP_BSI_IRQ_TX],
+			qpnp_bsi_isr, IRQF_TRIGGER_RISING, "bsi-tx", chip);
+	if (rc < 0) {
+		dev_err(dev, "%s: request for bsi-tx irq %d failed, rc=%d\n",
+			__func__, chip->irq[QPNP_BSI_IRQ_TX], rc);
+		goto set_unwakeable_irq_rx;
+	}
+
+	rc = irq_set_irq_wake(chip->irq[QPNP_BSI_IRQ_TX], 1);
+	if (rc < 0) {
+		dev_err(dev, "%s: unable to set bsi-tx irq %d as wakeable, rc=%d\n",
+			__func__, chip->irq[QPNP_BSI_IRQ_TX], rc);
+		goto set_unwakeable_irq_rx;
+	}
+
+	rc = devm_request_threaded_irq(dev, chip->batt_present_irq, NULL,
+		qpnp_bsi_batt_present_isr,
+		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_SHARED
+			| IRQF_ONESHOT,
+		"bsi-batt-present", chip);
+	if (rc < 0) {
+		dev_err(dev, "%s: request for bsi-batt-present irq %d failed, rc=%d\n",
+			__func__, chip->batt_present_irq, rc);
+		goto set_unwakeable_irq_tx;
+	}
+
+	rc = irq_set_irq_wake(chip->batt_present_irq, 1);
+	if (rc < 0) {
+		dev_err(dev, "%s: unable to set bsi-batt-present irq %d as wakeable, rc=%d\n",
+			__func__, chip->batt_present_irq, rc);
+		goto set_unwakeable_irq_tx;
+	}
+
+	return rc;
+
+set_unwakeable_irq_tx:
+	irq_set_irq_wake(chip->irq[QPNP_BSI_IRQ_TX], 0);
+set_unwakeable_irq_rx:
+	irq_set_irq_wake(chip->irq[QPNP_BSI_IRQ_RX], 0);
+set_unwakeable_irq_err:
+	irq_set_irq_wake(chip->irq[QPNP_BSI_IRQ_ERR], 0);
+	return rc;
+}
+
+static void qpnp_bsi_cleanup_irqs(struct qpnp_bsi_chip *chip)
+{
+	irq_set_irq_wake(chip->irq[QPNP_BSI_IRQ_ERR], 0);
+	irq_set_irq_wake(chip->irq[QPNP_BSI_IRQ_RX], 0);
+	irq_set_irq_wake(chip->irq[QPNP_BSI_IRQ_TX], 0);
+	irq_set_irq_wake(chip->batt_present_irq, 0);
+}
+
+static int __devinit qpnp_bsi_probe(struct spmi_device *spmi)
+{
+	struct device *dev = &spmi->dev;
+	struct qpnp_bsi_chip *chip;
+	int rc;
+	u8 type[2], reg;
+
+	if (!spmi->dev.of_node) {
+		dev_err(dev, "%s: device node missing\n", __func__);
+		return -ENODEV;
+	}
+
+	chip = devm_kzalloc(dev, sizeof(struct qpnp_bsi_chip), GFP_KERNEL);
+	if (!chip) {
+		dev_err(dev, "%s: Can't allocate qpnp_bsi\n", __func__);
+		return -ENOMEM;
+	}
+
+	rc = qpnp_bsi_parse_dt(chip, spmi);
+	if (rc) {
+		dev_err(dev, "%s: device tree parsing failed, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	INIT_WORK(&chip->slave_irq_work, qpnp_bsi_slave_irq_work);
+
+	rc = qpnp_bsi_init_irqs(chip, dev);
+	if (rc) {
+		dev_err(dev, "%s: IRQ initialization failed, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	chip->spmi_dev		= spmi;
+	chip->bdesc.ops		= &qpnp_bsi_ops;
+	chip->state		= BIF_BUS_STATE_POWER_DOWN;
+	chip->com_mode		= QPNP_BSI_COM_MODE_IRQ;
+
+	rc = qpnp_bsi_read(chip, QPNP_BSI_REG_TYPE, type, 2);
+	if (rc) {
+		dev_err(dev, "%s: could not read type register, rc=%d\n",
+			__func__, rc);
+		goto cleanup_irqs;
+	}
+
+	if (type[0] != QPNP_BSI_TYPE || type[1] != QPNP_BSI_SUBTYPE) {
+		dev_err(dev, "%s: BSI peripheral is not present; type=0x%02X, subtype=0x%02X\n",
+			__func__, type[0], type[1]);
+		rc = -ENODEV;
+		goto cleanup_irqs;
+	}
+
+	/* Ensure that ADC channel is available if it was specified. */
+	if (chip->batt_id_adc_channel < ADC_MAX_NUM) {
+		rc = qpnp_vadc_is_ready();
+		if (rc) {
+			/* Probe retry, do not print an error message */
+			goto cleanup_irqs;
+		}
+	}
+
+	rc = qpnp_bsi_set_tau_bif(chip, chip->bdesc.bus_clock_min_ns);
+	if (rc) {
+		dev_err(dev, "%s: qpnp_bsi_set_tau_bif() failed, rc=%d\n",
+			__func__, rc);
+		goto cleanup_irqs;
+	}
+
+	/* Enable the BSI module. */
+	reg = QPNP_BSI_ENABLE;
+	rc = qpnp_bsi_write(chip, QPNP_BSI_REG_ENABLE, &reg, 1);
+	if (rc) {
+		dev_err(dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
+			__func__, rc);
+		goto cleanup_irqs;
+	}
+
+	chip->bdev = bif_ctrl_register(&chip->bdesc, dev, chip,
+					spmi->dev.of_node);
+	if (IS_ERR(chip->bdev)) {
+		rc = PTR_ERR(chip->bdev);
+		dev_err(dev, "%s: bif_ctrl_register failed, rc=%d\n",
+			__func__, rc);
+		goto cleanup_irqs;
+	}
+
+	dev_set_drvdata(dev, chip);
+
+	return rc;
+
+cleanup_irqs:
+	qpnp_bsi_cleanup_irqs(chip);
+	return rc;
+}
+
+static int __devexit qpnp_bsi_remove(struct spmi_device *spmi)
+{
+	struct qpnp_bsi_chip *chip = dev_get_drvdata(&spmi->dev);
+	dev_set_drvdata(&spmi->dev, NULL);
+
+	if (chip) {
+		bif_ctrl_unregister(chip->bdev);
+		qpnp_bsi_cleanup_irqs(chip);
+	}
+
+	return 0;
+}
+
+static struct of_device_id spmi_match_table[] = {
+	{ .compatible = QPNP_BSI_DRIVER_NAME, },
+	{}
+};
+
+static const struct spmi_device_id qpnp_bsi_id[] = {
+	{ QPNP_BSI_DRIVER_NAME, 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(spmi, qpnp_bsi_id);
+
+static struct spmi_driver qpnp_bsi_driver = {
+	.driver = {
+		.name		= QPNP_BSI_DRIVER_NAME,
+		.of_match_table	= spmi_match_table,
+		.owner		= THIS_MODULE,
+	},
+	.probe		= qpnp_bsi_probe,
+	.remove		= __devexit_p(qpnp_bsi_remove),
+	.id_table	= qpnp_bsi_id,
+};
+
+static int __init qpnp_bsi_init(void)
+{
+	return spmi_driver_register(&qpnp_bsi_driver);
+}
+
+static void __exit qpnp_bsi_exit(void)
+{
+	spmi_driver_unregister(&qpnp_bsi_driver);
+}
+
+MODULE_DESCRIPTION("QPNP PMIC BSI driver");
+MODULE_LICENSE("GPL v2");
+
+arch_initcall(qpnp_bsi_init);
+module_exit(qpnp_bsi_exit);
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 23dd5a1..0867676 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.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
@@ -149,50 +149,63 @@
 
 void extract_dci_events(unsigned char *buf)
 {
-	uint16_t event_id, event_id_packet;
-	uint8_t *event_mask_ptr, byte_mask, payload_len;
-	uint8_t event_data[MAX_EVENT_SIZE], timestamp[8];
-	unsigned int byte_index;
-	int i, bit_index, length, temp_len;
-	int total_event_len, payload_len_field, timestamp_len;
+	uint16_t event_id, event_id_packet, length, temp_len;
+	uint8_t *event_mask_ptr, byte_mask, payload_len, payload_len_field;
+	uint8_t timestamp[8], bit_index, timestamp_len;
+	uint8_t event_data[MAX_EVENT_SIZE];
+	unsigned int byte_index, total_event_len, i;
 	struct diag_dci_client_tbl *entry;
 
-	length =  *(uint16_t *)(buf+1); /* total length of event series */
+	length =  *(uint16_t *)(buf + 1); /* total length of event series */
+	if (length == 0) {
+		pr_err("diag: Incoming dci event length is invalid\n");
+		return;
+	}
 	temp_len = 0;
 	buf = buf + 3; /* start of event series */
-	while (temp_len < length-1) {
-		*event_data = EVENT_CMD_CODE;
-		event_id_packet = *(uint16_t *)(buf+temp_len);
+	while (temp_len < (length - 1)) {
+		event_id_packet = *(uint16_t *)(buf + temp_len);
 		event_id = event_id_packet & 0x0FFF; /* extract 12 bits */
 		if (event_id_packet & 0x8000) {
 			timestamp_len = 2;
+			memset(timestamp, 0, 8);
 		} else {
 			timestamp_len = 8;
-			memcpy(timestamp, buf+temp_len+2, 8);
+			memcpy(timestamp, buf + temp_len + 2, timestamp_len);
 		}
+		/* 13th and 14th bit represent the payload length */
 		if (((event_id_packet & 0x6000) >> 13) == 3) {
 			payload_len_field = 1;
 			payload_len = *(uint8_t *)
-					(buf+temp_len+2+timestamp_len);
-			memcpy(event_data+13, buf+temp_len+2+timestamp_len, 1);
-			memcpy(event_data+14, buf+temp_len+2+timestamp_len+1,
-								 payload_len);
+					(buf + temp_len + 2 + timestamp_len);
+			if (payload_len < (MAX_EVENT_SIZE - 13)) {
+				/* copy the payload length and the payload */
+				memcpy(event_data + 12, buf + temp_len + 2 +
+							timestamp_len, 1);
+				memcpy(event_data + 13, buf + temp_len + 2 +
+					timestamp_len + 1, payload_len);
+			} else {
+				pr_err("diag: event > %d, payload_len = %d\n",
+					(MAX_EVENT_SIZE - 13), payload_len);
+				return;
+			}
 		} else {
 			payload_len_field = 0;
 			payload_len = (event_id_packet & 0x6000) >> 13;
-			if (payload_len < MAX_EVENT_SIZE)
-				memcpy(event_data+13,
-				 buf+temp_len+2+timestamp_len, payload_len);
-			else
-				pr_alert("diag: event > %d\n", MAX_EVENT_SIZE);
+			/* copy the payload */
+			memcpy(event_data + 12, buf + temp_len + 2 +
+						timestamp_len, payload_len);
 		}
 		/* 2 bytes for the event id & timestamp len is hard coded to 8,
 		   as individual events have full timestamp */
-		*(uint16_t *)(event_data+1) = 10+payload_len_field+payload_len;
-		*(uint16_t *)(event_data+3) = event_id_packet & 0x7FFF;
-		memcpy(event_data+5, timestamp, 8);
-		total_event_len = 3 + 10 + payload_len_field + payload_len;
-		byte_index = event_id/8;
+		*(uint16_t *)(event_data) = 10 +
+					payload_len_field + payload_len;
+		*(uint16_t *)(event_data + 2) = event_id_packet & 0x7FFF;
+		memcpy(event_data + 4, timestamp, 8);
+		/* 2 bytes for the event length field which is added to
+		   the event data */
+		total_event_len = 2 + 10 + payload_len_field + payload_len;
+		byte_index = event_id / 8;
 		bit_index = event_id % 8;
 		byte_mask = 0x1 << bit_index;
 		/* parse through event mask tbl of each client and check mask */
@@ -205,7 +218,7 @@
 					/* copy to client buffer */
 					if (DCI_CHK_CAPACITY(entry,
 							 4 + total_event_len)) {
-						pr_err("diag:DCI event drop\n");
+						pr_err("diag: DCI event drop\n");
 						driver->dci_client_tbl[i].
 							dropped_events++;
 						return;
@@ -214,8 +227,10 @@
 							received_events++;
 					*(int *)(entry->dci_data+
 					entry->data_len) = DCI_EVENT_TYPE;
-					memcpy(entry->dci_data+
-				entry->data_len+4, event_data, total_event_len);
+					/* 4 bytes for DCI_EVENT_TYPE */
+					memcpy(entry->dci_data +
+						entry->data_len + 4, event_data
+						, total_event_len);
 					entry->data_len += 4 + total_event_len;
 				}
 			}
@@ -228,44 +243,37 @@
 {
 	uint16_t log_code, item_num;
 	uint8_t equip_id, *log_mask_ptr, byte_mask;
-	unsigned int byte_index;
-	int i, found = 0;
+	unsigned int i, byte_index, byte_offset = 0;
 	struct diag_dci_client_tbl *entry;
 
-	log_code = *(uint16_t *)(buf+6);
+	log_code = *(uint16_t *)(buf + 6);
 	equip_id = LOG_GET_EQUIP_ID(log_code);
 	item_num = LOG_GET_ITEM_NUM(log_code);
 	byte_index = item_num/8 + 2;
 	byte_mask = 0x01 << (item_num % 8);
 
+	byte_offset = (equip_id * 514) + byte_index;
+	if (byte_offset >=  DCI_LOG_MASK_SIZE) {
+		pr_err("diag: Invalid byte_offset %d in dci log\n",
+							byte_offset);
+		return;
+	}
+
 	/* parse through log mask table of each client and check mask */
 	for (i = 0; i < MAX_DCI_CLIENTS; i++) {
 		if (driver->dci_client_tbl[i].client) {
 			entry = &(driver->dci_client_tbl[i]);
 			log_mask_ptr = entry->dci_log_mask;
-			found = 0;
-			while (log_mask_ptr) {
-				if (*log_mask_ptr == equip_id) {
-					found = 1;
-					pr_debug("diag: find equip id = %x at %p\n",
-					equip_id, log_mask_ptr);
-					break;
-				} else {
-					pr_debug("diag: did not find equip id = %x at %p\n",
-						 equip_id, log_mask_ptr);
-					log_mask_ptr += 514;
-				}
-			}
-			if (!found)
-				pr_err("diag: dci equip id not found\n");
-			log_mask_ptr = log_mask_ptr + byte_index;
+			if (!log_mask_ptr)
+				return;
+			log_mask_ptr = log_mask_ptr + byte_offset;
 			if (*log_mask_ptr & byte_mask) {
 				pr_debug("\t log code %x needed by client %d",
 					 log_code, entry->client->tgid);
 				/* copy to client buffer */
 				if (DCI_CHK_CAPACITY(entry,
-						 4 + *(uint16_t *)(buf+2))) {
-						pr_err("diag:DCI log drop\n");
+						 4 + *(uint16_t *)(buf + 2))) {
+						pr_err("diag: DCI log drop\n");
 						driver->dci_client_tbl[i].
 								dropped_logs++;
 						return;
@@ -273,9 +281,9 @@
 				driver->dci_client_tbl[i].received_logs++;
 				*(int *)(entry->dci_data+entry->data_len) =
 								DCI_LOG_TYPE;
-				memcpy(entry->dci_data+entry->data_len+4, buf+4,
-						 *(uint16_t *)(buf+2));
-				entry->data_len += 4 + *(uint16_t *)(buf+2);
+				memcpy(entry->dci_data + entry->data_len + 4,
+					    buf + 4, *(uint16_t *)(buf + 2));
+				entry->data_len += 4 + *(uint16_t *)(buf + 2);
 			}
 		}
 	}
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 56d1b91..0f47740 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.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
@@ -22,7 +22,7 @@
 #define DCI_EVENT_TYPE		-2
 #define SET_LOG_MASK		1
 #define DISABLE_LOG_MASK	0
-#define MAX_EVENT_SIZE		100
+#define MAX_EVENT_SIZE		512
 
 /* 16 log code categories, each has:
  * 1 bytes equip id + 1 dirty byte + 512 byte max log mask
diff --git a/drivers/char/diag/diagchar_hdlc.c b/drivers/char/diag/diagchar_hdlc.c
index b94ea2f..2369c4d 100644
--- a/drivers/char/diag/diagchar_hdlc.c
+++ b/drivers/char/diag/diagchar_hdlc.c
@@ -1,4 +1,5 @@
-/* Copyright (c) 2008-2009, 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2009, 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
@@ -172,11 +173,14 @@
 	uint8_t src_byte;
 
 	int pkt_bnd = 0;
+	int msg_start;
 
 	if (hdlc && hdlc->src_ptr && hdlc->dest_ptr &&
 	    (hdlc->src_size - hdlc->src_idx > 0) &&
 	    (hdlc->dest_size - hdlc->dest_idx > 0)) {
 
+		msg_start = (hdlc->src_idx == 0) ? 1 : 0;
+
 		src_ptr = hdlc->src_ptr;
 		src_ptr = &src_ptr[hdlc->src_idx];
 		src_length = hdlc->src_size - hdlc->src_idx;
@@ -203,8 +207,16 @@
 				}
 			} else if (src_byte == CONTROL_CHAR) {
 				dest_ptr[len++] = src_byte;
-				pkt_bnd = 1;
+				/*
+				 * If this is the first byte in the message,
+				 * then it is part of the command. Otherwise,
+				 * consider it as the last byte of the
+				 * message.
+				 */
+				if (msg_start && i == 0 && src_length > 1)
+					continue;
 				i++;
+				pkt_bnd = 1;
 				break;
 			} else {
 				dest_ptr[len++] = src_byte;
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 7f4edd1..2aca8cf 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -993,10 +993,18 @@
 
 	ret = diag_hdlc_decode(&hdlc);
 
-	if (hdlc.dest_idx < 3) {
-		pr_err("diag: Integer underflow in hdlc processing\n");
+	/*
+	 * If the message is 3 bytes or less in length then the message is
+	 * too short. A message will need 4 bytes minimum, since there are
+	 * 2 bytes for the CRC and 1 byte for the ending 0x7e for the hdlc
+	 * encoding
+	 */
+	if (hdlc.dest_idx < 4) {
+		pr_err_ratelimited("diag: In %s, message is too short, len: %d, dest len: %d\n",
+			__func__, len, hdlc.dest_idx);
 		return;
 	}
+
 	if (ret) {
 		type = diag_process_apps_pkt(driver->hdlc_buf,
 							  hdlc.dest_idx - 3);
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 3da06a5..1facf24 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -1523,6 +1523,9 @@
 		}
 	break;
 	default:
+		pr_err("Unknown mode of operation %d received, exiting now\n",
+			mode);
+		return -EINVAL;
 	break;
 	}
 
@@ -1686,6 +1689,8 @@
 		}
 	break;
 	default:
+		pr_err("Unknown algorithms %d received, exiting now\n", alg);
+		return -EINVAL;
 	break;
 	}
 
@@ -1893,6 +1898,8 @@
 								0, NULL);
 	break;
 	default:
+		pr_err("Unknown algorithms %d received, exiting now\n", alg);
+		return -EINVAL;
 	break;
 	}
 
@@ -2247,6 +2254,10 @@
 	if (q_req->mode != QCE_MODE_CCM) {
 		ivsize = crypto_aead_ivsize(aead);
 		auth_cmdlistinfo = &pce_dev->ce_sps.cmdlistptr.aead_sha1_hmac;
+		if (auth_cmdlistinfo == NULL) {
+			pr_err("Received NULL cmdlist, exiting now\n");
+			return -EINVAL;
+		}
 	}
 
 	ce_burst_size = pce_dev->ce_sps.ce_burst_size;
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 50d454c..41ab8dc 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -595,6 +595,9 @@
 		sreq.authklen = qcedev_areq->sha_op_req.authklen;
 		break;
 	default:
+		pr_err("Algorithm %d not supported, exiting\n",
+			qcedev_areq->sha_op_req.alg);
+		return -EINVAL;
 		break;
 	};
 
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index 7e063ca..05ef87c 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -1175,6 +1175,8 @@
 		sreq.authklen = SHA_HMAC_KEY_SIZE;
 		break;
 	default:
+		pr_err("Algorithm %d not supported, exiting", sha_ctx->alg);
+		ret = -1;
 		break;
 	};
 	ret =  qce_process_sha_req(cp->qce, &sreq);
@@ -1240,6 +1242,7 @@
 			if (rctx->data == NULL) {
 				pr_err("Mem Alloc fail rctx->data, err %ld\n",
 							PTR_ERR(rctx->data));
+				kzfree(qreq.assoc);
 				return -ENOMEM;
 			}
 
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 1ca457f..832a9a1 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -55,7 +55,7 @@
 	},
 	{
 		.id	= ION_CP_MM_HEAP_ID,
-		.type	= ION_HEAP_TYPE_CP,
+		.type	= ION_HEAP_TYPE_SECURE_DMA,
 		.name	= ION_MM_HEAP_NAME,
 		.permission_type = IPT_TYPE_MM_CARVEOUT,
 	},
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index b7d813c..b1a45bf 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -2000,8 +2000,17 @@
 		/* Is the ring buffer is empty? */
 		GSL_RB_GET_READPTR(rb, &rb->rptr);
 		if (!device->active_cnt && (rb->rptr == rb->wptr)) {
-			/* Is the core idle? */
-			status = is_adreno_rbbm_status_idle(device);
+			/*
+			 * Are there interrupts pending? If so then pretend we
+			 * are not idle - this avoids the possiblity that we go
+			 * to a lower power state without handling interrupts
+			 * first.
+			 */
+
+			if (!adreno_dev->gpudev->irq_pending(adreno_dev)) {
+				/* Is the core idle? */
+				status = is_adreno_rbbm_status_idle(device);
+			}
 		}
 	} else {
 		status = true;
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index cc6eb16..b1cab9b 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -125,6 +125,7 @@
 					struct adreno_context *);
 	irqreturn_t (*irq_handler)(struct adreno_device *);
 	void (*irq_control)(struct adreno_device *, int);
+	unsigned int (*irq_pending)(struct adreno_device *);
 	void * (*snapshot)(struct adreno_device *, void *, int *, int);
 	void (*rb_init)(struct adreno_device *, struct adreno_ringbuffer *);
 	void (*start)(struct adreno_device *);
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index 952d1f8..6db6e7b 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -1706,34 +1706,6 @@
 		return;
 	}
 
-	if (status & CP_INT_CNTL__RB_INT_MASK) {
-		/* signal intr completion event */
-		unsigned int context_id, timestamp;
-		kgsl_sharedmem_readl(&device->memstore, &context_id,
-				KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
-					current_context));
-
-		kgsl_sharedmem_readl(&device->memstore, &timestamp,
-				KGSL_MEMSTORE_OFFSET(context_id,
-					eoptimestamp));
-
-		if (context_id < KGSL_MEMSTORE_MAX) {
-			/* reset per context ts_cmp_enable */
-			kgsl_sharedmem_writel(&device->memstore,
-					KGSL_MEMSTORE_OFFSET(context_id,
-						ts_cmp_enable), 0);
-			/* Always reset global timestamp ts_cmp_enable */
-			kgsl_sharedmem_writel(&device->memstore,
-					KGSL_MEMSTORE_OFFSET(
-						KGSL_MEMSTORE_GLOBAL,
-						ts_cmp_enable), 0);
-			wmb();
-		}
-
-		KGSL_CMD_WARN(device, "<%d:0x%x> ringbuffer interrupt\n",
-				context_id, timestamp);
-	}
-
 	for (i = 0; i < ARRAY_SIZE(kgsl_cp_error_irqs); i++) {
 		if (status & kgsl_cp_error_irqs[i].mask) {
 			KGSL_CMD_CRIT(rb->device, "%s\n",
@@ -1840,6 +1812,19 @@
 	wmb();
 }
 
+static unsigned int a2xx_irq_pending(struct adreno_device *adreno_dev)
+{
+	struct kgsl_device *device = &adreno_dev->dev;
+	unsigned int rbbm, cp, mh;
+
+	adreno_regread(device, REG_RBBM_INT_CNTL, &rbbm);
+	adreno_regread(device, REG_CP_INT_CNTL, &cp);
+	adreno_regread(device, MH_INTERRUPT_MASK, &mh);
+
+	return ((rbbm & RBBM_INT_MASK) || (cp & CP_INT_MASK) ||
+		(mh & kgsl_mmu_get_int_mask())) ? 1 : 0;
+}
+
 static void a2xx_rb_init(struct adreno_device *adreno_dev,
 			struct adreno_ringbuffer *rb)
 {
@@ -2035,6 +2020,7 @@
 	.ctxt_draw_workaround = a2xx_drawctxt_draw_workaround,
 	.irq_handler = a2xx_irq_handler,
 	.irq_control = a2xx_irq_control,
+	.irq_pending = a2xx_irq_pending,
 	.snapshot = a2xx_snapshot,
 	.rb_init = a2xx_rb_init,
 	.busy_cycles = a2xx_busy_cycles,
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index a3739a2..73a7f52 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2591,33 +2591,7 @@
 {
 	struct kgsl_device *device = &adreno_dev->dev;
 
-	if (irq == A3XX_INT_CP_RB_INT) {
-		unsigned int context_id, timestamp;
-		kgsl_sharedmem_readl(&device->memstore, &context_id,
-				KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
-					current_context));
-
-		kgsl_sharedmem_readl(&device->memstore, &timestamp,
-				KGSL_MEMSTORE_OFFSET(context_id,
-					eoptimestamp));
-
-		if (context_id < KGSL_MEMSTORE_MAX) {
-			/* reset per context ts_cmp_enable */
-			kgsl_sharedmem_writel(&device->memstore,
-					KGSL_MEMSTORE_OFFSET(context_id,
-						ts_cmp_enable), 0);
-			/* Always reset global timestamp ts_cmp_enable */
-			kgsl_sharedmem_writel(&device->memstore,
-					KGSL_MEMSTORE_OFFSET(
-						KGSL_MEMSTORE_GLOBAL,
-						ts_cmp_enable), 0);
-			wmb();
-		}
-
-		KGSL_CMD_WARN(device, "<%d:0x%x> ringbuffer interrupt\n",
-				context_id, timestamp);
-	}
-
+	/* Wake up everybody waiting for the interrupt */
 	wake_up_interruptible_all(&device->wait_queue);
 
 	/* Schedule work to free mem and issue ibs */
@@ -2713,6 +2687,15 @@
 		adreno_regwrite(device, A3XX_RBBM_INT_0_MASK, 0);
 }
 
+static unsigned int a3xx_irq_pending(struct adreno_device *adreno_dev)
+{
+	unsigned int status;
+
+	adreno_regread(&adreno_dev->dev, A3XX_RBBM_INT_0_STATUS, &status);
+
+	return (status & A3XX_INT_MASK) ? 1 : 0;
+}
+
 static unsigned int a3xx_busy_cycles(struct adreno_device *adreno_dev)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
@@ -2958,6 +2941,7 @@
 	.rb_init = a3xx_rb_init,
 	.irq_control = a3xx_irq_control,
 	.irq_handler = a3xx_irq_handler,
+	.irq_pending = a3xx_irq_pending,
 	.busy_cycles = a3xx_busy_cycles,
 	.start = a3xx_start,
 	.snapshot = a3xx_snapshot,
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index c43ac51..1d25646 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -570,7 +570,7 @@
 	total_sizedwords += (flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE) ? 2 : 0;
 
 	/* Add CP_COND_EXEC commands to generate CP_INTERRUPT */
-	total_sizedwords += context ? 7 : 0;
+	total_sizedwords += context ? 13 : 0;
 
 	if (adreno_is_a3xx(adreno_dev))
 		total_sizedwords += 7;
@@ -720,7 +720,25 @@
 				context_id, ref_wait_ts)) >> 2);
 		GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
 		/* # of conditional command DWORDs */
-		GSL_RB_WRITE(ringcmds, rcmd_gpu, 2);
+		GSL_RB_WRITE(ringcmds, rcmd_gpu, 8);
+
+		/* Clear the ts_cmp_enable for the context */
+		GSL_RB_WRITE(ringcmds, rcmd_gpu,
+			cp_type3_packet(CP_MEM_WRITE, 2));
+		GSL_RB_WRITE(ringcmds, rcmd_gpu, gpuaddr +
+			KGSL_MEMSTORE_OFFSET(
+				context_id, ts_cmp_enable));
+		GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x0);
+
+		/* Clear the ts_cmp_enable for the global timestamp */
+		GSL_RB_WRITE(ringcmds, rcmd_gpu,
+			cp_type3_packet(CP_MEM_WRITE, 2));
+		GSL_RB_WRITE(ringcmds, rcmd_gpu, gpuaddr +
+			KGSL_MEMSTORE_OFFSET(
+				KGSL_MEMSTORE_GLOBAL, ts_cmp_enable));
+		GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x0);
+
+		/* Trigger the interrupt */
 		GSL_RB_WRITE(ringcmds, rcmd_gpu,
 			cp_type3_packet(CP_INTERRUPT, 1));
 		GSL_RB_WRITE(ringcmds, rcmd_gpu, CP_INT_CNTL__RB_INT_MASK);
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 115fcb7..7ed0b10 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -1088,10 +1088,7 @@
 				      result);
 
 	/* Fire off any pending suspend operations that are in flight */
-
-	INIT_COMPLETION(dev_priv->device->suspend_gate);
-	dev_priv->device->active_cnt--;
-	complete(&dev_priv->device->suspend_gate);
+	kgsl_active_count_put(dev_priv->device);
 
 	return result;
 }
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 62316f3..66390fc 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -133,6 +133,7 @@
 	void *priv;
 	struct list_head list;
 	void *owner;
+	unsigned int created;
 };
 
 
@@ -449,4 +450,23 @@
 	kref_put(&context->refcount, kgsl_context_destroy);
 }
 
+/**
+ * kgsl_active_count_put - Decrease the device active count
+ * @device: Pointer to a KGSL device
+ *
+ * Decrease the active count for the KGSL device and trigger the suspend_gate
+ * completion if it hits zero
+ */
+static inline void
+kgsl_active_count_put(struct kgsl_device *device)
+{
+	if (device->active_cnt == 1)
+		INIT_COMPLETION(device->suspend_gate);
+
+	device->active_cnt--;
+
+	if (device->active_cnt == 0)
+		complete(&device->suspend_gate);
+}
+
 #endif  /* __KGSL_DEVICE_H */
diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c
index be9b5eb..6798eed 100644
--- a/drivers/gpu/msm/kgsl_events.c
+++ b/drivers/gpu/msm/kgsl_events.c
@@ -16,6 +16,8 @@
 #include <linux/module.h>
 #include <kgsl_device.h>
 
+#include "kgsl_trace.h"
+
 static void _add_event_to_list(struct list_head *head, struct kgsl_event *event)
 {
 	struct list_head *n;
@@ -71,6 +73,7 @@
 	 */
 
 	if (timestamp_cmp(cur_ts, ts) >= 0) {
+		trace_kgsl_fire_event(id, ts, 0);
 		cb(device, priv, id, ts);
 		return 0;
 	}
@@ -84,6 +87,9 @@
 	event->priv = priv;
 	event->func = cb;
 	event->owner = owner;
+	event->created = jiffies;
+
+	trace_kgsl_register_event(id, ts);
 
 	/* inc refcount to avoid race conditions in cleanup */
 	if (context)
@@ -106,6 +112,13 @@
 	} else
 		_add_event_to_list(&device->events, event);
 
+	/*
+	 * Increase the active count on the device to avoid going into power
+	 * saving modes while events are pending
+	 */
+
+	device->active_cnt++;
+
 	queue_work(device->work_queue, &device->ts_expired_ws);
 	return 0;
 }
@@ -137,12 +150,16 @@
 		 * system got before the event was canceled
 		 */
 
+		trace_kgsl_fire_event(id, cur, jiffies - event->created);
+
 		if (event->func)
 			event->func(device, event->priv, id, cur);
 
 		kgsl_context_put(context);
 		list_del(&event->list);
 		kfree(event);
+
+		kgsl_active_count_put(device);
 	}
 
 	/* Remove ourselves from the master pending list */
@@ -175,6 +192,10 @@
 		 * the callback knows how far the GPU made it before things went
 		 * explosion
 		 */
+
+		trace_kgsl_fire_event(KGSL_MEMSTORE_GLOBAL, cur,
+			jiffies - event->created);
+
 		if (event->func)
 			event->func(device, event->priv, KGSL_MEMSTORE_GLOBAL,
 				cur);
@@ -184,6 +205,8 @@
 
 		list_del(&event->list);
 		kfree(event);
+
+		kgsl_active_count_put(device);
 	}
 }
 EXPORT_SYMBOL(kgsl_cancel_events);
@@ -207,6 +230,9 @@
 		 * to the timestamp they wanted
 		 */
 
+		trace_kgsl_fire_event(id, event->timestamp,
+			jiffies - event->created);
+
 		if (event->func)
 			event->func(device, event->priv, id, event->timestamp);
 
@@ -215,6 +241,8 @@
 
 		list_del(&event->list);
 		kfree(event);
+
+		kgsl_active_count_put(device);
 	}
 }
 
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index f7818bb..8c4811e 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -693,6 +693,41 @@
 	)
 );
 
+TRACE_EVENT(kgsl_register_event,
+		TP_PROTO(unsigned int id, unsigned int timestamp),
+		TP_ARGS(id, timestamp),
+		TP_STRUCT__entry(
+			__field(unsigned int, id)
+			__field(unsigned int, timestamp)
+		),
+		TP_fast_assign(
+			__entry->id = id;
+			__entry->timestamp = timestamp;
+		),
+		TP_printk(
+			"ctx=%d ts=%d",
+			__entry->id, __entry->timestamp)
+);
+
+TRACE_EVENT(kgsl_fire_event,
+		TP_PROTO(unsigned int id, unsigned int ts,
+			unsigned int age),
+		TP_ARGS(id, ts, age),
+		TP_STRUCT__entry(
+			__field(unsigned int, id)
+			__field(unsigned int, ts)
+			__field(unsigned int, age)
+		),
+		TP_fast_assign(
+			__entry->id = id;
+			__entry->ts = ts;
+			__entry->age = age;
+		),
+		TP_printk(
+			"ctx=%d ts=%d age=%u",
+			__entry->id, __entry->ts, __entry->age)
+);
+
 #endif /* _KGSL_TRACE_H */
 
 /* This part must be outside protection */
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 8f03ccb..e578b0e 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -817,9 +817,9 @@
 {
 	int status = -EINVAL;
 
-	/* Don't wait forever, set a max (10 sec) value for now */
+	/* Don't wait forever, set a max of Z180_IDLE_TIMEOUT */
 	if (msecs == -1)
-		msecs = 10 * MSEC_PER_SEC;
+		msecs = Z180_IDLE_TIMEOUT;
 
 	mutex_unlock(&device->mutex);
 	status = z180_wait(device, context, timestamp, msecs);
diff --git a/drivers/gud/mobicore_driver/arm.h b/drivers/gud/mobicore_driver/arm.h
index 0cddc0c..439feed 100644
--- a/drivers/gud/mobicore_driver/arm.h
+++ b/drivers/gud/mobicore_driver/arm.h
@@ -2,6 +2,7 @@
  * MobiCore driver module.(interface to the secure world SWD)
  *
  * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/drivers/gud/mobicore_driver/build_tag.h b/drivers/gud/mobicore_driver/build_tag.h
index a6898f1..4abd003 100644
--- a/drivers/gud/mobicore_driver/build_tag.h
+++ b/drivers/gud/mobicore_driver/build_tag.h
@@ -1,5 +1,5 @@
 /*
- * <-- Copyright Giesecke & Devrient GmbH 2012-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -26,4 +26,4 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #define MOBICORE_COMPONENT_BUILD_TAG \
-		"*** GC_MSM8960_Release_V013 ###"
+		"*** GC_MSM8960_Release_V016 ###"
diff --git a/drivers/gud/mobicore_driver/debug.h b/drivers/gud/mobicore_driver/debug.h
index 0195877..1f9a632 100644
--- a/drivers/gud/mobicore_driver/debug.h
+++ b/drivers/gud/mobicore_driver/debug.h
@@ -2,6 +2,7 @@
  * MobiCore driver module.(interface to the secure world SWD)
  *
  * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/drivers/gud/mobicore_driver/fastcall.h b/drivers/gud/mobicore_driver/fastcall.h
index d5f9abc..1c90520 100644
--- a/drivers/gud/mobicore_driver/fastcall.h
+++ b/drivers/gud/mobicore_driver/fastcall.h
@@ -4,6 +4,7 @@
  * MobiCore Fast Call interface
  *
  * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/drivers/gud/mobicore_driver/logging.c b/drivers/gud/mobicore_driver/logging.c
index 4160292..1f599f9 100644
--- a/drivers/gud/mobicore_driver/logging.c
+++ b/drivers/gud/mobicore_driver/logging.c
@@ -316,6 +316,7 @@
 		ret = -EIO;
 		goto err_stop_kthread;
 	}
+
 	set_task_state(log_thread, TASK_INTERRUPTIBLE);
 
 	MCDRV_DBG(mcd, "fc_log Logger version %u\n", log_buf->version);
diff --git a/drivers/gud/mobicore_driver/logging.h b/drivers/gud/mobicore_driver/logging.h
index ec7587f..ddb60fb 100644
--- a/drivers/gud/mobicore_driver/logging.h
+++ b/drivers/gud/mobicore_driver/logging.h
@@ -2,6 +2,7 @@
  * MobiCore driver module.(interface to the secure world SWD)
  *
  * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/drivers/gud/mobicore_driver/main.c b/drivers/gud/mobicore_driver/main.c
index df5675e..a2b3ad7 100644
--- a/drivers/gud/mobicore_driver/main.c
+++ b/drivers/gud/mobicore_driver/main.c
@@ -28,6 +28,11 @@
 #include <linux/mm.h>
 #include <linux/mman.h>
 #include <linux/completion.h>
+#include <linux/fdtable.h>
+#include <net/net_namespace.h>
+#include <net/sock.h>
+#include <net/tcp_states.h>
+#include <net/af_unix.h>
 
 #include "main.h"
 #include "fastcall.h"
@@ -51,6 +56,32 @@
 
 struct device *mcd = &mcd_debug_subname;
 
+#ifndef FMODE_PATH
+ #define FMODE_PATH 0x0
+#endif
+
+static struct sock *__get_socket(struct file *filp)
+{
+	struct sock *u_sock = NULL;
+	struct inode *inode = filp->f_path.dentry->d_inode;
+
+	/*
+	 *	Socket ?
+	 */
+	if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) {
+		struct socket *sock = SOCKET_I(inode);
+		struct sock *s = sock->sk;
+
+		/*
+		 *	PF_UNIX ?
+		 */
+		if (s && sock->ops && sock->ops->family == PF_UNIX)
+			u_sock = s;
+	}
+	return u_sock;
+}
+
+
 /* MobiCore interrupt context data */
 struct mc_context ctx;
 
@@ -137,8 +168,60 @@
 	return ret;
 }
 
+bool mc_check_owner_fd(struct mc_instance *instance, int32_t fd)
+{
+#ifndef __ARM_VE_A9X4_STD__
+	struct file *fp;
+	struct sock *s;
+	struct files_struct *files;
+	struct task_struct *peer = NULL;
+	bool ret = false;
+
+	MCDRV_DBG(mcd, "Finding wsm for fd = %d\n", fd);
+	if (!instance)
+		return false;
+
+	if (is_daemon(instance))
+		return true;
+
+	fp = fcheck_files(current->files, fd);
+	s = __get_socket(fp);
+	if (s) {
+		peer = get_pid_task(s->sk_peer_pid, PIDTYPE_PID);
+		MCDRV_DBG(mcd, "Found pid for fd %d\n", peer->pid);
+	}
+	if (peer) {
+		task_lock(peer);
+		files = peer->files;
+		if (!files)
+			goto out;
+		for (fd = 0; fd < files_fdtable(files)->max_fds; fd++) {
+			fp = fcheck_files(files, fd);
+			if (!fp)
+				continue;
+			if (fp->private_data == instance) {
+				MCDRV_DBG(mcd, "Found owner!");
+				ret = true;
+				goto out;
+			}
+
+		}
+	} else {
+		MCDRV_DBG(mcd, "Owner not found!");
+		return false;
+	}
+out:
+	if (peer)
+		task_unlock(peer);
+	if (!ret)
+		MCDRV_DBG(mcd, "Owner not found!");
+	return ret;
+#else
+	return true;
+#endif
+}
 static uint32_t mc_find_cont_wsm(struct mc_instance *instance, uint32_t handle,
-	uint32_t *phys, uint32_t *len)
+	int32_t fd, uint32_t *phys, uint32_t *len)
 {
 	int ret = 0;
 	struct mc_buffer *buffer;
@@ -158,9 +241,13 @@
 	/* search for the given handle in the buffers list */
 	list_for_each_entry(buffer, &ctx.cont_bufs, list) {
 		if (buffer->handle == handle) {
-			*phys = (uint32_t)buffer->phys;
-			*len = buffer->len;
-			goto found;
+			if (mc_check_owner_fd(buffer->instance, fd)) {
+				*phys = (uint32_t)buffer->phys;
+				*len = buffer->len;
+				goto found;
+			} else {
+				break;
+			}
 		}
 	}
 
@@ -206,36 +293,34 @@
 			goto found_buffer;
 		}
 	}
+	ret = -EINVAL;
 	goto err;
 found_buffer:
-	if (!is_daemon(instance) || buffer->instance != instance)
+	if (!is_daemon(instance) && buffer->instance != instance) {
+		ret = -EPERM;
 		goto err;
+	}
 	mutex_unlock(&ctx.bufs_lock);
 	/* Only unmap if the request is comming from the user space and
 	 * it hasn't already been unmapped */
-	if (unlock == false && uaddr != NULL)
+	if (unlock == false && uaddr != NULL) {
 #ifndef MC_VM_UNMAP
 		/* do_munmap must be done with mm->mmap_sem taken */
 		down_write(&mm->mmap_sem);
 		ret = do_munmap(mm, (long unsigned int)uaddr, len);
+		up_write(&mm->mmap_sem);
+
+#else
+		ret = vm_munmap((long unsigned int)uaddr, len);
+#endif
 		if (ret < 0) {
 			/* Something is not right if we end up here, better not
 			 * clean the buffer so we just leak memory instead of
 			 * creating security issues */
 			MCDRV_DBG_ERROR(mcd, "Memory can't be unmapped\n");
-		}
-		up_write(&mm->mmap_sem);
-		if (ret < 0)
-			return -EINVAL;
-#else
-		if (vm_munmap((long unsigned int)uaddr, len) < 0) {
-			/* Something is not right if we end up here, better not
-			 * clean the buffer so we just leak memory instead of
-			 * creating security issues */
-			MCDRV_DBG_ERROR(mcd, "Memory can't be unmapped\n");
 			return -EINVAL;
 		}
-#endif
+	}
 
 	mutex_lock(&ctx.bufs_lock);
 	/* search for the given handle in the buffers list */
@@ -247,7 +332,10 @@
 	goto err;
 
 del_buffer:
-	ret = free_buffer(buffer, unlock);
+	if (is_daemon(instance) || buffer->instance == instance)
+		ret = free_buffer(buffer, unlock);
+	else
+		ret = -EPERM;
 err:
 	mutex_unlock(&ctx.bufs_lock);
 	return ret;
@@ -324,6 +412,7 @@
 	cbuffer->order = order;
 	cbuffer->len = len;
 	cbuffer->instance = instance;
+	cbuffer->uaddr = 0;
 	/* Refcount +1 because the TLC is requesting it */
 	atomic_set(&cbuffer->usage, 1);
 
@@ -511,7 +600,8 @@
 	return ret;
 }
 
-static uint32_t mc_find_wsm_l2(struct mc_instance *instance, uint32_t handle)
+static uint32_t mc_find_wsm_l2(struct mc_instance *instance,
+	uint32_t handle, int32_t fd)
 {
 	uint32_t ret = 0;
 
@@ -523,9 +613,7 @@
 		return 0;
 	}
 
-	mutex_lock(&instance->lock);
-	ret = mc_find_l2_table(instance, handle);
-	mutex_unlock(&instance->lock);
+	ret = mc_find_l2_table(handle, fd);
 
 	return ret;
 }
@@ -569,10 +657,18 @@
 
 		/* search for the buffer list. */
 		list_for_each_entry(buffer, &ctx.cont_bufs, list) {
-			if (buffer->phys == paddr)
-				goto found;
-			else
+			/* Only allow mapping if the client owns it!*/
+			if (buffer->phys == paddr &&
+			    buffer->instance == instance) {
+				/* We shouldn't do remap with larger size */
+				if (buffer->len > len)
 					break;
+				/* We can't allow mapping the buffer twice */
+				if (!buffer->uaddr)
+					goto found;
+				else
+					break;
+			}
 		}
 		/* Nothing found return */
 		mutex_unlock(&ctx.bufs_lock);
@@ -738,16 +834,6 @@
 	if (ioctl_check_pointer(cmd, uarg))
 		return -EFAULT;
 
-	if (ctx.mcp) {
-		while (ctx.mcp->flags.sleep_mode.SleepReq) {
-			ctx.daemon = current;
-			set_current_state(TASK_INTERRUPTIBLE);
-			/* Back off daemon for a while */
-			schedule_timeout(msecs_to_jiffies(DAEMON_BACKOFF_TIME));
-			set_current_state(TASK_RUNNING);
-		}
-	}
-
 	switch (cmd) {
 	case MC_IO_INIT: {
 		struct mc_ioctl_init init;
@@ -798,13 +884,18 @@
 		ret = mc_clean_wsm_l2(instance);
 		break;
 	case MC_IO_RESOLVE_WSM: {
-		uint32_t handle, phys;
-		if (get_user(handle, uarg))
+		uint32_t phys;
+		struct mc_ioctl_resolv_wsm wsm;
+		if (copy_from_user(&wsm, uarg, sizeof(wsm)))
 			return -EFAULT;
-		phys = mc_find_wsm_l2(instance, handle);
+		phys = mc_find_wsm_l2(instance, wsm.handle, wsm.fd);
 		if (!phys)
+			return -EINVAL;
+
+		wsm.phys = phys;
+		if (copy_to_user(uarg, &wsm, sizeof(wsm)))
 			return -EFAULT;
-		ret = put_user(phys, uarg);
+		ret = 0;
 		break;
 	}
 	case MC_IO_RESOLVE_CONT_WSM: {
@@ -812,7 +903,8 @@
 		uint32_t phys = 0, len = 0;
 		if (copy_from_user(&cont_wsm, uarg, sizeof(cont_wsm)))
 			return -EFAULT;
-		ret = mc_find_cont_wsm(instance, cont_wsm.handle, &phys, &len);
+		ret = mc_find_cont_wsm(instance, cont_wsm.handle, cont_wsm.fd,
+					&phys, &len);
 		if (!ret) {
 			cont_wsm.phys = phys;
 			cont_wsm.length = len;
@@ -980,6 +1072,10 @@
 
 	/* Check if some buffers are orphaned. */
 	list_for_each_entry_safe(buffer, tmp, &ctx.cont_bufs, list) {
+		/* It's safe here to only call free_buffer() without unmapping
+		 * because mmap() takes a refcount to the file's fd so only
+		 * time we end up here is when everything has been unmaped or
+		 * the process called exit() */
 		if (buffer->instance == instance) {
 			buffer->instance = NULL;
 			free_buffer(buffer, false);
@@ -1163,13 +1259,17 @@
 		return -ENODEV;
 	}
 
+	ret = mc_fastcall_init(&ctx);
+	if (ret)
+		goto error;
+
 	init_completion(&ctx.isr_comp);
 	/* set up S-SIQ interrupt handler */
 	ret = request_irq(MC_INTR_SSIQ, mc_ssiq_isr, IRQF_TRIGGER_RISING,
 			MC_ADMIN_DEVNODE, &ctx);
 	if (ret != 0) {
 		MCDRV_DBG_ERROR(mcd, "interrupt request failed\n");
-		goto error;
+		goto err_req_irq;
 	}
 
 #ifdef MC_PM_RUNTIME
@@ -1219,6 +1319,8 @@
 	misc_deregister(&mc_admin_device);
 free_isr:
 	free_irq(MC_INTR_SSIQ, &ctx);
+err_req_irq:
+	mc_fastcall_destroy();
 error:
 	return ret;
 }
@@ -1243,6 +1345,9 @@
 
 	misc_deregister(&mc_admin_device);
 	misc_deregister(&mc_user_device);
+
+	mc_fastcall_destroy();
+
 	MCDRV_DBG_VERBOSE(mcd, "exit");
 }
 
diff --git a/drivers/gud/mobicore_driver/main.h b/drivers/gud/mobicore_driver/main.h
index 2c316bc..871191e 100644
--- a/drivers/gud/mobicore_driver/main.h
+++ b/drivers/gud/mobicore_driver/main.h
@@ -4,6 +4,7 @@
  * Internal structures of the McDrvModule
  *
  * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -143,4 +144,7 @@
 /* Free the buffer allocated above */
 int mc_free_buffer(struct mc_instance *instance, uint32_t handle);
 
+/* Check if the other end of the fd owns instance */
+bool mc_check_owner_fd(struct mc_instance *instance, int32_t fd);
+
 #endif /* _MC_MAIN_H_ */
diff --git a/drivers/gud/mobicore_driver/mem.c b/drivers/gud/mobicore_driver/mem.c
index 1fe351b..33c51b6 100644
--- a/drivers/gud/mobicore_driver/mem.c
+++ b/drivers/gud/mobicore_driver/mem.c
@@ -618,14 +618,11 @@
 	return ERR_PTR(ret);
 }
 
-uint32_t mc_find_l2_table(struct mc_instance *instance, uint32_t handle)
+uint32_t mc_find_l2_table(uint32_t handle, int32_t fd)
 {
 	uint32_t ret = 0;
 	struct mc_l2_table *table = NULL;
 
-	if (WARN(!instance, "No instance data available"))
-		return 0;
-
 	mutex_lock(&mem_ctx.table_lock);
 	table = find_l2_table(handle);
 
@@ -635,6 +632,14 @@
 		goto table_err;
 	}
 
+	/* It's safe here not to lock the instance since the owner of
+	 * the table will be cleared only with the table lock taken */
+	if (!mc_check_owner_fd(table->owner, fd)) {
+		MCDRV_DBG_ERROR(mcd, "not valid owner%u\n", handle);
+		ret = 0;
+		goto table_err;
+	}
+
 	ret = table->phys;
 table_err:
 	mutex_unlock(&mem_ctx.table_lock);
diff --git a/drivers/gud/mobicore_driver/mem.h b/drivers/gud/mobicore_driver/mem.h
index a90662a7..397a6cc 100644
--- a/drivers/gud/mobicore_driver/mem.h
+++ b/drivers/gud/mobicore_driver/mem.h
@@ -2,6 +2,7 @@
  * MobiCore driver module.(interface to the secure world SWD)
  *
  * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -117,7 +118,7 @@
 /* Unlock l2 table. */
 int mc_unlock_l2_table(struct mc_instance *instance, uint32_t handle);
 /* Return the phys address of l2 table. */
-uint32_t mc_find_l2_table(struct mc_instance *instance, uint32_t handle);
+uint32_t mc_find_l2_table(uint32_t handle, int32_t fd);
 /* Release all used l2 tables to Linux memory space */
 void mc_release_l2_tables(void);
 
diff --git a/drivers/gud/mobicore_driver/ops.c b/drivers/gud/mobicore_driver/ops.c
index b44a842..05c80b7 100644
--- a/drivers/gud/mobicore_driver/ops.c
+++ b/drivers/gud/mobicore_driver/ops.c
@@ -28,8 +28,83 @@
 #include "fastcall.h"
 #include "ops.h"
 #include "mem.h"
+#include "pm.h"
 #include "debug.h"
 
+/* MobiCore context data */
+static struct mc_context *ctx;
+
+static inline long smc(union fc_generic *fc)
+{
+	/* If we request sleep yields must be filtered out as they
+	 * make no sense */
+	if (ctx->mcp)
+		if (ctx->mcp->flags.sleep_mode.SleepReq) {
+			if (fc->as_in.cmd == MC_SMC_N_YIELD)
+				return MC_FC_RET_ERR_INVALID;
+		}
+	return _smc(fc);
+}
+
+#ifdef MC_FASTCALL_WORKER_THREAD
+
+static struct task_struct *fastcall_thread;
+static DEFINE_KTHREAD_WORKER(fastcall_worker);
+
+struct fastcall_work {
+	struct kthread_work work;
+	void *data;
+};
+
+static void fastcall_work_func(struct kthread_work *work)
+{
+	struct fastcall_work *fc_work =
+		container_of(work, struct fastcall_work, work);
+	smc(fc_work->data);
+}
+
+void mc_fastcall(void *data)
+{
+	struct fastcall_work fc_work = {
+		KTHREAD_WORK_INIT(fc_work.work, fastcall_work_func),
+		.data = data,
+	};
+
+	queue_kthread_work(&fastcall_worker, &fc_work.work);
+	flush_kthread_work(&fc_work.work);
+}
+
+int mc_fastcall_init(struct mc_context *context)
+{
+	int ret = 0;
+
+	ctx = context;
+
+	fastcall_thread = kthread_create(kthread_worker_fn, &fastcall_worker,
+					 "mc_fastcall");
+	if (IS_ERR(fastcall_thread)) {
+		ret = PTR_ERR(fastcall_thread);
+		fastcall_thread = NULL;
+		MCDRV_DBG_ERROR(mcd, "cannot create fastcall wq (%d)\n", ret);
+		return ret;
+	}
+
+	/* this thread MUST run on CPU 0 */
+	kthread_bind(fastcall_thread, 0);
+	wake_up_process(fastcall_thread);
+
+	return 0;
+}
+
+void mc_fastcall_destroy(void)
+{
+	if (!IS_ERR_OR_NULL(fastcall_thread)) {
+		kthread_stop(fastcall_thread);
+		fastcall_thread = NULL;
+	}
+}
+#else
+
 struct fastcall_work_struct {
 	struct work_struct work;
 	void *data;
@@ -39,7 +114,7 @@
 {
 	struct fastcall_work_struct *fc_work =
 		container_of(work, struct fastcall_work_struct, work);
-	_smc(fc_work->data);
+	smc(fc_work->data);
 }
 
 void mc_fastcall(void *data)
@@ -53,6 +128,15 @@
 	flush_work(&work.work);
 }
 
+int mc_fastcall_init(struct mc_context *context)
+{
+	ctx = context;
+	return 0;
+};
+
+void mc_fastcall_destroy(void) {};
+#endif
+
 int mc_info(uint32_t ext_info_id, uint32_t *state, uint32_t *ext_info)
 {
 	int ret = 0;
@@ -117,6 +201,21 @@
 	return ret;
 }
 
+/* call common notify */
+int _nsiq(void)
+{
+	int ret = 0;
+	union fc_generic nsiq;
+	MCDRV_DBG_VERBOSE(mcd, "enter\n");
+
+	memset(&nsiq, 0, sizeof(nsiq));
+	nsiq.as_in.cmd = MC_SMC_N_SIQ;
+	_smc(&nsiq);
+	ret = convert_fc_ret(nsiq.as_out.ret);
+
+	return ret;
+}
+
 /* Call the INIT fastcall to setup MobiCore initialization */
 int mc_init(uint32_t base, uint32_t nq_offset, uint32_t nq_length,
 	uint32_t mcp_offset, uint32_t mcp_length)
diff --git a/drivers/gud/mobicore_driver/ops.h b/drivers/gud/mobicore_driver/ops.h
index efe5f05..910c1f4 100644
--- a/drivers/gud/mobicore_driver/ops.h
+++ b/drivers/gud/mobicore_driver/ops.h
@@ -2,6 +2,7 @@
  * MobiCore driver module.(interface to the secure world SWD)
  *
  * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -16,6 +17,7 @@
 
 int mc_yield(void);
 int mc_nsiq(void);
+int _nsiq(void);
 uint32_t mc_get_version(void);
 
 int mc_info(uint32_t ext_info_id, uint32_t *state, uint32_t *ext_info);
@@ -24,4 +26,7 @@
 
 void mc_fastcall(void *data);
 
+int mc_fastcall_init(struct mc_context *context);
+void mc_fastcall_destroy(void);
+
 #endif /* _MC_OPS_H_ */
diff --git a/drivers/gud/mobicore_driver/pm.h b/drivers/gud/mobicore_driver/pm.h
index 067f095..3e73b8b 100644
--- a/drivers/gud/mobicore_driver/pm.h
+++ b/drivers/gud/mobicore_driver/pm.h
@@ -2,6 +2,7 @@
  * Header file of MobiCore Driver Kernel Module.
  *
  * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -11,7 +12,24 @@
 #ifndef _MC_PM_H_
 #define _MC_PM_H_
 
-/* How much time after resume the daemon should back off */
-#define DAEMON_BACKOFF_TIME	10
+#include "main.h"
+#ifdef MC_BL_NOTIFIER
+#include <asm/bL_switcher.h>
+#endif
+
+
+#define NO_SLEEP_REQ	0
+#define REQ_TO_SLEEP	1
+
+#define NORMAL_EXECUTION	0
+#define READY_TO_SLEEP		1
+
+/* How much time after resume the daemon should backoff */
+#define DAEMON_BACKOFF_TIME	500
+
+/* Initialize Power Management */
+int mc_pm_initialize(struct mc_context *context);
+/* Free all Power Management resources*/
+int mc_pm_free(void);
 
 #endif /* _MC_PM_H_ */
diff --git a/drivers/gud/mobicore_driver/public/mc_linux.h b/drivers/gud/mobicore_driver/public/mc_linux.h
index bb95c26..9c49aef 100644
--- a/drivers/gud/mobicore_driver/public/mc_linux.h
+++ b/drivers/gud/mobicore_driver/public/mc_linux.h
@@ -127,6 +127,20 @@
 	uint32_t phys;
 	/* length memory */
 	uint32_t length;
+	/* fd to owner of the buffer */
+	int32_t fd;
+};
+
+/*
+ * Data exchange structure of the MC_IO_RESOLVE_WSM ioctl command.
+ */
+struct mc_ioctl_resolv_wsm {
+	/* driver handle for buffer */
+	uint32_t handle;
+	/* fd to owner of the buffer */
+	int32_t fd;
+	/* base address of memory */
+	uint32_t phys;
 };
 
 
@@ -200,12 +214,14 @@
  * Get L2 phys address of a buffer handle allocated to the user.
  * Only available to the daemon.
  */
-#define MC_IO_RESOLVE_WSM	_IOWR(MC_IOC_MAGIC, 15, uint32_t)
+#define MC_IO_RESOLVE_WSM	_IOWR(MC_IOC_MAGIC, 15, \
+					struct mc_ioctl_resolv_wsm)
 
 /*
  * Get the phys address & length of a allocated contiguous buffer.
  * Only available to the daemon */
-#define MC_IO_RESOLVE_CONT_WSM	_IOWR(MC_IOC_MAGIC, 16, struct mc_ioctl_execute)
+#define MC_IO_RESOLVE_CONT_WSM	_IOWR(MC_IOC_MAGIC, 16, \
+					struct mc_ioctl_resolv_cont_wsm)
 
 /*
  * Setup the mem traces when called.
diff --git a/drivers/gud/mobicore_kernelapi/main.c b/drivers/gud/mobicore_kernelapi/main.c
index 73de93a..8943c26 100644
--- a/drivers/gud/mobicore_kernelapi/main.c
+++ b/drivers/gud/mobicore_kernelapi/main.c
@@ -139,29 +139,28 @@
 
 static int __init mcapi_init(void)
 {
-	/* struct netlink_kernel_cfg netlink_cfg; */
+#if defined MC_NETLINK_COMPAT || defined MC_NETLINK_COMPAT_V37
+	struct netlink_kernel_cfg cfg = {
+		.input  = mcapi_callback,
+	};
+#endif
 
 	dev_set_name(mc_kapi, "mcapi");
 
 	dev_info(mc_kapi, "Mobicore API module initialized!\n");
 
-	/*
-	 * netlink_cfg.groups = 0;
-	 * netlink_cfg.flags = 0;
-	 * netlink_cfg.input = mcapi_callback;
-	 * netlink_cfg.cb_mutex = NULL;
-	 * netlink_cfg.bind = NULL;
-	 */
 	mod_ctx = kzalloc(sizeof(struct mc_kernelapi_ctx), GFP_KERNEL);
-
+#ifdef MC_NETLINK_COMPAT_V37
+	mod_ctx->sk = netlink_kernel_create(&init_net, MC_DAEMON_NETLINK,
+					    &cfg);
+#elif defined MC_NETLINK_COMPAT
+	mod_ctx->sk = netlink_kernel_create(&init_net, MC_DAEMON_NETLINK,
+					    THIS_MODULE, &cfg);
+#else
 	/* start kernel thread */
-
-	/*
-	 * mod_ctx->sk = netlink_kernel_create(&init_net, MC_DAEMON_NETLINK,
-	 *					    &netlink_cfg);
-	 */
 	mod_ctx->sk = netlink_kernel_create(&init_net, MC_DAEMON_NETLINK, 0,
 					    mcapi_callback, NULL, THIS_MODULE);
+#endif
 
 	if (!mod_ctx->sk) {
 		MCDRV_ERROR(mc_kapi, "register of receive handler failed");
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index ca0a439..a77dacb 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, The Linux Foundation. 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
@@ -29,13 +29,14 @@
 #include <linux/mutex.h>
 #include <linux/timer.h>
 #include <linux/slab.h>
-#include <mach/board.h>
-#include <mach/gpiomux.h>
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
 #include <linux/gpio.h>
 #include <linux/of.h>
 #include <linux/of_i2c.h>
+#include <linux/of_gpio.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
 
 MODULE_LICENSE("GPL v2");
 MODULE_VERSION("0.2");
@@ -131,6 +132,7 @@
 #define DEFAULT_CLK_RATE		(19200000)
 #define I2C_STATUS_CLK_STATE		13
 #define QUP_OUT_FIFO_NOT_EMPTY		0x10
+#define I2C_GPIOS_DT_CNT		(2)		/* sda and scl */
 
 static char const * const i2c_rsrcs[] = {"i2c_clk", "i2c_sda"};
 
@@ -1088,6 +1090,72 @@
 	return ret;
 }
 
+enum msm_i2c_dt_entry_status {
+	DT_REQUIRED,
+	DT_SUGGESTED,
+	DT_OPTIONAL,
+};
+
+enum msm_i2c_dt_entry_type {
+	DT_U32,
+	DT_GPIO,
+};
+
+struct msm_i2c_dt_to_pdata_map {
+	const char                  *dt_name;
+	int                         *ptr_data;
+	enum msm_i2c_dt_entry_status status;
+	enum msm_i2c_dt_entry_type   type;
+	int                          default_val;
+};
+
+int __devinit msm_i2c_rsrcs_dt_to_pdata_map(struct platform_device *pdev,
+				struct msm_i2c_platform_data *pdata, int *gpios)
+{
+	int  ret, err = 0;
+	struct device_node *node = pdev->dev.of_node;
+	struct msm_i2c_dt_to_pdata_map *itr;
+	struct msm_i2c_dt_to_pdata_map  map[] = {
+	{"qcom,i2c-bus-freq", &pdata->clk_freq    , DT_REQUIRED , DT_U32 ,  0},
+	{"cell-index"       , &pdev->id           , DT_REQUIRED , DT_U32 , -1},
+	{"qcom,i2c-src-freq", &pdata->src_clk_rate, DT_SUGGESTED, DT_U32,   0},
+	{"qcom,scl-gpio"    , gpios               , DT_OPTIONAL , DT_GPIO, -1},
+	{"qcom,sda-gpio"    , gpios + 1           , DT_OPTIONAL , DT_GPIO, -1},
+	{NULL               , NULL                , 0           , 0      ,  0},
+	};
+
+	for (itr = map; itr->dt_name ; ++itr) {
+		if (itr->type == DT_GPIO) {
+			ret = of_get_named_gpio(node, itr->dt_name, 0);
+			if (ret >= 0) {
+				*itr->ptr_data = ret;
+				ret = 0;
+			}
+		} else {
+			ret = of_property_read_u32(node, itr->dt_name,
+								itr->ptr_data);
+		}
+
+		dev_dbg(&pdev->dev, "DT entry ret:%d name:%s val:%d\n",
+					ret, itr->dt_name, *itr->ptr_data);
+
+		if (ret) {
+			*itr->ptr_data = itr->default_val;
+
+			if (itr->status < DT_OPTIONAL) {
+				dev_err(&pdev->dev, "Missing '%s' DT entry\n",
+								itr->dt_name);
+
+				/* cont on err to dump all missing entries */
+				if (itr->status == DT_REQUIRED && !err)
+					err = ret;
+			}
+		}
+	}
+
+	return err;
+}
+
 static u32
 qup_i2c_func(struct i2c_adapter *adap)
 {
@@ -1106,28 +1174,23 @@
 	struct resource         *qup_mem, *gsbi_mem, *qup_io, *gsbi_io, *res;
 	struct resource		*in_irq, *out_irq, *err_irq;
 	struct clk         *clk, *pclk;
-	int ret = 0;
-	int i;
+	int  ret = 0;
+	int  i;
+	int  dt_gpios[I2C_GPIOS_DT_CNT];
+	bool use_device_tree = pdev->dev.of_node;
 	struct msm_i2c_platform_data *pdata;
 
 	gsbi_mem = NULL;
 	dev_dbg(&pdev->dev, "qup_i2c_probe\n");
 
-	if (pdev->dev.of_node) {
-		struct device_node *node = pdev->dev.of_node;
-		pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+	if (use_device_tree) {
+		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 		if (!pdata)
 			return -ENOMEM;
-		ret = of_property_read_u32(node, "qcom,i2c-bus-freq",
-					&pdata->clk_freq);
+
+		ret = msm_i2c_rsrcs_dt_to_pdata_map(pdev, pdata, dt_gpios);
 		if (ret)
 			goto get_res_failed;
-		ret = of_property_read_u32(node, "cell-index", &pdev->id);
-		if (ret)
-			goto get_res_failed;
-		/* Optional property */
-		of_property_read_u32(node, "qcom,i2c-src-freq",
-					&pdata->src_clk_rate);
 	} else
 		pdata = pdev->dev.platform_data;
 
@@ -1247,9 +1310,13 @@
 	}
 
 	for (i = 0; i < ARRAY_SIZE(i2c_rsrcs); ++i) {
-		res = platform_get_resource_byname(pdev, IORESOURCE_IO,
-						   i2c_rsrcs[i]);
-		dev->i2c_gpios[i] = res ? res->start : -1;
+		if (use_device_tree && i < I2C_GPIOS_DT_CNT) {
+			dev->i2c_gpios[i] = dt_gpios[i];
+		} else {
+			res = platform_get_resource_byname(pdev, IORESOURCE_IO,
+							   i2c_rsrcs[i]);
+			dev->i2c_gpios[i] = res ? res->start : -1;
+		}
 	}
 
 	platform_set_drvdata(pdev, dev);
@@ -1261,8 +1328,7 @@
 
 	if (dev->pdata->src_clk_rate <= 0) {
 		dev_info(&pdev->dev,
-			"No src_clk_rate specified in platfrom data or "
-						"qcom,i2c-src-freq in DT\n");
+			"No src_clk_rate specified in platfrom data\n");
 		dev_info(&pdev->dev, "Using default clock rate %dHz\n",
 							DEFAULT_CLK_RATE);
 		dev->pdata->src_clk_rate = DEFAULT_CLK_RATE;
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index 899c83b..2c79276 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -82,6 +82,8 @@
 #define RMI4_I2C_LOAD_UA	10000
 #define RMI4_I2C_LPM_LOAD_UA	10
 
+#define RMI4_GPIO_SLEEP_LOW_US 10000
+#define RMI4_GPIO_WAIT_HIGH_MS 25
 
 static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data,
 		unsigned short addr, unsigned char *data,
@@ -1871,15 +1873,60 @@
 	retval = synaptics_rmi4_regulator_configure(rmi4_data, true);
 	if (retval < 0) {
 		dev_err(&client->dev, "Failed to configure regulators\n");
-		goto err_input_device;
+		goto err_reg_configure;
 	}
 
 	retval = synaptics_rmi4_power_on(rmi4_data, true);
 	if (retval < 0) {
 		dev_err(&client->dev, "Failed to power on\n");
-		goto err_input_device;
+		goto err_power_device;
 	}
 
+	if (gpio_is_valid(platform_data->irq_gpio)) {
+		/* configure touchscreen irq gpio */
+		retval = gpio_request(platform_data->irq_gpio, "rmi4_irq_gpio");
+		if (retval) {
+			dev_err(&client->dev, "unable to request gpio [%d]\n",
+						platform_data->irq_gpio);
+			goto err_query_device;
+		}
+		retval = gpio_direction_input(platform_data->irq_gpio);
+		if (retval) {
+			dev_err(&client->dev,
+				"unable to set direction for gpio [%d]\n",
+				platform_data->irq_gpio);
+			goto err_irq_gpio_req;
+		}
+	} else {
+		dev_err(&client->dev, "irq gpio not provided\n");
+		goto err_query_device;
+	}
+
+	if (gpio_is_valid(platform_data->reset_gpio)) {
+		/* configure touchscreen reset out gpio */
+		retval = gpio_request(platform_data->reset_gpio,
+				"rmi4_reset_gpio");
+		if (retval) {
+			dev_err(&client->dev, "unable to request gpio [%d]\n",
+						platform_data->reset_gpio);
+			goto err_irq_gpio_req;
+		}
+
+		retval = gpio_direction_output(platform_data->reset_gpio, 1);
+		if (retval) {
+			dev_err(&client->dev,
+				"unable to set direction for gpio [%d]\n",
+				platform_data->reset_gpio);
+			goto err_reset_gpio_req;
+		}
+
+		gpio_set_value(platform_data->reset_gpio, 0);
+		usleep(RMI4_GPIO_SLEEP_LOW_US);
+		gpio_set_value(platform_data->reset_gpio, 1);
+		msleep(RMI4_GPIO_WAIT_HIGH_MS);
+	}
+
+
 	init_waitqueue_head(&rmi4_data->wait);
 	mutex_init(&(rmi4_data->rmi4_io_ctrl_mutex));
 
@@ -1888,7 +1935,7 @@
 		dev_err(&client->dev,
 				"%s: Failed to query device\n",
 				__func__);
-		goto err_query_device;
+		goto err_reset_gpio_req;
 	}
 
 	i2c_set_clientdata(client, rmi4_data);
@@ -1972,9 +2019,6 @@
 	input_unregister_device(rmi4_data->input_dev);
 
 err_register_input:
-err_query_device:
-	synaptics_rmi4_power_on(rmi4_data, false);
-	synaptics_rmi4_regulator_configure(rmi4_data, false);
 	if (!list_empty(&rmi->support_fn_list)) {
 		list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
 			if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
@@ -1984,6 +2028,17 @@
 			kfree(fhandler);
 		}
 	}
+err_reset_gpio_req:
+	if (gpio_is_valid(platform_data->reset_gpio))
+		gpio_free(platform_data->reset_gpio);
+err_irq_gpio_req:
+	if (gpio_is_valid(platform_data->irq_gpio))
+		gpio_free(platform_data->irq_gpio);
+err_query_device:
+	synaptics_rmi4_power_on(rmi4_data, false);
+err_power_device:
+	synaptics_rmi4_regulator_configure(rmi4_data, false);
+err_reg_configure:
 	input_free_device(rmi4_data->input_dev);
 	rmi4_data->input_dev = NULL;
 err_input_device:
@@ -2036,7 +2091,11 @@
 			kfree(fhandler);
 		}
 	}
-	input_free_device(rmi4_data->input_dev);
+
+	if (gpio_is_valid(rmi4_data->board->reset_gpio))
+		gpio_free(rmi4_data->board->reset_gpio);
+	if (gpio_is_valid(rmi4_data->board->irq_gpio))
+		gpio_free(rmi4_data->board->irq_gpio);
 
 	synaptics_rmi4_power_on(rmi4_data, false);
 	synaptics_rmi4_regulator_configure(rmi4_data, false);
diff --git a/drivers/iommu/msm_iommu-v1.c b/drivers/iommu/msm_iommu-v1.c
index 15a81ed..24d2854 100644
--- a/drivers/iommu/msm_iommu-v1.c
+++ b/drivers/iommu/msm_iommu-v1.c
@@ -202,7 +202,6 @@
 	struct msm_iommu_drvdata *iommu_drvdata;
 	struct msm_iommu_ctx_drvdata *ctx_drvdata;
 	int ret = 0;
-	int asid;
 
 	list_for_each_entry(ctx_drvdata, &priv->list_attached, attached_elm) {
 		BUG_ON(!ctx_drvdata->pdev || !ctx_drvdata->pdev->dev.parent);
@@ -215,11 +214,8 @@
 		if (ret)
 			goto fail;
 
-		asid = GET_CB_CONTEXTIDR_ASID(iommu_drvdata->base,
-					   ctx_drvdata->num);
-
 		SET_TLBIVA(iommu_drvdata->base, ctx_drvdata->num,
-			   asid | (va & CB_TLBIVA_VA));
+			   ctx_drvdata->asid | (va & CB_TLBIVA_VA));
 		mb();
 		__sync_tlb(iommu_drvdata->base, ctx_drvdata->num);
 		__disable_clocks(iommu_drvdata);
@@ -234,7 +230,6 @@
 	struct msm_iommu_drvdata *iommu_drvdata;
 	struct msm_iommu_ctx_drvdata *ctx_drvdata;
 	int ret = 0;
-	int asid;
 
 	list_for_each_entry(ctx_drvdata, &priv->list_attached, attached_elm) {
 		BUG_ON(!ctx_drvdata->pdev || !ctx_drvdata->pdev->dev.parent);
@@ -246,10 +241,8 @@
 		if (ret)
 			goto fail;
 
-		asid = GET_CB_CONTEXTIDR_ASID(iommu_drvdata->base,
-					   ctx_drvdata->num);
-
-		SET_TLBIASID(iommu_drvdata->base, ctx_drvdata->num, asid);
+		SET_TLBIASID(iommu_drvdata->base, ctx_drvdata->num,
+			     ctx_drvdata->asid);
 		mb();
 		__sync_tlb(iommu_drvdata->base, ctx_drvdata->num);
 		__disable_clocks(iommu_drvdata);
@@ -342,69 +335,46 @@
 
 static void msm_iommu_assign_ASID(const struct msm_iommu_drvdata *iommu_drvdata,
 				  struct msm_iommu_ctx_drvdata *curr_ctx,
-				  phys_addr_t pgtable)
+				  struct msm_priv *priv)
 {
-	struct platform_device *pdev;
-	struct device_node *child;
-	struct msm_iommu_ctx_drvdata *ctx;
 	unsigned int found = 0;
 	void __iomem *base = iommu_drvdata->base;
-	struct device_node *iommu_node = iommu_drvdata->dev->of_node;
-	unsigned int asid;
+	unsigned int i;
 	unsigned int ncb = iommu_drvdata->ncb;
+	struct msm_iommu_ctx_drvdata *tmp_drvdata;
 
 	/* Find if this page table is used elsewhere, and re-use ASID */
-	for_each_child_of_node(iommu_node, child) {
-		pdev = of_find_device_by_node(child);
-		ctx = dev_get_drvdata(&pdev->dev);
+	if (!list_empty(&priv->list_attached)) {
+		tmp_drvdata = list_first_entry(&priv->list_attached,
+				struct msm_iommu_ctx_drvdata, attached_elm);
 
-		if (ctx->secure_context) {
-			of_dev_put(pdev);
-			continue;
-		}
+		++iommu_drvdata->asid[tmp_drvdata->asid - 1];
+		curr_ctx->asid = tmp_drvdata->asid;
 
-		if ((ctx != curr_ctx) &&
-		    (GET_CB_TTBR0_ADDR(base, ctx->num) == pgtable)) {
-			SET_CB_CONTEXTIDR_ASID(base, curr_ctx->num, ctx->asid);
-			curr_ctx->asid = ctx->asid;
-			found = 1;
-			of_dev_put(pdev);
-			of_node_put(child);
-			break;
-		}
-		of_dev_put(pdev);
+		SET_CB_CONTEXTIDR_ASID(base, curr_ctx->num, curr_ctx->asid);
+		found = 1;
 	}
 
 	/* If page table is new, find an unused ASID */
 	if (!found) {
-		for (asid = 1; asid < ncb + 1; ++asid) {
-			found = 0;
-			for_each_child_of_node(iommu_node, child) {
-				pdev = of_find_device_by_node(child);
-				ctx = dev_get_drvdata(&pdev->dev);
+		for (i = 0; i < ncb; ++i) {
+			if (iommu_drvdata->asid[i] == 0) {
+				++iommu_drvdata->asid[i];
+				curr_ctx->asid = i + 1;
 
-				if (ctx != curr_ctx && ctx->asid == asid) {
-					found = 1;
-					of_dev_put(pdev);
-					of_node_put(child);
-					break;
-				}
-				of_dev_put(pdev);
-			}
-			if (!found) {
 				SET_CB_CONTEXTIDR_ASID(base, curr_ctx->num,
-						       asid);
-				curr_ctx->asid = asid;
+						       curr_ctx->asid);
+				found = 1;
 				break;
 			}
 		}
-		BUG_ON(found);
+		BUG_ON(!found);
 	}
 }
 
 static void __program_context(struct msm_iommu_drvdata *iommu_drvdata,
 			      struct msm_iommu_ctx_drvdata *ctx_drvdata,
-			      phys_addr_t pgtable, int redirect, bool is_secure)
+			      struct msm_priv *priv, bool is_secure)
 {
 	unsigned int prrr, nmrr;
 	unsigned int pn;
@@ -413,6 +383,7 @@
 	unsigned int ctx = ctx_drvdata->num;
 	u32 *sids = ctx_drvdata->sids;
 	int len = ctx_drvdata->nsid;
+	phys_addr_t pgtable = __pa(priv->pt.fl_table);
 
 	__reset_context(base, ctx);
 
@@ -443,7 +414,7 @@
 	/* Configure page tables as inner-cacheable and shareable to reduce
 	 * the TLB miss penalty.
 	 */
-	if (redirect) {
+	if (priv->pt.redirect) {
 		SET_CB_TTBR0_S(base, ctx, 1);
 		SET_CB_TTBR0_NOS(base, ctx, 1);
 		SET_CB_TTBR0_IRGN1(base, ctx, 0); /* WB, WA */
@@ -489,7 +460,7 @@
 
 	}
 
-	msm_iommu_assign_ASID(iommu_drvdata, ctx_drvdata, pn);
+	msm_iommu_assign_ASID(iommu_drvdata, ctx_drvdata, priv);
 
 	/* Enable the MMU */
 	SET_CB_SCTLR_M(base, ctx, 1);
@@ -535,27 +506,6 @@
 	mutex_unlock(&msm_iommu_lock);
 }
 
-static int msm_iommu_ctx_attached(struct device *dev)
-{
-	struct platform_device *pdev;
-	struct device_node *child;
-	struct msm_iommu_ctx_drvdata *ctx;
-
-	for_each_child_of_node(dev->of_node, child) {
-		pdev = of_find_device_by_node(child);
-
-		ctx = dev_get_drvdata(&pdev->dev);
-		if (ctx->attached_domain) {
-			of_dev_put(pdev);
-			of_node_put(child);
-			return 1;
-		}
-		of_dev_put(pdev);
-	}
-
-	return 0;
-}
-
 static int msm_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
 {
 	struct msm_priv *priv;
@@ -603,8 +553,8 @@
 		goto fail;
 	}
 
-
-	if (!msm_iommu_ctx_attached(dev->parent)) {
+	/* We can only do this once */
+	if (!iommu_drvdata->ctx_attach_count) {
 		if (!is_secure) {
 			iommu_halt(iommu_drvdata);
 			__program_iommu(iommu_drvdata->base);
@@ -624,8 +574,7 @@
 
 	iommu_halt(iommu_drvdata);
 
-	__program_context(iommu_drvdata, ctx_drvdata, __pa(priv->pt.fl_table),
-			  priv->pt.redirect, is_secure);
+	__program_context(iommu_drvdata, ctx_drvdata, priv, is_secure);
 
 	iommu_resume(iommu_drvdata);
 
@@ -633,6 +582,7 @@
 
 	list_add(&(ctx_drvdata->attached_elm), &priv->list_attached);
 	ctx_drvdata->attached_domain = domain;
+	++iommu_drvdata->ctx_attach_count;
 
 	mutex_unlock(&msm_iommu_lock);
 
@@ -671,6 +621,9 @@
 	is_secure = iommu_drvdata->sec_id != -1;
 
 	SET_TLBIASID(iommu_drvdata->base, ctx_drvdata->num, ctx_drvdata->asid);
+
+	BUG_ON(iommu_drvdata->asid[ctx_drvdata->asid - 1] == 0);
+	iommu_drvdata->asid[ctx_drvdata->asid - 1]--;
 	ctx_drvdata->asid = -1;
 
 	iommu_halt(iommu_drvdata);
@@ -687,7 +640,8 @@
 
 	list_del_init(&ctx_drvdata->attached_elm);
 	ctx_drvdata->attached_domain = NULL;
-
+	BUG_ON(iommu_drvdata->ctx_attach_count == 0);
+	--iommu_drvdata->ctx_attach_count;
 fail:
 	mutex_unlock(&msm_iommu_lock);
 }
diff --git a/drivers/iommu/msm_iommu_dev-v1.c b/drivers/iommu/msm_iommu_dev-v1.c
index 3f9f1c4..f994413 100644
--- a/drivers/iommu/msm_iommu_dev-v1.c
+++ b/drivers/iommu/msm_iommu_dev-v1.c
@@ -104,6 +104,15 @@
 			pr_err("Failed to create %s device\n", child->name);
 	}
 
+	drvdata->asid = devm_kzalloc(&pdev->dev, drvdata->ncb * sizeof(int),
+				     GFP_KERNEL);
+
+	if (!drvdata->asid) {
+		pr_err("Unable to get memory for asid array\n");
+		ret = -ENOMEM;
+		goto fail;
+	}
+
 	ret = of_property_read_string(pdev->dev.of_node, "label",
 				      &drvdata->name);
 	if (ret)
diff --git a/drivers/iommu/msm_iommu_pagetable.c b/drivers/iommu/msm_iommu_pagetable.c
index 99841cd..b32bd26 100644
--- a/drivers/iommu/msm_iommu_pagetable.c
+++ b/drivers/iommu/msm_iommu_pagetable.c
@@ -357,14 +357,14 @@
 	return ret;
 }
 
-static unsigned int get_phys_addr(struct scatterlist *sg)
+static phys_addr_t get_phys_addr(struct scatterlist *sg)
 {
 	/*
 	 * Try sg_dma_address first so that we can
 	 * map carveout regions that do not have a
 	 * struct page associated with them.
 	 */
-	unsigned int pa = sg_dma_address(sg);
+	phys_addr_t pa = sg_dma_address(sg);
 	if (pa == 0)
 		pa = sg_phys(sg);
 	return pa;
@@ -380,7 +380,7 @@
 int msm_iommu_pagetable_map_range(struct iommu_pt *pt, unsigned int va,
 		       struct scatterlist *sg, unsigned int len, int prot)
 {
-	unsigned int pa;
+	phys_addr_t pa;
 	unsigned int offset = 0;
 	unsigned long *fl_pte;
 	unsigned long fl_offset;
diff --git a/drivers/iommu/msm_iommu_sec.c b/drivers/iommu/msm_iommu_sec.c
index 4e55bd6..29cf0c1 100644
--- a/drivers/iommu/msm_iommu_sec.c
+++ b/drivers/iommu/msm_iommu_sec.c
@@ -359,26 +359,30 @@
 	if (ret)
 		goto fail;
 
-	ret = __enable_clocks(iommu_drvdata);
-	if (ret) {
-		regulator_disable(iommu_drvdata->gdsc);
-		goto fail;
-	}
+	/* We can only do this once */
+	if (!iommu_drvdata->ctx_attach_count) {
+		ret = __enable_clocks(iommu_drvdata);
+		if (ret) {
+			regulator_disable(iommu_drvdata->gdsc);
+			goto fail;
+		}
 
-	ret = msm_iommu_sec_program_iommu(iommu_drvdata->sec_id);
+		ret = msm_iommu_sec_program_iommu(iommu_drvdata->sec_id);
 
-	/* bfb settings are always programmed by HLOS */
-	program_iommu_bfb_settings(iommu_drvdata->base,
-				   iommu_drvdata->bfb_settings);
+		/* bfb settings are always programmed by HLOS */
+		program_iommu_bfb_settings(iommu_drvdata->base,
+					   iommu_drvdata->bfb_settings);
 
-	__disable_clocks(iommu_drvdata);
-	if (ret) {
-		regulator_disable(iommu_drvdata->gdsc);
-		goto fail;
+		__disable_clocks(iommu_drvdata);
+		if (ret) {
+			regulator_disable(iommu_drvdata->gdsc);
+			goto fail;
+		}
 	}
 
 	list_add(&(ctx_drvdata->attached_elm), &priv->list_attached);
 	ctx_drvdata->attached_domain = domain;
+	++iommu_drvdata->ctx_attach_count;
 
 	mutex_unlock(&msm_iommu_lock);
 
@@ -410,7 +414,8 @@
 	ctx_drvdata->attached_domain = NULL;
 
 	regulator_disable(iommu_drvdata->gdsc);
-
+	BUG_ON(iommu_drvdata->ctx_attach_count == 0);
+	--iommu_drvdata->ctx_attach_count;
 fail:
 	mutex_unlock(&msm_iommu_lock);
 }
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index fb1882c..9e0a147 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -62,7 +62,7 @@
 #define WLED_OP_FDBCK_MASK		0x07
 #define WLED_OP_FDBCK_BIT_SHFT		0x00
 
-#define WLED_MAX_LEVEL			255
+#define WLED_MAX_LEVEL			4095
 #define WLED_8_BIT_MASK			0xFF
 #define WLED_4_BIT_MASK			0x0F
 #define WLED_8_BIT_SHFT			0x08
@@ -365,8 +365,8 @@
 
 static int qpnp_wled_set(struct qpnp_led_data *led)
 {
-	int rc, duty;
-	u8 level, val, i, num_wled_strings;
+	int rc, duty, level;
+	u8 val, i, num_wled_strings;
 
 	level = led->cdev.brightness;
 
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index dfb8d58..2a0cde9 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -514,6 +514,10 @@
 			((feed->pid != pid) && (feed->pid != 0x2000)))
 			continue;
 
+		if (feed->secure_mode.is_secured &&
+			!dvb_dmx_is_rec_feed(feed))
+			return 0;
+
 		if (feed->type == DMX_TYPE_TS) {
 			desired_space = 192; /* upper bound */
 			ts = &feed->feed.ts;
@@ -593,19 +597,23 @@
 		if (!feed->feed.ts.is_filtering)
 			break;
 		if (feed->ts_type & TS_PACKET) {
-			if (feed->ts_type & TS_PAYLOAD_ONLY)
-				dvb_dmx_swfilter_payload(feed, buf);
-			else
+			if (feed->ts_type & TS_PAYLOAD_ONLY) {
+				if (!feed->secure_mode.is_secured)
+					dvb_dmx_swfilter_payload(feed, buf);
+			} else {
 				dvb_dmx_swfilter_output_packet(feed,
 						buf, timestamp);
+			}
 		}
-		if (feed->ts_type & TS_DECODER)
+		if ((feed->ts_type & TS_DECODER) &&
+			!feed->secure_mode.is_secured)
 			if (feed->demux->write_to_decoder)
 				feed->demux->write_to_decoder(feed, buf, 188);
 		break;
 
 	case DMX_TYPE_SEC:
-		if (!feed->feed.sec.is_filtering)
+		if (!feed->feed.sec.is_filtering ||
+			feed->secure_mode.is_secured)
 			break;
 		if (dvb_dmx_swfilter_section_packet(feed, buf) < 0)
 			feed->feed.sec.seclen = feed->feed.sec.secbufp = 0;
@@ -1212,17 +1220,22 @@
 {
 	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
 	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+	int ret = 0;
 
 	mutex_lock(&dvbdmx->mutex);
 
-	dvbdmxfeed->secure_mode = *secure_mode;
-
 	if ((dvbdmxfeed->state == DMX_STATE_GO) &&
-		dvbdmxfeed->demux->set_secure_mode)
-		dvbdmxfeed->demux->set_secure_mode(dvbdmxfeed, secure_mode);
+		dvbdmxfeed->demux->set_secure_mode) {
+		ret = dvbdmxfeed->demux->set_secure_mode(dvbdmxfeed,
+			secure_mode);
+		if (!ret)
+			dvbdmxfeed->secure_mode = *secure_mode;
+	} else {
+		dvbdmxfeed->secure_mode = *secure_mode;
+	}
 
 	mutex_unlock(&dvbdmx->mutex);
-	return 0;
+	return ret;
 }
 
 static int dmx_ts_set_indexing_params(
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index f5f6039..f3dc4b8 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -203,5 +203,85 @@
 void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf,
 				const u8 timestamp[TIMESTAMP_LEN]);
 
+/**
+ * dvb_dmx_is_video_feed - Returns whether the PES feed
+ * is video one.
+ *
+ * @feed: The feed to be checked.
+ *
+ * Return     1 if feed is video feed, 0 otherwise.
+ */
+static inline int dvb_dmx_is_video_feed(struct dvb_demux_feed *feed)
+{
+	if (feed->type != DMX_TYPE_TS)
+		return 0;
+
+	if (feed->ts_type & (~TS_DECODER))
+		return 0;
+
+	if ((feed->pes_type == DMX_TS_PES_VIDEO0) ||
+		(feed->pes_type == DMX_TS_PES_VIDEO1) ||
+		(feed->pes_type == DMX_TS_PES_VIDEO2) ||
+		(feed->pes_type == DMX_TS_PES_VIDEO3))
+		return 1;
+
+	return 0;
+}
+
+/**
+ * dvb_dmx_is_pcr_feed - Returns whether the PES feed
+ * is PCR one.
+ *
+ * @feed: The feed to be checked.
+ *
+ * Return     1 if feed is PCR feed, 0 otherwise.
+ */
+static inline int dvb_dmx_is_pcr_feed(struct dvb_demux_feed *feed)
+{
+	if (feed->type != DMX_TYPE_TS)
+		return 0;
+
+	if (feed->ts_type & (~TS_DECODER))
+		return 0;
+
+	if ((feed->pes_type == DMX_TS_PES_PCR0) ||
+		(feed->pes_type == DMX_TS_PES_PCR1) ||
+		(feed->pes_type == DMX_TS_PES_PCR2) ||
+		(feed->pes_type == DMX_TS_PES_PCR3))
+		return 1;
+
+	return 0;
+}
+
+/**
+ * dvb_dmx_is_sec_feed - Returns whether this is a section feed
+ *
+ * @feed: The feed to be checked.
+ *
+ * Return 1 if feed is a section feed, 0 otherwise.
+ */
+static inline int dvb_dmx_is_sec_feed(struct dvb_demux_feed *feed)
+{
+	return (feed->type == DMX_TYPE_SEC);
+}
+
+/**
+ * dvb_dmx_is_rec_feed - Returns whether this is a recording feed
+ *
+ * @feed: The feed to be checked.
+ *
+ * Return 1 if feed is recording feed, 0 otherwise.
+ */
+static inline int dvb_dmx_is_rec_feed(struct dvb_demux_feed *feed)
+{
+	if (feed->type != DMX_TYPE_TS)
+		return 0;
+
+	if (feed->ts_type & (TS_DECODER | TS_PAYLOAD_ONLY))
+		return 0;
+
+	return 1;
+}
+
 
 #endif /* _DVB_DEMUX_H_ */
diff --git a/drivers/media/platform/msm/camera_v2/Kconfig b/drivers/media/platform/msm/camera_v2/Kconfig
index 2bbdc22..e4777e6 100644
--- a/drivers/media/platform/msm/camera_v2/Kconfig
+++ b/drivers/media/platform/msm/camera_v2/Kconfig
@@ -82,6 +82,15 @@
 		snapshot config = 4000 * 3000 at 20 fps,
 		hfr video at 60, 90 and 120 fps.
 
+config IMX135
+	bool "Sensor IMX135 (BAYER 12M)"
+	depends on MSMB_CAMERA
+	---help---
+		Sony 12 MP Bayer Sensor with auto focus, uses
+		4 mipi lanes, preview config = 2104 x 1560 at 49 fps,
+		snapshot config = 4208 x 3120 at 24 fps,
+		Video HDR support.
+
 config OV2720
 	bool "Sensor OV2720 (BAYER 2M)"
 	depends on MSMB_CAMERA
diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c
index 63ab4bf..6b27048 100644
--- a/drivers/media/platform/msm/camera_v2/camera/camera.c
+++ b/drivers/media/platform/msm/camera_v2/camera/camera.c
@@ -314,7 +314,7 @@
 	return rc;
 
 set_fmt_fail:
-	kfree(sp->vb2_q.drv_priv);
+	kzfree(sp->vb2_q.drv_priv);
 	return rc;
 }
 
@@ -445,7 +445,7 @@
 		v4l2_fh_exit(&sp->fh);
 	}
 
-	kfree(sp);
+	kzfree(sp);
 	return 0;
 }
 
@@ -479,7 +479,7 @@
 {
 	struct camera_v4l2_private *sp = filep->private_data;
 
-	kfree(sp->vb2_q.drv_priv);
+	kzfree(sp->vb2_q.drv_priv);
 	vb2_queue_release(&sp->vb2_q);
 }
 
@@ -687,14 +687,14 @@
 entity_fail:
 	media_device_unregister(v4l2_dev->mdev);
 media_fail:
-	kfree(v4l2_dev->mdev);
+	kzfree(v4l2_dev->mdev);
 mdev_fail:
 #endif
-	kfree(v4l2_dev);
+	kzfree(v4l2_dev);
 v4l2_fail:
 	video_device_release(pvdev->vdev);
 video_fail:
-	kfree(pvdev);
+	kzfree(pvdev);
 init_end:
 	return rc;
 }
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index 1d931df..5385d1e 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -88,8 +88,8 @@
 	{
 		.src = MSM_BUS_MASTER_VFE,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab  = 1027648000,
-		.ib  = 1105920000,
+		.ab  = 2027648000U,
+		.ib  = 2805920000U,
 	},
 };
 
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index 08a4566..f8cddb2 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -129,7 +129,7 @@
 		if (node->sd == q_node) {				\
 			__q->len--;				\
 			list_del_init(&node->member);		\
-			kfree(node);				\
+			kzfree(node);				\
 			break;					\
 		}						\
 	}							\
@@ -146,7 +146,7 @@
 		if (node == q_node) {				\
 			__q->len--;				\
 			list_del_init(&node->member);		\
-			kfree(node);				\
+			kzfree(node);				\
 			break;					\
 		}						\
 	}							\
@@ -165,7 +165,7 @@
 		if (node) {					\
 			if (&node->member) \
 				list_del_init(&node->member);		\
-			kfree(node);	\
+			kzfree(node);	\
 		}	\
 	}	\
 	spin_unlock_irqrestore(&__q->lock, flags);		\
@@ -288,14 +288,14 @@
 
 	list_del_init(&stream->list);
 	session->stream_q.len--;
-	kfree(stream);
+	kzfree(stream);
 }
 
 static void msm_sd_unregister_subdev(struct video_device *vdev)
 {
 	struct v4l2_subdev *sd = video_get_drvdata(vdev);
 	sd->devnode = NULL;
-	kfree(vdev);
+	kzfree(vdev);
 }
 
 static inline int __msm_sd_register_subdev(struct v4l2_subdev *sd)
@@ -330,7 +330,7 @@
 	rc = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
 		  sd->owner);
 	if (rc < 0) {
-		kfree(vdev);
+		kzfree(vdev);
 		goto clean_up;
 	}
 
@@ -461,9 +461,6 @@
 static inline int __msm_sd_close_session_streams(struct v4l2_subdev *sd,
 	struct msm_sd_close_ioctl *sd_close)
 {
-	v4l2_subdev_call(sd, core, ioctl,
-		MSM_SD_CLOSE_SESSION_AND_STREAM, &sd_close);
-
 	return 0;
 }
 
@@ -591,7 +588,7 @@
 			__msm_queue_find_command_ack_q,
 			&stream_id);
 		if (WARN_ON(!cmd_ack)) {
-			kfree(ret_cmd);
+			kzfree(ret_cmd);
 			rc = -EFAULT;
 			break;
 		}
@@ -713,7 +710,7 @@
 
 	*event = cmd->event;
 
-	kfree(cmd);
+	kzfree(cmd);
 	return rc;
 }
 
@@ -1005,14 +1002,14 @@
 entity_fail:
 	media_device_unregister(msm_v4l2_dev->mdev);
 media_fail:
-	kfree(msm_v4l2_dev->mdev);
+	kzfree(msm_v4l2_dev->mdev);
 mdev_fail:
 #endif
 	video_device_release(pvdev->vdev);
 video_fail:
-	kfree(pvdev);
+	kzfree(pvdev);
 pvdev_fail:
-	kfree(msm_v4l2_dev);
+	kzfree(msm_v4l2_dev);
 probe_end:
 	return rc;
 }
diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
index 6ea86ae..079dbb5 100644
--- a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
+++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
@@ -77,7 +77,7 @@
 
 static void msm_vb2_dma_contig_put_userptr(void *buf_priv)
 {
-	kfree(buf_priv);
+	kzfree(buf_priv);
 }
 
 static struct vb2_mem_ops msm_vb2_get_q_mem_op = {
@@ -105,7 +105,7 @@
 	unsigned long flags;
 
 	stream = msm_get_stream(session_id, stream_id);
-	if (!stream)
+	if (IS_ERR_OR_NULL(stream))
 		return NULL;
 
 	spin_lock_irqsave(&stream->stream_lock, flags);
@@ -163,7 +163,7 @@
 	int rc = 0;
 
 	stream = msm_get_stream(session_id, stream_id);
-	if (!stream)
+	if (IS_ERR_OR_NULL(stream))
 		return 0;
 	spin_lock_irqsave(&stream->stream_lock, flags);
 	if (vb) {
@@ -172,6 +172,7 @@
 		/* put buf before buf done */
 		if (msm_vb2->in_freeq) {
 			vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+			msm_vb2->in_freeq = 0;
 			rc = 0;
 		} else
 			rc = -EINVAL;
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 637bce3..41234c3 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -293,6 +293,14 @@
 		goto vbif_remap_failed;
 	}
 
+	cpp_dev->cpp_hw_base = ioremap(cpp_dev->cpp_hw_mem->start,
+		resource_size(cpp_dev->cpp_hw_mem));
+	if (!cpp_dev->cpp_hw_base) {
+		rc = -ENOMEM;
+		pr_err("ioremap failed\n");
+		goto cpp_hw_remap_failed;
+	}
+
 	if (cpp_dev->state != CPP_STATE_BOOT) {
 		rc = request_irq(cpp_dev->irq->start, msm_cpp_irq,
 			IRQF_TRIGGER_RISING, "cpp", cpp_dev);
@@ -303,11 +311,19 @@
 		}
 	}
 
+	cpp_dev->hw_info.cpp_hw_version =
+		msm_camera_io_r(cpp_dev->cpp_hw_base);
+	pr_debug("CPP HW Version: 0x%x\n", cpp_dev->hw_info.cpp_hw_version);
+	cpp_dev->hw_info.cpp_hw_caps =
+		msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4);
+	pr_debug("CPP HW Caps: 0x%x\n", cpp_dev->hw_info.cpp_hw_caps);
 	msm_camera_io_w(0x1, cpp_dev->vbif_base + 0x4);
 	if (cpp_dev->is_firmware_loaded == 1)
 		msm_cpp_boot_hw(cpp_dev);
 	return rc;
 req_irq_fail:
+	iounmap(cpp_dev->cpp_hw_base);
+cpp_hw_remap_failed:
 	iounmap(cpp_dev->vbif_base);
 vbif_remap_failed:
 	iounmap(cpp_dev->base);
@@ -327,6 +343,8 @@
 		free_irq(cpp_dev->irq->start, cpp_dev);
 
 	iounmap(cpp_dev->base);
+	iounmap(cpp_dev->vbif_base);
+	iounmap(cpp_dev->cpp_hw_base);
 	msm_cam_clk_enable(&cpp_dev->pdev->dev, cpp_clk_info,
 		cpp_dev->cpp_clk, ARRAY_SIZE(cpp_clk_info), 0);
 	if (0) {
@@ -336,15 +354,15 @@
 	}
 }
 
-static void cpp_load_fw(struct cpp_device *cpp_dev)
+static void cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin)
 {
 	uint32_t i;
 	uint32_t *ptr_bin = NULL;
 	int32_t rc = -EFAULT;
 	const struct firmware *fw = NULL;
-	char *fw_name_bin = "cpp_firmware_v1_1_1.fw";
 	struct device *dev = &cpp_dev->pdev->dev;
 
+	pr_debug("%s: FW file: %s\n", __func__, fw_name_bin);
 	rc = request_firmware(&fw, fw_name_bin, dev);
 	if (rc) {
 		dev_err(dev, "Failed to locate blob %s from device %p, Error: %d\n",
@@ -690,14 +708,44 @@
 	struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd);
 	struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
 	int rc = 0;
+	char *fw_name_bin;
 
 	mutex_lock(&cpp_dev->mutex);
 	CPP_DBG("E cmd: %d\n", cmd);
 	switch (cmd) {
+	case VIDIOC_MSM_CPP_GET_HW_INFO: {
+		if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
+			&cpp_dev->hw_info,
+			sizeof(struct cpp_hw_info))) {
+			mutex_unlock(&cpp_dev->mutex);
+			return -EINVAL;
+		}
+		break;
+	}
+
 	case VIDIOC_MSM_CPP_LOAD_FIRMWARE: {
 		if (cpp_dev->is_firmware_loaded == 0) {
+			fw_name_bin = kzalloc(ioctl_ptr->len, GFP_KERNEL);
+			if (!fw_name_bin) {
+				pr_err("%s:%d: malloc error\n", __func__,
+					__LINE__);
+				mutex_unlock(&cpp_dev->mutex);
+				return -EINVAL;
+			}
+
+			rc = (copy_from_user(fw_name_bin,
+				(void __user *)ioctl_ptr->ioctl_ptr,
+				ioctl_ptr->len) ? -EFAULT : 0);
+			if (rc) {
+				ERR_COPY_FROM_USER();
+				kfree(fw_name_bin);
+				mutex_unlock(&cpp_dev->mutex);
+				return -EINVAL;
+			}
+
 			disable_irq(cpp_dev->irq->start);
-			cpp_load_fw(cpp_dev);
+			cpp_load_fw(cpp_dev, fw_name_bin);
+			kfree(fw_name_bin);
 			enable_irq(cpp_dev->irq->start);
 			cpp_dev->is_firmware_loaded = 1;
 		}
@@ -894,6 +942,14 @@
 		goto ERROR2;
 	}
 
+	cpp_dev->cpp_hw_mem = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, "cpp_hw");
+	if (!cpp_dev->cpp_hw_mem) {
+		pr_err("no mem resource?\n");
+		rc = -ENODEV;
+		goto ERROR2;
+	}
+
 	cpp_dev->irq = platform_get_resource_byname(pdev,
 					IORESOURCE_IRQ, "cpp");
 	if (!cpp_dev->irq) {
@@ -999,6 +1055,10 @@
 	iommu_detach_device(cpp_dev->domain, cpp_dev->iommu_ctx);
 	msm_sd_unregister(&cpp_dev->msm_sd);
 	release_mem_region(cpp_dev->mem->start, resource_size(cpp_dev->mem));
+	release_mem_region(cpp_dev->vbif_mem->start,
+		resource_size(cpp_dev->vbif_mem));
+	release_mem_region(cpp_dev->cpp_hw_mem->start,
+		resource_size(cpp_dev->cpp_hw_mem));
 	mutex_destroy(&cpp_dev->mutex);
 	kfree(cpp_dev->cpp_clk);
 	kfree(cpp_dev);
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
index e8e37ed..0c586ca 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
@@ -125,8 +125,10 @@
 	struct resource *io;
 	struct resource	*vbif_mem;
 	struct resource *vbif_io;
+	struct resource	*cpp_hw_mem;
 	void __iomem *vbif_base;
 	void __iomem *base;
+	void __iomem *cpp_hw_base;
 	struct clk **cpp_clk;
 	struct regulator *fs_cpp;
 	struct mutex mutex;
@@ -141,6 +143,7 @@
 
 	struct cpp_subscribe_info cpp_subscribe_list[MAX_ACTIVE_CPP_INSTANCE];
 	uint32_t cpp_open_cnt;
+	struct cpp_hw_info hw_info;
 
 	struct msm_device_queue eventData_q; /* V4L2 Event Payload Queue */
 
diff --git a/drivers/media/platform/msm/camera_v2/sensor/Makefile b/drivers/media/platform/msm/camera_v2/sensor/Makefile
index f6011ba..6f941f7 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/Makefile
+++ b/drivers/media/platform/msm/camera_v2/sensor/Makefile
@@ -6,5 +6,6 @@
 obj-$(CONFIG_MSMB_CAMERA) += cci/ io/ csiphy/ csid/ actuator/ flash/
 obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor.o
 obj-$(CONFIG_S5K3L1YX) += s5k3l1yx.o
+obj-$(CONFIG_IMX135) += imx135.o
 obj-$(CONFIG_OV2720) += ov2720.o
 obj-$(CONFIG_MT9M114) += mt9m114.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/imx135.c b/drivers/media/platform/msm/camera_v2/sensor/imx135.c
new file mode 100644
index 0000000..c9476ee
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/imx135.c
@@ -0,0 +1,149 @@
+/* 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 "msm_sensor.h"
+#define IMX135_SENSOR_NAME "imx135"
+DEFINE_MSM_MUTEX(imx135_mut);
+
+static struct msm_sensor_ctrl_t imx135_s_ctrl;
+
+static struct msm_sensor_power_setting imx135_power_setting[] = {
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VDIG,
+		.config_val = 0,
+		.delay = 0,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VANA,
+		.config_val = 0,
+		.delay = 0,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VIO,
+		.config_val = 0,
+		.delay = 0,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_RESET,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_RESET,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 30,
+	},
+	{
+		.seq_type = SENSOR_CLK,
+		.seq_val = SENSOR_CAM_MCLK,
+		.config_val = 0,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_I2C_MUX,
+		.seq_val = 0,
+		.config_val = 0,
+		.delay = 0,
+	},
+};
+
+static struct v4l2_subdev_info imx135_subdev_info[] = {
+	{
+		.code = V4L2_MBUS_FMT_SBGGR10_1X10,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.fmt = 1,
+		.order = 0,
+	},
+};
+
+static const struct i2c_device_id imx135_i2c_id[] = {
+	{IMX135_SENSOR_NAME, (kernel_ulong_t)&imx135_s_ctrl},
+	{ }
+};
+
+static struct i2c_driver imx135_i2c_driver = {
+	.id_table = imx135_i2c_id,
+	.probe  = msm_sensor_i2c_probe,
+	.driver = {
+		.name = IMX135_SENSOR_NAME,
+	},
+};
+
+static struct msm_camera_i2c_client imx135_sensor_i2c_client = {
+	.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+static const struct of_device_id imx135_dt_match[] = {
+	{.compatible = "qcom,imx135", .data = &imx135_s_ctrl},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, imx135_dt_match);
+
+static struct platform_driver imx135_platform_driver = {
+	.driver = {
+		.name = "qcom,imx135",
+		.owner = THIS_MODULE,
+		.of_match_table = imx135_dt_match,
+	},
+};
+
+static int32_t imx135_platform_probe(struct platform_device *pdev)
+{
+	int32_t rc = 0;
+	const struct of_device_id *match;
+	match = of_match_device(imx135_dt_match, &pdev->dev);
+	rc = msm_sensor_platform_probe(pdev, match->data);
+	return rc;
+}
+
+static int __init imx135_init_module(void)
+{
+	int32_t rc = 0;
+	pr_info("%s:%d\n", __func__, __LINE__);
+	rc = platform_driver_probe(&imx135_platform_driver,
+		imx135_platform_probe);
+	if (!rc)
+		return rc;
+	pr_err("%s:%d rc %d\n", __func__, __LINE__, rc);
+	return i2c_add_driver(&imx135_i2c_driver);
+}
+
+static void __exit imx135_exit_module(void)
+{
+	pr_info("%s:%d\n", __func__, __LINE__);
+	if (imx135_s_ctrl.pdev) {
+		msm_sensor_free_sensor_data(&imx135_s_ctrl);
+		platform_driver_unregister(&imx135_platform_driver);
+	} else
+		i2c_del_driver(&imx135_i2c_driver);
+	return;
+}
+
+static struct msm_sensor_ctrl_t imx135_s_ctrl = {
+	.sensor_i2c_client = &imx135_sensor_i2c_client,
+	.power_setting_array.power_setting = imx135_power_setting,
+	.power_setting_array.size = ARRAY_SIZE(imx135_power_setting),
+	.msm_sensor_mutex = &imx135_mut,
+	.sensor_v4l2_subdev_info = imx135_subdev_info,
+	.sensor_v4l2_subdev_info_size = ARRAY_SIZE(imx135_subdev_info),
+};
+
+module_init(imx135_init_module);
+module_exit(imx135_exit_module);
+MODULE_DESCRIPTION("imx135");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index 9d89a7e..499b36c 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -95,6 +95,10 @@
 static int mpq_sdmx_proc_limit = MAX_TS_PACKETS_FOR_SDMX_PROCESS;
 module_param(mpq_sdmx_proc_limit, int, S_IRUGO | S_IWUSR);
 
+/* Debug flag for secure demux process */
+static int mpq_sdmx_debug;
+module_param(mpq_sdmx_debug, int, S_IRUGO | S_IWUSR);
+
 
 /**
  * Maximum allowed framing pattern size
@@ -903,6 +907,8 @@
 
 		mutex_init(&mpq_demux->mutex);
 
+		mpq_demux->num_secure_feeds = 0;
+		mpq_demux->num_active_feeds = 0;
 		mpq_demux->sdmx_filter_count = 0;
 		mpq_demux->sdmx_session_handle = SDMX_INVALID_SESSION_HANDLE;
 
@@ -1230,7 +1236,7 @@
 		return -EINVAL;
 	}
 
-	if (mpq_dmx_is_video_feed(feed)) {
+	if (dvb_dmx_is_video_feed(feed)) {
 		struct mpq_video_feed_info *feed_data;
 		struct mpq_feed *mpq_feed;
 		struct mpq_streambuffer *stream_buffer;
@@ -1957,9 +1963,10 @@
 		}
 
 		mpq_sdmx_close_session(mpq_demux);
+		mpq_demux->num_secure_feeds--;
 	}
 
-	if (mpq_dmx_is_video_feed(feed)) {
+	if (dvb_dmx_is_video_feed(feed)) {
 		ret = mpq_dmx_terminate_video_feed(mpq_feed);
 		if (ret)
 			MPQ_DVB_ERR_PRINT(
@@ -1973,6 +1980,7 @@
 	}
 
 	mpq_sdmx_terminate_metadata_buffer(mpq_feed);
+	mpq_demux->num_active_feeds--;
 
 	mutex_unlock(&mpq_demux->mutex);
 
@@ -1982,7 +1990,7 @@
 
 int mpq_dmx_decoder_fullness_init(struct dvb_demux_feed *feed)
 {
-	if (mpq_dmx_is_video_feed(feed)) {
+	if (dvb_dmx_is_video_feed(feed)) {
 		struct mpq_feed *mpq_feed;
 		struct mpq_video_feed_info *feed_data;
 
@@ -2056,7 +2064,7 @@
 	struct mpq_feed *mpq_feed;
 	int ret = 0;
 
-	if (!mpq_dmx_is_video_feed(feed)) {
+	if (!dvb_dmx_is_video_feed(feed)) {
 		MPQ_DVB_DBG_PRINT("%s: Invalid feed type %d\n",
 			__func__,
 			feed->pes_type);
@@ -2139,7 +2147,7 @@
 
 int mpq_dmx_decoder_fullness_abort(struct dvb_demux_feed *feed)
 {
-	if (mpq_dmx_is_video_feed(feed)) {
+	if (dvb_dmx_is_video_feed(feed)) {
 		struct mpq_feed *mpq_feed;
 		struct mpq_video_feed_info *feed_data;
 		struct dvb_ringbuffer *video_buff;
@@ -3087,7 +3095,7 @@
 	struct mpq_streambuffer *video_buff;
 	struct mpq_feed *mpq_feed;
 
-	if (!mpq_dmx_is_video_feed(feed)) {
+	if (!dvb_dmx_is_video_feed(feed)) {
 		MPQ_DVB_ERR_PRINT(
 			"%s: Invalid feed type %d\n",
 			__func__,
@@ -3230,67 +3238,6 @@
 }
 EXPORT_SYMBOL(mpq_dmx_process_pcr_packet);
 
-int mpq_dmx_set_secure_mode(struct dvb_demux_feed *feed,
-	struct dmx_secure_mode *sec_mode)
-{
-	struct mpq_feed *mpq_feed;
-	struct mpq_demux *mpq_demux;
-	int ret;
-
-	if (!feed || !feed->priv || !sec_mode) {
-		MPQ_DVB_ERR_PRINT(
-			"%s: invalid parameters\n",
-			__func__);
-		return -EINVAL;
-	}
-
-	MPQ_DVB_DBG_PRINT("%s(%d, %d, %d)\n",
-		__func__, sec_mode->pid,
-		sec_mode->is_secured,
-		sec_mode->key_ladder_id);
-
-	mpq_feed = feed->priv;
-	mpq_demux = mpq_feed->mpq_demux;
-
-	mutex_lock(&mpq_demux->mutex);
-
-	/*
-	 * If secure demux is active, set the KL now,
-	 * otherwise it will be set when secure-demux is started
-	 * (when filtering starts).
-	 */
-	if (mpq_demux->sdmx_session_handle !=
-		SDMX_INVALID_SESSION_HANDLE) {
-		if (sec_mode->is_secured) {
-			MPQ_DVB_DBG_PRINT(
-				"%s: set key-ladder %d to PID %d\n",
-				__func__,
-				sec_mode->key_ladder_id,
-				sec_mode->pid);
-			ret = sdmx_set_kl_ind(mpq_demux->sdmx_session_handle,
-				sec_mode->pid, sec_mode->key_ladder_id);
-			if (ret) {
-				MPQ_DVB_ERR_PRINT(
-					"%s: FAILED to set keyladder, ret=%d\n",
-					__func__, ret);
-				ret = -EINVAL;
-			}
-		} else {
-			MPQ_DVB_DBG_PRINT("%s: setting non-secure mode\n",
-				__func__);
-			ret = 0;
-		}
-	} else {
-		MPQ_DVB_DBG_PRINT("%s: SDMX not started yet\n", __func__);
-		ret = 0;
-	}
-
-	mutex_unlock(&mpq_demux->mutex);
-
-	return ret;
-}
-EXPORT_SYMBOL(mpq_dmx_set_secure_mode);
-
 int mpq_sdmx_open_session(struct mpq_demux *mpq_demux)
 {
 	enum sdmx_status ret = SDMX_SUCCESS;
@@ -3409,7 +3356,7 @@
 
 	*buf_mode = SDMX_RING_BUF;
 
-	if (mpq_dmx_is_video_feed(feed->dvb_demux_feed)) {
+	if (dvb_dmx_is_video_feed(feed->dvb_demux_feed)) {
 		if (feed_data->buffer_desc.decoder_buffers_num > 1)
 			*buf_mode = SDMX_LINEAR_GROUP_BUF;
 		*num_buffers = feed_data->buffer_desc.decoder_buffers_num;
@@ -3429,8 +3376,8 @@
 		}
 	} else {
 		*num_buffers = 1;
-		if (mpq_dmx_is_sec_feed(dvbdmx_feed) ||
-			mpq_dmx_is_pcr_feed(dvbdmx_feed)) {
+		if (dvb_dmx_is_sec_feed(dvbdmx_feed) ||
+			dvb_dmx_is_pcr_feed(dvbdmx_feed)) {
 			buffer = &feed->sdmx_buf;
 			sdmx_buff = feed->sdmx_buf_handle;
 		} else {
@@ -3481,18 +3428,18 @@
 
 	feed = dvbdmx_feed->priv;
 
-	if (mpq_dmx_is_sec_feed(dvbdmx_feed)) {
+	if (dvb_dmx_is_sec_feed(dvbdmx_feed)) {
 		feed->filter_type = SDMX_SECTION_FILTER;
 		if (dvbdmx_feed->feed.sec.check_crc)
 			filter_flags |= SDMX_FILTER_FLAG_VERIFY_SECTION_CRC;
 		MPQ_DVB_DBG_PRINT("%s: SDMX_SECTION_FILTER\n", __func__);
-	} else if (mpq_dmx_is_pcr_feed(dvbdmx_feed)) {
+	} else if (dvb_dmx_is_pcr_feed(dvbdmx_feed)) {
 		feed->filter_type = SDMX_PCR_FILTER;
 		MPQ_DVB_DBG_PRINT("%s: SDMX_PCR_FILTER\n", __func__);
-	} else if (mpq_dmx_is_video_feed(dvbdmx_feed)) {
+	} else if (dvb_dmx_is_video_feed(dvbdmx_feed)) {
 		feed->filter_type = SDMX_SEPARATED_PES_FILTER;
 		MPQ_DVB_DBG_PRINT("%s: SDMX_SEPARATED_PES_FILTER\n", __func__);
-	} else if (mpq_dmx_is_rec_feed(dvbdmx_feed)) {
+	} else if (dvb_dmx_is_rec_feed(dvbdmx_feed)) {
 		feed->filter_type = SDMX_RAW_FILTER;
 		switch (dvbdmx_feed->tsp_out_format) {
 		case (DMX_TSP_FORMAT_188):
@@ -3546,7 +3493,7 @@
 		/* Meta-data initialization,
 		 * Recording filters do no need meta-data buffers.
 		 */
-		if (mpq_dmx_is_rec_feed(dvbdmx_feed)) {
+		if (dvb_dmx_is_rec_feed(dvbdmx_feed)) {
 			metadata_buff_desc.base_addr = 0;
 			metadata_buff_desc.size = 0;
 		} else {
@@ -3640,6 +3587,63 @@
 	return ret;
 }
 
+/**
+ * mpq_sdmx_init_feed - initialize secure demux related elements of mpq feed
+ *
+ * @mpq_demux: mpq_demux object
+ * @mpq_feed: mpq_feed object
+ *
+ * Note: the function assumes mpq_demux->mutex locking is done by caller.
+ */
+static int mpq_sdmx_init_feed(struct mpq_demux *mpq_demux,
+	struct mpq_feed *mpq_feed)
+{
+	int ret;
+
+	ret = mpq_sdmx_open_session(mpq_demux);
+	if (ret) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: mpq_sdmx_open_session failed, ret=%d\n",
+			__func__, ret);
+
+		ret = -ENODEV;
+		goto init_sdmx_feed_failed;
+	}
+
+	/* PCR and sections have internal buffer for SDMX */
+	if (dvb_dmx_is_pcr_feed(mpq_feed->dvb_demux_feed))
+		ret = mpq_sdmx_alloc_data_buf(mpq_feed, SDMX_PCR_BUFFER_SIZE);
+	else if (dvb_dmx_is_sec_feed(mpq_feed->dvb_demux_feed))
+		ret = mpq_sdmx_alloc_data_buf(mpq_feed,
+			SDMX_SECTION_BUFFER_SIZE);
+	else
+		ret = 0;
+
+	if (ret) {
+		MPQ_DVB_ERR_PRINT("%s: init buffer failed, ret=%d\n",
+			__func__, ret);
+		goto init_sdmx_feed_failed_free_sdmx;
+	}
+
+	ret = mpq_sdmx_filter_setup(mpq_demux, mpq_feed->dvb_demux_feed);
+	if (ret) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: mpq_sdmx_filter_setup failed, ret=%d\n",
+			__func__, ret);
+		goto init_sdmx_feed_failed_free_data_buff;
+	}
+
+	mpq_demux->num_secure_feeds++;
+	return 0;
+
+init_sdmx_feed_failed_free_data_buff:
+	mpq_sdmx_free_data_buf(mpq_feed);
+init_sdmx_feed_failed_free_sdmx:
+	mpq_sdmx_close_session(mpq_demux);
+init_sdmx_feed_failed:
+	return ret;
+}
+
 int mpq_dmx_init_mpq_feed(struct dvb_demux_feed *feed)
 {
 	int ret = 0;
@@ -3648,80 +3652,113 @@
 
 	mutex_lock(&mpq_demux->mutex);
 
-	if (mpq_dmx_is_video_feed(feed)) {
-		ret = mpq_dmx_init_video_feed(mpq_feed);
-
-		if (ret) {
-			MPQ_DVB_ERR_PRINT(
-				"%s: mpq_dmx_init_video_feed failed, ret=%d\n",
-				__func__, ret);
-			goto init_mpq_feed_failed;
-		}
-	}
-
 	mpq_feed->sdmx_buf_handle = NULL;
 	mpq_feed->metadata_buf_handle = NULL;
 	mpq_feed->sdmx_filter_handle = SDMX_INVALID_FILTER_HANDLE;
 
-	if (!mpq_sdmx_is_loaded()) {
-		/* nothing more to do */
-		mpq_demux->sdmx_session_handle = SDMX_INVALID_SESSION_HANDLE;
-		mutex_unlock(&mpq_demux->mutex);
-		return ret;
+	if (dvb_dmx_is_video_feed(feed)) {
+		ret = mpq_dmx_init_video_feed(mpq_feed);
+		if (ret) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: mpq_dmx_init_video_feed failed, ret=%d\n",
+				__func__, ret);
+			goto init_mpq_feed_end;
+		}
 	}
 
-	/* Further initializations for secure demux */
-	ret = mpq_sdmx_open_session(mpq_demux);
+	/*
+	 * sdmx is not relevant for recording filters, which always use
+	 * regular filters (non-sdmx)
+	 */
+	if (!mpq_sdmx_is_loaded() || !feed->secure_mode.is_secured ||
+		dvb_dmx_is_rec_feed(feed)) {
+		if (!mpq_sdmx_is_loaded())
+			mpq_demux->sdmx_session_handle =
+				SDMX_INVALID_SESSION_HANDLE;
+		goto init_mpq_feed_end;
+	}
+
+	 /* Initialization of secure demux filters (PES/PCR/Video/Section) */
+	ret = mpq_sdmx_init_feed(mpq_demux, mpq_feed);
 	if (ret) {
 		MPQ_DVB_ERR_PRINT(
-			"%s: mpq_sdmx_open_session failed, ret=%d\n",
+			"%s: mpq_sdmx_init_feed failed, ret=%d\n",
 			__func__, ret);
-
-		ret = -ENODEV;
-		goto init_mpq_feed_failed_free_video;
+		if (dvb_dmx_is_video_feed(feed))
+			mpq_dmx_terminate_video_feed(mpq_feed);
 	}
 
-	/* PCR and sections have internal buffer for SDMX */
-	if (mpq_dmx_is_pcr_feed(feed))
-		ret = mpq_sdmx_alloc_data_buf(mpq_feed,
-			SDMX_PCR_BUFFER_SIZE);
-	else if (mpq_dmx_is_sec_feed(feed))
-		ret = mpq_sdmx_alloc_data_buf(mpq_feed,
-			SDMX_SECTION_BUFFER_SIZE);
-	else
-		ret = 0;
-
-	if (ret) {
-		MPQ_DVB_ERR_PRINT(
-			"%s: init buffer failed, ret=%d\n",
-			__func__, ret);
-		goto init_mpq_feed_failed_free_sdmx;
-	}
-
-	ret = mpq_sdmx_filter_setup(mpq_demux, feed);
-	if (ret) {
-		MPQ_DVB_ERR_PRINT(
-			"%s: mpq_sdmx_filter_setup failed, ret=%d\n",
-			__func__, ret);
-		goto init_mpq_feed_failed_free_data_buff;
-	}
-
-	mutex_unlock(&mpq_demux->mutex);
-	return 0;
-
-init_mpq_feed_failed_free_data_buff:
-	mpq_sdmx_free_data_buf(mpq_feed);
-init_mpq_feed_failed_free_sdmx:
-	mpq_sdmx_close_session(mpq_demux);
-init_mpq_feed_failed_free_video:
-	if (mpq_dmx_is_video_feed(feed))
-		mpq_dmx_terminate_video_feed(mpq_feed);
-init_mpq_feed_failed:
+init_mpq_feed_end:
+	if (!ret)
+		mpq_demux->num_active_feeds++;
 	mutex_unlock(&mpq_demux->mutex);
 	return ret;
 }
 EXPORT_SYMBOL(mpq_dmx_init_mpq_feed);
 
+/**
+ * Note: Called only when filter is in "GO" state - after feed has been started.
+ */
+int mpq_dmx_set_secure_mode(struct dvb_demux_feed *feed,
+	struct dmx_secure_mode *sec_mode)
+{
+	struct mpq_feed *mpq_feed;
+	struct mpq_demux *mpq_demux;
+	int ret = 0;
+
+	if (!feed || !feed->priv || !sec_mode) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: invalid parameters\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	MPQ_DVB_DBG_PRINT("%s(%d, %d, %d)\n",
+		__func__, sec_mode->pid,
+		sec_mode->is_secured,
+		sec_mode->key_ladder_id);
+
+	mpq_feed = feed->priv;
+	mpq_demux = mpq_feed->mpq_demux;
+
+	mutex_lock(&mpq_demux->mutex);
+
+	if (feed->secure_mode.is_secured != sec_mode->is_secured) {
+		/*
+		 * Switching between secure & non-secure mode is not allowed
+		 * while filter is running
+		 */
+		MPQ_DVB_ERR_PRINT(
+			"%s: Cannot switch between secure mode while filter is running\n",
+			__func__);
+		mutex_unlock(&mpq_demux->mutex);
+		return -EPERM;
+	}
+
+	/*
+	 * Feed is running in secure mode, this secure mode request is to
+	 * update the key ladder id
+	 */
+	if (feed->secure_mode.pid == sec_mode->pid && sec_mode->is_secured &&
+		feed->secure_mode.key_ladder_id != sec_mode->key_ladder_id &&
+		mpq_demux->sdmx_session_handle != SDMX_INVALID_SESSION_HANDLE) {
+		ret = sdmx_set_kl_ind(mpq_demux->sdmx_session_handle,
+			sec_mode->pid,
+			sec_mode->key_ladder_id);
+		if (ret) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: FAILED to set key ladder, ret=%d\n",
+				__func__, ret);
+			ret = -ENODEV;
+		}
+	}
+
+	mutex_unlock(&mpq_demux->mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL(mpq_dmx_set_secure_mode);
+
 static void mpq_sdmx_prepare_filter_status(struct mpq_demux *mpq_demux,
 	struct sdmx_filter_status *filter_sts,
 	struct mpq_feed *mpq_feed)
@@ -3742,11 +3779,11 @@
 		__func__, filter_sts->metadata_fill_count,
 		filter_sts->metadata_write_offset);
 
-	if (!mpq_dmx_is_video_feed(feed)) {
+	if (!dvb_dmx_is_video_feed(feed)) {
 		struct dvb_ringbuffer *buffer;
 
-		if (mpq_dmx_is_sec_feed(feed) ||
-			mpq_dmx_is_pcr_feed(feed)) {
+		if (dvb_dmx_is_sec_feed(feed) ||
+			dvb_dmx_is_pcr_feed(feed)) {
 			buffer = (struct dvb_ringbuffer *)
 				&mpq_feed->sdmx_buf;
 		} else {
@@ -4421,7 +4458,8 @@
 {
 	struct sdmx_filter_status *sts;
 	struct mpq_feed *mpq_feed;
-	u8 flags = 0;	/* MPQ_TODO: EOS handling */
+	/* MPQ_TODO: EOS handling */
+	u8 flags = mpq_sdmx_debug ? SDMX_INPUT_FLAG_DBG_ENABLE : 0;
 	u32 errors;
 	u32 status;
 	u32 prev_read_offset;
@@ -4521,7 +4559,7 @@
 	int total_bytes_read = 0;
 	int limit = mpq_sdmx_proc_limit * mpq_demux->demux.ts_packet_size;
 
-	do {
+	while (fill_count >= mpq_demux->demux.ts_packet_size) {
 		todo = fill_count > limit ? limit : fill_count;
 		ret = mpq_sdmx_process_buffer(mpq_demux, input, todo,
 			read_offset);
@@ -4541,7 +4579,7 @@
 				__func__, ret);
 			break;
 		}
-	} while (fill_count > 0);
+	}
 
 	return total_bytes_read;
 }
@@ -4584,6 +4622,7 @@
 {
 	struct dvb_demux *dvb_demux;
 	struct mpq_demux *mpq_demux;
+	int ret = count;
 
 	if (demux == NULL)
 		return -EINVAL;
@@ -4591,20 +4630,35 @@
 	dvb_demux = demux->priv;
 	mpq_demux = dvb_demux->priv;
 
-	if (mpq_sdmx_is_loaded()) {
-		/* route through secure demux */
-		return mpq_sdmx_write(mpq_demux,
+	/* Route through secure demux - process secure feeds if any exist */
+	if (mpq_sdmx_is_loaded() && mpq_demux->sdmx_filter_count) {
+		ret = mpq_sdmx_write(mpq_demux,
 			demux->dvr_input.priv_handle,
 			buf,
 			count);
-	} else {
-		/* route through sw filter */
-		dvb_dmx_swfilter_format(dvb_demux, buf, count,
-			dvb_demux->tsp_format);
-		if (signal_pending(current))
-			return -EINTR;
-		return count;
+		if (ret < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: mpq_sdmx_write failed. ret = %d\n",
+				__func__, ret);
+			ret = count;
+		}
 	}
+
+	/*
+	 * Route through sw filter - process non-secure feeds if any exist.
+	 * For sw filter, should process the same amount of bytes the sdmx
+	 * process managed to consume, unless some sdmx error occurred, for
+	 * which should process the whole buffer
+	 */
+	if (mpq_demux->num_active_feeds > mpq_demux->num_secure_feeds) {
+		dvb_dmx_swfilter_format(dvb_demux, buf, ret,
+			dvb_demux->tsp_format);
+	}
+
+	if (signal_pending(current))
+		return -EINTR;
+
+	return ret;
 }
 EXPORT_SYMBOL(mpq_dmx_write);
 
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h
index 2c2420b..7affcc6 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h
@@ -362,6 +362,9 @@
  * @ion_client: ION demux client used to allocate memory from ION.
  * @mutex: Lock used to protect against private feed data
  * @feeds: mpq common feed object pool
+ * @num_active_feeds: Number of active mpq feeds
+ * @num_secure_feeds: Number of secure feeds (have a sdmx filter associated)
+ * currently allocated.
  * @filters_status: Array holding buffers status for each secure demux filter.
  * Used before each call to sdmx_process() to build up to date state.
  * @sdmx_session_handle: Secure demux open session handle
@@ -406,6 +409,8 @@
 	struct ion_client *ion_client;
 	struct mutex mutex;
 	struct mpq_feed feeds[MPQ_MAX_DMX_FILES];
+	u32 num_active_feeds;
+	u32 num_secure_feeds;
 	struct sdmx_filter_status filters_status[MPQ_MAX_DMX_FILES];
 	int sdmx_session_handle;
 	int sdmx_session_ref_count;
@@ -615,86 +620,6 @@
 int mpq_dmx_process_pcr_packet(struct dvb_demux_feed *feed, const u8 *buf);
 
 /**
- * mpq_dmx_is_video_feed - Returns whether the PES feed
- * is video one.
- *
- * @feed: The feed to be checked.
- *
- * Return     1 if feed is video feed, 0 otherwise.
- */
-static inline int mpq_dmx_is_video_feed(struct dvb_demux_feed *feed)
-{
-	if (feed->type != DMX_TYPE_TS)
-		return 0;
-
-	if (feed->ts_type & (~TS_DECODER))
-		return 0;
-
-	if ((feed->pes_type == DMX_TS_PES_VIDEO0) ||
-		(feed->pes_type == DMX_TS_PES_VIDEO1) ||
-		(feed->pes_type == DMX_TS_PES_VIDEO2) ||
-		(feed->pes_type == DMX_TS_PES_VIDEO3))
-		return 1;
-
-	return 0;
-}
-
-/**
- * mpq_dmx_is_pcr_feed - Returns whether the PES feed
- * is PCR one.
- *
- * @feed: The feed to be checked.
- *
- * Return     1 if feed is PCR feed, 0 otherwise.
- */
-static inline int mpq_dmx_is_pcr_feed(struct dvb_demux_feed *feed)
-{
-	if (feed->type != DMX_TYPE_TS)
-		return 0;
-
-	if (feed->ts_type & (~TS_DECODER))
-		return 0;
-
-	if ((feed->pes_type == DMX_TS_PES_PCR0) ||
-		(feed->pes_type == DMX_TS_PES_PCR1) ||
-		(feed->pes_type == DMX_TS_PES_PCR2) ||
-		(feed->pes_type == DMX_TS_PES_PCR3))
-		return 1;
-
-	return 0;
-}
-
-/**
- * mpq_dmx_is_sec_feed - Returns whether this is a section feed
- *
- * @feed: The feed to be checked.
- *
- * Return 1 if feed is a section feed, 0 otherwise.
- */
-static inline int mpq_dmx_is_sec_feed(struct dvb_demux_feed *feed)
-{
-	return (feed->type == DMX_TYPE_SEC);
-}
-
-/**
- * mpq_dmx_is_rec_feed - Returns whether this is a recording feed
- *
- * @feed: The feed to be checked.
- *
- * Return 1 if feed is recording feed, 0 otherwise.
- */
-static inline int mpq_dmx_is_rec_feed(struct dvb_demux_feed *feed)
-{
-	if (feed->type != DMX_TYPE_TS)
-		return 0;
-
-	if (feed->ts_type & (TS_DECODER | TS_PAYLOAD_ONLY))
-		return 0;
-
-	return 1;
-}
-
-/**
  * mpq_dmx_init_hw_statistics -
  * Extend dvb-demux debugfs with HW statistics.
  *
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c
index b29759c..3d48441 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c
@@ -518,10 +518,10 @@
 				"%s: warnning - len larger than one packet\n",
 				__func__);
 
-	if (mpq_dmx_is_video_feed(feed))
+	if (dvb_dmx_is_video_feed(feed))
 		return mpq_dmx_process_video_packet(feed, buf);
 
-	if (mpq_dmx_is_pcr_feed(feed))
+	if (dvb_dmx_is_pcr_feed(feed))
 		return mpq_dmx_process_pcr_packet(feed, buf);
 
 	return 0;
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
index 632e864..beb4cce 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
@@ -306,6 +306,30 @@
 }
 
 /**
+ * mpq_dmx_tspp_swfilter_desc - helper function
+ *
+ * Takes a tspp buffer descriptor and send it to the SW filter for demuxing,
+ * one TS packet at a time.
+ *
+ * @mpq_demux - mpq demux object
+ * @tspp_data_desc - tspp buffer descriptor
+ */
+static inline void mpq_dmx_tspp_swfilter_desc(struct mpq_demux *mpq_demux,
+	const struct tspp_data_descriptor *tspp_data_desc)
+{
+	u32 notif_size;
+	int i;
+
+	notif_size = tspp_data_desc->size / TSPP_RAW_TTS_SIZE;
+	for (i = 0; i < notif_size; i++)
+		dvb_dmx_swfilter_packet(&mpq_demux->demux,
+			((u8 *)tspp_data_desc->virt_base) +
+			i * TSPP_RAW_TTS_SIZE,
+			((u8 *)tspp_data_desc->virt_base) +
+			i * TSPP_RAW_TTS_SIZE + TSPP_RAW_SIZE);
+}
+
+/**
  * Demux TS packets from TSPP by secure-demux.
  * The fucntion assumes the buffer is physically contiguous
  * and that TSPP descriptors are continuous in memory.
@@ -320,37 +344,46 @@
 	struct sdmx_buff_descr input;
 	size_t aggregate_len = 0;
 	size_t aggregate_count = 0;
-	phys_addr_t buff_start_addr;
-	phys_addr_t buff_current_addr = 0;
+	phys_addr_t buff_start_addr_phys;
+	phys_addr_t buff_current_addr_phys = 0;
+	u32 notif_size;
 	int i;
 
 	while ((tspp_data_desc = tspp_get_buffer(0, channel_id)) != NULL) {
 		if (0 == aggregate_count)
-			buff_current_addr = tspp_data_desc->phys_base;
+			buff_current_addr_phys = tspp_data_desc->phys_base;
+		notif_size = tspp_data_desc->size / TSPP_RAW_TTS_SIZE;
 		mpq_dmx_tspp_info.tsif[tsif].aggregate_ids[aggregate_count] =
 			tspp_data_desc->id;
 		aggregate_len += tspp_data_desc->size;
 		aggregate_count++;
-		mpq_demux->hw_notification_size +=
-			tspp_data_desc->size / TSPP_RAW_TTS_SIZE;
+		mpq_demux->hw_notification_size += notif_size;
+
+		/* Let SW filter process only if it might be relevant */
+		if (mpq_demux->num_active_feeds > mpq_demux->num_secure_feeds)
+			mpq_dmx_tspp_swfilter_desc(mpq_demux, tspp_data_desc);
+
 	}
 
 	if (!aggregate_count)
 		return;
 
-	buff_start_addr = mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_phys_base;
-	input.base_addr = (void *)buff_start_addr;
+	buff_start_addr_phys =
+		mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_phys_base;
+	input.base_addr = (void *)buff_start_addr_phys;
 	input.size = mpq_dmx_tspp_info.tsif[tsif].buffer_count *
 		TSPP_DESCRIPTOR_SIZE;
 
-	MPQ_DVB_DBG_PRINT(
-		"%s: Processing %d descriptors: %d bytes at start address 0x%x, read offset %d\n",
-		__func__, aggregate_count, aggregate_len,
-		(unsigned int)input.base_addr,
-		buff_current_addr - buff_start_addr);
+	if (mpq_sdmx_is_loaded() && mpq_demux->sdmx_filter_count) {
+		MPQ_DVB_DBG_PRINT(
+			"%s: SDMX Processing %d descriptors: %d bytes at start address 0x%x, read offset %d\n",
+			__func__, aggregate_count, aggregate_len,
+			(unsigned int)input.base_addr,
+			buff_current_addr_phys - buff_start_addr_phys);
 
-	mpq_sdmx_process(mpq_demux, &input, aggregate_len,
-		 buff_current_addr - buff_start_addr);
+		mpq_sdmx_process(mpq_demux, &input, aggregate_len,
+			buff_current_addr_phys - buff_start_addr_phys);
+	}
 
 	for (i = 0; i < aggregate_count; i++)
 		tspp_release_buffer(0, channel_id,
@@ -373,7 +406,6 @@
 	int channel_id;
 	int ref_count;
 	int ret;
-	int j;
 
 	do {
 		ret = wait_event_interruptible(
@@ -427,13 +459,8 @@
 					TSPP_RAW_TTS_SIZE;
 				mpq_demux->hw_notification_size += notif_size;
 
-				for (j = 0; j < notif_size; j++)
-					dvb_dmx_swfilter_packet(
-					 &mpq_demux->demux,
-					 ((u8 *)tspp_data_desc->virt_base) +
-					 j * TSPP_RAW_TTS_SIZE,
-					 ((u8 *)tspp_data_desc->virt_base) +
-					 j * TSPP_RAW_TTS_SIZE + TSPP_RAW_SIZE);
+				mpq_dmx_tspp_swfilter_desc(mpq_demux,
+					tspp_data_desc);
 				/*
 				 * Notify TSPP that the buffer
 				 * is no longer needed
@@ -1554,10 +1581,10 @@
 				"%s: warnning - len larger than one packet\n",
 				__func__);
 
-	if (mpq_dmx_is_video_feed(feed))
+	if (dvb_dmx_is_video_feed(feed))
 		return mpq_dmx_process_video_packet(feed, buf);
 
-	if (mpq_dmx_is_pcr_feed(feed))
+	if (dvb_dmx_is_pcr_feed(feed))
 		return mpq_dmx_process_pcr_packet(feed, buf);
 
 	return 0;
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h
index d292992..f9d85aa 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h
+++ b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h
@@ -52,7 +52,8 @@
 #define SDMX_INVALID_FILTER_HANDLE		(-1)
 
 /* Input flags */
-#define SDMX_INPUT_FLAG_EOS BIT(0)
+#define SDMX_INPUT_FLAG_EOS		BIT(0)
+#define SDMX_INPUT_FLAG_DBG_ENABLE	BIT(1)
 
 
 enum sdmx_buf_mode {
@@ -177,9 +178,7 @@
 	/* Payload length */
 	u32 payload_length;
 
-	/* Total metadata length (including this header, plus optional
-	 * additional metadata.
-	 */
+	/* Number of meta data bytes immediately following this header */
 	u32 metadata_length;
 };
 
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 8593760..c8599d5 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -184,24 +184,27 @@
 	case HAL_BUFFER_OUTPUT:
 		buffer = HFI_BUFFER_OUTPUT;
 		break;
-	case HAL_BUFFER_OUTPUT2:
-		buffer = HFI_BUFFER_OUTPUT;
-		break;
 	case HAL_BUFFER_EXTRADATA_INPUT:
 		buffer = HFI_BUFFER_EXTRADATA_INPUT;
 		break;
 	case HAL_BUFFER_EXTRADATA_OUTPUT:
 		buffer = HFI_BUFFER_EXTRADATA_OUTPUT;
 		break;
-	case HAL_BUFFER_EXTRADATA_OUTPUT2:
-		buffer = HFI_BUFFER_EXTRADATA_OUTPUT2;
-		break;
 	case HAL_BUFFER_INTERNAL_SCRATCH:
 		buffer = HFI_BUFFER_INTERNAL_SCRATCH;
 		break;
+	case HAL_BUFFER_INTERNAL_SCRATCH_1:
+		buffer = HFI_BUFFER_INTERNAL_SCRATCH_1;
+		break;
+	case HAL_BUFFER_INTERNAL_SCRATCH_2:
+		buffer = HFI_BUFFER_INTERNAL_SCRATCH_2;
+		break;
 	case HAL_BUFFER_INTERNAL_PERSIST:
 		buffer = HFI_BUFFER_INTERNAL_PERSIST;
 		break;
+	case HAL_BUFFER_INTERNAL_PERSIST_1:
+		buffer = HFI_BUFFER_INTERNAL_PERSIST_1;
+		break;
 	default:
 		dprintk(VIDC_ERR, "Invalid buffer :0x%x\n",
 				hal_buffer);
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 709eafc..be9458d 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -391,12 +391,30 @@
 			buffreq->buffer[6].buffer_type =
 				HAL_BUFFER_INTERNAL_SCRATCH;
 			break;
-		case HFI_BUFFER_INTERNAL_PERSIST:
+		case HFI_BUFFER_INTERNAL_SCRATCH_1:
 			memcpy(&buffreq->buffer[7], hfi_buf_req,
-			sizeof(struct hfi_buffer_requirements));
+				sizeof(struct hfi_buffer_requirements));
 			buffreq->buffer[7].buffer_type =
+				HAL_BUFFER_INTERNAL_SCRATCH_1;
+			break;
+		case HFI_BUFFER_INTERNAL_SCRATCH_2:
+			memcpy(&buffreq->buffer[8], hfi_buf_req,
+				sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[8].buffer_type =
+				HAL_BUFFER_INTERNAL_SCRATCH_2;
+			break;
+		case HFI_BUFFER_INTERNAL_PERSIST:
+			memcpy(&buffreq->buffer[9], hfi_buf_req,
+			sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[9].buffer_type =
 				HAL_BUFFER_INTERNAL_PERSIST;
 			break;
+		case HFI_BUFFER_INTERNAL_PERSIST_1:
+			memcpy(&buffreq->buffer[10], hfi_buf_req,
+				sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[10].buffer_type =
+				HAL_BUFFER_INTERNAL_PERSIST_1;
+			break;
 		default:
 			dprintk(VIDC_ERR,
 			"hal_process_sess_get_prop_buf_req: bad_buffer_type: %d",
diff --git a/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c
index 125c699..b3bce5f 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.c
+++ b/drivers/media/platform/msm/vidc/msm_smem.c
@@ -19,43 +19,86 @@
 struct smem_client {
 	int mem_type;
 	void *clnt;
+	struct msm_vidc_platform_resources *res;
 };
 
-static int get_device_address(struct ion_client *clnt,
-		struct ion_handle *hndl, int domain_num, int partition_num,
-		unsigned long align, unsigned long *iova,
-		unsigned long *buffer_size, int flags)
+static u32 get_tz_usage(struct smem_client *client, enum hal_buffer buffer_type)
+{
+	int i;
+	struct buffer_usage_set *buffer_usage_set;
+	struct buffer_usage_table *buffer_usage_tbl;
+
+	buffer_usage_set = &client->res->buffer_usage_set;
+	if (!buffer_usage_set) {
+		dprintk(VIDC_DBG, "no buffer usage set present!\n");
+		return 0;
+	}
+
+	for (i = 0; i < buffer_usage_set->count; i++) {
+		buffer_usage_tbl = &buffer_usage_set->buffer_usage_tbl[i];
+		if (buffer_usage_tbl->buffer_type & buffer_type)
+			return buffer_usage_tbl->tz_usage;
+	}
+	dprintk(VIDC_DBG, "No tz usage found for buffer type: %x\n",
+			buffer_type);
+	return 0;
+}
+
+static int get_device_address(struct smem_client *smem_client,
+		struct ion_handle *hndl, unsigned long align,
+		unsigned long *iova, unsigned long *buffer_size,
+		u32 flags, enum hal_buffer buffer_type)
 {
 	int rc = 0;
-	if (!iova || !buffer_size || !hndl || !clnt) {
+	int domain, partition;
+	struct ion_client *clnt = NULL;
+
+	if (!iova || !buffer_size || !hndl || !smem_client) {
 		dprintk(VIDC_ERR, "Invalid params: %p, %p, %p, %p\n",
-				clnt, hndl, iova, buffer_size);
+				smem_client, hndl, iova, buffer_size);
 		return -EINVAL;
 	}
-	dprintk(VIDC_DBG, "domain: %d, partition: %d\n",
-		domain_num, partition_num);
+
+	clnt = smem_client->clnt;
+	if (!clnt) {
+		dprintk(VIDC_ERR, "Invalid client");
+		return -EINVAL;
+	}
+
+	rc = msm_smem_get_domain_partition(smem_client, flags, buffer_type,
+			&domain, &partition);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to get domain and partition: %d", rc);
+		goto mem_domain_get_failed;
+	}
+
 	if (flags & SMEM_SECURE) {
-		if (flags & SMEM_INPUT)
-			rc = msm_ion_secure_buffer(clnt, hndl, 0x1, 0);
-		else
-			rc = msm_ion_secure_buffer(clnt, hndl, 0x2, 0);
+		rc = msm_ion_secure_buffer(clnt, hndl,
+			get_tz_usage(smem_client, buffer_type), 0);
 		if (rc) {
 			dprintk(VIDC_ERR, "Failed to secure memory\n");
-			goto mem_secure_failed;
+			goto mem_domain_get_failed;
 		}
 	}
-	rc = ion_map_iommu(clnt, hndl, domain_num, partition_num, align,
+	rc = ion_map_iommu(clnt, hndl, domain, partition, align,
 			0, iova, buffer_size, 0, 0);
-	if (rc)
+	if (rc) {
 		dprintk(VIDC_ERR,
 		"ion_map_iommu failed(%d).domain: %d,partition: %d\n",
-		rc, domain_num, partition_num);
-mem_secure_failed:
+		rc, domain, partition);
+		goto mem_map_failed;
+	}
+
+	return 0;
+mem_map_failed:
+	if (flags & SMEM_SECURE)
+		msm_ion_unsecure_buffer(clnt, hndl);
+mem_domain_get_failed:
 	return rc;
 }
 
 static void put_device_address(struct ion_client *clnt,
-	struct ion_handle *hndl, int domain_num, int partition_num, int flags)
+	struct ion_handle *hndl, int domain_num, int partition_num, u32 flags)
 {
 	ion_unmap_iommu(clnt, hndl, domain_num, partition_num);
 	if (flags & SMEM_SECURE) {
@@ -64,9 +107,8 @@
 	}
 }
 
-static int ion_user_to_kernel(struct smem_client *client,
-			int fd, u32 offset, int domain, int partition,
-			struct msm_smem *mem, int flags)
+static int ion_user_to_kernel(struct smem_client *client, int fd, u32 offset,
+		struct msm_smem *mem, enum hal_buffer buffer_type)
 {
 	struct ion_handle *hndl;
 	unsigned long iova = 0;
@@ -74,6 +116,7 @@
 	unsigned long ionflags = 0;
 	int rc = 0;
 	int align = SZ_4K;
+
 	hndl = ion_import_dma_buf(client->clnt, fd);
 	if (IS_ERR_OR_NULL(hndl)) {
 		dprintk(VIDC_ERR, "Failed to get handle: %p, %d, %d, %p\n",
@@ -82,9 +125,6 @@
 		goto fail_import_fd;
 	}
 	mem->kvaddr = NULL;
-	mem->domain = domain;
-	mem->partition_num = partition;
-	mem->flags = flags;
 	rc = ion_handle_get_flags(client->clnt, hndl, &ionflags);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to get ion flags: %d\n", rc);
@@ -99,11 +139,14 @@
 			goto fail_map;
 		}
 	}
-	if (flags & SMEM_SECURE)
+
+	mem->flags = ionflags;
+	mem->buffer_type = buffer_type;
+	if (mem->flags & SMEM_SECURE)
 		align = ALIGN(align, SZ_1M);
 
-	rc = get_device_address(client->clnt, hndl, mem->domain,
-		mem->partition_num, align, &iova, &buffer_size, flags);
+	rc = get_device_address(client, hndl, align, &iova, &buffer_size,
+					mem->flags, buffer_type);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to get device address: %d\n", rc);
 		goto fail_device_address;
@@ -125,49 +168,40 @@
 	return rc;
 }
 
-static int alloc_ion_mem(struct smem_client *client, size_t size,
-		u32 align, u32 flags, int domain, int partition,
-		struct msm_smem *mem, int map_kernel)
+static int alloc_ion_mem(struct smem_client *client, size_t size, u32 align,
+	u32 flags, enum hal_buffer buffer_type, struct msm_smem *mem,
+	int map_kernel)
 {
 	struct ion_handle *hndl;
 	unsigned long iova = 0;
 	unsigned long buffer_size = 0;
-	unsigned long ionflags = 0;
 	unsigned long heap_mask = 0;
 	int rc = 0;
-	if (flags & SMEM_CACHED)
-		ionflags = ION_SET_CACHED(ionflags);
-	else
-		ionflags = ION_SET_UNCACHED(ionflags);
 
 	align = ALIGN(align, SZ_4K);
 	size = ALIGN(size, SZ_4K);
 
 	if (flags & SMEM_SECURE) {
-		ionflags |= ION_SECURE;
 		size = ALIGN(size, SZ_1M);
 		align = ALIGN(align, SZ_1M);
 	}
 
-	heap_mask = ION_HEAP(ION_CP_MM_HEAP_ID);
-	if (!(flags & SMEM_SECURE))
-		heap_mask |= ION_HEAP(ION_IOMMU_HEAP_ID);
+	heap_mask = ION_HEAP(ION_IOMMU_HEAP_ID);
+	if (flags & SMEM_SECURE)
+		heap_mask = ION_HEAP(ION_CP_MM_HEAP_ID);
 
-	dprintk(VIDC_DBG, "domain: %d, partition: %d\n",
-		domain, partition);
-	hndl = ion_alloc(client->clnt, size, align, heap_mask, ionflags);
+	hndl = ion_alloc(client->clnt, size, align, heap_mask, flags);
 	if (IS_ERR_OR_NULL(hndl)) {
 		dprintk(VIDC_ERR,
-		"Failed to allocate shared memory = %p, %d, %d, 0x%lx\n",
-		client, size, align, ionflags);
+		"Failed to allocate shared memory = %p, %d, %d, 0x%x\n",
+		client, size, align, flags);
 		rc = -ENOMEM;
 		goto fail_shared_mem_alloc;
 	}
 	mem->mem_type = client->mem_type;
 	mem->smem_priv = hndl;
-	mem->domain = domain;
-	mem->partition_num = partition;
 	mem->flags = flags;
+	mem->buffer_type = buffer_type;
 	if (map_kernel) {
 		mem->kvaddr = ion_map_kernel(client->clnt, hndl);
 		if (!mem->kvaddr) {
@@ -179,8 +213,8 @@
 	} else
 		mem->kvaddr = NULL;
 
-	rc = get_device_address(client->clnt, hndl, mem->domain,
-		mem->partition_num, align, &iova, &buffer_size, flags);
+	rc = get_device_address(client, hndl, align, &iova, &buffer_size,
+				flags, buffer_type);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to get device address: %d\n",
 			rc);
@@ -202,10 +236,18 @@
 
 static void free_ion_mem(struct smem_client *client, struct msm_smem *mem)
 {
+	int domain, partition, rc;
+
+	rc = msm_smem_get_domain_partition((void *)client, mem->flags,
+			mem->buffer_type, &domain, &partition);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to get domain, partition: %d", rc);
+		return;
+	}
+
 	if (mem->device_addr)
 		put_device_address(client->clnt,
-			mem->smem_priv, mem->domain,
-			mem->partition_num, mem->flags);
+			mem->smem_priv, domain, partition, mem->flags);
 	if (mem->kvaddr)
 		ion_unmap_kernel(client->clnt, mem->smem_priv);
 	if (mem->smem_priv)
@@ -227,7 +269,7 @@
 }
 
 struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset,
-	int domain, int partition, int flags)
+		enum hal_buffer buffer_type)
 {
 	struct smem_client *client = clt;
 	int rc = 0;
@@ -243,8 +285,7 @@
 	}
 	switch (client->mem_type) {
 	case SMEM_ION:
-		rc = ion_user_to_kernel(clt, fd, offset,
-			domain, partition, mem, flags);
+		rc = ion_user_to_kernel(clt, fd, offset, mem, buffer_type);
 		break;
 	default:
 		dprintk(VIDC_ERR, "Mem type not supported\n");
@@ -337,7 +378,8 @@
 	return rc;
 }
 
-void *msm_smem_new_client(enum smem_type mtype)
+void *msm_smem_new_client(enum smem_type mtype,
+		struct msm_vidc_platform_resources *res)
 {
 	struct smem_client *client = NULL;
 	void *clnt = NULL;
@@ -354,6 +396,7 @@
 		if (client) {
 			client->mem_type = mtype;
 			client->clnt = clnt;
+			client->res = res;
 		}
 	} else {
 		dprintk(VIDC_ERR, "Failed to create new client: mtype = %d\n",
@@ -363,7 +406,7 @@
 };
 
 struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
-		int domain, int partition, int map_kernel)
+		enum hal_buffer buffer_type, int map_kernel)
 {
 	struct smem_client *client;
 	int rc = 0;
@@ -385,8 +428,8 @@
 	}
 	switch (client->mem_type) {
 	case SMEM_ION:
-		rc = alloc_ion_mem(client, size, align, flags,
-			domain, partition, mem, map_kernel);
+		rc = alloc_ion_mem(client, size, align, flags, buffer_type,
+					mem, map_kernel);
 		break;
 	default:
 		dprintk(VIDC_ERR, "Mem type not supported\n");
@@ -436,3 +479,36 @@
 	}
 	kfree(client);
 }
+
+int msm_smem_get_domain_partition(void *clt, u32 flags, enum hal_buffer
+		buffer_type, int *domain_num, int *partition_num)
+{
+	struct smem_client *client = clt;
+	struct iommu_set *iommu_group_set = &client->res->iommu_group_set;
+	int i;
+	bool is_secure = (flags & SMEM_SECURE);
+	struct iommu_info *iommu_map;
+
+	*domain_num = -1;
+	*partition_num = -1;
+	if (!iommu_group_set) {
+		dprintk(VIDC_DBG, "no iommu group set present!\n");
+		return -ENOENT;
+	}
+
+	for (i = 0; i < iommu_group_set->count; i++) {
+		iommu_map = &iommu_group_set->iommu_maps[i];
+		if ((iommu_map->is_secure == is_secure) &&
+			(iommu_map->buffer_type & buffer_type)) {
+			*domain_num = iommu_map->domain;
+			*partition_num = 0;
+			if ((buffer_type & HAL_BUFFER_INTERNAL_CMD_QUEUE) &&
+				(iommu_map->npartitions == 2))
+				*partition_num = 1;
+			break;
+		}
+	}
+	dprintk(VIDC_DBG, "domain: %d, partition: %d found!\n",
+			*domain_num, *partition_num);
+	return 0;
+}
diff --git a/drivers/media/platform/msm/vidc/msm_smem.h b/drivers/media/platform/msm/vidc/msm_smem.h
index d1c8293..b80d63e 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.h
+++ b/drivers/media/platform/msm/vidc/msm_smem.h
@@ -15,15 +15,32 @@
 
 #include <linux/types.h>
 #include <linux/msm_ion.h>
+#include "msm_vidc_resources.h"
+
+#define HAL_BUFFER_MAX 0xb
 
 enum smem_type {
 	SMEM_ION,
 };
 
 enum smem_prop {
-	SMEM_CACHED = 0x1,
-	SMEM_SECURE = 0x2,
-	SMEM_INPUT = 0x4,
+	SMEM_CACHED = ION_FLAG_CACHED,
+	SMEM_SECURE = ION_SECURE,
+};
+
+enum hal_buffer {
+	HAL_BUFFER_INPUT = 0x1,
+	HAL_BUFFER_OUTPUT = 0x2,
+	HAL_BUFFER_OUTPUT2 = 0x2,
+	HAL_BUFFER_EXTRADATA_INPUT = 0x4,
+	HAL_BUFFER_EXTRADATA_OUTPUT = 0x8,
+	HAL_BUFFER_EXTRADATA_OUTPUT2 = 0x8,
+	HAL_BUFFER_INTERNAL_SCRATCH = 0x10,
+	HAL_BUFFER_INTERNAL_SCRATCH_1 = 0x20,
+	HAL_BUFFER_INTERNAL_SCRATCH_2 = 0x40,
+	HAL_BUFFER_INTERNAL_PERSIST = 0x80,
+	HAL_BUFFER_INTERNAL_PERSIST_1 = 0x100,
+	HAL_BUFFER_INTERNAL_CMD_QUEUE = 0x200,
 };
 
 struct msm_smem {
@@ -31,10 +48,9 @@
 	size_t size;
 	void *kvaddr;
 	unsigned long device_addr;
-	int domain;
-	int partition_num;
-	int flags;
+	u32 flags;
 	void *smem_priv;
+	enum hal_buffer buffer_type;
 };
 
 enum smem_cache_ops {
@@ -43,14 +59,17 @@
 	SMEM_CACHE_CLEAN_INVALIDATE,
 };
 
-
-void *msm_smem_new_client(enum smem_type mtype);
+void *msm_smem_new_client(enum smem_type mtype,
+				struct msm_vidc_platform_resources *res);
 struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
-		int domain, int partition, int map_kernel);
+		enum hal_buffer buffer_type, int map_kernel);
 void msm_smem_free(void *clt, struct msm_smem *mem);
 void msm_smem_delete_client(void *clt);
-struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset, int
-		domain, int partition, int flags);
 int msm_smem_cache_operations(void *clt, struct msm_smem *mem,
 		enum smem_cache_ops);
+struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset,
+				enum hal_buffer buffer_type);
+int msm_smem_clean_invalidate(void *clt, struct msm_smem *mem);
+int msm_smem_get_domain_partition(void *clt, u32 flags, enum hal_buffer
+		buffer_type, int *domain_num, int *partition_num);
 #endif
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index 181b2b6..4f8c257 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -227,7 +227,7 @@
 		rc = -ENOMEM;
 		goto fail_nomem;
 	}
-	v4l2_inst->mem_client = msm_smem_new_client(SMEM_ION);
+	v4l2_inst->mem_client = msm_smem_new_client(SMEM_ION, &core->resources);
 	if (!v4l2_inst->mem_client) {
 		dprintk(VIDC_ERR, "Failed to create memory client\n");
 		rc = -ENOMEM;
@@ -400,9 +400,8 @@
 	struct msm_v4l2_vid_inst *v4l2_inst;
 	int plane = 0;
 	int i, rc = 0;
-	int smem_flags = 0;
-	int domain;
 	struct hfi_device *hdev;
+	enum hal_buffer buffer_type;
 
 	vidc_inst = get_vidc_inst(file, fh);
 	v4l2_inst = get_v4l2_inst(file, fh);
@@ -432,7 +431,7 @@
 		goto exit;
 	}
 	for (i = 0; i < b->length; ++i) {
-		smem_flags = 0;
+		buffer_type = HAL_BUFFER_OUTPUT;
 		if (EXTRADATA_IDX(b->length) &&
 			(i == EXTRADATA_IDX(b->length)) &&
 			!b->m.planes[i].length) {
@@ -449,18 +448,8 @@
 			kfree(binfo);
 			goto exit;
 		}
-		if ((vidc_inst->mode == VIDC_SECURE)
-				&& (!EXTRADATA_IDX(b->length)
-					|| (i != EXTRADATA_IDX(b->length)))) {
-			smem_flags |= SMEM_SECURE;
-			domain = call_hfi_op(hdev, get_domain,
-					hdev->hfi_device_data, CP_MAP);
-		} else
-			domain = call_hfi_op(hdev, get_domain,
-					hdev->hfi_device_data, NS_MAP);
-
 		if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
-			smem_flags |= SMEM_INPUT;
+			buffer_type = HAL_BUFFER_INPUT;
 
 		temp = get_same_fd_buffer(&v4l2_inst->registered_bufs,
 				b->m.planes[i].reserved[0], &plane);
@@ -476,9 +465,9 @@
 			binfo->handle[i] = NULL;
 		} else {
 			handle = msm_smem_user_to_kernel(v4l2_inst->mem_client,
-			b->m.planes[i].reserved[0],
-			b->m.planes[i].reserved[1],
-			domain,	0, smem_flags);
+					b->m.planes[i].reserved[0],
+					b->m.planes[i].reserved[1],
+					buffer_type);
 			if (!handle) {
 				dprintk(VIDC_ERR,
 					"Failed to get device buffer address\n");
@@ -796,13 +785,6 @@
 	res->load_freq_tbl = NULL;
 }
 
-static inline void msm_vidc_free_iommu_maps(
-		struct msm_vidc_platform_resources *res)
-{
-	kfree(res->iommu_maps);
-	res->iommu_maps = NULL;
-}
-
 static inline void msm_vidc_free_reg_table(
 			struct msm_vidc_platform_resources *res)
 {
@@ -828,6 +810,20 @@
 	}
 }
 
+static inline void msm_vidc_free_iommu_groups(
+			struct msm_vidc_platform_resources *res)
+{
+	kfree(res->iommu_group_set.iommu_maps);
+	res->iommu_group_set.iommu_maps = NULL;
+}
+
+static inline void msm_vidc_free_buffer_usage_table(
+			struct msm_vidc_platform_resources *res)
+{
+	kfree(res->buffer_usage_set.buffer_usage_tbl);
+	res->buffer_usage_set.buffer_usage_tbl = NULL;
+}
+
 static int msm_vidc_load_freq_table(struct msm_vidc_platform_resources *res)
 {
 	int rc = 0;
@@ -861,60 +857,6 @@
 	return rc;
 }
 
-static int msm_vidc_load_iommu_maps(struct msm_vidc_platform_resources *res)
-{
-	int rc = 0;
-	int num_elements = 0;
-	int i;
-	struct platform_device *pdev = res->pdev;
-	char *names[MAX_MAP] = {
-		[CP_MAP] = "qcom,vidc-cp-map",
-		[NS_MAP] = "qcom,vidc-ns-map",
-	};
-	char *contexts[MAX_MAP] = {
-		[CP_MAP] = "venus_cp",
-		[NS_MAP] = "venus_ns",
-	};
-
-
-	res->iommu_maps = kzalloc(MAX_MAP * sizeof(*res->iommu_maps),
-			GFP_KERNEL);
-	if (!res->iommu_maps) {
-		dprintk(VIDC_ERR, "%s Failed to alloc iommu_maps\n", __func__);
-		return -ENOMEM;
-	}
-
-	res->iommu_maps_size = MAX_MAP;
-	for (i = 0; i < MAX_MAP; i++) {
-		num_elements = get_u32_array_num_elements(pdev, names[i]);
-		if ((num_elements == 0)) {
-			if (i == NS_MAP) {
-				dprintk(VIDC_ERR,
-				"Domain not found in dtsi file :%s\n",
-				names[i]);
-				goto error;
-			} else
-				continue;
-		}
-		memcpy(&res->iommu_maps[i].name, names[i],
-				strlen(names[i]));
-		memcpy(&res->iommu_maps[i].ctx, contexts[i],
-				strlen(contexts[i]));
-
-		if (of_property_read_u32_array(pdev->dev.of_node, names[i],
-			res->iommu_maps[i].addr_range, num_elements * 2)) {
-			dprintk(VIDC_ERR, "Failed to read iommu map :%s\n",
-					names[i]);
-			rc = -EINVAL;
-			goto error;
-		}
-	}
-	return rc;
-error:
-	msm_vidc_free_iommu_maps(res);
-	return rc;
-}
-
 static int msm_vidc_load_reg_table(struct msm_vidc_platform_resources *res)
 {
 	struct reg_set *reg_set;
@@ -932,7 +874,7 @@
 	reg_set->reg_tbl = kzalloc(reg_set->count *
 			sizeof(*(reg_set->reg_tbl)), GFP_KERNEL);
 	if (!reg_set->reg_tbl) {
-		dprintk(VIDC_ERR, "%s Failed to alloc temp\n",
+		dprintk(VIDC_ERR, "%s Failed to alloc register table\n",
 			__func__);
 		return -ENOMEM;
 	}
@@ -1091,6 +1033,153 @@
 	return rc;
 }
 
+static int msm_vidc_load_iommu_groups(struct msm_vidc_platform_resources *res)
+{
+	int rc = 0;
+	struct platform_device *pdev = res->pdev;
+	struct device_node *ctx_node;
+	struct iommu_set *iommu_group_set = &res->iommu_group_set;
+	int array_size;
+	int i;
+	struct iommu_info *iommu_map;
+	u32 *buffer_types = NULL;
+
+	if (!of_get_property(pdev->dev.of_node, "qcom,iommu-groups",
+				&array_size)) {
+		dprintk(VIDC_ERR, "Could not find iommu_groups property\n");
+		iommu_group_set->count = 0;
+		rc = -ENOENT;
+		goto err_no_of_node;
+	}
+
+	iommu_group_set->count = array_size / sizeof(u32);
+	if (iommu_group_set->count == 0) {
+		dprintk(VIDC_ERR, "No group present in iommu_groups\n");
+		rc = -ENOENT;
+		goto err_no_of_node;
+	}
+
+	iommu_group_set->iommu_maps = kzalloc(iommu_group_set->count *
+			sizeof(*(iommu_group_set->iommu_maps)), GFP_KERNEL);
+	if (!iommu_group_set->iommu_maps) {
+		dprintk(VIDC_ERR, "%s Failed to alloc iommu_maps\n",
+			__func__);
+		rc = -ENOMEM;
+		goto err_no_of_node;
+	}
+
+	buffer_types = kzalloc(iommu_group_set->count * sizeof(*buffer_types),
+				GFP_KERNEL);
+	if (!buffer_types) {
+		dprintk(VIDC_ERR,
+			"%s Failed to alloc iommu group buffer types\n",
+			__func__);
+		rc = -ENOMEM;
+		goto err_load_groups;
+	}
+
+	rc = of_property_read_u32_array(pdev->dev.of_node,
+			"qcom,iommu-group-buffer-types", buffer_types,
+			iommu_group_set->count);
+	if (rc) {
+		dprintk(VIDC_ERR,
+		    "%s Failed to read iommu group buffer types\n", __func__);
+		goto err_load_groups;
+	}
+
+	for (i = 0; i < iommu_group_set->count; i++) {
+		iommu_map = &iommu_group_set->iommu_maps[i];
+		ctx_node = of_parse_phandle(pdev->dev.of_node,
+				"qcom,iommu-groups", i);
+		if (!ctx_node) {
+			dprintk(VIDC_ERR, "Unable to parse phandle : %u\n", i);
+			rc = -EBADHANDLE;
+			goto err_load_groups;
+		}
+
+		rc = of_property_read_string(ctx_node, "label",
+				&(iommu_map->name));
+		if (rc) {
+			dprintk(VIDC_ERR, "Could not find label property\n");
+			goto err_load_groups;
+		}
+
+		if (!of_get_property(ctx_node, "qcom,virtual-addr-pool",
+				&array_size)) {
+			dprintk(VIDC_ERR,
+				"Could not find any addr pool for group : %s\n",
+				iommu_map->name);
+			rc = -EBADHANDLE;
+			goto err_load_groups;
+		}
+
+		iommu_map->npartitions = array_size / sizeof(u32) / 2;
+
+		rc = of_property_read_u32_array(ctx_node,
+				"qcom,virtual-addr-pool",
+				(u32 *)iommu_map->addr_range,
+				iommu_map->npartitions * 2);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Could not read addr pool for group : %s\n",
+				iommu_map->name);
+			goto err_load_groups;
+		}
+
+		iommu_map->buffer_type = buffer_types[i];
+		iommu_map->is_secure =
+			of_property_read_bool(ctx_node,	"qcom,secure-domain");
+	}
+	kfree(buffer_types);
+	return 0;
+err_load_groups:
+	kfree(buffer_types);
+	msm_vidc_free_iommu_groups(res);
+err_no_of_node:
+	return rc;
+}
+
+static int msm_vidc_load_buffer_usage_table(
+		struct msm_vidc_platform_resources *res)
+{
+	int rc = 0;
+	struct platform_device *pdev = res->pdev;
+	struct buffer_usage_set *buffer_usage_set = &res->buffer_usage_set;
+
+	buffer_usage_set->count = get_u32_array_num_elements(
+				    pdev, "qcom,buffer-type-tz-usage-table");
+	if (buffer_usage_set->count == 0) {
+		dprintk(VIDC_DBG, "no elements in buffer usage set\n");
+		return 0;
+	}
+
+	buffer_usage_set->buffer_usage_tbl = kzalloc(buffer_usage_set->count *
+			sizeof(*(buffer_usage_set->buffer_usage_tbl)),
+			GFP_KERNEL);
+	if (!buffer_usage_set->buffer_usage_tbl) {
+		dprintk(VIDC_ERR, "%s Failed to alloc buffer usage table\n",
+			__func__);
+		rc = -ENOMEM;
+		goto err_load_buf_usage;
+	}
+
+	rc = of_property_read_u32_array(pdev->dev.of_node,
+		    "qcom,buffer-type-tz-usage-table",
+		(u32 *)buffer_usage_set->buffer_usage_tbl,
+		buffer_usage_set->count *
+		(sizeof(*buffer_usage_set->buffer_usage_tbl)/sizeof(u32)));
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to read buffer usage table\n");
+		goto err_load_buf_usage;
+	}
+
+	return 0;
+err_load_buf_usage:
+	msm_vidc_free_buffer_usage_table(res);
+	return rc;
+}
+
+
 static int read_platform_resources_from_dt(
 		struct msm_vidc_platform_resources *res)
 {
@@ -1117,29 +1206,36 @@
 		dprintk(VIDC_ERR, "Failed to load freq table: %d\n", rc);
 		goto err_load_freq_table;
 	}
-	rc = msm_vidc_load_iommu_maps(res);
-	if (rc) {
-		dprintk(VIDC_ERR, "Failed to load iommu maps: %d\n", rc);
-		goto err_load_iommu_maps;
-	}
 	rc = msm_vidc_load_reg_table(res);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to load reg table: %d\n", rc);
 		goto err_load_reg_table;
 	}
-
 	rc = msm_vidc_load_bus_vectors(res);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to load bus vectors: %d\n", rc);
 		goto err_load_bus_vectors;
 	}
+	rc = msm_vidc_load_iommu_groups(res);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to load iommu groups: %d\n", rc);
+		goto err_load_iommu_groups;
+	}
+	rc = msm_vidc_load_buffer_usage_table(res);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to load buffer usage table: %d\n", rc);
+		goto err_load_buffer_usage_table;
+	}
 	return rc;
 
+err_load_buffer_usage_table:
+	msm_vidc_free_iommu_groups(res);
+err_load_iommu_groups:
+	msm_vidc_free_bus_vectors(res);
 err_load_bus_vectors:
 	msm_vidc_free_reg_table(res);
 err_load_reg_table:
-	msm_vidc_free_iommu_maps(res);
-err_load_iommu_maps:
 	msm_vidc_free_freq_table(res);
 err_load_freq_table:
 	return rc;
@@ -1151,7 +1247,6 @@
 	struct resource *kres = NULL;
 	struct platform_device *pdev = res->pdev;
 	struct msm_vidc_v4l2_platform_data *pdata = pdev->dev.platform_data;
-	int64_t start, size;
 	int c = 0, rc = 0;
 
 	if (!pdata) {
@@ -1182,33 +1277,6 @@
 		res->load_freq_tbl[c].load = pdata->load_table[c][0];
 		res->load_freq_tbl[c].freq = pdata->load_table[c][1];
 	}
-
-	res->iommu_maps = kzalloc(MAX_MAP *
-			sizeof(*res->iommu_maps), GFP_KERNEL);
-	if (!res->iommu_maps) {
-		dprintk(VIDC_ERR, "%s Failed to alloc iommu_maps\n",
-				__func__);
-		kfree(res->load_freq_tbl);
-		return -ENOMEM;
-	}
-
-	res->iommu_maps_size = MAX_MAP;
-
-	start = pdata->iommu_table[MSM_VIDC_V4L2_IOMMU_MAP_CP][0];
-	size = pdata->iommu_table[MSM_VIDC_V4L2_IOMMU_MAP_CP][1];
-	res->iommu_maps[CP_MAP] = (struct msm_vidc_iommu_info) {
-		.addr_range = {(u32) start, (u32) size},
-			.name = "qcom,vidc-cp-map",
-			.ctx = "venus_cp",
-	};
-
-	start = pdata->iommu_table[MSM_VIDC_V4L2_IOMMU_MAP_NS][0];
-	size = pdata->iommu_table[MSM_VIDC_V4L2_IOMMU_MAP_NS][1];
-	res->iommu_maps[NS_MAP] = (struct msm_vidc_iommu_info) {
-		.addr_range = {(u32) start, (u32) size},
-			.name = "qcom,vidc-ns-map",
-			.ctx = "venus_ns",
-	};
 	return rc;
 }
 
@@ -1365,9 +1433,10 @@
 	v4l2_device_unregister(&core->v4l2_dev);
 
 	msm_vidc_free_freq_table(&core->resources);
-	msm_vidc_free_iommu_maps(&core->resources);
 	msm_vidc_free_reg_table(&core->resources);
 	msm_vidc_free_bus_vectors(&core->resources);
+	msm_vidc_free_iommu_groups(&core->resources);
+	msm_vidc_free_buffer_usage_table(&core->resources);
 	kfree(core);
 	return rc;
 }
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index ae98afb..5966d12 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -584,6 +584,7 @@
 	int rc = 0;
 	int ret;
 	int i;
+	struct hal_buffer_requirements *buff_req_buffer;
 	if (!inst || !f || !inst->core || !inst->core->device) {
 		dprintk(VIDC_ERR,
 			"Invalid input, inst = %p, format = %p\n", inst, f);
@@ -636,12 +637,26 @@
 				dprintk(VIDC_WARN,
 					"Color format not recognized\n");
 			}
-			f->fmt.pix_mp.plane_fmt[0].sizeimage =
-			inst->buff_req.buffer[HAL_BUFFER_OUTPUT].buffer_size;
+			buff_req_buffer =
+				get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+			if (buff_req_buffer)
+				f->fmt.pix_mp.plane_fmt[0].sizeimage =
+				buff_req_buffer->buffer_size;
+			else
+				f->fmt.pix_mp.plane_fmt[0].sizeimage = 0;
+
 			extra_idx = EXTRADATA_IDX(fmt->num_planes);
 			if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
-				f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
-		inst->buff_req.buffer[HAL_BUFFER_EXTRADATA_OUTPUT].buffer_size;
+				buff_req_buffer =
+					get_buff_req_buffer(inst,
+					HAL_BUFFER_EXTRADATA_OUTPUT);
+				if (buff_req_buffer)
+					f->fmt.pix_mp.plane_fmt[extra_idx].
+						sizeimage =
+						buff_req_buffer->buffer_size;
+				else
+					f->fmt.pix_mp.plane_fmt[extra_idx].
+						sizeimage = 0;
 			}
 			for (i = 0; i < fmt->num_planes; ++i)
 				inst->bufq[CAPTURE_PORT].
@@ -708,6 +723,7 @@
 	int rc = 0;
 	int ret = 0;
 	int i;
+	struct hal_buffer_requirements *buff_req_buffer;
 	if (!inst || !f) {
 		dprintk(VIDC_ERR,
 			"Invalid input, inst = %p, format = %p\n", inst, f);
@@ -743,12 +759,24 @@
 						f->fmt.pix_mp.width);
 			}
 		} else {
-			f->fmt.pix_mp.plane_fmt[0].sizeimage =
-			inst->buff_req.buffer[HAL_BUFFER_OUTPUT].buffer_size;
+			buff_req_buffer =
+				get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+			if (buff_req_buffer)
+				f->fmt.pix_mp.plane_fmt[0].sizeimage =
+				buff_req_buffer->buffer_size;
+			else
+				f->fmt.pix_mp.plane_fmt[0].sizeimage = 0;
 			extra_idx = EXTRADATA_IDX(fmt->num_planes);
 			if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
-				f->fmt.pix_mp.plane_fmt[1].sizeimage =
-		inst->buff_req.buffer[HAL_BUFFER_EXTRADATA_OUTPUT].buffer_size;
+				buff_req_buffer =
+					get_buff_req_buffer(inst,
+					HAL_BUFFER_EXTRADATA_OUTPUT);
+				if (buff_req_buffer)
+					f->fmt.pix_mp.plane_fmt[1].sizeimage =
+					buff_req_buffer->buffer_size;
+				else
+					f->fmt.pix_mp.plane_fmt[1].sizeimage =
+					0;
 			}
 		}
 		f->fmt.pix_mp.num_planes = fmt->num_planes;
@@ -893,9 +921,16 @@
 			break;
 		}
 		mutex_lock(&inst->lock);
+		bufreq = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+		if (!bufreq) {
+			dprintk(VIDC_ERR,
+				"No buffer requirement for buffer type %x\n",
+				HAL_BUFFER_OUTPUT);
+			rc = -EINVAL;
+			break;
+		}
 		if (*num_buffers && *num_buffers >
-			inst->buff_req.buffer[HAL_BUFFER_OUTPUT].
-				buffer_count_actual) {
+			bufreq->buffer_count_actual) {
 			struct hal_buffer_count_actual new_buf_count;
 			enum hal_property property_id =
 				HAL_PARAM_BUFFER_COUNT_ACTUAL;
@@ -906,22 +941,25 @@
 				inst->session, property_id, &new_buf_count);
 
 		}
-		bufreq = &inst->buff_req.buffer[HAL_BUFFER_OUTPUT];
 		if (bufreq->buffer_count_actual > *num_buffers)
 			*num_buffers =  bufreq->buffer_count_actual;
 		else
-			bufreq->buffer_count_actual = *num_buffers ;
+			bufreq->buffer_count_actual = *num_buffers;
 		mutex_unlock(&inst->lock);
 		dprintk(VIDC_DBG, "count =  %d, size = %d, alignment = %d\n",
 				inst->buff_req.buffer[1].buffer_count_actual,
 				inst->buff_req.buffer[1].buffer_size,
 				inst->buff_req.buffer[1].buffer_alignment);
-		sizes[0] = inst->buff_req.buffer[HAL_BUFFER_OUTPUT].buffer_size;
+		sizes[0] = bufreq->buffer_size;
 		extra_idx =
 			EXTRADATA_IDX(inst->fmts[CAPTURE_PORT]->num_planes);
 		if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
-			sizes[extra_idx] =
-		inst->buff_req.buffer[HAL_BUFFER_EXTRADATA_OUTPUT].buffer_size;
+			bufreq = get_buff_req_buffer(inst,
+					HAL_BUFFER_EXTRADATA_OUTPUT);
+			if (bufreq)
+				sizes[extra_idx] = bufreq->buffer_size;
+			else
+				sizes[extra_idx] = 0;
 		}
 		break;
 	default:
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 042900e..218987e 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -82,18 +82,16 @@
 	return rc;
 }
 
-int msm_vidc_get_iommu_maps(void *instance,
-		struct msm_vidc_iommu_info maps[MAX_MAP])
+int msm_vidc_get_iommu_domain_partition(void *instance, u32 flags,
+		enum v4l2_buf_type buf_type, int *domain, int *partition)
 {
 	struct msm_vidc_inst *inst = instance;
-	struct hfi_device *hdev;
 
-	if (!inst || !maps || !inst->core || !inst->core->device)
+	if (!inst || !inst->core || !inst->core->device)
 		return -EINVAL;
 
-	hdev = inst->core->device;
-
-	return call_hfi_op(hdev, iommu_get_map, hdev->hfi_device_data, maps);
+	return msm_comm_get_domain_partition(inst, flags, buf_type, domain,
+		partition);
 }
 
 int msm_vidc_querycap(void *instance, struct v4l2_capability *cap)
@@ -436,7 +434,8 @@
 		i <= SESSION_MSG_INDEX(SESSION_MSG_END); i++) {
 		init_completion(&inst->completions[i]);
 	}
-	inst->mem_client = msm_smem_new_client(SMEM_ION);
+	inst->mem_client = msm_smem_new_client(SMEM_ION,
+					&inst->core->resources);
 	if (!inst->mem_client) {
 		dprintk(VIDC_ERR, "Failed to create memory client\n");
 		goto fail_mem_client;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index d43e5ba..e55c0f1 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -193,7 +193,7 @@
 }
 
 struct buf_queue *msm_comm_get_vb2q(
-		struct msm_vidc_inst *inst,	enum v4l2_buf_type type)
+		struct msm_vidc_inst *inst, enum v4l2_buf_type type)
 {
 	if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
 		return &inst->bufq[CAPTURE_PORT];
@@ -417,7 +417,7 @@
 	memcpy(&inst->buff_req, response->data,
 			sizeof(struct buffer_requirements));
 	mutex_unlock(&inst->lock);
-	for (i = 0; i < 8; i++) {
+	for (i = 0; i < HAL_BUFFER_MAX; i++) {
 		dprintk(VIDC_DBG,
 			"buffer type: %d, count : %d, size: %d\n",
 			inst->buff_req.buffer[i].buffer_type,
@@ -1123,8 +1123,8 @@
 		}
 		mutex_lock(&core->lock);
 		core->state = VIDC_CORE_UNINIT;
-		call_hfi_op(hdev, unload_fw, hdev->hfi_device_data);
 		mutex_unlock(&core->lock);
+		call_hfi_op(hdev, unload_fw, hdev->hfi_device_data);
 		msm_comm_unvote_buses(core, DDR_MEM|OCMEM_MEM);
 	}
 core_already_uninited:
@@ -1443,6 +1443,186 @@
 	return flipped_state;
 }
 
+struct hal_buffer_requirements *get_buff_req_buffer(
+		struct msm_vidc_inst *inst, enum hal_buffer buffer_type)
+{
+	int i;
+	for (i = 0; i < HAL_BUFFER_MAX; i++) {
+		if (inst->buff_req.buffer[i].buffer_type == buffer_type)
+			return &inst->buff_req.buffer[i];
+	}
+	return NULL;
+}
+
+static int set_scratch_buffers(struct msm_vidc_inst *inst,
+	enum hal_buffer buffer_type)
+{
+	int rc = 0;
+	struct msm_smem *handle;
+	struct internal_buf *binfo;
+	struct vidc_buffer_addr_info buffer_info;
+	u32 smem_flags = 0;
+	struct hal_buffer_requirements *scratch_buf;
+	int i;
+	struct hfi_device *hdev;
+
+	hdev = inst->core->device;
+
+	scratch_buf = get_buff_req_buffer(inst, buffer_type);
+	if (!scratch_buf) {
+		dprintk(VIDC_DBG,
+			"This scratch buffer not required, buffer_type: %x\n",
+			buffer_type);
+		return 0;
+	}
+	dprintk(VIDC_DBG,
+		"scratch: num = %d, size = %d\n",
+		scratch_buf->buffer_count_actual,
+		scratch_buf->buffer_size);
+
+	if (inst->mode == VIDC_SECURE)
+		smem_flags |= SMEM_SECURE;
+
+	if (scratch_buf->buffer_size) {
+		for (i = 0; i < scratch_buf->buffer_count_actual;
+				i++) {
+			handle = msm_smem_alloc(inst->mem_client,
+				scratch_buf->buffer_size, 1, smem_flags,
+				buffer_type, 0);
+			if (!handle) {
+				dprintk(VIDC_ERR,
+					"Failed to allocate scratch memory\n");
+				rc = -ENOMEM;
+				goto err_no_mem;
+			}
+			rc = msm_smem_cache_operations(inst->mem_client,
+					handle, SMEM_CACHE_CLEAN);
+			if (rc) {
+				dprintk(VIDC_WARN,
+				"Failed to clean cache may cause undefined behavior\n");
+			}
+			binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+			if (!binfo) {
+				dprintk(VIDC_ERR, "Out of memory\n");
+				rc = -ENOMEM;
+				goto fail_kzalloc;
+			}
+			binfo->handle = handle;
+			buffer_info.buffer_size = scratch_buf->buffer_size;
+			buffer_info.buffer_type = buffer_type;
+			binfo->buffer_type = buffer_type;
+			buffer_info.num_buffers = 1;
+			buffer_info.align_device_addr = handle->device_addr;
+			dprintk(VIDC_DBG, "Scratch buffer address: %x",
+					buffer_info.align_device_addr);
+			rc = call_hfi_op(hdev, session_set_buffers,
+				(void *) inst->session, &buffer_info);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"vidc_hal_session_set_buffers failed");
+				goto fail_set_buffers;
+			}
+			mutex_lock(&inst->lock);
+			list_add_tail(&binfo->list, &inst->internalbufs);
+			mutex_unlock(&inst->lock);
+		}
+	}
+	return rc;
+fail_set_buffers:
+	kfree(binfo);
+fail_kzalloc:
+	msm_smem_free(inst->mem_client, handle);
+err_no_mem:
+	return rc;
+}
+
+static int set_persist_buffers(struct msm_vidc_inst *inst,
+	enum hal_buffer buffer_type)
+{
+	int rc = 0;
+	struct msm_smem *handle;
+	struct internal_buf *binfo;
+	struct vidc_buffer_addr_info buffer_info;
+	u32 smem_flags = 0;
+	struct hal_buffer_requirements *persist_buf;
+	int i;
+	struct hfi_device *hdev;
+
+	hdev = inst->core->device;
+
+	persist_buf = get_buff_req_buffer(inst, buffer_type);
+	if (!persist_buf) {
+		dprintk(VIDC_DBG,
+			"This persist buffer not required, buffer_type: %x\n",
+			buffer_type);
+		return 0;
+	}
+
+	dprintk(VIDC_DBG,
+		"persist: num = %d, size = %d\n",
+		persist_buf->buffer_count_actual,
+		persist_buf->buffer_size);
+	if (!list_empty(&inst->persistbufs)) {
+		dprintk(VIDC_ERR,
+			"Persist buffers already allocated\n");
+		return rc;
+	}
+
+	if (inst->mode == VIDC_SECURE)
+		smem_flags |= SMEM_SECURE;
+
+	if (persist_buf->buffer_size) {
+		for (i = 0; i < persist_buf->buffer_count_actual; i++) {
+			handle = msm_smem_alloc(inst->mem_client,
+				persist_buf->buffer_size, 1, smem_flags,
+				buffer_type, 0);
+			if (!handle) {
+				dprintk(VIDC_ERR,
+					"Failed to allocate persist memory\n");
+				rc = -ENOMEM;
+				goto err_no_mem;
+			}
+			rc = msm_smem_cache_operations(inst->mem_client,
+					handle, SMEM_CACHE_CLEAN);
+			if (rc) {
+				dprintk(VIDC_WARN,
+				"Failed to clean cache may cause undefined behavior\n");
+			}
+			binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+			if (!binfo) {
+				dprintk(VIDC_ERR, "Out of memory\n");
+				rc = -ENOMEM;
+				goto fail_kzalloc;
+			}
+			binfo->handle = handle;
+			buffer_info.buffer_size = persist_buf->buffer_size;
+			buffer_info.buffer_type = buffer_type;
+			binfo->buffer_type = buffer_type;
+			buffer_info.num_buffers = 1;
+			buffer_info.align_device_addr = handle->device_addr;
+			dprintk(VIDC_DBG, "Persist buffer address: %x",
+					buffer_info.align_device_addr);
+			rc = call_hfi_op(hdev, session_set_buffers,
+					(void *) inst->session, &buffer_info);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"vidc_hal_session_set_buffers failed");
+				goto fail_set_buffers;
+			}
+			mutex_lock(&inst->lock);
+			list_add_tail(&binfo->list, &inst->persistbufs);
+			mutex_unlock(&inst->lock);
+		}
+	}
+	return rc;
+fail_set_buffers:
+	kfree(binfo);
+fail_kzalloc:
+	msm_smem_free(inst->mem_client, handle);
+err_no_mem:
+	return rc;
+}
+
 int msm_comm_try_state(struct msm_vidc_inst *inst, int state)
 {
 	int rc = 0;
@@ -1723,6 +1903,7 @@
 	mutex_unlock(&inst->sync_lock);
 	return rc;
 }
+
 int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst)
 {
 	struct msm_smem *handle;
@@ -1755,7 +1936,7 @@
 					list);
 			handle = buf->handle;
 			buffer_info.buffer_size = handle->size;
-			buffer_info.buffer_type = HAL_BUFFER_INTERNAL_SCRATCH;
+			buffer_info.buffer_type = buf->buffer_type;
 			buffer_info.num_buffers = 1;
 			buffer_info.align_device_addr = handle->device_addr;
 			if (inst->state != MSM_VIDC_CORE_INVALID &&
@@ -1819,7 +2000,7 @@
 					list);
 			handle = buf->handle;
 			buffer_info.buffer_size = handle->size;
-			buffer_info.buffer_type = HAL_BUFFER_INTERNAL_PERSIST;
+			buffer_info.buffer_type = buf->buffer_type;
 			buffer_info.num_buffers = 1;
 			buffer_info.align_device_addr = handle->device_addr;
 			if (inst->state != MSM_VIDC_CORE_INVALID &&
@@ -1885,178 +2066,50 @@
 int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst)
 {
 	int rc = 0;
-	struct msm_smem *handle;
-	struct internal_buf *binfo;
-	struct vidc_buffer_addr_info buffer_info;
-	int domain;
-	unsigned long smem_flags = 0;
-	struct hal_buffer_requirements *scratch_buf;
-	int i;
-	struct hfi_device *hdev;
-
 	if (!inst || !inst->core || !inst->core->device) {
 		dprintk(VIDC_ERR, "%s invalid parameters", __func__);
 		return -EINVAL;
 	}
 
-	hdev = inst->core->device;
-
-	scratch_buf =
-		&inst->buff_req.buffer[HAL_BUFFER_INTERNAL_SCRATCH];
-	dprintk(VIDC_DBG,
-		"scratch: num = %d, size = %d\n",
-		scratch_buf->buffer_count_actual,
-		scratch_buf->buffer_size);
 	if (msm_comm_release_scratch_buffers(inst))
 		dprintk(VIDC_WARN, "Failed to release scratch buffers\n");
-	if (inst->mode == VIDC_SECURE) {
-		domain = call_hfi_op(hdev, get_domain,
-				hdev->hfi_device_data, CP_MAP);
-		smem_flags |= SMEM_SECURE;
-	} else
-		domain = call_hfi_op(hdev, get_domain,
-				hdev->hfi_device_data, NS_MAP);
 
-	if (scratch_buf->buffer_size) {
-		for (i = 0; i < scratch_buf->buffer_count_actual;
-				i++) {
-			handle = msm_smem_alloc(inst->mem_client,
-				scratch_buf->buffer_size, 1, smem_flags,
-				domain, 0, 0);
-			if (!handle) {
-				dprintk(VIDC_ERR,
-					"Failed to allocate scratch memory\n");
-				rc = -ENOMEM;
-				goto err_no_mem;
-			}
-			rc = msm_smem_cache_operations(inst->mem_client,
-					handle, SMEM_CACHE_CLEAN);
-			if (rc) {
-				dprintk(VIDC_WARN,
-				"Failed to clean cache may cause undefined behavior\n");
-			}
-			binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
-			if (!binfo) {
-				dprintk(VIDC_ERR, "Out of memory\n");
-				rc = -ENOMEM;
-				goto fail_kzalloc;
-			}
-			binfo->handle = handle;
-			buffer_info.buffer_size = scratch_buf->buffer_size;
-			buffer_info.buffer_type = HAL_BUFFER_INTERNAL_SCRATCH;
-			buffer_info.num_buffers = 1;
-			buffer_info.align_device_addr = handle->device_addr;
-			dprintk(VIDC_DBG, "Scratch buffer address: %x",
-					buffer_info.align_device_addr);
-			rc = call_hfi_op(hdev, session_set_buffers,
-				(void *) inst->session, &buffer_info);
-			if (rc) {
-				dprintk(VIDC_ERR,
-					"vidc_hal_session_set_buffers failed");
-				goto fail_set_buffers;
-			}
-			mutex_lock(&inst->lock);
-			list_add_tail(&binfo->list, &inst->internalbufs);
-			mutex_unlock(&inst->lock);
-		}
-	}
+	rc = set_scratch_buffers(inst, HAL_BUFFER_INTERNAL_SCRATCH);
+	if (rc)
+		goto error;
+
+	rc = set_scratch_buffers(inst, HAL_BUFFER_INTERNAL_SCRATCH_1);
+	if (rc)
+		goto error;
+
+	rc = set_scratch_buffers(inst, HAL_BUFFER_INTERNAL_SCRATCH_2);
+	if (rc)
+		goto error;
+
 	return rc;
-fail_set_buffers:
-	kfree(binfo);
-fail_kzalloc:
-	msm_smem_free(inst->mem_client, handle);
-err_no_mem:
+error:
+	msm_comm_release_scratch_buffers(inst);
 	return rc;
 }
 
 int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst)
 {
 	int rc = 0;
-	struct msm_smem *handle;
-	struct internal_buf *binfo;
-	struct vidc_buffer_addr_info buffer_info;
-	unsigned long flags;
-	unsigned long smem_flags = 0;
-	int domain;
-	struct hal_buffer_requirements *persist_buf;
-	int i;
-	struct hfi_device *hdev;
-
 	if (!inst || !inst->core || !inst->core->device) {
 		dprintk(VIDC_ERR, "%s invalid parameters", __func__);
 		return -EINVAL;
 	}
 
-	hdev = inst->core->device;
+	rc = set_persist_buffers(inst, HAL_BUFFER_INTERNAL_PERSIST);
+	if (rc)
+		goto error;
 
-	persist_buf =
-		&inst->buff_req.buffer[HAL_BUFFER_INTERNAL_PERSIST];
-	dprintk(VIDC_DBG,
-		"persist: num = %d, size = %d\n",
-		persist_buf->buffer_count_actual,
-		persist_buf->buffer_size);
-	if (!list_empty(&inst->persistbufs)) {
-		dprintk(VIDC_ERR,
-			"Persist buffers already allocated\n");
-		return rc;
-	}
-
-	if (inst->mode == VIDC_SECURE) {
-		domain = call_hfi_op(hdev, get_domain,
-				hdev->hfi_device_data, CP_MAP);
-		flags |= SMEM_SECURE;
-	} else
-		domain = call_hfi_op(hdev, get_domain,
-				hdev->hfi_device_data, NS_MAP);
-
-	if (persist_buf->buffer_size) {
-		for (i = 0;	i <	persist_buf->buffer_count_actual; i++) {
-			handle = msm_smem_alloc(inst->mem_client,
-				persist_buf->buffer_size, 1, smem_flags,
-				domain, 0, 0);
-			if (!handle) {
-				dprintk(VIDC_ERR,
-					"Failed to allocate persist memory\n");
-				rc = -ENOMEM;
-				goto err_no_mem;
-			}
-			rc = msm_smem_cache_operations(inst->mem_client,
-					handle, SMEM_CACHE_CLEAN);
-			if (rc) {
-				dprintk(VIDC_WARN,
-				"Failed to clean cache may cause undefined behavior\n");
-			}
-			binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
-			if (!binfo) {
-				dprintk(VIDC_ERR, "Out of memory\n");
-				rc = -ENOMEM;
-				goto fail_kzalloc;
-			}
-			binfo->handle = handle;
-			buffer_info.buffer_size = persist_buf->buffer_size;
-			buffer_info.buffer_type = HAL_BUFFER_INTERNAL_PERSIST;
-			buffer_info.num_buffers = 1;
-			buffer_info.align_device_addr = handle->device_addr;
-			dprintk(VIDC_DBG, "Persist buffer address: %x",
-					buffer_info.align_device_addr);
-			rc = call_hfi_op(hdev, session_set_buffers,
-					(void *) inst->session, &buffer_info);
-			if (rc) {
-				dprintk(VIDC_ERR,
-					"vidc_hal_session_set_buffers failed");
-				goto fail_set_buffers;
-			}
-			mutex_lock(&inst->lock);
-			list_add_tail(&binfo->list, &inst->persistbufs);
-			mutex_unlock(&inst->lock);
-		}
-	}
+	rc = set_persist_buffers(inst, HAL_BUFFER_INTERNAL_PERSIST_1);
+	if (rc)
+		goto error;
 	return rc;
-fail_set_buffers:
-	kfree(binfo);
-fail_kzalloc:
-	msm_smem_free(inst->mem_client, handle);
-err_no_mem:
+error:
+	msm_comm_release_persist_buffers(inst);
 	return rc;
 }
 
@@ -2245,6 +2298,41 @@
 	return ret;
 };
 
+int msm_comm_get_domain_partition(struct msm_vidc_inst *inst, u32 flags,
+	enum v4l2_buf_type buf_type, int *domain, int *partition)
+{
+	struct hfi_device *hdev;
+	u32 hal_buffer_type = 0;
+	if (!inst || !inst->core || !inst->core->device)
+		return -EINVAL;
+
+	hdev = inst->core->device;
+
+	/*
+	 * TODO: Due to the way in which the underlying smem mechanism
+	 * maps buffer types to corresponding IOMMU domains, we need to
+	 * pass in HAL_BUFFER_OUTPUT for input buffers (and vice versa)
+	 * so that buffers are mapped into the correct domains. In the
+	 * future, we should try to remove this workaround.
+	 */
+	switch (buf_type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		hal_buffer_type = (inst->session_type == MSM_VIDC_ENCODER) ?
+			HAL_BUFFER_INPUT : HAL_BUFFER_OUTPUT;
+		break;
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		hal_buffer_type = (inst->session_type == MSM_VIDC_ENCODER) ?
+			HAL_BUFFER_OUTPUT : HAL_BUFFER_INPUT;
+		break;
+	default:
+		dprintk(VIDC_ERR, "v4l2 buf type not found %d\n", buf_type);
+		return -ENOTSUPP;
+	}
+	return call_hfi_op(hdev, iommu_get_domain_partition,
+		hdev->hfi_device_data, flags, hal_buffer_type, domain,
+		partition);
+};
+
 int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
 	enum hal_ssr_trigger_type type)
 {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index 69f41c7..4f3deb6 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.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
@@ -39,6 +39,10 @@
 int msm_comm_force_cleanup(struct msm_vidc_inst *inst);
 enum hal_extradata_id msm_comm_get_hal_extradata_index(
 	enum v4l2_mpeg_vidc_extradata index);
+int msm_comm_get_domain_partition(struct msm_vidc_inst *inst, u32 flags,
+	enum v4l2_buf_type buf_type, int *domain, int *partition);
+struct hal_buffer_requirements *get_buff_req_buffer(
+			struct msm_vidc_inst *inst, u32 buffer_type);
 #define IS_PRIV_CTRL(idx) (\
 		(V4L2_CTRL_ID2CLASS(idx) == V4L2_CTRL_CLASS_MPEG) && \
 		V4L2_CTRL_DRIVER_PRIV(idx))
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index c03a4c4..8238d42 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -92,6 +92,7 @@
 
 struct internal_buf {
 	struct list_head list;
+	enum hal_buffer buffer_type;
 	struct msm_smem *handle;
 };
 
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
index 8fc6452..54c0878 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
@@ -32,6 +32,36 @@
 	int count;
 };
 
+struct addr_range {
+	u32 start;
+	u32 size;
+};
+
+struct iommu_info {
+	const char *name;
+	u32 buffer_type;
+	struct iommu_group *group;
+	int domain;
+	bool is_secure;
+	struct addr_range addr_range[2];
+	int npartitions;
+};
+
+struct iommu_set {
+	struct iommu_info *iommu_maps;
+	u32 count;
+};
+
+struct buffer_usage_table {
+	u32 buffer_type;
+	u32 tz_usage;
+};
+
+struct buffer_usage_set {
+	struct buffer_usage_table *buffer_usage_tbl;
+	u32 count;
+};
+
 struct msm_vidc_platform_resources {
 	uint32_t fw_base_addr;
 	uint32_t register_base;
@@ -39,10 +69,10 @@
 	uint32_t irq;
 	struct load_freq_table *load_freq_tbl;
 	uint32_t load_freq_tbl_size;
-	struct msm_vidc_iommu_info *iommu_maps;
-	uint32_t iommu_maps_size;
 	struct reg_set reg_set;
 	struct msm_bus_scale_pdata *bus_pdata;
+	struct iommu_set iommu_group_set;
+	struct buffer_usage_set buffer_usage_set;
 	struct platform_device *pdev;
 };
 
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index 25cc239..88dc4fe 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -1113,25 +1113,14 @@
 	return 0;
 }
 
-static int q6_hfi_get_domain(void *dev, enum msm_vidc_io_maps iomap)
+static int q6_hfi_iommu_get_domain_partition(void *dev, u32 flags,
+	u32 buffer_type, int *domain, int *partition)
 {
 	(void)dev;
-	(void)iomap;
 
 	dprintk(VIDC_ERR, "Not implemented: %s", __func__);
 
-	return 0;
-}
-
-static int q6_hfi_iommu_get_map(void *dev,
-			struct msm_vidc_iommu_info maps[MAX_MAP])
-{
-	(void)dev;
-	(void)maps;
-
-	dprintk(VIDC_ERR, "Not implemented: %s", __func__);
-
-	return 0;
+	return -ENOTSUPP;
 }
 
 static int q6_hfi_iommu_attach(void *dev)
@@ -1230,8 +1219,7 @@
 	hdev->alloc_ocmem = q6_hfi_alloc_ocmem;
 	hdev->free_ocmem = q6_hfi_free_ocmem;
 	hdev->is_ocmem_present = q6_hfi_is_ocmem_present;
-	hdev->get_domain = q6_hfi_get_domain;
-	hdev->iommu_get_map = q6_hfi_iommu_get_map;
+	hdev->iommu_get_domain_partition = q6_hfi_iommu_get_domain_partition;
 	hdev->load_fw = q6_hfi_load_fw;
 	hdev->unload_fw = q6_hfi_unload_fw;
 	hdev->get_fw_info = q6_hfi_get_fw_info;
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index af8b761..8c30b6c 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -333,7 +333,7 @@
 }
 
 static int venus_hfi_alloc(void *mem, void *clnt, u32 size, u32 align,
-						   u32 flags, int domain)
+		u32 flags, u32 usage)
 {
 	struct vidc_mem_addr *vmem;
 	struct msm_smem *alloc;
@@ -346,7 +346,7 @@
 	vmem = (struct vidc_mem_addr *)mem;
 	dprintk(VIDC_INFO, "start to alloc: size:%d, Flags: %d", size, flags);
 
-	alloc  = msm_smem_alloc(clnt, size, align, flags, domain, 1, 1);
+	alloc = msm_smem_alloc(clnt, size, align, flags, usage, 1);
 	dprintk(VIDC_DBG, "Alloc done");
 	if (!alloc) {
 		dprintk(VIDC_ERR, "Alloc failed\n");
@@ -632,6 +632,7 @@
 	struct hfi_mem_map_table *qdss;
 	struct hfi_mem_map *mem_map;
 	int num_entries = sizeof(venus_qdss_entries)/(2 * sizeof(u32));
+	int domain, partition;
 
 	if (device->qdss.mem_data) {
 		qdss = (struct hfi_mem_map_table *)
@@ -641,11 +642,12 @@
 			(u32 *)((u32)device->qdss.align_device_addr +
 				sizeof(struct hfi_mem_map_table));
 		mem_map = (struct hfi_mem_map *)(qdss + 1);
+		msm_smem_get_domain_partition(device->hal_client, 0,
+			HAL_BUFFER_INTERNAL_CMD_QUEUE, &domain, &partition);
 		for (i = 0; i < num_entries; i++) {
 			msm_iommu_unmap_contig_buffer(
 				(unsigned long)(mem_map[i].virtual_addr),
-				device->resources.io_map[NS_MAP].domain,
-				1, SZ_4K);
+				domain, partition, SZ_4K);
 		}
 		venus_hfi_free(device->hal_client, device->qdss.mem_data);
 	}
@@ -674,7 +676,7 @@
 	device->hal_client = NULL;
 }
 static int venus_hfi_get_qdss_iommu_virtual_addr(struct hfi_mem_map *mem_map,
-	int domain)
+						int domain, int partition)
 {
 	int i;
 	int rc = 0;
@@ -703,14 +705,13 @@
 		for (--i; i >= 0; i--) {
 			msm_iommu_unmap_contig_buffer(
 				(unsigned long)(mem_map[i].virtual_addr),
-				domain, 1, SZ_4K);
+				domain, partition, SZ_4K);
 		}
 	}
 	return rc;
 }
 
-static int venus_hfi_interface_queues_init(struct venus_hfi_device *dev,
-					int domain)
+static int venus_hfi_interface_queues_init(struct venus_hfi_device *dev)
 {
 	struct hfi_queue_table_header *q_tbl_hdr;
 	struct hfi_queue_header *q_hdr;
@@ -723,10 +724,11 @@
 	struct vidc_mem_addr *mem_addr;
 	int offset = 0;
 	int num_entries = sizeof(venus_qdss_entries)/(2 * sizeof(u32));
+	int domain, partition;
 	mem_addr = &dev->mem_addr;
 	rc = venus_hfi_alloc((void *) mem_addr,
-			dev->hal_client, QUEUE_SIZE, 1,
-			0, domain);
+			dev->hal_client, QUEUE_SIZE, 1, 0,
+			HAL_BUFFER_INTERNAL_CMD_QUEUE);
 	if (rc) {
 		dprintk(VIDC_ERR, "iface_q_table_alloc_fail");
 		goto fail_alloc_queue;
@@ -752,8 +754,8 @@
 	}
 
 	rc = venus_hfi_alloc((void *) mem_addr,
-			dev->hal_client, QDSS_SIZE, 1,
-			0, domain);
+			dev->hal_client, QDSS_SIZE, 1, 0,
+			HAL_BUFFER_INTERNAL_CMD_QUEUE);
 	if (rc) {
 		dprintk(VIDC_WARN,
 			"qdss_alloc_fail: QDSS messages logging will not work");
@@ -765,8 +767,8 @@
 		dev->qdss.mem_data = mem_addr->mem_data;
 	}
 	rc = venus_hfi_alloc((void *) mem_addr,
-			dev->hal_client, SFR_SIZE, 1,
-			0, domain);
+			dev->hal_client, SFR_SIZE, 1, 0,
+			HAL_BUFFER_INTERNAL_CMD_QUEUE);
 	if (rc) {
 		dprintk(VIDC_WARN, "sfr_alloc_fail: SFR not will work");
 		dev->sfr.align_device_addr = NULL;
@@ -824,7 +826,9 @@
 		(u32 *)	((u32)dev->qdss.align_device_addr +
 		sizeof(struct hfi_mem_map_table));
 	mem_map = (struct hfi_mem_map *)(qdss + 1);
-	rc = venus_hfi_get_qdss_iommu_virtual_addr(mem_map, domain);
+	msm_smem_get_domain_partition(dev->hal_client, 0,
+		HAL_BUFFER_INTERNAL_CMD_QUEUE, &domain, &partition);
+	rc = venus_hfi_get_qdss_iommu_virtual_addr(mem_map, domain, partition);
 	if (rc) {
 		dprintk(VIDC_ERR,
 			"IOMMU mapping failed, Freeing qdss memdata");
@@ -940,7 +944,7 @@
 	venus_hfi_set_registers(dev);
 
 	if (!dev->hal_client) {
-		dev->hal_client = msm_smem_new_client(SMEM_ION);
+		dev->hal_client = msm_smem_new_client(SMEM_ION, dev->res);
 		if (dev->hal_client == NULL) {
 			dprintk(VIDC_ERR, "Failed to alloc ION_Client");
 			rc = -ENODEV;
@@ -951,8 +955,7 @@
 		dev->hal_data->device_base_addr,
 		(u32) dev->hal_data->register_base_addr);
 
-		rc = venus_hfi_interface_queues_init(dev,
-				dev->resources.io_map[NS_MAP].domain);
+		rc = venus_hfi_interface_queues_init(dev);
 		if (rc) {
 			dprintk(VIDC_ERR, "failed to init queues");
 			rc = -ENOMEM;
@@ -2038,68 +2041,69 @@
 static int venus_hfi_register_iommu_domains(struct venus_hfi_device *device,
 					struct msm_vidc_platform_resources *res)
 {
-	struct msm_iova_partition partition[2];
-	struct msm_iova_layout layout;
-	int rc = 0;
-	int i;
-	struct msm_vidc_iommu_info *io_map;
+	struct iommu_domain *domain;
+	int rc = 0, i = 0;
+	struct iommu_set *iommu_group_set;
+	struct iommu_info *iommu_map;
 
-	if (!device)
+	if (!device || !res)
 		return -EINVAL;
 
-	io_map = device->resources.io_map;
+	iommu_group_set = &device->res->iommu_group_set;
 
-	strlcpy(io_map[CP_MAP].name, "vidc-cp-map",
-			sizeof(io_map[CP_MAP].name));
-	strlcpy(io_map[CP_MAP].ctx, "venus_cp",
-			sizeof(io_map[CP_MAP].ctx));
-	strlcpy(io_map[NS_MAP].name, "vidc-ns-map",
-			sizeof(io_map[NS_MAP].name));
-	strlcpy(io_map[NS_MAP].ctx, "venus_ns",
-			sizeof(io_map[NS_MAP].ctx));
-
-	for (i = 0; i < MAX_MAP; i++) {
-		if (!res->iommu_maps[i].addr_range[1])
-			continue;
-		memcpy(io_map[i].addr_range, &res->iommu_maps[i].addr_range,
-				sizeof(u32) * 2);
-
-		partition[0].start = io_map[i].addr_range[0];
-		if (i == NS_MAP) {
-			partition[0].size =
-				io_map[i].addr_range[1] - SHARED_QSIZE;
-			partition[1].start =
-				partition[0].start + io_map[i].addr_range[1]
-					- SHARED_QSIZE;
-			partition[1].size = SHARED_QSIZE;
-			layout.npartitions = 2;
-			layout.is_secure = 0;
-		} else {
-			partition[0].size = io_map[i].addr_range[1];
-			layout.npartitions = 1;
-			layout.is_secure = 1;
+	for (i = 0; i < iommu_group_set->count; i++) {
+		iommu_map = &iommu_group_set->iommu_maps[i];
+		iommu_map->group = iommu_group_find(iommu_map->name);
+		if (!iommu_map->group) {
+			dprintk(VIDC_ERR, "Failed to find group :%s\n",
+				iommu_map->name);
+			goto fail_group;
 		}
-		layout.partitions = &partition[0];
-		layout.client_name = io_map[i].name;
-		layout.domain_flags = 0;
-		dprintk(VIDC_DBG, "Registering domain 1 with: %lx, %lx, %s\n",
-			partition[0].start, partition[0].size,
-			layout.client_name);
-		dprintk(VIDC_DBG, "Registering domain 2 with: %lx, %lx, %s\n",
-			partition[1].start, partition[1].size,
-			layout.client_name);
-		io_map[i].domain = msm_register_domain(&layout);
-		if (io_map[i].domain < 0) {
-			dprintk(VIDC_ERR, "Failed to register cp domain\n");
-			rc = -EINVAL;
-			break;
+		domain = iommu_group_get_iommudata(iommu_map->group);
+		if (!domain) {
+			dprintk(VIDC_ERR,
+				"Failed to get domain data for group %p",
+				iommu_map->group);
+			goto fail_group;
+		}
+		iommu_map->domain = msm_find_domain_no(domain);
+		if (iommu_map->domain < 0) {
+			dprintk(VIDC_ERR,
+				"Failed to get domain index for domain %p",
+				domain);
+			goto fail_group;
 		}
 	}
-	/* There is no api provided as msm_unregister_domain, so
-	 * we are not able to unregister the previously
-	 * registered domains if any domain registration fails.*/
-	BUG_ON(i < MAX_MAP);
 	return rc;
+
+fail_group:
+	for (--i; i >= 0; i--) {
+		iommu_map = &iommu_group_set->iommu_maps[i];
+		if (iommu_map->group)
+			iommu_group_put(iommu_map->group);
+		iommu_map->group = NULL;
+		iommu_map->domain = -1;
+	}
+	return -EINVAL;
+}
+
+static void venus_hfi_deregister_iommu_domains(struct venus_hfi_device *device)
+{
+	struct iommu_set *iommu_group_set;
+	struct iommu_info *iommu_map;
+	int i = 0;
+
+	if (!device)
+		return;
+
+	iommu_group_set = &device->res->iommu_group_set;
+	for (i = 0; i < iommu_group_set->count; i++) {
+		iommu_map = &iommu_group_set->iommu_maps[i];
+		if (iommu_map->group)
+			iommu_group_put(iommu_map->group);
+		iommu_map->group = NULL;
+		iommu_map->domain = -1;
+	}
 }
 
 static void venus_hfi_deinit_bus(struct venus_hfi_device *device)
@@ -2462,6 +2466,7 @@
 static void venus_hfi_deinit_resources(struct venus_hfi_device *device)
 {
 	venus_hfi_deinit_ocmem(device);
+	venus_hfi_deregister_iommu_domains(device);
 	venus_hfi_deinit_bus(device);
 	venus_hfi_deinit_clocks(device);
 }
@@ -2471,39 +2476,39 @@
 	int rc;
 	struct iommu_domain *domain;
 	int i;
-	struct msm_vidc_iommu_info *io_map;
-	struct device *dev;
+	struct iommu_set *iommu_group_set;
+	struct iommu_group *group;
+	struct iommu_info *iommu_map;
 
-	if (!device)
+	if (!device || !device->res)
 		return -EINVAL;
 
-	for (i = 0; i < MAX_MAP; i++) {
-		io_map = &device->resources.io_map[i];
-		if (!io_map->domain)
-			continue;
-		dev = msm_iommu_get_ctx(io_map->ctx);
-		domain = msm_get_iommu_domain(io_map->domain);
+	iommu_group_set = &device->res->iommu_group_set;
+	for (i = 0; i < iommu_group_set->count; i++) {
+		iommu_map = &iommu_group_set->iommu_maps[i];
+		group = iommu_map->group;
+		domain = msm_get_iommu_domain(iommu_map->domain);
 		if (IS_ERR_OR_NULL(domain)) {
 			dprintk(VIDC_ERR,
-				"Failed to get domain: %s\n", io_map->name);
+				"Failed to get domain: %s\n", iommu_map->name);
 			rc = PTR_ERR(domain);
 			break;
 		}
-		rc = iommu_attach_device(domain, dev);
+		rc = iommu_attach_group(domain, group);
 		if (rc) {
 			dprintk(VIDC_ERR,
-				"IOMMU attach failed: %s\n", io_map->name);
+				"IOMMU attach failed: %s\n", iommu_map->name);
 			break;
 		}
 	}
-	if (i < MAX_MAP) {
+	if (i < iommu_group_set->count) {
 		i--;
 		for (; i >= 0; i--) {
-			io_map = &device->resources.io_map[i];
-			dev = msm_iommu_get_ctx(io_map->ctx);
-			domain = msm_get_iommu_domain(io_map->domain);
-			if (dev && domain)
-				iommu_detach_device(domain, dev);
+			iommu_map = &iommu_group_set->iommu_maps[i];
+			group = iommu_map->group;
+			domain = msm_get_iommu_domain(iommu_map->domain);
+			if (group && domain)
+				iommu_detach_group(domain, group);
 		}
 	}
 	return rc;
@@ -2511,51 +2516,40 @@
 
 static void venus_hfi_iommu_detach(struct venus_hfi_device *device)
 {
-	struct device *dev;
+	struct iommu_group *group;
 	struct iommu_domain *domain;
-	struct msm_vidc_iommu_info *io_map;
+	struct iommu_set *iommu_group_set;
+	struct iommu_info *iommu_map;
 	int i;
 
-	if (!device) {
+	if (!device || !device->res) {
 		dprintk(VIDC_ERR, "Invalid paramter: %p\n", device);
 		return;
 	}
 
-	for (i = 0; i < MAX_MAP; i++) {
-		io_map = &device->resources.io_map[i];
-		dev = msm_iommu_get_ctx(io_map->ctx);
-		domain = msm_get_iommu_domain(io_map->domain);
-		if (dev && domain)
-			iommu_detach_device(domain, dev);
+	iommu_group_set = &device->res->iommu_group_set;
+	for (i = 0; i < iommu_group_set->count; i++) {
+		iommu_map = &iommu_group_set->iommu_maps[i];
+		group = iommu_map->group;
+		domain = msm_get_iommu_domain(iommu_map->domain);
+		if (group && domain)
+			iommu_detach_group(domain, group);
 	}
 }
 
-static int venus_hfi_get_domain(void *dev, enum msm_vidc_io_maps iomap)
+static int venus_hfi_iommu_get_domain_partition(void *dev, u32 flags,
+			u32 buffer_type, int *domain, int *partition)
 {
 	struct venus_hfi_device *device = dev;
-	if (!device || iomap < CP_MAP || iomap >= MAX_MAP) {
-		dprintk(VIDC_ERR, "%s: Invalid parameter: %p iomap: %d\n",
-				__func__, device, iomap);
-		return -EINVAL;
-	}
-	return device->resources.io_map[iomap].domain;
-}
 
-static int venus_hfi_iommu_get_map(void *dev,
-			struct msm_vidc_iommu_info maps[MAX_MAP])
-{
-	int i = 0;
-	struct venus_hfi_device *device = dev;
-
-	if (!device || !maps) {
-		dprintk(VIDC_ERR, "%s: Invalid param device: %p maps: %p\n",
-		 __func__, device, maps);
+	if (!device) {
+		dprintk(VIDC_ERR, "%s: Invalid param device: %p\n",
+		 __func__, device);
 		return -EINVAL;
 	}
 
-	for (i = 0; i < MAX_MAP; i++)
-		maps[i] = device->resources.io_map[i];
-
+	msm_smem_get_domain_partition(device->hal_client, flags, buffer_type,
+			domain, partition);
 	return 0;
 }
 
@@ -2564,22 +2558,36 @@
 	struct tzbsp_memprot memprot;
 	unsigned int resp = 0;
 	int rc = 0;
-	struct msm_vidc_iommu_info *io_map;
+	struct iommu_set *iommu_group_set;
+	struct iommu_info *iommu_map;
+	int i;
+
 	if (!device)
 		return -EINVAL;
 
-	io_map = device->resources.io_map;
-	if (!io_map) {
-		dprintk(VIDC_ERR, "invalid params: %p\n", io_map);
+	iommu_group_set = &device->res->iommu_group_set;
+	if (!iommu_group_set) {
+		dprintk(VIDC_ERR, "invalid params: %p\n", iommu_group_set);
 		return -EINVAL;
 	}
-	if (!io_map[CP_MAP].addr_range[1])
-		return 0;
+
 	memprot.cp_start = 0x0;
-	memprot.cp_size = io_map[CP_MAP].addr_range[0] +
-			io_map[CP_MAP].addr_range[1];
-	memprot.cp_nonpixel_start = 0;
-	memprot.cp_nonpixel_size = 0;
+	memprot.cp_size = 0x0;
+	memprot.cp_nonpixel_start = 0x0;
+	memprot.cp_nonpixel_size = 0x0;
+
+	for (i = 0; i < iommu_group_set->count; i++) {
+		iommu_map = &iommu_group_set->iommu_maps[i];
+		if (strcmp(iommu_map->name, "venus_ns") == 0)
+			memprot.cp_size = iommu_map->addr_range[0].start;
+
+		if (strcmp(iommu_map->name, "venus_sec_non_pixel") == 0) {
+			memprot.cp_nonpixel_start =
+				iommu_map->addr_range[0].start;
+			memprot.cp_nonpixel_size =
+				iommu_map->addr_range[0].size;
+		}
+	}
 
 	rc = scm_call(SCM_SVC_CP, TZBSP_MEM_PROTECT_VIDEO_VAR, &memprot,
 			sizeof(memprot), &resp, sizeof(resp));
@@ -2833,8 +2841,7 @@
 	hdev->alloc_ocmem = venus_hfi_alloc_ocmem;
 	hdev->free_ocmem = venus_hfi_free_ocmem;
 	hdev->is_ocmem_present = venus_hfi_is_ocmem_present;
-	hdev->get_domain = venus_hfi_get_domain;
-	hdev->iommu_get_map = venus_hfi_iommu_get_map;
+	hdev->iommu_get_domain_partition = venus_hfi_iommu_get_domain_partition;
 	hdev->load_fw = venus_hfi_load_fw;
 	hdev->unload_fw = venus_hfi_unload_fw;
 	hdev->get_fw_info = venus_hfi_get_fw_info;
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.h b/drivers/media/platform/msm/vidc/venus_hfi.h
index 2ffb9d4..7a96ff4 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.h
+++ b/drivers/media/platform/msm/vidc/venus_hfi.h
@@ -164,7 +164,6 @@
 
 struct venus_resources {
 	struct msm_vidc_fw fw;
-	struct msm_vidc_iommu_info io_map[MAX_MAP];
 	struct venus_core_clock clock[VCODEC_MAX_CLKS];
 	struct venus_bus_info bus_info;
 	struct on_chip_mem ocmem;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
index 75594b3..8b3e7cb 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.h
@@ -53,6 +53,8 @@
 #define HFI_BUFFER_EXTRADATA_INPUT (HFI_OX_BASE + 0x2)
 #define HFI_BUFFER_EXTRADATA_OUTPUT (HFI_OX_BASE + 0x3)
 #define HFI_BUFFER_EXTRADATA_OUTPUT2 (HFI_OX_BASE + 0x4)
+#define HFI_BUFFER_INTERNAL_SCRATCH_1 (HFI_OX_BASE + 0x5)
+#define HFI_BUFFER_INTERNAL_SCRATCH_2 (HFI_OX_BASE + 0x6)
 
 #define HFI_BUFFER_MODE_STATIC (HFI_OX_BASE + 0x1)
 #define HFI_BUFFER_MODE_RING (HFI_OX_BASE + 0x2)
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index d06ea51..fad29f1 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -18,6 +18,7 @@
 #include <linux/types.h>
 #include <media/msm_vidc.h>
 #include "msm_vidc_resources.h"
+#include "msm_smem.h"
 
 #define CONTAINS(__a, __sz, __t) ({\
 	int __rc = __t >= __a && \
@@ -375,18 +376,6 @@
 	HAL_UNUSED_MVC_LEVEL = 0x10000000,
 };
 
-enum hal_buffer {
-	HAL_BUFFER_INPUT,
-	HAL_BUFFER_OUTPUT,
-	HAL_BUFFER_OUTPUT2,
-	HAL_BUFFER_EXTRADATA_INPUT,
-	HAL_BUFFER_EXTRADATA_OUTPUT,
-	HAL_BUFFER_EXTRADATA_OUTPUT2,
-	HAL_BUFFER_INTERNAL_SCRATCH,
-	HAL_BUFFER_INTERNAL_PERSIST,
-	HAL_BUFFER_MAX
-};
-
 struct hal_frame_rate {
 	enum hal_buffer buffer_type;
 	u32 frame_rate;
@@ -1058,9 +1047,8 @@
 	int (*alloc_ocmem)(void *dev, unsigned long size);
 	int (*free_ocmem)(void *dev);
 	int (*is_ocmem_present)(void *dev);
-	int (*get_domain)(void *dev, enum msm_vidc_io_maps iomap);
-	int (*iommu_get_map)(void *dev,
-			struct msm_vidc_iommu_info maps[MAX_MAP]);
+	int (*iommu_get_domain_partition)(void *dev, u32 flags, u32 buffer_type,
+			int *domain_num, int *partition_num);
 	int (*load_fw)(void *dev);
 	void (*unload_fw)(void *dev);
 	int (*get_fw_info)(void *dev, enum fw_info info);
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index 37c051e..01c5e0b 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -179,6 +179,7 @@
 #define HFI_BUFFER_OUTPUT				(HFI_COMMON_BASE + 0x2)
 #define HFI_BUFFER_OUTPUT2				(HFI_COMMON_BASE + 0x3)
 #define HFI_BUFFER_INTERNAL_PERSIST		(HFI_COMMON_BASE + 0x4)
+#define HFI_BUFFER_INTERNAL_PERSIST_1		(HFI_COMMON_BASE + 0x5)
 
 struct hfi_buffer_info {
 	u32 buffer_addr;
diff --git a/drivers/media/platform/msm/wfd/enc-venus-subdev.c b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
index b41ece6..40362f0 100644
--- a/drivers/media/platform/msm/wfd/enc-venus-subdev.c
+++ b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
@@ -46,7 +46,6 @@
 	bool callback_thread_running;
 	struct completion dq_complete, cmd_complete;
 	bool secure;
-	int domain;
 };
 
 int venc_load_fw(struct v4l2_subdev *sd)
@@ -252,18 +251,6 @@
 	return msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
 }
 
-static long get_iommu_domain(struct venc_inst *inst)
-{
-	struct msm_vidc_iommu_info maps[MAX_MAP];
-	int rc = msm_vidc_get_iommu_maps(inst->vidc_context, maps);
-	if (rc) {
-		WFD_MSG_ERR("Failed to retreive domain mappings\n");
-		return rc;
-	}
-
-	return maps[inst->secure ? CP_MAP : NS_MAP].domain;
-}
-
 static long venc_open(struct v4l2_subdev *sd, void *arg)
 {
 	struct venc_inst *inst = NULL;
@@ -316,12 +303,6 @@
 		goto vidc_subscribe_fail;
 	}
 
-	inst->domain = get_iommu_domain(inst);
-	if (inst->domain < 0) {
-		WFD_MSG_ERR("Failed to get domain\n");
-		goto vidc_subscribe_fail;
-	}
-
 	inst->callback_thread = kthread_run(venc_vidc_callback_thread, inst,
 					"venc_vidc_callback_thread");
 	if (IS_ERR(inst->callback_thread)) {
@@ -641,7 +622,9 @@
 		struct mem_region *mregion)
 {
 	int rc = 0;
-	unsigned long size = 0, align_req = 0;
+	unsigned long size = 0, align_req = 0, flags = 0;
+	int domain = 0, partition = 0;
+
 	if (!mregion) {
 		rc = -EINVAL;
 		goto venc_map_fail;
@@ -663,6 +646,12 @@
 		goto venc_map_fail;
 	}
 
+	rc = ion_handle_get_flags(venc_ion_client, mregion->ion_handle, &flags);
+	if (rc) {
+		WFD_MSG_ERR("Failed to get ion flags %d\n", rc);
+		goto venc_map_fail;
+	}
+
 	if (!inst->secure) {
 		mregion->kvaddr = ion_map_kernel(venc_ion_client,
 				mregion->ion_handle);
@@ -685,10 +674,16 @@
 		}
 	}
 
-	rc = ion_map_iommu(venc_ion_client, mregion->ion_handle,
-			inst->domain, 0, align_req, 0,
-			(unsigned long *)&mregion->paddr, &size, 0, 0);
+	rc = msm_vidc_get_iommu_domain_partition(inst->vidc_context,
+			flags, BUF_TYPE_OUTPUT, &domain, &partition);
+	if (rc) {
+		WFD_MSG_ERR("Failed to get domain for output buffer\n");
+		goto venc_domain_fail;
+	}
 
+	rc = ion_map_iommu(venc_ion_client, mregion->ion_handle,
+			domain, partition, align_req, 0,
+			(unsigned long *)&mregion->paddr, &size, 0, 0);
 	if (rc) {
 		WFD_MSG_ERR("Failed to map into iommu\n");
 		goto venc_map_iommu_map_fail;
@@ -700,8 +695,8 @@
 	return 0;
 venc_map_iommu_size_fail:
 	ion_unmap_iommu(venc_ion_client, mregion->ion_handle,
-			inst->domain, 0);
-
+			domain, partition);
+venc_domain_fail:
 	if (inst->secure)
 		msm_ion_unsecure_buffer(venc_ion_client, mregion->ion_handle);
 venc_map_iommu_map_fail:
@@ -714,12 +709,28 @@
 static int venc_unmap_user_to_kernel(struct venc_inst *inst,
 		struct mem_region *mregion)
 {
+	unsigned long flags = 0;
+	int domain = 0, partition = 0, rc = 0;
+
 	if (!mregion || !mregion->ion_handle)
 		return 0;
 
+	rc = ion_handle_get_flags(venc_ion_client, mregion->ion_handle, &flags);
+	if (rc) {
+		WFD_MSG_ERR("Failed to get ion flags %d\n", rc);
+		return rc;
+	}
+
+	rc = msm_vidc_get_iommu_domain_partition(inst->vidc_context,
+		flags, BUF_TYPE_OUTPUT, &domain, &partition);
+	if (rc) {
+		WFD_MSG_ERR("Failed to get domain for input buffer\n");
+		return rc;
+	}
+
 	if (mregion->paddr) {
 		ion_unmap_iommu(venc_ion_client, mregion->ion_handle,
-				inst->domain, 0);
+				domain, partition);
 		mregion->paddr = NULL;
 	}
 
@@ -731,7 +742,7 @@
 	if (inst->secure)
 		msm_ion_unsecure_buffer(venc_ion_client, mregion->ion_handle);
 
-	return 0;
+	return rc;
 }
 
 static long venc_set_output_buffer(struct v4l2_subdev *sd, void *arg)
@@ -1145,7 +1156,8 @@
 {
 	struct mem_region_map *mmap = arg;
 	struct mem_region *mregion = NULL;
-	unsigned long rc = 0, size = 0, align_req = 0;
+	unsigned long size = 0, align_req = 0, flags = 0;
+	int domain = 0, partition = 0, rc = 0;
 	void *paddr = NULL;
 	struct venc_inst *inst = NULL;
 
@@ -1167,21 +1179,34 @@
 		goto venc_map_bad_align;
 	}
 
+	rc = ion_handle_get_flags(mmap->ion_client, mregion->ion_handle,
+			&flags);
+	if (rc) {
+		WFD_MSG_ERR("Failed to get ion flags %d\n", rc);
+		goto venc_map_bad_align;
+	}
+
 	if (inst->secure) {
 		rc = msm_ion_secure_buffer(mmap->ion_client,
-			mregion->ion_handle, VIDEO_PIXEL, 0);
+				mregion->ion_handle, VIDEO_PIXEL, 0);
 		if (rc) {
 			WFD_MSG_ERR("Failed to secure input buffer\n");
 			goto venc_map_bad_align;
 		}
 	}
 
-	rc = ion_map_iommu(mmap->ion_client, mregion->ion_handle,
-			inst->domain, 0, align_req, 0, (unsigned long *)&paddr,
-			&size, 0, 0);
-
+	rc = msm_vidc_get_iommu_domain_partition(inst->vidc_context,
+			flags, BUF_TYPE_INPUT, &domain, &partition);
 	if (rc) {
-		WFD_MSG_ERR("Failed to get physical addr %ld\n", rc);
+		WFD_MSG_ERR("Failed to get domain for output buffer\n");
+		goto venc_map_domain_fail;
+	}
+
+	rc = ion_map_iommu(mmap->ion_client, mregion->ion_handle,
+			domain, partition, align_req, 0,
+			(unsigned long *)&paddr, &size, 0, 0);
+	if (rc) {
+		WFD_MSG_ERR("Failed to get physical addr %d\n", rc);
 		paddr = NULL;
 		goto venc_map_bad_align;
 	} else if (size < mregion->size) {
@@ -1191,12 +1216,12 @@
 	}
 
 	mregion->paddr = paddr;
-	return 0;
+	return rc;
 
 venc_map_iommu_size_fail:
 	ion_unmap_iommu(venc_ion_client, mregion->ion_handle,
-			inst->domain, 0);
-
+			domain, partition);
+venc_map_domain_fail:
 	if (inst->secure)
 		msm_ion_unsecure_buffer(mmap->ion_client, mregion->ion_handle);
 venc_map_bad_align:
@@ -1208,6 +1233,8 @@
 	struct mem_region_map *mmap = arg;
 	struct mem_region *mregion = NULL;
 	struct venc_inst *inst = NULL;
+	unsigned long flags = 0;
+	int domain = 0, partition = 0, rc = 0;
 
 	if (!sd) {
 		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
@@ -1220,14 +1247,28 @@
 	inst = (struct venc_inst *)sd->dev_priv;
 	mregion = mmap->mregion;
 
+	rc = ion_handle_get_flags(mmap->ion_client,
+			mregion->ion_handle, &flags);
+	if (rc) {
+		WFD_MSG_ERR("Failed to get ion flags %d\n", rc);
+		return rc;
+	}
+
+	rc = msm_vidc_get_iommu_domain_partition(inst->vidc_context,
+		flags, BUF_TYPE_INPUT, &domain, &partition);
+	if (rc) {
+		WFD_MSG_ERR("Failed to get domain for input buffer\n");
+		return rc;
+	}
+
 	if (mregion->paddr)
 		ion_unmap_iommu(mmap->ion_client, mregion->ion_handle,
-			inst->domain, 0);
+			domain, partition);
 
 	if (inst->secure)
 		msm_ion_unsecure_buffer(mmap->ion_client, mregion->ion_handle);
 
-	return 0;
+	return rc;
 }
 
 static long venc_set_framerate_mode(struct v4l2_subdev *sd,
@@ -1239,24 +1280,6 @@
 	return 0;
 }
 
-static long secure_toggle(struct venc_inst *inst, bool secure)
-{
-	if (inst->secure == secure)
-		return 0;
-
-	if (!list_empty(&inst->registered_input_bufs.list) ||
-		!list_empty(&inst->registered_output_bufs.list)) {
-		WFD_MSG_ERR(
-			"Attempt to (un)secure encoder not allowed after registering buffers"
-			);
-		return -EEXIST;
-	}
-
-	inst->secure = secure;
-	inst->domain = get_iommu_domain(inst);
-	return 0;
-}
-
 static long venc_secure(struct v4l2_subdev *sd)
 {
 	struct venc_inst *inst = NULL;
@@ -1269,9 +1292,18 @@
 	}
 
 	inst = sd->dev_priv;
-	rc = secure_toggle(inst, true);
-	if (rc) {
-		WFD_MSG_ERR("Failed to toggle into secure mode\n");
+
+	if (!list_empty(&inst->registered_input_bufs.list) ||
+		!list_empty(&inst->registered_output_bufs.list)) {
+		WFD_MSG_ERR(
+			"Attempt to (un)secure encoder not allowed after registering buffers"
+			);
+		rc = -EEXIST;
+	}
+
+	if (inst->secure) {
+		/* Nothing to do! */
+		rc = 0;
 		goto secure_fail;
 	}
 
@@ -1282,9 +1314,8 @@
 		goto secure_fail;
 	}
 
-	return 0;
+	inst->secure = true;
 secure_fail:
-	secure_toggle(sd->dev_priv, false);
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/wfd/vsg-subdev.c b/drivers/media/platform/msm/wfd/vsg-subdev.c
index bbe2b7b..90b1957 100644
--- a/drivers/media/platform/msm/wfd/vsg-subdev.c
+++ b/drivers/media/platform/msm/wfd/vsg-subdev.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
@@ -101,8 +101,8 @@
 
 	list_for_each_entry(temp, &context->busy_queue.node, node) {
 		if (++count > MAX_BUFS_BUSY_WITH_ENC) {
-			WFD_MSG_WARN("Skipping encode, too many "
-				"buffers with encoder");
+			WFD_MSG_WARN(
+				"Skipping encode, too many buffers with encoder\n");
 			goto err_skip_encode;
 		}
 	}
@@ -158,8 +158,11 @@
 				&& can_release) {
 				vsg_release_input_buffer(context,
 					old_last_buffer);
-				kfree(old_last_buffer);
 			}
+
+			if (last_buf_with_us)
+				kfree(old_last_buffer);
+
 		}
 		vsg_set_last_buffer(context, buf_info);
 	}
@@ -406,8 +409,8 @@
 			if (!is_last_buffer &&
 				!(temp->flags & VSG_NEVER_RELEASE)) {
 				vsg_release_input_buffer(context, temp);
-				kfree(temp);
 			}
+			kfree(temp);
 		}
 	}
 
@@ -458,8 +461,8 @@
 static long vsg_return_ip_buffer(struct v4l2_subdev *sd, void *arg)
 {
 	struct vsg_context *context = NULL;
-	struct vsg_buf_info *buf_info, *last_buffer,
-			*expected_buffer;
+	struct vsg_buf_info *buf_info = NULL, *last_buffer = NULL,
+			*expected_buffer = NULL;
 	int rc = 0;
 
 	if (!arg || !sd) {
@@ -473,8 +476,10 @@
 	buf_info = (struct vsg_buf_info *)arg;
 	last_buffer = context->last_buffer;
 
-	expected_buffer = list_first_entry(&context->busy_queue.node,
-			struct vsg_buf_info, node);
+	if (!list_empty(&context->busy_queue.node)) {
+		expected_buffer = list_first_entry(&context->busy_queue.node,
+				struct vsg_buf_info, node);
+	}
 
 	WFD_MSG_DBG("Return frame with paddr %p\n",
 			(void *)buf_info->mdp_buf_info.paddr);
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index 11a8f4d..bbc18a4 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -49,6 +49,7 @@
 static char utf_8_flag;
 static char rt_ert_flag;
 static char formatting_dir;
+static DEFINE_MUTEX(iris_fm);
 
 module_param(rds_buf, uint, 0);
 MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
@@ -1167,6 +1168,7 @@
 
 	DECLARE_WAITQUEUE(wait, current);
 
+	mutex_lock(&iris_fm);
 	hdev->req_status = HCI_REQ_PEND;
 
 	add_wait_queue(&hdev->req_wait_q, &wait);
@@ -1178,8 +1180,10 @@
 
 	remove_wait_queue(&hdev->req_wait_q, &wait);
 
-	if (signal_pending(current))
+	if (signal_pending(current)) {
+		mutex_unlock(&iris_fm);
 		return -EINTR;
+	}
 
 	switch (hdev->req_status) {
 	case HCI_REQ_DONE:
@@ -1197,6 +1201,7 @@
 	}
 
 	hdev->req_status = hdev->req_result = 0;
+	mutex_unlock(&iris_fm);
 
 	return err;
 }
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index a79009b..d3ddeef 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -1354,13 +1354,16 @@
 	/* Set channel spacing */
 	switch (region) {
 	case TAVARUA_REGION_US:
-		if (adie_type_bahma) {
+		if ((adie_type_bahma) && (bahama_version == 0x09)) {
 			FMDBG("Adie type : Bahama\n");
 			/*
 			Configuring all 200KHZ spaced regions as 100KHz due to
 			change in the new Bahma FM SoC search algorithm.
 			*/
 			value = FM_CH_SPACE_100KHZ;
+		} else if ((adie_type_bahma) && (bahama_version == 0x0a)) {
+			FMDBG("Adie type : Bahama B1\n");
+			value = FM_CH_SPACE_200KHZ;
 		} else {
 			FMDBG("Adie type : Marimba\n");
 			value = FM_CH_SPACE_200KHZ;
@@ -1368,7 +1371,7 @@
 		break;
 	case TAVARUA_REGION_JAPAN:
 	case TAVARUA_REGION_OTHER:
-		if (adie_type_bahma) {
+		if ((adie_type_bahma) && (bahama_version == 0x09)) {
 			FMDBG("Adie type : Bahama\n");
 			FMDBG("%s: Configuring the channel-spacing as 50KHz"
 				"for the Region : %d", __func__, region);
@@ -1377,6 +1380,9 @@
 			change in the new Bahma FM SoC search algorithm.
 			*/
 			value = FM_CH_SPACE_50KHZ;
+		} else if ((adie_type_bahma) && (bahama_version == 0x0a)) {
+			FMDBG("Adie type : Bahama B1\n");
+			value = FM_CH_SPACE_100KHZ;
 		} else {
 			FMDBG("Adie type : Marimba\n");
 			value = FM_CH_SPACE_100KHZ;
diff --git a/drivers/misc/qseecom_kernel.h b/drivers/misc/qseecom_kernel.h
index 0c93ef2..c6c8fc9 100644
--- a/drivers/misc/qseecom_kernel.h
+++ b/drivers/misc/qseecom_kernel.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
@@ -14,6 +14,12 @@
 #define __QSEECOM_KERNEL_H_
 
 #include <linux/types.h>
+
+#define QSEECOM_ALIGN_SIZE	0x40
+#define QSEECOM_ALIGN_MASK	(QSEECOM_ALIGN_SIZE - 1)
+#define QSEECOM_ALIGN(x)	\
+	((x + QSEECOM_ALIGN_SIZE) & (~QSEECOM_ALIGN_MASK))
+
 /*
  * struct qseecom_handle -
  *      Handle to the qseecom device for kernel clients
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index a037c17..cf6f97c 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -3016,14 +3016,27 @@
 {
 	struct mmc_blk_data *part_md;
 	struct mmc_blk_data *md = mmc_get_drvdata(card);
+	int rc = 0;
 
 	if (md) {
-		mmc_queue_suspend(&md->queue);
+		rc = mmc_queue_suspend(&md->queue);
+		if (rc)
+			goto out;
 		list_for_each_entry(part_md, &md->part, part) {
-			mmc_queue_suspend(&part_md->queue);
+			rc = mmc_queue_suspend(&part_md->queue);
+			if (rc)
+				goto out_resume;
 		}
 	}
-	return 0;
+	goto out;
+
+ out_resume:
+	mmc_queue_resume(&md->queue);
+	list_for_each_entry(part_md, &md->part, part) {
+		mmc_queue_resume(&part_md->queue);
+	}
+ out:
+	return rc;
 }
 
 static int mmc_blk_resume(struct mmc_card *card)
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 64ece67..65a1322 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -435,10 +435,11 @@
  * complete any outstanding requests.  This ensures that we
  * won't suspend while a request is being processed.
  */
-void mmc_queue_suspend(struct mmc_queue *mq)
+int mmc_queue_suspend(struct mmc_queue *mq)
 {
 	struct request_queue *q = mq->queue;
 	unsigned long flags;
+	int rc = 0;
 
 	if (!(mq->flags & MMC_QUEUE_SUSPENDED)) {
 		mq->flags |= MMC_QUEUE_SUSPENDED;
@@ -447,8 +448,20 @@
 		blk_stop_queue(q);
 		spin_unlock_irqrestore(q->queue_lock, flags);
 
-		down(&mq->thread_sem);
+		rc = down_trylock(&mq->thread_sem);
+		if (rc) {
+			/*
+			 * Failed to take the lock so better to abort the
+			 * suspend because mmcqd thread is processing requests.
+			 */
+			mq->flags &= ~MMC_QUEUE_SUSPENDED;
+			spin_lock_irqsave(q->queue_lock, flags);
+			blk_start_queue(q);
+			spin_unlock_irqrestore(q->queue_lock, flags);
+			rc = -EBUSY;
+		}
 	}
+	return rc;
 }
 
 /**
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index 99c3c60..9280d1b 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -60,7 +60,7 @@
 extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
 			  const char *);
 extern void mmc_cleanup_queue(struct mmc_queue *);
-extern void mmc_queue_suspend(struct mmc_queue *);
+extern int mmc_queue_suspend(struct mmc_queue *);
 extern void mmc_queue_resume(struct mmc_queue *);
 
 extern unsigned int mmc_queue_map_sg(struct mmc_queue *,
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index be4315e..b395fc8 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1907,6 +1907,14 @@
 	mmc_host_clk_release(host);
 }
 
+void mmc_power_cycle(struct mmc_host *host)
+{
+	mmc_power_off(host);
+	/* Wait at least 1 ms according to SD spec */
+	mmc_delay(1);
+	mmc_power_up(host);
+}
+
 /*
  * Cleanup when the last reference to the bus operator is dropped.
  */
@@ -2571,7 +2579,7 @@
 	if (!host->bus_ops->power_restore)
 		return -EOPNOTSUPP;
 
-	if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
+	if (!(host->caps & MMC_CAP_HW_RESET))
 		return -EOPNOTSUPP;
 
 	if (!card)
@@ -2583,7 +2591,10 @@
 	mmc_host_clk_hold(host);
 	mmc_set_clock(host, host->f_init);
 
-	host->ops->hw_reset(host);
+	if (mmc_card_sd(card))
+		mmc_power_cycle(host);
+	else if (host->ops->hw_reset)
+		host->ops->hw_reset(host);
 
 	/* If the reset has happened, then a status command will fail */
 	if (check) {
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 6fa51e0..153c821 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -48,6 +48,7 @@
 void mmc_set_timing(struct mmc_host *host, unsigned int timing);
 void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
 void mmc_power_off(struct mmc_host *host);
+void mmc_power_cycle(struct mmc_host *host);
 
 static inline void mmc_delay(unsigned int ms)
 {
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index da38122..2c1e11a 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -458,6 +458,19 @@
 config MMC_TMIO_CORE
 	tristate
 
+config MMC_SDHCI_MSM
+	tristate "Qualcomm SDHCI Controller Support"
+	depends on ARCH_MSM
+	depends on MMC_SDHCI_PLTFM
+	help
+	  This selects the Secure Digital Host Controller Interface (SDHCI)
+	  support present in MSM SOCs from Qualcomm. The controller
+	  supports SD/MMC/SDIO devices.
+
+	  If you have a controller with this interface, say Y or M here.
+
+	  If unsure, say N.
+
 config MMC_MSM
 	tristate "Qualcomm SDCC Controller Support"
 	depends on MMC && ARCH_MSM
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 843ce06..c0232fa 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -56,6 +56,7 @@
 obj-$(CONFIG_MMC_SDHCI_TEGRA)		+= sdhci-tegra.o
 obj-$(CONFIG_MMC_SDHCI_OF_ESDHC)	+= sdhci-of-esdhc.o
 obj-$(CONFIG_MMC_SDHCI_OF_HLWD)		+= sdhci-of-hlwd.o
+obj-$(CONFIG_MMC_SDHCI_MSM)		+= sdhci-msm.o
 
 ifeq ($(CONFIG_CB710_DEBUG),y)
 	CFLAGS-cb710-mmc	+= -DDEBUG
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
new file mode 100644
index 0000000..f0706e83
--- /dev/null
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -0,0 +1,1779 @@
+/*
+ * drivers/mmc/host/sdhci-msm.c - Qualcomm MSM SDHCI Platform
+ * driver source file
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/gfp.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/wait.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/mmc/mmc.h>
+#include <mach/gpio.h>
+
+#include "sdhci-pltfm.h"
+
+#define SDHCI_VER_100		0x2B
+#define CORE_HC_MODE		0x78
+#define HC_MODE_EN		0x1
+
+#define CORE_POWER		0x0
+#define CORE_SW_RST		(1 << 7)
+
+#define CORE_PWRCTL_STATUS	0xDC
+#define CORE_PWRCTL_MASK	0xE0
+#define CORE_PWRCTL_CLEAR	0xE4
+#define CORE_PWRCTL_CTL		0xE8
+
+#define CORE_PWRCTL_BUS_OFF	0x01
+#define CORE_PWRCTL_BUS_ON	(1 << 1)
+#define CORE_PWRCTL_IO_LOW	(1 << 2)
+#define CORE_PWRCTL_IO_HIGH	(1 << 3)
+
+#define CORE_PWRCTL_BUS_SUCCESS	0x01
+#define CORE_PWRCTL_BUS_FAIL	(1 << 1)
+#define CORE_PWRCTL_IO_SUCCESS	(1 << 2)
+#define CORE_PWRCTL_IO_FAIL	(1 << 3)
+
+#define INT_MASK		0xF
+#define MAX_PHASES		16
+
+#define CORE_DLL_LOCK		(1 << 7)
+#define CORE_DLL_EN		(1 << 16)
+#define CORE_CDR_EN		(1 << 17)
+#define CORE_CK_OUT_EN		(1 << 18)
+#define CORE_CDR_EXT_EN		(1 << 19)
+#define CORE_DLL_PDN		(1 << 29)
+#define CORE_DLL_RST		(1 << 30)
+#define CORE_DLL_CONFIG		0x100
+#define CORE_DLL_TEST_CTL	0x104
+#define CORE_DLL_STATUS		0x108
+
+#define CORE_VENDOR_SPEC	0x10C
+#define CORE_CLK_PWRSAVE	(1 << 1)
+#define CORE_IO_PAD_PWR_SWITCH	(1 << 16)
+
+static const u32 tuning_block_64[] = {
+	0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
+	0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
+	0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
+	0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
+};
+
+static const u32 tuning_block_128[] = {
+	0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
+	0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
+	0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
+	0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
+	0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
+	0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
+	0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
+	0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
+};
+
+/* This structure keeps information per regulator */
+struct sdhci_msm_reg_data {
+	/* voltage regulator handle */
+	struct regulator *reg;
+	/* regulator name */
+	const char *name;
+	/* voltage level to be set */
+	u32 low_vol_level;
+	u32 high_vol_level;
+	/* Load values for low power and high power mode */
+	u32 lpm_uA;
+	u32 hpm_uA;
+
+	/* is this regulator enabled? */
+	bool is_enabled;
+	/* is this regulator needs to be always on? */
+	bool is_always_on;
+	/* is low power mode setting required for this regulator? */
+	bool lpm_sup;
+};
+
+/*
+ * This structure keeps information for all the
+ * regulators required for a SDCC slot.
+ */
+struct sdhci_msm_slot_reg_data {
+	/* keeps VDD/VCC regulator info */
+	struct sdhci_msm_reg_data *vdd_data;
+	 /* keeps VDD IO regulator info */
+	struct sdhci_msm_reg_data *vdd_io_data;
+};
+
+struct sdhci_msm_gpio {
+	u32 no;
+	const char *name;
+	bool is_enabled;
+};
+
+struct sdhci_msm_gpio_data {
+	struct sdhci_msm_gpio *gpio;
+	u8 size;
+};
+
+struct sdhci_msm_pad_pull {
+	enum msm_tlmm_pull_tgt no;
+	u32 val;
+};
+
+struct sdhci_msm_pad_pull_data {
+	struct sdhci_msm_pad_pull *on;
+	struct sdhci_msm_pad_pull *off;
+	u8 size;
+};
+
+struct sdhci_msm_pad_drv {
+	enum msm_tlmm_hdrive_tgt no;
+	u32 val;
+};
+
+struct sdhci_msm_pad_drv_data {
+	struct sdhci_msm_pad_drv *on;
+	struct sdhci_msm_pad_drv *off;
+	u8 size;
+};
+
+struct sdhci_msm_pad_data {
+	struct sdhci_msm_pad_pull_data *pull;
+	struct sdhci_msm_pad_drv_data *drv;
+};
+
+
+struct sdhci_msm_pin_data {
+	/*
+	 * = 1 if controller pins are using gpios
+	 * = 0 if controller has dedicated MSM pads
+	 */
+	u8 is_gpio;
+	bool cfg_sts;
+	struct sdhci_msm_gpio_data *gpio_data;
+	struct sdhci_msm_pad_data *pad_data;
+};
+
+struct sdhci_msm_pltfm_data {
+	/* Supported UHS-I Modes */
+	u32 caps;
+
+	/* More capabilities */
+	u32 caps2;
+
+	unsigned long mmc_bus_width;
+	u32 max_clk;
+	struct sdhci_msm_slot_reg_data *vreg_data;
+	bool nonremovable;
+	struct sdhci_msm_pin_data *pin_data;
+};
+
+struct sdhci_msm_host {
+	void __iomem *core_mem;    /* MSM SDCC mapped address */
+	struct clk	 *clk;     /* main SD/MMC bus clock */
+	struct clk	 *pclk;    /* SDHC peripheral bus clock */
+	struct clk	 *bus_clk; /* SDHC bus voter clock */
+	struct sdhci_msm_pltfm_data *pdata;
+	struct mmc_host  *mmc;
+	struct sdhci_pltfm_data sdhci_msm_pdata;
+	wait_queue_head_t pwr_irq_wait;
+};
+
+enum vdd_io_level {
+	/* set vdd_io_data->low_vol_level */
+	VDD_IO_LOW,
+	/* set vdd_io_data->high_vol_level */
+	VDD_IO_HIGH,
+	/*
+	 * set whatever there in voltage_level (third argument) of
+	 * sdhci_msm_set_vdd_io_vol() function.
+	 */
+	VDD_IO_SET_LEVEL,
+};
+
+/* MSM platform specific tuning */
+static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host,
+						u8 poll)
+{
+	int rc = 0;
+	u32 wait_cnt = 50;
+	u8 ck_out_en = 0;
+	struct mmc_host *mmc = host->mmc;
+
+	/* poll for CK_OUT_EN bit.  max. poll time = 50us */
+	ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) &
+			CORE_CK_OUT_EN);
+
+	while (ck_out_en != poll) {
+		if (--wait_cnt == 0) {
+			pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
+				mmc_hostname(mmc), __func__, poll);
+			rc = -ETIMEDOUT;
+			goto out;
+		}
+		udelay(1);
+
+		ck_out_en = !!(readl_relaxed(host->ioaddr +
+				CORE_DLL_CONFIG) & CORE_CK_OUT_EN);
+	}
+out:
+	return rc;
+}
+
+static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase)
+{
+	int rc = 0;
+	u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
+					0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
+					0x8};
+	unsigned long flags;
+	u32 config;
+	struct mmc_host *mmc = host->mmc;
+
+	pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
+	spin_lock_irqsave(&host->lock, flags);
+
+	config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
+	config &= ~(CORE_CDR_EN | CORE_CK_OUT_EN);
+	config |= (CORE_CDR_EXT_EN | CORE_DLL_EN);
+	writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
+
+	/* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '0' */
+	rc = msm_dll_poll_ck_out_en(host, 0);
+	if (rc)
+		goto err_out;
+
+	/*
+	 * Write the selected DLL clock output phase (0 ... 15)
+	 * to CDR_SELEXT bit field of DLL_CONFIG register.
+	 */
+	writel_relaxed(((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+			& ~(0xF << 20))
+			| (grey_coded_phase_table[phase] << 20)),
+			host->ioaddr + CORE_DLL_CONFIG);
+
+	/* Set CK_OUT_EN bit of DLL_CONFIG register to 1. */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+			| CORE_CK_OUT_EN), host->ioaddr + CORE_DLL_CONFIG);
+
+	/* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '1' */
+	rc = msm_dll_poll_ck_out_en(host, 1);
+	if (rc)
+		goto err_out;
+
+	config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
+	config |= CORE_CDR_EN;
+	config &= ~CORE_CDR_EXT_EN;
+	writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
+	goto out;
+
+err_out:
+	pr_err("%s: %s: Failed to set DLL phase: %d\n",
+		mmc_hostname(mmc), __func__, phase);
+out:
+	spin_unlock_irqrestore(&host->lock, flags);
+	pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
+	return rc;
+}
+
+/*
+ * Find out the greatest range of consecuitive selected
+ * DLL clock output phases that can be used as sampling
+ * setting for SD3.0 UHS-I card read operation (in SDR104
+ * timing mode) or for eMMC4.5 card read operation (in HS200
+ * timing mode).
+ * Select the 3/4 of the range and configure the DLL with the
+ * selected DLL clock output phase.
+ */
+
+static int msm_find_most_appropriate_phase(struct sdhci_host *host,
+				u8 *phase_table, u8 total_phases)
+{
+	int ret;
+	u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
+	u8 phases_per_row[MAX_PHASES] = {0};
+	int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
+	int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
+	bool phase_0_found = false, phase_15_found = false;
+	struct mmc_host *mmc = host->mmc;
+
+	pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
+	if (!total_phases || (total_phases > MAX_PHASES)) {
+		pr_err("%s: %s: invalid argument: total_phases=%d\n",
+			mmc_hostname(mmc), __func__, total_phases);
+		return -EINVAL;
+	}
+
+	for (cnt = 0; cnt < total_phases; cnt++) {
+		ranges[row_index][col_index] = phase_table[cnt];
+		phases_per_row[row_index] += 1;
+		col_index++;
+
+		if ((cnt + 1) == total_phases) {
+			continue;
+		/* check if next phase in phase_table is consecutive or not */
+		} else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
+			row_index++;
+			col_index = 0;
+		}
+	}
+
+	if (row_index >= MAX_PHASES)
+		return -EINVAL;
+
+	/* Check if phase-0 is present in first valid window? */
+	if (!ranges[0][0]) {
+		phase_0_found = true;
+		phase_0_raw_index = 0;
+		/* Check if cycle exist between 2 valid windows */
+		for (cnt = 1; cnt <= row_index; cnt++) {
+			if (phases_per_row[cnt]) {
+				for (i = 0; i < phases_per_row[cnt]; i++) {
+					if (ranges[cnt][i] == 15) {
+						phase_15_found = true;
+						phase_15_raw_index = cnt;
+						break;
+					}
+				}
+			}
+		}
+	}
+
+	/* If 2 valid windows form cycle then merge them as single window */
+	if (phase_0_found && phase_15_found) {
+		/* number of phases in raw where phase 0 is present */
+		u8 phases_0 = phases_per_row[phase_0_raw_index];
+		/* number of phases in raw where phase 15 is present */
+		u8 phases_15 = phases_per_row[phase_15_raw_index];
+
+		if (phases_0 + phases_15 >= MAX_PHASES)
+			/*
+			 * If there are more than 1 phase windows then total
+			 * number of phases in both the windows should not be
+			 * more than or equal to MAX_PHASES.
+			 */
+			return -EINVAL;
+
+		/* Merge 2 cyclic windows */
+		i = phases_15;
+		for (cnt = 0; cnt < phases_0; cnt++) {
+			ranges[phase_15_raw_index][i] =
+				ranges[phase_0_raw_index][cnt];
+			if (++i >= MAX_PHASES)
+				break;
+		}
+
+		phases_per_row[phase_0_raw_index] = 0;
+		phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
+	}
+
+	for (cnt = 0; cnt <= row_index; cnt++) {
+		if (phases_per_row[cnt] > curr_max) {
+			curr_max = phases_per_row[cnt];
+			selected_row_index = cnt;
+		}
+	}
+
+	i = ((curr_max * 3) / 4);
+	if (i)
+		i--;
+
+	ret = (int)ranges[selected_row_index][i];
+
+	if (ret >= MAX_PHASES) {
+		ret = -EINVAL;
+		pr_err("%s: %s: invalid phase selected=%d\n",
+			mmc_hostname(mmc), __func__, ret);
+	}
+
+	pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
+	return ret;
+}
+
+static inline void msm_cm_dll_set_freq(struct sdhci_host *host)
+{
+	u32 mclk_freq = 0;
+
+	/* Program the MCLK value to MCLK_FREQ bit field */
+	if (host->clock <= 112000000)
+		mclk_freq = 0;
+	else if (host->clock <= 125000000)
+		mclk_freq = 1;
+	else if (host->clock <= 137000000)
+		mclk_freq = 2;
+	else if (host->clock <= 150000000)
+		mclk_freq = 3;
+	else if (host->clock <= 162000000)
+		mclk_freq = 4;
+	else if (host->clock <= 175000000)
+		mclk_freq = 5;
+	else if (host->clock <= 187000000)
+		mclk_freq = 6;
+	else if (host->clock <= 200000000)
+		mclk_freq = 7;
+
+	writel_relaxed(((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+			& ~(7 << 24)) | (mclk_freq << 24)),
+			host->ioaddr + CORE_DLL_CONFIG);
+}
+
+/* Initialize the DLL (Programmable Delay Line ) */
+static int msm_init_cm_dll(struct sdhci_host *host)
+{
+	struct mmc_host *mmc = host->mmc;
+	int rc = 0;
+	unsigned long flags;
+	u32 wait_cnt;
+
+	pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
+	spin_lock_irqsave(&host->lock, flags);
+
+	/*
+	 * Make sure that clock is always enabled when DLL
+	 * tuning is in progress. Keeping PWRSAVE ON may
+	 * turn off the clock. So let's disable the PWRSAVE
+	 * here and re-enable it once tuning is completed.
+	 */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
+			& ~CORE_CLK_PWRSAVE),
+			host->ioaddr + CORE_VENDOR_SPEC);
+
+	/* Write 1 to DLL_RST bit of DLL_CONFIG register */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+			| CORE_DLL_RST), host->ioaddr + CORE_DLL_CONFIG);
+
+	/* Write 1 to DLL_PDN bit of DLL_CONFIG register */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+			| CORE_DLL_PDN), host->ioaddr + CORE_DLL_CONFIG);
+	msm_cm_dll_set_freq(host);
+
+	/* Write 0 to DLL_RST bit of DLL_CONFIG register */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+			& ~CORE_DLL_RST), host->ioaddr + CORE_DLL_CONFIG);
+
+	/* Write 0 to DLL_PDN bit of DLL_CONFIG register */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+			& ~CORE_DLL_PDN), host->ioaddr + CORE_DLL_CONFIG);
+
+	/* Set DLL_EN bit to 1. */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+			| CORE_DLL_EN), host->ioaddr + CORE_DLL_CONFIG);
+
+	/* Set CK_OUT_EN bit to 1. */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+			| CORE_CK_OUT_EN), host->ioaddr + CORE_DLL_CONFIG);
+
+	wait_cnt = 50;
+	/* Wait until DLL_LOCK bit of DLL_STATUS register becomes '1' */
+	while (!(readl_relaxed(host->ioaddr + CORE_DLL_STATUS) &
+		CORE_DLL_LOCK)) {
+		/* max. wait for 50us sec for LOCK bit to be set */
+		if (--wait_cnt == 0) {
+			pr_err("%s: %s: DLL failed to LOCK\n",
+				mmc_hostname(mmc), __func__);
+			rc = -ETIMEDOUT;
+			goto out;
+		}
+		/* wait for 1us before polling again */
+		udelay(1);
+	}
+
+out:
+	/* re-enable PWRSAVE */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) |
+			CORE_CLK_PWRSAVE),
+			host->ioaddr + CORE_VENDOR_SPEC);
+	spin_unlock_irqrestore(&host->lock, flags);
+	pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
+	return rc;
+}
+
+int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
+{
+	unsigned long flags;
+	u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
+	const u32 *tuning_block_pattern = tuning_block_64;
+	int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
+	int rc;
+	struct mmc_host *mmc = host->mmc;
+
+	pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
+	/* Tuning is only required for SDR104 modes */
+	spin_lock_irqsave(&host->lock, flags);
+
+	if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
+		(mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
+		tuning_block_pattern = tuning_block_128;
+		size = sizeof(tuning_block_128);
+	}
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	/* first of all reset the tuning block */
+	rc = msm_init_cm_dll(host);
+	if (rc)
+		goto out;
+
+	data_buf = kmalloc(size, GFP_KERNEL);
+	if (!data_buf) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	phase = 0;
+	do {
+		struct mmc_command cmd = {0};
+		struct mmc_data data = {0};
+		struct mmc_request mrq = {
+			.cmd = &cmd,
+			.data = &data
+		};
+		struct scatterlist sg;
+
+		/* set the phase in delay line hw block */
+		rc = msm_config_cm_dll_phase(host, phase);
+		if (rc)
+			goto kfree;
+
+		cmd.opcode = opcode;
+		cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+		data.blksz = size;
+		data.blocks = 1;
+		data.flags = MMC_DATA_READ;
+		data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
+
+		data.sg = &sg;
+		data.sg_len = 1;
+		sg_init_one(&sg, data_buf, size);
+		memset(data_buf, 0, size);
+		mmc_wait_for_req(mmc, &mrq);
+
+		if (!cmd.error && !data.error &&
+			!memcmp(data_buf, tuning_block_pattern, size)) {
+			/* tuning is successful at this tuning point */
+			tuned_phases[tuned_phase_cnt++] = phase;
+			pr_debug("%s: %s: found good phase = %d\n",
+				mmc_hostname(mmc), __func__, phase);
+		}
+	} while (++phase < 16);
+
+	if (tuned_phase_cnt) {
+		rc = msm_find_most_appropriate_phase(host, tuned_phases,
+							tuned_phase_cnt);
+		if (rc < 0)
+			goto kfree;
+		else
+			phase = (u8)rc;
+
+		/*
+		 * Finally set the selected phase in delay
+		 * line hw block.
+		 */
+		rc = msm_config_cm_dll_phase(host, phase);
+		if (rc)
+			goto kfree;
+		pr_debug("%s: %s: finally setting the tuning phase to %d\n",
+				mmc_hostname(mmc), __func__, phase);
+	} else {
+		/* tuning failed */
+		pr_err("%s: %s: no tuning point found\n",
+			mmc_hostname(mmc), __func__);
+		rc = -EAGAIN;
+	}
+
+kfree:
+	kfree(data_buf);
+out:
+	pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
+	return rc;
+}
+
+static int sdhci_msm_setup_gpio(struct sdhci_msm_pltfm_data *pdata, bool enable)
+{
+	struct sdhci_msm_gpio_data *curr;
+	int i, ret = 0;
+
+	curr = pdata->pin_data->gpio_data;
+	for (i = 0; i < curr->size; i++) {
+		if (!gpio_is_valid(curr->gpio[i].no)) {
+			ret = -EINVAL;
+			pr_err("%s: Invalid gpio = %d\n", __func__,
+					curr->gpio[i].no);
+			goto free_gpios;
+		}
+		if (enable) {
+			ret = gpio_request(curr->gpio[i].no,
+						curr->gpio[i].name);
+			if (ret) {
+				pr_err("%s: gpio_request(%d, %s) failed %d\n",
+					__func__, curr->gpio[i].no,
+					curr->gpio[i].name, ret);
+				goto free_gpios;
+			}
+			curr->gpio[i].is_enabled = true;
+		} else {
+			gpio_free(curr->gpio[i].no);
+			curr->gpio[i].is_enabled = false;
+		}
+	}
+	return ret;
+
+free_gpios:
+	for (i--; i >= 0; i--) {
+		gpio_free(curr->gpio[i].no);
+		curr->gpio[i].is_enabled = false;
+	}
+	return ret;
+}
+
+static int sdhci_msm_setup_pad(struct sdhci_msm_pltfm_data *pdata, bool enable)
+{
+	struct sdhci_msm_pad_data *curr;
+	int i;
+
+	curr = pdata->pin_data->pad_data;
+	for (i = 0; i < curr->drv->size; i++) {
+		if (enable)
+			msm_tlmm_set_hdrive(curr->drv->on[i].no,
+				curr->drv->on[i].val);
+		else
+			msm_tlmm_set_hdrive(curr->drv->off[i].no,
+				curr->drv->off[i].val);
+	}
+
+	for (i = 0; i < curr->pull->size; i++) {
+		if (enable)
+			msm_tlmm_set_pull(curr->pull->on[i].no,
+				curr->pull->on[i].val);
+		else
+			msm_tlmm_set_pull(curr->pull->off[i].no,
+				curr->pull->off[i].val);
+	}
+
+	return 0;
+}
+
+static int sdhci_msm_setup_pins(struct sdhci_msm_pltfm_data *pdata, bool enable)
+{
+	int ret = 0;
+
+	if (!pdata->pin_data || (pdata->pin_data->cfg_sts == enable))
+		return 0;
+	if (pdata->pin_data->is_gpio)
+		ret = sdhci_msm_setup_gpio(pdata, enable);
+	else
+		ret = sdhci_msm_setup_pad(pdata, enable);
+
+	if (!ret)
+		pdata->pin_data->cfg_sts = enable;
+
+	return ret;
+}
+
+static int sdhci_msm_dt_get_array(struct device *dev, const char *prop_name,
+				 u32 **out, int *len, u32 size)
+{
+	int ret = 0;
+	struct device_node *np = dev->of_node;
+	size_t sz;
+	u32 *arr = NULL;
+
+	if (!of_get_property(np, prop_name, len)) {
+		ret = -EINVAL;
+		goto out;
+	}
+	sz = *len = *len / sizeof(*arr);
+	if (sz <= 0 || (size > 0 && (sz != size))) {
+		dev_err(dev, "%s invalid size\n", prop_name);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	arr = devm_kzalloc(dev, sz * sizeof(*arr), GFP_KERNEL);
+	if (!arr) {
+		dev_err(dev, "%s failed allocating memory\n", prop_name);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = of_property_read_u32_array(np, prop_name, arr, sz);
+	if (ret < 0) {
+		dev_err(dev, "%s failed reading array %d\n", prop_name, ret);
+		goto out;
+	}
+	*out = arr;
+out:
+	if (ret)
+		*len = 0;
+	return ret;
+}
+
+#define MAX_PROP_SIZE 32
+static int sdhci_msm_dt_parse_vreg_info(struct device *dev,
+		struct sdhci_msm_reg_data **vreg_data, const char *vreg_name)
+{
+	int len, ret = 0;
+	const __be32 *prop;
+	char prop_name[MAX_PROP_SIZE];
+	struct sdhci_msm_reg_data *vreg;
+	struct device_node *np = dev->of_node;
+
+	snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
+	if (!of_parse_phandle(np, prop_name, 0)) {
+		dev_err(dev, "No vreg data found for %s\n", vreg_name);
+		ret = -EINVAL;
+		return ret;
+	}
+
+	vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
+	if (!vreg) {
+		dev_err(dev, "No memory for vreg: %s\n", vreg_name);
+		ret = -ENOMEM;
+		return ret;
+	}
+
+	vreg->name = vreg_name;
+
+	snprintf(prop_name, MAX_PROP_SIZE,
+			"qcom,%s-always-on", vreg_name);
+	if (of_get_property(np, prop_name, NULL))
+		vreg->is_always_on = true;
+
+	snprintf(prop_name, MAX_PROP_SIZE,
+			"qcom,%s-lpm-sup", vreg_name);
+	if (of_get_property(np, prop_name, NULL))
+		vreg->lpm_sup = true;
+
+	snprintf(prop_name, MAX_PROP_SIZE,
+			"qcom,%s-voltage-level", vreg_name);
+	prop = of_get_property(np, prop_name, &len);
+	if (!prop || (len != (2 * sizeof(__be32)))) {
+		dev_warn(dev, "%s %s property\n",
+			prop ? "invalid format" : "no", prop_name);
+	} else {
+		vreg->low_vol_level = be32_to_cpup(&prop[0]);
+		vreg->high_vol_level = be32_to_cpup(&prop[1]);
+	}
+
+	snprintf(prop_name, MAX_PROP_SIZE,
+			"qcom,%s-current-level", vreg_name);
+	prop = of_get_property(np, prop_name, &len);
+	if (!prop || (len != (2 * sizeof(__be32)))) {
+		dev_warn(dev, "%s %s property\n",
+			prop ? "invalid format" : "no", prop_name);
+	} else {
+		vreg->lpm_uA = be32_to_cpup(&prop[0]);
+		vreg->hpm_uA = be32_to_cpup(&prop[1]);
+	}
+
+	*vreg_data = vreg;
+	dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n",
+		vreg->name, vreg->is_always_on ? "always_on," : "",
+		vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level,
+		vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA);
+
+	return ret;
+}
+
+/* GPIO/Pad data extraction */
+static int sdhci_msm_dt_get_pad_pull_info(struct device *dev, int id,
+		struct sdhci_msm_pad_pull_data **pad_pull_data)
+{
+	int ret = 0, base = 0, len, i;
+	u32 *tmp;
+	struct sdhci_msm_pad_pull_data *pull_data;
+	struct sdhci_msm_pad_pull *pull;
+
+	switch (id) {
+	case 1:
+		base = TLMM_PULL_SDC1_CLK;
+		break;
+	case 2:
+		base = TLMM_PULL_SDC2_CLK;
+		break;
+	case 3:
+		base = TLMM_PULL_SDC3_CLK;
+		break;
+	case 4:
+		base = TLMM_PULL_SDC4_CLK;
+		break;
+	default:
+		dev_err(dev, "%s: Invalid slot id\n", __func__);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	pull_data = devm_kzalloc(dev, sizeof(struct sdhci_msm_pad_pull_data),
+			GFP_KERNEL);
+	if (!pull_data) {
+		dev_err(dev, "No memory for msm_mmc_pad_pull_data\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+	pull_data->size = 3; /* array size for clk, cmd, data */
+
+	/* Allocate on, off configs for clk, cmd, data */
+	pull = devm_kzalloc(dev, 2 * pull_data->size *\
+			sizeof(struct sdhci_msm_pad_pull), GFP_KERNEL);
+	if (!pull) {
+		dev_err(dev, "No memory for msm_mmc_pad_pull\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+	pull_data->on = pull;
+	pull_data->off = pull + pull_data->size;
+
+	ret = sdhci_msm_dt_get_array(dev, "qcom,pad-pull-on",
+			&tmp, &len, pull_data->size);
+	if (ret)
+		goto out;
+
+	for (i = 0; i < len; i++) {
+		pull_data->on[i].no = base + i;
+		pull_data->on[i].val = tmp[i];
+		dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
+				i, pull_data->on[i].val);
+	}
+
+	ret = sdhci_msm_dt_get_array(dev, "qcom,pad-pull-off",
+			&tmp, &len, pull_data->size);
+	if (ret)
+		goto out;
+
+	for (i = 0; i < len; i++) {
+		pull_data->off[i].no = base + i;
+		pull_data->off[i].val = tmp[i];
+		dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
+				i, pull_data->off[i].val);
+	}
+
+	*pad_pull_data = pull_data;
+out:
+	return ret;
+}
+
+static int sdhci_msm_dt_get_pad_drv_info(struct device *dev, int id,
+		struct sdhci_msm_pad_drv_data **pad_drv_data)
+{
+	int ret = 0, base = 0, len, i;
+	u32 *tmp;
+	struct sdhci_msm_pad_drv_data *drv_data;
+	struct sdhci_msm_pad_drv *drv;
+
+	switch (id) {
+	case 1:
+		base = TLMM_HDRV_SDC1_CLK;
+		break;
+	case 2:
+		base = TLMM_HDRV_SDC2_CLK;
+		break;
+	case 3:
+		base = TLMM_HDRV_SDC3_CLK;
+		break;
+	case 4:
+		base = TLMM_HDRV_SDC4_CLK;
+		break;
+	default:
+		dev_err(dev, "%s: Invalid slot id\n", __func__);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	drv_data = devm_kzalloc(dev, sizeof(struct sdhci_msm_pad_drv_data),
+			GFP_KERNEL);
+	if (!drv_data) {
+		dev_err(dev, "No memory for msm_mmc_pad_drv_data\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+	drv_data->size = 3; /* array size for clk, cmd, data */
+
+	/* Allocate on, off configs for clk, cmd, data */
+	drv = devm_kzalloc(dev, 2 * drv_data->size *\
+			sizeof(struct sdhci_msm_pad_drv), GFP_KERNEL);
+	if (!drv) {
+		dev_err(dev, "No memory msm_mmc_pad_drv\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+	drv_data->on = drv;
+	drv_data->off = drv + drv_data->size;
+
+	ret = sdhci_msm_dt_get_array(dev, "qcom,pad-drv-on",
+			&tmp, &len, drv_data->size);
+	if (ret)
+		goto out;
+
+	for (i = 0; i < len; i++) {
+		drv_data->on[i].no = base + i;
+		drv_data->on[i].val = tmp[i];
+		dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
+				i, drv_data->on[i].val);
+	}
+
+	ret = sdhci_msm_dt_get_array(dev, "qcom,pad-drv-off",
+			&tmp, &len, drv_data->size);
+	if (ret)
+		goto out;
+
+	for (i = 0; i < len; i++) {
+		drv_data->off[i].no = base + i;
+		drv_data->off[i].val = tmp[i];
+		dev_dbg(dev, "%s: val[%d]=0x%x\n", __func__,
+				i, drv_data->off[i].val);
+	}
+
+	*pad_drv_data = drv_data;
+out:
+	return ret;
+}
+
+#define GPIO_NAME_MAX_LEN 32
+static int sdhci_msm_dt_parse_gpio_info(struct device *dev,
+		struct sdhci_msm_pltfm_data *pdata)
+{
+	int ret = 0, id = 0, cnt, i;
+	struct sdhci_msm_pin_data *pin_data;
+	struct device_node *np = dev->of_node;
+
+	pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
+	if (!pin_data) {
+		dev_err(dev, "No memory for pin_data\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	cnt = of_gpio_count(np);
+	if (cnt > 0) {
+		pin_data->is_gpio = true;
+		pin_data->gpio_data = devm_kzalloc(dev,
+				sizeof(struct sdhci_msm_gpio_data), GFP_KERNEL);
+		if (!pin_data->gpio_data) {
+			dev_err(dev, "No memory for gpio_data\n");
+			ret = -ENOMEM;
+			goto out;
+		}
+		pin_data->gpio_data->size = cnt;
+		pin_data->gpio_data->gpio = devm_kzalloc(dev, cnt *
+				sizeof(struct sdhci_msm_gpio), GFP_KERNEL);
+
+		if (!pin_data->gpio_data->gpio) {
+			dev_err(dev, "No memory for gpio\n");
+			ret = -ENOMEM;
+			goto out;
+		}
+		for (i = 0; i < cnt; i++) {
+			const char *name = NULL;
+			char result[GPIO_NAME_MAX_LEN];
+			pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
+			of_property_read_string_index(np,
+					"qcom,gpio-names", i, &name);
+
+			snprintf(result, GPIO_NAME_MAX_LEN, "%s-%s",
+					dev_name(dev), name ? name : "?");
+			pin_data->gpio_data->gpio[i].name = result;
+			dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
+				pin_data->gpio_data->gpio[i].name,
+				pin_data->gpio_data->gpio[i].no);
+		}
+	} else {
+		pin_data->pad_data =
+			devm_kzalloc(dev,
+				     sizeof(struct sdhci_msm_pad_data),
+				     GFP_KERNEL);
+		if (!pin_data->pad_data) {
+			dev_err(dev,
+				"No memory for pin_data->pad_data\n");
+			ret = -ENOMEM;
+			goto out;
+		}
+
+		ret = of_alias_get_id(np, "sdhc");
+		if (ret < 0) {
+			dev_err(dev, "Failed to get slot index %d\n", ret);
+			goto out;
+		}
+		id = ret;
+
+		ret = sdhci_msm_dt_get_pad_pull_info(
+			dev, id, &pin_data->pad_data->pull);
+		if (ret)
+			goto out;
+		ret = sdhci_msm_dt_get_pad_drv_info(
+			dev, id, &pin_data->pad_data->drv);
+		if (ret)
+			goto out;
+
+	}
+	pdata->pin_data = pin_data;
+out:
+	if (ret)
+		dev_err(dev, "%s failed with err %d\n", __func__, ret);
+	return ret;
+}
+
+/* Parse platform data */
+static struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev)
+{
+	struct sdhci_msm_pltfm_data *pdata = NULL;
+	struct device_node *np = dev->of_node;
+	u32 bus_width = 0;
+	int len, i;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		dev_err(dev, "failed to allocate memory for platform data\n");
+		goto out;
+	}
+
+	of_property_read_u32(np, "qcom,bus-width", &bus_width);
+	if (bus_width == 8)
+		pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
+	else if (bus_width == 4)
+		pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
+	else {
+		dev_notice(dev, "invalid bus-width, default to 1-bit mode\n");
+		pdata->mmc_bus_width = 0;
+	}
+
+	pdata->vreg_data = devm_kzalloc(dev, sizeof(struct
+						    sdhci_msm_slot_reg_data),
+					GFP_KERNEL);
+	if (!pdata->vreg_data) {
+		dev_err(dev, "failed to allocate memory for vreg data\n");
+		goto out;
+	}
+
+	if (sdhci_msm_dt_parse_vreg_info(dev, &pdata->vreg_data->vdd_data,
+					 "vdd")) {
+		dev_err(dev, "failed parsing vdd data\n");
+		goto out;
+	}
+	if (sdhci_msm_dt_parse_vreg_info(dev,
+					 &pdata->vreg_data->vdd_io_data,
+					 "vdd-io")) {
+		dev_err(dev, "failed parsing vdd-io data\n");
+		goto out;
+	}
+
+	if (sdhci_msm_dt_parse_gpio_info(dev, pdata)) {
+		dev_err(dev, "failed parsing gpio data\n");
+		goto out;
+	}
+
+	of_property_read_u32(np, "qcom,max-clk-rate", &pdata->max_clk);
+
+	len = of_property_count_strings(np, "qcom,bus-speed-mode");
+
+	for (i = 0; i < len; i++) {
+		const char *name = NULL;
+
+		of_property_read_string_index(np,
+			"qcom,bus-speed-mode", i, &name);
+		if (!name)
+			continue;
+
+		if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
+			pdata->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
+		else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
+			pdata->caps2 |= MMC_CAP2_HS200_1_2V_SDR;
+		else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v")))
+			pdata->caps |= MMC_CAP_1_8V_DDR
+						| MMC_CAP_UHS_DDR50;
+		else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v")))
+			pdata->caps |= MMC_CAP_1_2V_DDR
+						| MMC_CAP_UHS_DDR50;
+	}
+
+	if (of_get_property(np, "qcom,nonremovable", NULL))
+		pdata->nonremovable = true;
+
+	return pdata;
+out:
+	return NULL;
+}
+
+/* Regulator utility functions */
+static int sdhci_msm_vreg_init_reg(struct device *dev,
+					struct sdhci_msm_reg_data *vreg)
+{
+	int ret = 0;
+
+	/* check if regulator is already initialized? */
+	if (vreg->reg)
+		goto out;
+
+	/* Get the regulator handle */
+	vreg->reg = devm_regulator_get(dev, vreg->name);
+	if (IS_ERR(vreg->reg)) {
+		ret = PTR_ERR(vreg->reg);
+		pr_err("%s: devm_regulator_get(%s) failed. ret=%d\n",
+			__func__, vreg->name, ret);
+		goto out;
+	}
+
+	/* sanity check */
+	if (!vreg->high_vol_level || !vreg->hpm_uA) {
+		pr_err("%s: %s invalid constraints specified\n",
+		       __func__, vreg->name);
+		ret = -EINVAL;
+	}
+
+out:
+	return ret;
+}
+
+static void sdhci_msm_vreg_deinit_reg(struct sdhci_msm_reg_data *vreg)
+{
+	if (vreg->reg)
+		devm_regulator_put(vreg->reg);
+}
+
+static int sdhci_msm_vreg_set_optimum_mode(struct sdhci_msm_reg_data
+						  *vreg, int uA_load)
+{
+	int ret = 0;
+
+	/*
+	 * regulators that do not support regulator_set_voltage also
+	 * do not support regulator_set_optimum_mode
+	 */
+	ret = regulator_set_optimum_mode(vreg->reg, uA_load);
+	if (ret < 0)
+		pr_err("%s: regulator_set_optimum_mode(reg=%s,uA_load=%d) failed. ret=%d\n",
+			       __func__, vreg->name, uA_load, ret);
+		else
+			/*
+			 * regulator_set_optimum_mode() can return non zero
+			 * value even for success case.
+			 */
+			ret = 0;
+	return ret;
+}
+
+static int sdhci_msm_vreg_set_voltage(struct sdhci_msm_reg_data *vreg,
+					int min_uV, int max_uV)
+{
+	int ret = 0;
+
+	ret = regulator_set_voltage(vreg->reg, min_uV, max_uV);
+	if (ret) {
+		pr_err("%s: regulator_set_voltage(%s)failed. min_uV=%d,max_uV=%d,ret=%d\n",
+			       __func__, vreg->name, min_uV, max_uV, ret);
+		}
+
+	return ret;
+}
+
+static int sdhci_msm_vreg_enable(struct sdhci_msm_reg_data *vreg)
+{
+	int ret = 0;
+
+	/* Put regulator in HPM (high power mode) */
+	ret = sdhci_msm_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
+	if (ret < 0)
+		return ret;
+
+	if (!vreg->is_enabled) {
+		/* Set voltage level */
+		ret = sdhci_msm_vreg_set_voltage(vreg, vreg->high_vol_level,
+						vreg->high_vol_level);
+		if (ret)
+			return ret;
+	}
+	ret = regulator_enable(vreg->reg);
+	if (ret) {
+		pr_err("%s: regulator_enable(%s) failed. ret=%d\n",
+				__func__, vreg->name, ret);
+		return ret;
+	}
+	vreg->is_enabled = true;
+	return ret;
+}
+
+static int sdhci_msm_vreg_disable(struct sdhci_msm_reg_data *vreg)
+{
+	int ret = 0;
+
+	/* Never disable regulator marked as always_on */
+	if (vreg->is_enabled && !vreg->is_always_on) {
+		ret = regulator_disable(vreg->reg);
+		if (ret) {
+			pr_err("%s: regulator_disable(%s) failed. ret=%d\n",
+				__func__, vreg->name, ret);
+			goto out;
+		}
+		vreg->is_enabled = false;
+
+		ret = sdhci_msm_vreg_set_optimum_mode(vreg, 0);
+		if (ret < 0)
+			goto out;
+
+		/* Set min. voltage level to 0 */
+		ret = sdhci_msm_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
+		if (ret)
+			goto out;
+	} else if (vreg->is_enabled && vreg->is_always_on) {
+		if (vreg->lpm_sup) {
+			/* Put always_on regulator in LPM (low power mode) */
+			ret = sdhci_msm_vreg_set_optimum_mode(vreg,
+							      vreg->lpm_uA);
+			if (ret < 0)
+				goto out;
+		}
+	}
+out:
+	return ret;
+}
+
+static int sdhci_msm_setup_vreg(struct sdhci_msm_pltfm_data *pdata,
+			bool enable, bool is_init)
+{
+	int ret = 0, i;
+	struct sdhci_msm_slot_reg_data *curr_slot;
+	struct sdhci_msm_reg_data *vreg_table[2];
+
+	curr_slot = pdata->vreg_data;
+	if (!curr_slot) {
+		pr_debug("%s: vreg info unavailable,assuming the slot is powered by always on domain\n",
+			 __func__);
+		goto out;
+	}
+
+	vreg_table[0] = curr_slot->vdd_data;
+	vreg_table[1] = curr_slot->vdd_io_data;
+
+	for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
+		if (vreg_table[i]) {
+			if (enable)
+				ret = sdhci_msm_vreg_enable(vreg_table[i]);
+			else
+				ret = sdhci_msm_vreg_disable(vreg_table[i]);
+			if (ret)
+				goto out;
+		}
+	}
+out:
+	return ret;
+}
+
+/*
+ * Reset vreg by ensuring it is off during probe. A call
+ * to enable vreg is needed to balance disable vreg
+ */
+static int sdhci_msm_vreg_reset(struct sdhci_msm_pltfm_data *pdata)
+{
+	int ret;
+
+	ret = sdhci_msm_setup_vreg(pdata, 1, true);
+	if (ret)
+		return ret;
+	ret = sdhci_msm_setup_vreg(pdata, 0, true);
+	return ret;
+}
+
+/* This init function should be called only once for each SDHC slot */
+static int sdhci_msm_vreg_init(struct device *dev,
+				struct sdhci_msm_pltfm_data *pdata,
+				bool is_init)
+{
+	int ret = 0;
+	struct sdhci_msm_slot_reg_data *curr_slot;
+	struct sdhci_msm_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
+
+	curr_slot = pdata->vreg_data;
+	if (!curr_slot)
+		goto out;
+
+	curr_vdd_reg = curr_slot->vdd_data;
+	curr_vdd_io_reg = curr_slot->vdd_io_data;
+
+	if (!is_init)
+		/* Deregister all regulators from regulator framework */
+		goto vdd_io_reg_deinit;
+
+	/*
+	 * Get the regulator handle from voltage regulator framework
+	 * and then try to set the voltage level for the regulator
+	 */
+	if (curr_vdd_reg) {
+		ret = sdhci_msm_vreg_init_reg(dev, curr_vdd_reg);
+		if (ret)
+			goto out;
+	}
+	if (curr_vdd_io_reg) {
+		ret = sdhci_msm_vreg_init_reg(dev, curr_vdd_io_reg);
+		if (ret)
+			goto vdd_reg_deinit;
+	}
+	ret = sdhci_msm_vreg_reset(pdata);
+	if (ret)
+		dev_err(dev, "vreg reset failed (%d)\n", ret);
+	goto out;
+
+vdd_io_reg_deinit:
+	if (curr_vdd_io_reg)
+		sdhci_msm_vreg_deinit_reg(curr_vdd_io_reg);
+vdd_reg_deinit:
+	if (curr_vdd_reg)
+		sdhci_msm_vreg_deinit_reg(curr_vdd_reg);
+out:
+	return ret;
+}
+
+
+static int sdhci_msm_set_vdd_io_vol(struct sdhci_msm_pltfm_data *pdata,
+			enum vdd_io_level level,
+			unsigned int voltage_level)
+{
+	int ret = 0;
+	int set_level;
+	struct sdhci_msm_reg_data *vdd_io_reg;
+
+	if (!pdata->vreg_data)
+		return ret;
+
+	vdd_io_reg = pdata->vreg_data->vdd_io_data;
+	if (vdd_io_reg && vdd_io_reg->is_enabled) {
+		switch (level) {
+		case VDD_IO_LOW:
+			set_level = vdd_io_reg->low_vol_level;
+			break;
+		case VDD_IO_HIGH:
+			set_level = vdd_io_reg->high_vol_level;
+			break;
+		case VDD_IO_SET_LEVEL:
+			set_level = voltage_level;
+			break;
+		default:
+			pr_err("%s: invalid argument level = %d",
+					__func__, level);
+			ret = -EINVAL;
+			return ret;
+		}
+		ret = sdhci_msm_vreg_set_voltage(vdd_io_reg, set_level,
+				set_level);
+	}
+	return ret;
+}
+
+static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
+{
+	struct sdhci_host *host = (struct sdhci_host *)data;
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = pltfm_host->priv;
+	u8 irq_status = 0;
+	u8 irq_ack = 0;
+	int ret = 0;
+
+	irq_status = readb_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
+	pr_debug("%s: Received IRQ(%d), status=0x%x\n",
+		mmc_hostname(msm_host->mmc), irq, irq_status);
+
+	/* Clear the interrupt */
+	writeb_relaxed(irq_status, (msm_host->core_mem + CORE_PWRCTL_CLEAR));
+	/*
+	 * SDHC has core_mem and hc_mem device memory and these memory
+	 * addresses do not fall within 1KB region. Hence, any update to
+	 * core_mem address space would require an mb() to ensure this gets
+	 * completed before its next update to registers within hc_mem.
+	 */
+	mb();
+
+	/* Handle BUS ON/OFF*/
+	if (irq_status & CORE_PWRCTL_BUS_ON) {
+		ret = sdhci_msm_setup_vreg(msm_host->pdata, true, false);
+		if (!ret)
+			ret = sdhci_msm_setup_pins(msm_host->pdata, true);
+		if (ret)
+			irq_ack |= CORE_PWRCTL_BUS_FAIL;
+		else
+			irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
+	}
+	if (irq_status & CORE_PWRCTL_BUS_OFF) {
+		ret = sdhci_msm_setup_vreg(msm_host->pdata, false, false);
+		if (!ret)
+			ret = sdhci_msm_setup_pins(msm_host->pdata, false);
+		if (ret)
+			irq_ack |= CORE_PWRCTL_BUS_FAIL;
+		else
+			irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
+	}
+	/* Handle IO LOW/HIGH */
+	if (irq_status & CORE_PWRCTL_IO_LOW) {
+		/* Switch voltage Low */
+		ret = sdhci_msm_set_vdd_io_vol(msm_host->pdata, VDD_IO_LOW, 0);
+		if (ret)
+			irq_ack |= CORE_PWRCTL_IO_FAIL;
+		else
+			irq_ack |= CORE_PWRCTL_IO_SUCCESS;
+	}
+	if (irq_status & CORE_PWRCTL_IO_HIGH) {
+		/* Switch voltage High */
+		ret = sdhci_msm_set_vdd_io_vol(msm_host->pdata, VDD_IO_HIGH, 0);
+		if (ret)
+			irq_ack |= CORE_PWRCTL_IO_FAIL;
+		else
+			irq_ack |= CORE_PWRCTL_IO_SUCCESS;
+	}
+
+	/* ACK status to the core */
+	writeb_relaxed(irq_ack, (msm_host->core_mem + CORE_PWRCTL_CTL));
+	/*
+	 * SDHC has core_mem and hc_mem device memory and these memory
+	 * addresses do not fall within 1KB region. Hence, any update to
+	 * core_mem address space would require an mb() to ensure this gets
+	 * completed before its next update to registers within hc_mem.
+	 */
+	mb();
+
+	if (irq_status & CORE_PWRCTL_IO_HIGH)
+		writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) &
+				~CORE_IO_PAD_PWR_SWITCH),
+				host->ioaddr + CORE_VENDOR_SPEC);
+	if (irq_status & CORE_PWRCTL_IO_LOW)
+		writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) |
+				CORE_IO_PAD_PWR_SWITCH),
+				host->ioaddr + CORE_VENDOR_SPEC);
+	mb();
+
+	pr_debug("%s: Handled IRQ(%d), ret=%d, ack=0x%x\n",
+		mmc_hostname(msm_host->mmc), irq, ret, irq_ack);
+	wake_up_interruptible(&msm_host->pwr_irq_wait);
+	return IRQ_HANDLED;
+}
+
+/* This function returns the max. current supported by VDD rail in mA */
+static unsigned int sdhci_msm_get_vreg_vdd_max_current(struct sdhci_msm_host
+						       *host)
+{
+	struct sdhci_msm_slot_reg_data *curr_slot = host->pdata->vreg_data;
+	if (!curr_slot)
+		return 0;
+	if (curr_slot->vdd_data)
+		return curr_slot->vdd_data->hpm_uA / 1000;
+	else
+		return 0;
+}
+
+static void sdhci_msm_check_power_status(struct sdhci_host *host)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = pltfm_host->priv;
+	int ret = 0;
+
+	pr_debug("%s: %s: power status before waiting 0x%x\n",
+		mmc_hostname(host->mmc), __func__,
+		readb_relaxed(msm_host->core_mem + CORE_PWRCTL_CTL));
+
+	ret = wait_event_interruptible(msm_host->pwr_irq_wait,
+				       (readb_relaxed(msm_host->core_mem +
+						      CORE_PWRCTL_CTL)) != 0x0);
+	if (ret)
+		pr_warning("%s: %s: returned due to error %d\n",
+				mmc_hostname(host->mmc), __func__, ret);
+	pr_debug("%s: %s: ret %d power status after handling power IRQ 0x%x\n",
+		mmc_hostname(host->mmc), __func__, ret,
+		readb_relaxed(msm_host->core_mem + CORE_PWRCTL_CTL));
+}
+
+static void sdhci_msm_toggle_cdr(struct sdhci_host *host, bool enable)
+{
+	if (enable)
+		writel_relaxed((readl_relaxed(host->ioaddr +
+					      CORE_DLL_CONFIG) | CORE_CDR_EN),
+			       host->ioaddr + CORE_DLL_CONFIG);
+	else
+		writel_relaxed((readl_relaxed(host->ioaddr +
+					      CORE_DLL_CONFIG) & ~CORE_CDR_EN),
+			       host->ioaddr + CORE_DLL_CONFIG);
+}
+
+static struct sdhci_ops sdhci_msm_ops = {
+	.check_power_status = sdhci_msm_check_power_status,
+	.execute_tuning = sdhci_msm_execute_tuning,
+	.toggle_cdr = sdhci_msm_toggle_cdr,
+};
+
+static int __devinit sdhci_msm_probe(struct platform_device *pdev)
+{
+	struct sdhci_host *host;
+	struct sdhci_pltfm_host *pltfm_host;
+	struct sdhci_msm_host *msm_host;
+	struct resource *core_memres = NULL;
+	int ret = 0, pwr_irq = 0, dead = 0;
+	u32 vdd_max_current;
+	u32 host_version;
+
+	pr_debug("%s: Enter %s\n", dev_name(&pdev->dev), __func__);
+	msm_host = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_msm_host),
+				GFP_KERNEL);
+	if (!msm_host) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	init_waitqueue_head(&msm_host->pwr_irq_wait);
+
+	msm_host->sdhci_msm_pdata.ops = &sdhci_msm_ops;
+	host = sdhci_pltfm_init(pdev, &msm_host->sdhci_msm_pdata);
+	if (IS_ERR(host)) {
+		ret = PTR_ERR(host);
+		goto out;
+	}
+
+	pltfm_host = sdhci_priv(host);
+	pltfm_host->priv = msm_host;
+	msm_host->mmc = host->mmc;
+
+	/* Extract platform data */
+	if (pdev->dev.of_node) {
+		msm_host->pdata = sdhci_msm_populate_pdata(&pdev->dev);
+		if (!msm_host->pdata) {
+			dev_err(&pdev->dev, "DT parsing error\n");
+			goto pltfm_free;
+		}
+	} else {
+		dev_err(&pdev->dev, "No device tree node\n");
+		goto pltfm_free;
+	}
+
+	/* Setup Clocks */
+
+	/* Setup SDCC bus voter clock. */
+	msm_host->bus_clk = devm_clk_get(&pdev->dev, "bus_clk");
+	if (!IS_ERR_OR_NULL(msm_host->bus_clk)) {
+		/* Vote for max. clk rate for max. performance */
+		ret = clk_set_rate(msm_host->bus_clk, INT_MAX);
+		if (ret)
+			goto pltfm_free;
+		ret = clk_prepare_enable(msm_host->bus_clk);
+		if (ret)
+			goto pltfm_free;
+	}
+
+	/* Setup main peripheral bus clock */
+	msm_host->pclk = devm_clk_get(&pdev->dev, "iface_clk");
+	if (!IS_ERR(msm_host->pclk)) {
+		ret = clk_prepare_enable(msm_host->pclk);
+		if (ret)
+			goto bus_clk_disable;
+	}
+
+	/* Setup SDC MMC clock */
+	msm_host->clk = devm_clk_get(&pdev->dev, "core_clk");
+	if (IS_ERR(msm_host->clk)) {
+		ret = PTR_ERR(msm_host->clk);
+		goto pclk_disable;
+	}
+
+	ret = clk_prepare_enable(msm_host->clk);
+	if (ret)
+		goto pclk_disable;
+
+	/* Setup regulators */
+	ret = sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, true);
+	if (ret) {
+		dev_err(&pdev->dev, "Regulator setup failed (%d)\n", ret);
+		goto clk_disable;
+	}
+
+	/* Reset the core and Enable SDHC mode */
+	core_memres = platform_get_resource_byname(pdev,
+				IORESOURCE_MEM, "core_mem");
+	msm_host->core_mem = devm_ioremap(&pdev->dev, core_memres->start,
+					resource_size(core_memres));
+
+	if (!msm_host->core_mem) {
+		dev_err(&pdev->dev, "Failed to remap registers\n");
+		ret = -ENOMEM;
+		goto vreg_deinit;
+	}
+
+	/* Set SW_RST bit in POWER register (Offset 0x0) */
+	writel_relaxed(CORE_SW_RST, msm_host->core_mem + CORE_POWER);
+	/* Set HC_MODE_EN bit in HC_MODE register */
+	writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
+
+	/*
+	 * Following are the deviations from SDHC spec v3.0 -
+	 * 1. Card detection is handled using separate GPIO.
+	 * 2. Bus power control is handled by interacting with PMIC.
+	 */
+	host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+	host->quirks |= SDHCI_QUIRK_SINGLE_POWER_WRITE;
+	host->quirks2 |= SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING;
+
+	host_version = readl_relaxed((host->ioaddr + SDHCI_HOST_VERSION));
+	dev_dbg(&pdev->dev, "Host Version: 0x%x Vendor Version 0x%x\n",
+		host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >>
+		  SDHCI_VENDOR_VER_SHIFT));
+	if (((host_version & SDHCI_VENDOR_VER_MASK) >>
+		SDHCI_VENDOR_VER_SHIFT) == SDHCI_VER_100) {
+		/*
+		 * Add 40us delay in interrupt handler when
+		 * operating at initialization frequency(400KHz).
+		 */
+		host->quirks2 |= SDHCI_QUIRK2_SLOW_INT_CLR;
+		/*
+		 * Set Software Reset for DAT line in Software
+		 * Reset Register (Bit 2).
+		 */
+		host->quirks2 |= SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT;
+	}
+
+	/* Setup PWRCTL irq */
+	pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
+	if (pwr_irq < 0) {
+		dev_err(&pdev->dev, "Failed to get pwr_irq by name (%d)\n",
+				pwr_irq);
+		goto vreg_deinit;
+	}
+	ret = devm_request_threaded_irq(&pdev->dev, pwr_irq, NULL,
+					sdhci_msm_pwr_irq, IRQF_ONESHOT,
+					dev_name(&pdev->dev), host);
+	if (ret) {
+		dev_err(&pdev->dev, "Request threaded irq(%d) failed (%d)\n",
+				pwr_irq, ret);
+		goto vreg_deinit;
+	}
+
+	/* Enable pwr irq interrupts */
+	writel_relaxed(INT_MASK, (msm_host->core_mem + CORE_PWRCTL_MASK));
+
+	/* Set host capabilities */
+	msm_host->mmc->caps |= msm_host->pdata->mmc_bus_width;
+	msm_host->mmc->caps |= msm_host->pdata->caps;
+
+	vdd_max_current = sdhci_msm_get_vreg_vdd_max_current(msm_host);
+	if (vdd_max_current >= 800)
+		msm_host->mmc->caps |= MMC_CAP_MAX_CURRENT_800;
+	else if (vdd_max_current >= 600)
+		msm_host->mmc->caps |= MMC_CAP_MAX_CURRENT_600;
+	else if (vdd_max_current >= 400)
+		msm_host->mmc->caps |= MMC_CAP_MAX_CURRENT_400;
+	else
+		msm_host->mmc->caps |= MMC_CAP_MAX_CURRENT_200;
+
+	if (vdd_max_current > 150)
+		msm_host->mmc->caps |= MMC_CAP_SET_XPC_180 |
+					MMC_CAP_SET_XPC_300|
+					MMC_CAP_SET_XPC_330;
+
+	msm_host->mmc->caps |= MMC_CAP_HW_RESET;
+	msm_host->mmc->caps2 |= msm_host->pdata->caps2;
+	msm_host->mmc->caps2 |= MMC_CAP2_PACKED_WR;
+	msm_host->mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
+	msm_host->mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC |
+				MMC_CAP2_DETECT_ON_ERR);
+	msm_host->mmc->caps2 |= MMC_CAP2_SANITIZE;
+	msm_host->mmc->caps2 |= MMC_CAP2_CACHE_CTRL;
+	msm_host->mmc->caps2 |= MMC_CAP2_INIT_BKOPS;
+	msm_host->mmc->caps2 |= MMC_CAP2_POWEROFF_NOTIFY;
+
+	if (msm_host->pdata->nonremovable)
+		msm_host->mmc->caps |= MMC_CAP_NONREMOVABLE;
+
+	ret = sdhci_add_host(host);
+	if (ret) {
+		dev_err(&pdev->dev, "Add host failed (%d)\n", ret);
+		goto vreg_deinit;
+	}
+
+	 /* Set core clk rate, optionally override from dts */
+	if (msm_host->pdata->max_clk)
+		host->max_clk = msm_host->pdata->max_clk;
+	ret = clk_set_rate(msm_host->clk, host->max_clk);
+	if (ret) {
+		dev_err(&pdev->dev, "MClk rate set failed (%d)\n", ret);
+		goto remove_host;
+	}
+
+	/* Successful initialization */
+	goto out;
+
+remove_host:
+	dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
+	sdhci_remove_host(host, dead);
+vreg_deinit:
+	sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, false);
+clk_disable:
+	if (!IS_ERR(msm_host->clk))
+		clk_disable_unprepare(msm_host->clk);
+pclk_disable:
+	if (!IS_ERR(msm_host->pclk))
+		clk_disable_unprepare(msm_host->pclk);
+bus_clk_disable:
+	if (!IS_ERR_OR_NULL(msm_host->bus_clk))
+		clk_disable_unprepare(msm_host->bus_clk);
+pltfm_free:
+	sdhci_pltfm_free(pdev);
+out:
+	pr_debug("%s: Exit %s\n", dev_name(&pdev->dev), __func__);
+	return ret;
+}
+
+static int __devexit sdhci_msm_remove(struct platform_device *pdev)
+{
+	struct sdhci_host *host = platform_get_drvdata(pdev);
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = pltfm_host->priv;
+	struct sdhci_msm_pltfm_data *pdata = msm_host->pdata;
+	int dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) ==
+			0xffffffff);
+
+	pr_debug("%s: %s\n", dev_name(&pdev->dev), __func__);
+	sdhci_remove_host(host, dead);
+	sdhci_pltfm_free(pdev);
+	sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, false);
+	if (!IS_ERR(msm_host->clk))
+		clk_disable_unprepare(msm_host->clk);
+	if (!IS_ERR(msm_host->pclk))
+		clk_disable_unprepare(msm_host->pclk);
+	if (!IS_ERR_OR_NULL(msm_host->bus_clk))
+		clk_disable_unprepare(msm_host->bus_clk);
+	if (pdata->pin_data)
+		sdhci_msm_setup_pins(pdata, false);
+	return 0;
+}
+
+static const struct of_device_id sdhci_msm_dt_match[] = {
+	{.compatible = "qcom,sdhci-msm"},
+};
+MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
+
+static struct platform_driver sdhci_msm_driver = {
+	.probe		= sdhci_msm_probe,
+	.remove		= __devexit_p(sdhci_msm_remove),
+	.driver		= {
+		.name	= "sdhci_msm",
+		.owner	= THIS_MODULE,
+		.of_match_table = sdhci_msm_dt_match,
+	},
+};
+
+module_platform_driver(sdhci_msm_driver);
+
+MODULE_DESCRIPTION("Qualcomm Secure Digital Host Controller Interface driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 8c2bea09..b9bd3a1 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2049,6 +2049,9 @@
 		   controllers do not like that. */
 		sdhci_reset(host, SDHCI_RESET_CMD);
 		sdhci_reset(host, SDHCI_RESET_DATA);
+	} else {
+		if (host->quirks2 & SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT)
+			sdhci_reset(host, SDHCI_RESET_DATA);
 	}
 
 	host->mrq = NULL;
@@ -2135,6 +2138,16 @@
 			SDHCI_INT_INDEX))
 		host->cmd->error = -EILSEQ;
 
+	if (host->quirks2 & SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING) {
+		if ((host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) ||
+			(host->cmd->opcode == MMC_SEND_TUNING_BLOCK)) {
+			if (intmask & SDHCI_INT_CRC) {
+				sdhci_reset(host, SDHCI_RESET_CMD);
+				host->cmd->error = 0;
+			}
+		}
+	}
+
 	if (host->cmd->error) {
 		tasklet_schedule(&host->finish_tasklet);
 		return;
@@ -2162,6 +2175,16 @@
 		 * fall through and take the SDHCI_INT_RESPONSE */
 	}
 
+	if (host->quirks2 & SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING) {
+		if ((host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) ||
+			(host->cmd->opcode == MMC_SEND_TUNING_BLOCK)) {
+			if (intmask & SDHCI_INT_CRC) {
+				sdhci_finish_command(host);
+				return;
+			}
+		}
+	}
+
 	if (intmask & SDHCI_INT_RESPONSE)
 		sdhci_finish_command(host);
 }
@@ -2349,12 +2372,18 @@
 	if (intmask & SDHCI_INT_CMD_MASK) {
 		sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK,
 			SDHCI_INT_STATUS);
+		if ((host->quirks2 & SDHCI_QUIRK2_SLOW_INT_CLR) &&
+		    (host->clock <= 400000))
+			udelay(40);
 		sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
 	}
 
 	if (intmask & SDHCI_INT_DATA_MASK) {
 		sdhci_writel(host, intmask & SDHCI_INT_DATA_MASK,
 			SDHCI_INT_STATUS);
+		if ((host->quirks2 & SDHCI_QUIRK2_SLOW_INT_CLR) &&
+		    (host->clock <= 400000))
+			udelay(40);
 		sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
 	}
 
diff --git a/drivers/net/ethernet/msm/Kconfig b/drivers/net/ethernet/msm/Kconfig
index e15f4a9..4e95614 100644
--- a/drivers/net/ethernet/msm/Kconfig
+++ b/drivers/net/ethernet/msm/Kconfig
@@ -42,6 +42,16 @@
 	help
 	  Debug stats on wakeup counts.
 
+config MSM_RMNET_WWAN
+	tristate "MSM RMNET WWAN Network Device"
+	depends on IPA
+	default n
+	help
+	  WWAN Network Driver
+	  Provides an API to embedded
+	  applications to send and receive
+	  the data to/from A2
+
 config QFEC
 	tristate "QFEC ethernet driver"
 	select MII
diff --git a/drivers/net/ethernet/msm/Makefile b/drivers/net/ethernet/msm/Makefile
index e152ec7..0afa00f 100644
--- a/drivers/net/ethernet/msm/Makefile
+++ b/drivers/net/ethernet/msm/Makefile
@@ -3,6 +3,7 @@
 #
 
 obj-$(CONFIG_MSM_RMNET) += msm_rmnet.o
+obj-$(CONFIG_MSM_RMNET_WWAN) += msm_rmnet_wwan.o
 obj-$(CONFIG_MSM_RMNET_SDIO) += msm_rmnet_sdio.o
 obj-$(CONFIG_MSM_RMNET_BAM) += msm_rmnet_bam.o
 obj-$(CONFIG_MSM_RMNET_SMUX) += msm_rmnet_smux.o
diff --git a/drivers/net/ethernet/msm/msm_rmnet_wwan.c b/drivers/net/ethernet/msm/msm_rmnet_wwan.c
new file mode 100644
index 0000000..fe1ac46
--- /dev/null
+++ b/drivers/net/ethernet/msm/msm_rmnet_wwan.c
@@ -0,0 +1,736 @@
+/* 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.
+ */
+
+/*
+ * WWAN Network Interface.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/wakelock.h>
+#include <linux/msm_rmnet.h>
+#include <linux/if_arp.h>
+#include <linux/platform_device.h>
+#include <net/pkt_sched.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#include <mach/ipa.h>
+
+#define WWAN_DEV_NAME "rmnet%d"
+#define WWAN_METADATA_MASK 0x00FF0000
+#define IPA_RM_INACTIVITY_TIMER 1000
+#define WWAN_DEVICE_COUNT (8)
+#define WWAN_DATA_LEN 2000
+#define HEADROOM_FOR_A2_MUX   8 /* for mux header */
+#define TAILROOM              8 /* for padding by mux layer */
+
+enum wwan_device_status {
+	WWAN_DEVICE_INACTIVE = 0,
+	WWAN_DEVICE_ACTIVE   = 1
+};
+static enum ipa_rm_resource_name
+	ipa_rm_resource_by_ch_id[WWAN_DEVICE_COUNT] = {
+	IPA_RM_RESOURCE_WWAN_0_PROD,
+	IPA_RM_RESOURCE_WWAN_1_PROD,
+	IPA_RM_RESOURCE_WWAN_2_PROD,
+	IPA_RM_RESOURCE_WWAN_3_PROD,
+	IPA_RM_RESOURCE_WWAN_4_PROD,
+	IPA_RM_RESOURCE_WWAN_5_PROD,
+	IPA_RM_RESOURCE_WWAN_6_PROD,
+	IPA_RM_RESOURCE_WWAN_7_PROD
+};
+static enum a2_mux_logical_channel_id
+	a2_mux_lcid_by_ch_id[WWAN_DEVICE_COUNT] = {
+	A2_MUX_WWAN_0,
+	A2_MUX_WWAN_1,
+	A2_MUX_WWAN_2,
+	A2_MUX_WWAN_3,
+	A2_MUX_WWAN_4,
+	A2_MUX_WWAN_5,
+	A2_MUX_WWAN_6,
+	A2_MUX_WWAN_7
+};
+
+/**
+ * struct wwan_private - WWAN private data
+ * @stats: iface statistics
+ * @ch_id: channel id
+ * @lock: spinlock for mutual exclusion
+ * @device_status: holds device status
+ *
+ * WWAN private - holds all relevant info about WWAN driver
+ */
+struct wwan_private {
+	struct net_device_stats stats;
+	uint32_t ch_id;
+	spinlock_t lock;
+	struct completion resource_granted_completion;
+	enum wwan_device_status device_status;
+};
+
+static struct net_device *netdevs[WWAN_DEVICE_COUNT];
+
+static __be16 wwan_ip_type_trans(struct sk_buff *skb)
+{
+	__be16 protocol = 0;
+	/* Determine L3 protocol */
+	switch (skb->data[0] & 0xf0) {
+	case 0x40:
+		protocol = htons(ETH_P_IP);
+		break;
+	case 0x60:
+		protocol = htons(ETH_P_IPV6);
+		break;
+	default:
+		pr_err("[%s] %s() L3 protocol decode error: 0x%02x",
+		       skb->dev->name, __func__, skb->data[0] & 0xf0);
+		/* skb will be dropped in upper layer for unknown protocol */
+		break;
+	}
+	return protocol;
+}
+
+/**
+ * a2_mux_recv_notify() - Deliver an RX packet to network stack
+ *
+ * @skb: skb to be delivered
+ * @dev: network device
+ *
+ * Return codes:
+ * None
+ */
+static void a2_mux_recv_notify(void *dev, struct sk_buff *skb)
+{
+	struct wwan_private *wwan_ptr = netdev_priv(dev);
+
+	skb->dev = dev;
+	skb->protocol = wwan_ip_type_trans(skb);
+	wwan_ptr->stats.rx_packets++;
+	wwan_ptr->stats.rx_bytes += skb->len;
+	pr_debug("[%s] Rx packet #%lu len=%d\n",
+		skb->dev->name,
+		wwan_ptr->stats.rx_packets, skb->len);
+	netif_rx(skb);
+}
+
+/**
+ * wwan_send_packet() - Deliver a TX packet to A2 MUX driver.
+ *
+ * @skb: skb to be delivered
+ * @dev: network device
+ *
+ * Return codes:
+ * 0: success
+ * -EAGAIN: A2 MUX is not ready to send the skb. try later
+ * -EFAULT: A2 MUX rejected the skb
+ * -EPREM: Unknown error
+ */
+static int wwan_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+	struct wwan_private *wwan_ptr = netdev_priv(dev);
+	int ret;
+
+	dev->trans_start = jiffies;
+	ret = a2_mux_write(a2_mux_lcid_by_ch_id[wwan_ptr->ch_id], skb);
+	if (ret != 0 && ret != -EAGAIN && ret != -EFAULT) {
+		pr_err("[%s] %s: write returned error %d",
+			dev->name, __func__, ret);
+		return -EPERM;
+	}
+	return ret;
+}
+
+/**
+ * a2_mux_write_done() - Update device statistics and start
+ * network stack queue is was stop and A2 MUX queue is below low
+ * watermark.
+ *
+ * @dev: network device
+ * @skb: skb to be delivered
+ *
+ * Return codes:
+ * None
+ */
+static void a2_mux_write_done(void *dev, struct sk_buff *skb)
+{
+	struct wwan_private *wwan_ptr = netdev_priv(dev);
+	unsigned long flags;
+
+	pr_debug("%s: write complete\n", __func__);
+	wwan_ptr->stats.tx_packets++;
+	wwan_ptr->stats.tx_bytes += skb->len;
+	pr_debug("[%s] Tx packet #%lu len=%d mark=0x%x\n",
+	    ((struct net_device *)(dev))->name, wwan_ptr->stats.tx_packets,
+	    skb->len, skb->mark);
+	dev_kfree_skb_any(skb);
+	spin_lock_irqsave(&wwan_ptr->lock, flags);
+	if (netif_queue_stopped(dev) &&
+	    a2_mux_is_ch_low(a2_mux_lcid_by_ch_id[wwan_ptr->ch_id])) {
+		pr_debug("%s: Low WM hit, waking queue=%p\n",
+		      __func__, skb);
+		netif_wake_queue(dev);
+	}
+	spin_unlock_irqrestore(&wwan_ptr->lock, flags);
+}
+
+/**
+ * a2_mux_notify() - Callback function for A2 MUX events Handles
+ * A2_MUX_RECEIVE and A2_MUX_WRITE_DONE events.
+ *
+ * @dev: network device
+ * @event: A2 MUX event
+ * @data: Additional data provided by A2 MUX
+ *
+ * Return codes:
+ * None
+ */
+static void a2_mux_notify(void *dev, enum a2_mux_event_type event,
+			  unsigned long data)
+{
+	struct sk_buff *skb = (struct sk_buff *)data;
+
+	switch (event) {
+	case A2_MUX_RECEIVE:
+		if (!skb) {
+			pr_err("[%s] %s: No skb received",
+			   ((struct net_device *)dev)->name, __func__);
+			return;
+		}
+		a2_mux_recv_notify(dev, skb);
+		break;
+	case A2_MUX_WRITE_DONE:
+		a2_mux_write_done(dev, skb);
+		break;
+	default:
+		pr_err("%s: unknown event %d\n", __func__, event);
+		break;
+	}
+}
+
+/**
+ * ipa_rm_resource_granted() - Called upon
+ * IPA_RM_RESOURCE_GRANTED event. Wakes up queue is was stopped.
+ *
+ * @work: work object supplied ny workqueue
+ *
+ * Return codes:
+ * None
+ */
+static void ipa_rm_resource_granted(void *dev)
+{
+	netif_wake_queue(dev);
+}
+/**
+ * ipa_rm_notify() - Callback function for RM events. Handles
+ * IPA_RM_RESOURCE_GRANTED and IPA_RM_RESOURCE_RELEASED events.
+ * IPA_RM_RESOURCE_GRANTED is handled in the context of shared
+ * workqueue.
+ *
+ * @dev: network device
+ * @event: IPA RM event
+ * @data: Additional data provided by IPA RM
+ *
+ * Return codes:
+ * None
+ */
+static void ipa_rm_notify(void *dev, enum ipa_rm_event event,
+			  unsigned long data)
+{
+	struct wwan_private *wwan_ptr = netdev_priv(dev);
+
+	pr_debug("%s: event %d\n", __func__, event);
+	switch (event) {
+	case IPA_RM_RESOURCE_GRANTED:
+		if (wwan_ptr->device_status == WWAN_DEVICE_INACTIVE) {
+			complete_all(&wwan_ptr->resource_granted_completion);
+			break;
+		}
+		ipa_rm_resource_granted(dev);
+		break;
+	case IPA_RM_RESOURCE_RELEASED:
+		break;
+	default:
+		pr_err("%s: unknown event %d\n", __func__, event);
+		break;
+	}
+}
+
+static int wwan_register_to_ipa(struct net_device *dev)
+{
+	struct wwan_private *wwan_ptr = netdev_priv(dev);
+	struct ipa_tx_intf tx_properties = {0};
+	struct ipa_ioc_tx_intf_prop tx_ioc_properties[2] = { {0}, {0} };
+	struct ipa_ioc_tx_intf_prop *tx_ipv4_property;
+	struct ipa_ioc_tx_intf_prop *tx_ipv6_property;
+	struct ipa_rx_intf rx_properties = {0};
+	struct ipa_ioc_rx_intf_prop rx_ioc_properties[2] = { {0}, {0} };
+	struct ipa_ioc_rx_intf_prop *rx_ipv4_property;
+	struct ipa_ioc_rx_intf_prop *rx_ipv6_property;
+	int ret = 0;
+
+	pr_debug("[%s] %s:\n", dev->name, __func__);
+	tx_properties.prop = tx_ioc_properties;
+	tx_ipv4_property = &tx_properties.prop[0];
+	tx_ipv4_property->ip = IPA_IP_v4;
+	tx_ipv4_property->dst_pipe = IPA_CLIENT_A2_EMBEDDED_CONS;
+	snprintf(tx_ipv4_property->hdr_name, IPA_RESOURCE_NAME_MAX, "%s%d",
+		 A2_MUX_HDR_NAME_V4_PREF,
+		 a2_mux_lcid_by_ch_id[wwan_ptr->ch_id]);
+	tx_ipv6_property = &tx_properties.prop[1];
+	tx_ipv6_property->ip = IPA_IP_v6;
+	tx_ipv6_property->dst_pipe = IPA_CLIENT_A2_EMBEDDED_CONS;
+	snprintf(tx_ipv6_property->hdr_name, IPA_RESOURCE_NAME_MAX, "%s%d",
+		 A2_MUX_HDR_NAME_V6_PREF,
+		 a2_mux_lcid_by_ch_id[wwan_ptr->ch_id]);
+	tx_properties.num_props = 2;
+	rx_properties.prop = rx_ioc_properties;
+	rx_ipv4_property = &rx_properties.prop[0];
+	rx_ipv4_property->ip = IPA_IP_v4;
+	rx_ipv4_property->attrib.attrib_mask |= IPA_FLT_META_DATA;
+	rx_ipv4_property->attrib.meta_data = wwan_ptr->ch_id;
+	rx_ipv4_property->attrib.meta_data_mask = WWAN_METADATA_MASK;
+	rx_ipv4_property->src_pipe = IPA_CLIENT_A2_EMBEDDED_PROD;
+	rx_ipv6_property = &rx_properties.prop[1];
+	rx_ipv6_property->ip = IPA_IP_v6;
+	rx_ipv6_property->attrib.attrib_mask |= IPA_FLT_META_DATA;
+	rx_ipv6_property->attrib.meta_data = wwan_ptr->ch_id;
+	rx_ipv6_property->attrib.meta_data_mask = WWAN_METADATA_MASK;
+	rx_ipv6_property->src_pipe = IPA_CLIENT_A2_EMBEDDED_PROD;
+	rx_properties.num_props = 2;
+	ret = ipa_register_intf(dev->name, &tx_properties, &rx_properties);
+	if (ret) {
+		pr_err("[%s] %s: ipa_register_intf failed %d\n", dev->name,
+		       __func__, ret);
+		return ret;
+	}
+	return 0;
+}
+
+static int __wwan_open(struct net_device *dev)
+{
+	int r;
+	struct wwan_private *wwan_ptr = netdev_priv(dev);
+
+	pr_debug("[%s] __wwan_open()\n", dev->name);
+	if (wwan_ptr->device_status != WWAN_DEVICE_ACTIVE) {
+		INIT_COMPLETION(wwan_ptr->resource_granted_completion);
+		r = ipa_rm_inactivity_timer_request_resource(
+			ipa_rm_resource_by_ch_id[wwan_ptr->ch_id]);
+		if (r < 0 && r != -EINPROGRESS) {
+			pr_err("%s: ipa rm timer request resource failed %d\n",
+					__func__, r);
+			return -ENODEV;
+		}
+		if (r == -EINPROGRESS) {
+			wait_for_completion(
+				&wwan_ptr->resource_granted_completion);
+		}
+		r = a2_mux_open_channel(a2_mux_lcid_by_ch_id[wwan_ptr->ch_id],
+					dev, a2_mux_notify);
+		if (r < 0) {
+			pr_err("%s: ch=%d failed with rc %d\n",
+					__func__, wwan_ptr->ch_id, r);
+			ipa_rm_inactivity_timer_release_resource(
+				ipa_rm_resource_by_ch_id[wwan_ptr->ch_id]);
+			return -ENODEV;
+		}
+		ipa_rm_inactivity_timer_release_resource(
+			ipa_rm_resource_by_ch_id[wwan_ptr->ch_id]);
+		r = wwan_register_to_ipa(dev);
+		if (r < 0) {
+			pr_err("%s: ch=%d failed to register to IPA rc %d\n",
+					__func__, wwan_ptr->ch_id, r);
+			return -ENODEV;
+		}
+	}
+	wwan_ptr->device_status = WWAN_DEVICE_ACTIVE;
+	return 0;
+}
+
+/**
+ * wwan_open() - Opens the wwan network interface. Opens logical
+ * channel on A2 MUX driver and starts the network stack queue
+ *
+ * @dev: network device
+ *
+ * Return codes:
+ * 0: success
+ * -ENODEV: Error while opening logical channel on A2 MUX driver
+ */
+static int wwan_open(struct net_device *dev)
+{
+	int rc = 0;
+
+	pr_debug("[%s] wwan_open()\n", dev->name);
+	rc = __wwan_open(dev);
+	if (rc == 0)
+		netif_start_queue(dev);
+	return rc;
+}
+
+
+static int __wwan_close(struct net_device *dev)
+{
+	struct wwan_private *wwan_ptr = netdev_priv(dev);
+	int rc = 0;
+
+	if (wwan_ptr->device_status == WWAN_DEVICE_ACTIVE) {
+		wwan_ptr->device_status = WWAN_DEVICE_INACTIVE;
+		/* do not close wwan port once up,  this causes
+			remote side to hang if tried to open again */
+		INIT_COMPLETION(wwan_ptr->resource_granted_completion);
+		rc = ipa_rm_inactivity_timer_request_resource(
+			ipa_rm_resource_by_ch_id[wwan_ptr->ch_id]);
+		if (rc < 0 && rc != -EINPROGRESS) {
+			pr_err("%s: ipa rm timer request resource failed %d\n",
+					__func__, rc);
+			return -ENODEV;
+		}
+		if (rc == -EINPROGRESS) {
+			wait_for_completion(
+				&wwan_ptr->resource_granted_completion);
+		}
+		rc = a2_mux_close_channel(
+			a2_mux_lcid_by_ch_id[wwan_ptr->ch_id]);
+		if (rc) {
+			pr_err("[%s] %s: a2_mux_close_channel failed %d\n",
+			       dev->name, __func__, rc);
+			ipa_rm_inactivity_timer_release_resource(
+				ipa_rm_resource_by_ch_id[wwan_ptr->ch_id]);
+			return rc;
+		}
+		ipa_rm_inactivity_timer_release_resource(
+			ipa_rm_resource_by_ch_id[wwan_ptr->ch_id]);
+		rc = ipa_deregister_intf(dev->name);
+		if (rc) {
+			pr_err("[%s] %s: ipa_deregister_intf failed %d\n",
+			       dev->name, __func__, rc);
+			return rc;
+		}
+		return rc;
+	} else
+		return -EBADF;
+}
+
+/**
+ * wwan_stop() - Stops the wwan network interface. Closes
+ * logical channel on A2 MUX driver and stops the network stack
+ * queue
+ *
+ * @dev: network device
+ *
+ * Return codes:
+ * 0: success
+ * -ENODEV: Error while opening logical channel on A2 MUX driver
+ */
+static int wwan_stop(struct net_device *dev)
+{
+	pr_debug("[%s] wwan_stop()\n", dev->name);
+	__wwan_close(dev);
+	netif_stop_queue(dev);
+	return 0;
+}
+
+static int wwan_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if (0 > new_mtu || WWAN_DATA_LEN < new_mtu)
+		return -EINVAL;
+	pr_debug("[%s] MTU change: old=%d new=%d\n",
+		dev->name, dev->mtu, new_mtu);
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+/**
+ * wwan_xmit() - Transmits an skb. In charge of asking IPA
+ * RM needed resources. In case that IPA RM is not ready, then
+ * the skb is saved for tranmitting as soon as IPA RM resources
+ * are granted.
+ *
+ * @skb: skb to be transmitted
+ * @dev: network device
+ *
+ * Return codes:
+ * 0: success
+ * NETDEV_TX_BUSY: Error while transmitting the skb. Try again
+ * later
+ * -EFAULT: Error while transmitting the skb
+ */
+static int wwan_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct wwan_private *wwan_ptr = netdev_priv(dev);
+	unsigned long flags;
+	int ret = 0;
+
+	if (netif_queue_stopped(dev)) {
+		pr_err("[%s]fatal: wwan_xmit called when netif_queue stopped\n",
+		       dev->name);
+		return 0;
+	}
+	ret = ipa_rm_inactivity_timer_request_resource(
+		ipa_rm_resource_by_ch_id[wwan_ptr->ch_id]);
+	if (ret == -EINPROGRESS) {
+		netif_stop_queue(dev);
+		return NETDEV_TX_BUSY;
+	}
+	if (ret) {
+		pr_err("[%s] fatal: ipa rm timer request resource failed %d\n",
+		       dev->name, ret);
+		return -EFAULT;
+	}
+	ret = wwan_send_packet(skb, dev);
+	if (ret == -EPERM) {
+		ret = NETDEV_TX_BUSY;
+		goto exit;
+	}
+	/*
+	 * detected SSR a bit early.  shut some things down now, and leave
+	 * the rest to the main ssr handling code when that happens later
+	 */
+	if (ret == -EFAULT) {
+		netif_carrier_off(dev);
+		dev_kfree_skb_any(skb);
+		ret = 0;
+		goto exit;
+	}
+	if (ret == -EAGAIN) {
+		/*
+		 * This should not happen
+		 * EAGAIN means we attempted to overflow the high watermark
+		 * Clearly the queue is not stopped like it should be, so
+		 * stop it and return BUSY to the TCP/IP framework.  It will
+		 * retry this packet with the queue is restarted which happens
+		 * in the write_done callback when the low watermark is hit.
+		 */
+		netif_stop_queue(dev);
+		ret = NETDEV_TX_BUSY;
+		goto exit;
+	}
+	spin_lock_irqsave(&wwan_ptr->lock, flags);
+	if (a2_mux_is_ch_full(a2_mux_lcid_by_ch_id[wwan_ptr->ch_id])) {
+		netif_stop_queue(dev);
+		pr_debug("%s: High WM hit, stopping queue=%p\n",
+		       __func__, skb);
+	}
+	spin_unlock_irqrestore(&wwan_ptr->lock, flags);
+exit:
+	ipa_rm_inactivity_timer_release_resource(
+		ipa_rm_resource_by_ch_id[wwan_ptr->ch_id]);
+	return ret;
+}
+
+static struct net_device_stats *wwan_get_stats(struct net_device *dev)
+{
+	struct wwan_private *wwan_ptr = netdev_priv(dev);
+	return &wwan_ptr->stats;
+}
+
+static void wwan_tx_timeout(struct net_device *dev)
+{
+	pr_warning("[%s] wwan_tx_timeout()\n", dev->name);
+}
+
+/**
+ * wwan_ioctl() - I/O control for wwan network driver.
+ *
+ * @dev: network device
+ * @ifr: ignored
+ * @cmd: cmd to be excecuded. can be one of the following:
+ * WWAN_IOCTL_OPEN - Open the network interface
+ * WWAN_IOCTL_CLOSE - Close the network interface
+ *
+ * Return codes:
+ * 0: success
+ * NETDEV_TX_BUSY: Error while transmitting the skb. Try again
+ * later
+ * -EFAULT: Error while transmitting the skb
+ */
+static int wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	int rc = 0;
+
+	switch (cmd) {
+	case RMNET_IOCTL_SET_LLP_IP:        /* Set RAWIP protocol */
+		break;
+	case RMNET_IOCTL_GET_LLP:           /* Get link protocol state */
+		ifr->ifr_ifru.ifru_data = (void *) RMNET_MODE_LLP_IP;
+		break;
+	case RMNET_IOCTL_SET_QOS_DISABLE:   /* Set QoS header disabled */
+		break;
+	case RMNET_IOCTL_FLOW_ENABLE:
+		tc_qdisc_flow_control(dev, (u32)ifr->ifr_data, 1);
+		pr_debug("[%s] %s: enabled flow", dev->name, __func__);
+		break;
+	case RMNET_IOCTL_FLOW_DISABLE:
+		tc_qdisc_flow_control(dev, (u32)ifr->ifr_data, 0);
+		pr_debug("[%s] %s: disabled flow", dev->name, __func__);
+		break;
+	case RMNET_IOCTL_GET_QOS:           /* Get QoS header state    */
+		/* QoS disabled */
+		ifr->ifr_ifru.ifru_data = (void *) 0;
+		break;
+	case RMNET_IOCTL_GET_OPMODE:        /* Get operation mode      */
+		ifr->ifr_ifru.ifru_data = (void *) RMNET_MODE_LLP_IP;
+		break;
+	case RMNET_IOCTL_OPEN:  /* Open transport port */
+		rc = __wwan_open(dev);
+		pr_debug("[%s] wwan_ioctl(): open transport port\n",
+		     dev->name);
+		break;
+	case RMNET_IOCTL_CLOSE:  /* Close transport port */
+		rc = __wwan_close(dev);
+		pr_debug("[%s] wwan_ioctl(): close transport port\n",
+		     dev->name);
+		break;
+	default:
+		pr_err("[%s] error: wwan_ioct called for unsupported cmd[%d]",
+		       dev->name, cmd);
+		return -EINVAL;
+	}
+	return rc;
+}
+
+static const struct net_device_ops wwan_ops_ip = {
+	.ndo_open = wwan_open,
+	.ndo_stop = wwan_stop,
+	.ndo_start_xmit = wwan_xmit,
+	.ndo_get_stats = wwan_get_stats,
+	.ndo_tx_timeout = wwan_tx_timeout,
+	.ndo_do_ioctl = wwan_ioctl,
+	.ndo_change_mtu = wwan_change_mtu,
+	.ndo_set_mac_address = 0,
+	.ndo_validate_addr = 0,
+};
+
+/**
+ * wwan_setup() - Setups the wwan network driver.
+ *
+ * @dev: network device
+ *
+ * Return codes:
+ * None
+ */
+static void wwan_setup(struct net_device *dev)
+{
+	dev->netdev_ops = &wwan_ops_ip;
+	ether_setup(dev);
+	/* set this after calling ether_setup */
+	dev->header_ops = 0;  /* No header */
+	dev->type = ARPHRD_RAWIP;
+	dev->hard_header_len = 0;
+	dev->mtu = WWAN_DATA_LEN;
+	dev->addr_len = 0;
+	dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST);
+	dev->needed_headroom = HEADROOM_FOR_A2_MUX;
+	dev->needed_tailroom = TAILROOM;
+	dev->watchdog_timeo = 1000;
+}
+
+/**
+ * wwan_init() - Initialized the module and registers as a
+ * network interface to the network stack
+ *
+ * Return codes:
+ * 0: success
+ * -ENOMEM: No memory available
+ * -EFAULT: Internal error
+ */
+static int __init wwan_init(void)
+{
+	int ret;
+	struct net_device *dev;
+	struct wwan_private *wwan_ptr;
+	unsigned n;
+	struct ipa_rm_create_params ipa_rm_params;
+
+	pr_info("%s: WWAN devices[%d]\n", __func__, WWAN_DEVICE_COUNT);
+	for (n = 0; n < WWAN_DEVICE_COUNT; n++) {
+		dev = alloc_netdev(sizeof(struct wwan_private),
+				   WWAN_DEV_NAME, wwan_setup);
+		if (!dev) {
+			pr_err("%s: no memory for netdev %d\n", __func__, n);
+			ret = -ENOMEM;
+			goto fail;
+		}
+		netdevs[n] = dev;
+		wwan_ptr = netdev_priv(dev);
+		wwan_ptr->ch_id = n;
+		spin_lock_init(&wwan_ptr->lock);
+		init_completion(&wwan_ptr->resource_granted_completion);
+		memset(&ipa_rm_params, 0, sizeof(struct ipa_rm_create_params));
+		ipa_rm_params.name = ipa_rm_resource_by_ch_id[n];
+		ipa_rm_params.reg_params.user_data = dev;
+		ipa_rm_params.reg_params.notify_cb = ipa_rm_notify;
+		ret = ipa_rm_create_resource(&ipa_rm_params);
+		if (ret) {
+			pr_err("%s: unable to create resourse %d in IPA RM\n",
+			       __func__, ipa_rm_resource_by_ch_id[n]);
+			goto fail;
+		}
+		ret = ipa_rm_inactivity_timer_init(ipa_rm_resource_by_ch_id[n],
+						   IPA_RM_INACTIVITY_TIMER);
+		if (ret) {
+			pr_err("%s: ipa rm timer init failed %d on ins %d\n",
+			       __func__, ret, n);
+			goto fail;
+		}
+		ret = ipa_rm_add_dependency(ipa_rm_resource_by_ch_id[n],
+					    IPA_RM_RESOURCE_A2_CONS);
+		if (ret) {
+			pr_err("%s: unable to add dependency %d rc=%d\n",
+			       __func__, n, ret);
+			goto fail;
+		}
+		ret = register_netdev(dev);
+		if (ret) {
+			pr_err("%s: unable to register netdev %d rc=%d\n",
+			       __func__, n, ret);
+			goto fail;
+		}
+	}
+	return 0;
+fail:
+	for (n = 0; n < WWAN_DEVICE_COUNT; n++) {
+		if (!netdevs[n])
+			break;
+		unregister_netdev(netdevs[n]);
+		ipa_rm_inactivity_timer_destroy(ipa_rm_resource_by_ch_id[n]);
+		free_netdev(netdevs[n]);
+		netdevs[n] = NULL;
+	}
+	return ret;
+}
+late_initcall(wwan_init);
+
+void wwan_cleanup(void)
+{
+	unsigned n;
+
+	pr_info("%s: WWAN devices[%d]\n", __func__, WWAN_DEVICE_COUNT);
+	for (n = 0; n < WWAN_DEVICE_COUNT; n++) {
+		unregister_netdev(netdevs[n]);
+		ipa_rm_inactivity_timer_destroy(ipa_rm_resource_by_ch_id[n]);
+		free_netdev(netdevs[n]);
+		netdevs[n] = NULL;
+	}
+}
+
+MODULE_DESCRIPTION("WWAN Network Interface");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c
index 6a315d2..0aa9677 100644
--- a/drivers/net/wireless/wcnss/wcnss_vreg.c
+++ b/drivers/net/wireless/wcnss/wcnss_vreg.c
@@ -156,8 +156,15 @@
 			goto fail;
 		}
 
-		/* power on thru SSR should not set NV bit,
-		 * during SSR, NV bin is downloaded by WLAN driver
+		/* Enable IRIS XO */
+		rc = clk_prepare_enable(clk);
+		if (rc) {
+			pr_err("clk enable failed\n");
+			goto fail;
+		}
+		/* NV bit is set to indicate that platform driver is capable
+		 * of doing NV download. SSR should not set NV bit; during
+		 * SSR NV bin is downloaded by WLAN driver.
 		 */
 		if (!wcnss_cold_boot_done()) {
 			pr_debug("wcnss: Indicate NV bin download\n");
@@ -168,13 +175,6 @@
 		}
 
 		pmu_conf_reg = msm_wcnss_base + pmu_offset;
-
-		/* Enable IRIS XO */
-		rc = clk_prepare_enable(clk);
-		if (rc) {
-			pr_err("clk enable failed\n");
-			goto fail;
-		}
 		writel_relaxed(0, pmu_conf_reg);
 		reg = readl_relaxed(pmu_conf_reg);
 		reg |= WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP |
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index ed4e246..867aec1 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -58,16 +58,35 @@
 
 #define MSM_RIVA_CCU_BASE			0x03200800
 
-#define CCU_INVALID_ADDR_OFFSET		0x100
-#define CCU_LAST_ADDR0_OFFSET		0x104
-#define CCU_LAST_ADDR1_OFFSET		0x108
-#define CCU_LAST_ADDR2_OFFSET		0x10c
+#define CCU_RIVA_INVALID_ADDR_OFFSET		0x100
+#define CCU_RIVA_LAST_ADDR0_OFFSET		0x104
+#define CCU_RIVA_LAST_ADDR1_OFFSET		0x108
+#define CCU_RIVA_LAST_ADDR2_OFFSET		0x10c
 
 #define MSM_PRONTO_A2XB_BASE		0xfb100400
-#define A2XB_CFG_OFFSET		        0x00
-#define A2XB_INT_SRC_OFFSET		0x0c
+#define A2XB_CFG_OFFSET				0x00
+#define A2XB_INT_SRC_OFFSET			0x0c
+#define A2XB_TSTBUS_CTRL_OFFSET		0x14
+#define A2XB_TSTBUS_OFFSET			0x18
 #define A2XB_ERR_INFO_OFFSET		0x1c
 
+#define WCNSS_TSTBUS_CTRL_EN		BIT(0)
+#define WCNSS_TSTBUS_CTRL_AXIM		(0x02 << 1)
+#define WCNSS_TSTBUS_CTRL_CMDFIFO	(0x03 << 1)
+#define WCNSS_TSTBUS_CTRL_WRFIFO	(0x04 << 1)
+#define WCNSS_TSTBUS_CTRL_RDFIFO	(0x05 << 1)
+#define WCNSS_TSTBUS_CTRL_CTRL		(0x07 << 1)
+#define WCNSS_TSTBUS_CTRL_AXIM_CFG0	(0x00 << 6)
+#define WCNSS_TSTBUS_CTRL_AXIM_CFG1	(0x01 << 6)
+#define WCNSS_TSTBUS_CTRL_CTRL_CFG0	(0x00 << 12)
+#define WCNSS_TSTBUS_CTRL_CTRL_CFG1	(0x01 << 12)
+
+#define MSM_PRONTO_CCPU_BASE			0xfb205050
+#define CCU_PRONTO_INVALID_ADDR_OFFSET		0x08
+#define CCU_PRONTO_LAST_ADDR0_OFFSET		0x0c
+#define CCU_PRONTO_LAST_ADDR1_OFFSET		0x10
+#define CCU_PRONTO_LAST_ADDR2_OFFSET		0x14
+
 #define WCNSS_CTRL_CHANNEL			"WCNSS_CTRL"
 #define WCNSS_MAX_FRAME_SIZE		500
 #define WCNSS_VERSION_LEN			30
@@ -173,6 +192,7 @@
 	void __iomem *msm_wcnss_base;
 	void __iomem *riva_ccu_base;
 	void __iomem *pronto_a2xb_base;
+	void __iomem *pronto_ccpu_base;
 } *penv = NULL;
 
 static ssize_t wcnss_serial_number_show(struct device *dev,
@@ -253,19 +273,19 @@
 	void __iomem *ccu_reg;
 	u32 reg = 0;
 
-	ccu_reg = penv->riva_ccu_base + CCU_INVALID_ADDR_OFFSET;
+	ccu_reg = penv->riva_ccu_base + CCU_RIVA_INVALID_ADDR_OFFSET;
 	reg = readl_relaxed(ccu_reg);
 	pr_info_ratelimited("%s: CCU_CCPU_INVALID_ADDR %08x\n", __func__, reg);
 
-	ccu_reg = penv->riva_ccu_base + CCU_LAST_ADDR0_OFFSET;
+	ccu_reg = penv->riva_ccu_base + CCU_RIVA_LAST_ADDR0_OFFSET;
 	reg = readl_relaxed(ccu_reg);
 	pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR0 %08x\n", __func__, reg);
 
-	ccu_reg = penv->riva_ccu_base + CCU_LAST_ADDR1_OFFSET;
+	ccu_reg = penv->riva_ccu_base + CCU_RIVA_LAST_ADDR1_OFFSET;
 	reg = readl_relaxed(ccu_reg);
 	pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR1 %08x\n", __func__, reg);
 
-	ccu_reg = penv->riva_ccu_base + CCU_LAST_ADDR2_OFFSET;
+	ccu_reg = penv->riva_ccu_base + CCU_RIVA_LAST_ADDR2_OFFSET;
 	reg = readl_relaxed(ccu_reg);
 	pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg);
 
@@ -275,7 +295,7 @@
 /* Log pronto debug registers before sending reset interrupt */
 void wcnss_pronto_log_debug_regs(void)
 {
-	void __iomem *reg_addr;
+	void __iomem *reg_addr, *tst_addr, *tst_ctrl_addr;
 	u32 reg = 0;
 
 	reg_addr = penv->pronto_a2xb_base + A2XB_CFG_OFFSET;
@@ -290,6 +310,84 @@
 	reg = readl_relaxed(reg_addr);
 	pr_info_ratelimited("%s: A2XB_ERR_INFO_OFFSET %08x\n", __func__, reg);
 
+	reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_INVALID_ADDR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_info_ratelimited("%s: CCU_CCPU_INVALID_ADDR %08x\n", __func__, reg);
+
+	reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_LAST_ADDR0_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR0 %08x\n", __func__, reg);
+
+	reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_LAST_ADDR1_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR1 %08x\n", __func__, reg);
+
+	reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_LAST_ADDR2_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg);
+
+	tst_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_OFFSET;
+	tst_ctrl_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_CTRL_OFFSET;
+
+	/*  read data FIFO */
+	reg = 0;
+	reg = reg | WCNSS_TSTBUS_CTRL_EN | WCNSS_TSTBUS_CTRL_RDFIFO;
+	writel_relaxed(reg, tst_ctrl_addr);
+	reg = readl_relaxed(tst_addr);
+	pr_info_ratelimited("%s:  Read data FIFO testbus %08x\n",
+					__func__, reg);
+
+	/*  command FIFO */
+	reg = 0;
+	reg = reg | WCNSS_TSTBUS_CTRL_EN | WCNSS_TSTBUS_CTRL_CMDFIFO;
+	writel_relaxed(reg, tst_ctrl_addr);
+	reg = readl_relaxed(tst_addr);
+	pr_info_ratelimited("%s:  Command FIFO testbus %08x\n",
+					__func__, reg);
+
+	/*  write data FIFO */
+	reg = 0;
+	reg = reg | WCNSS_TSTBUS_CTRL_EN | WCNSS_TSTBUS_CTRL_WRFIFO;
+	writel_relaxed(reg, tst_ctrl_addr);
+	reg = readl_relaxed(tst_addr);
+	pr_info_ratelimited("%s:  Rrite data FIFO testbus %08x\n",
+					__func__, reg);
+
+	/*   AXIM SEL CFG0 */
+	reg = 0;
+	reg = reg | WCNSS_TSTBUS_CTRL_EN | WCNSS_TSTBUS_CTRL_AXIM |
+				WCNSS_TSTBUS_CTRL_AXIM_CFG0;
+	writel_relaxed(reg, tst_ctrl_addr);
+	reg = readl_relaxed(tst_addr);
+	pr_info_ratelimited("%s:  AXIM SEL CFG0 testbus %08x\n",
+					__func__, reg);
+
+	/*   AXIM SEL CFG1 */
+	reg = 0;
+	reg = reg | WCNSS_TSTBUS_CTRL_EN | WCNSS_TSTBUS_CTRL_AXIM |
+				WCNSS_TSTBUS_CTRL_AXIM_CFG1;
+	writel_relaxed(reg, tst_ctrl_addr);
+	reg = readl_relaxed(tst_addr);
+	pr_info_ratelimited("%s:  AXIM SEL CFG1 testbus %08x\n",
+					__func__, reg);
+
+	/*   CTRL SEL CFG0 */
+	reg = 0;
+	reg = reg | WCNSS_TSTBUS_CTRL_EN | WCNSS_TSTBUS_CTRL_CTRL |
+		WCNSS_TSTBUS_CTRL_CTRL_CFG0;
+	writel_relaxed(reg, tst_ctrl_addr);
+	reg = readl_relaxed(tst_addr);
+	pr_info_ratelimited("%s:  CTRL SEL CFG0 testbus %08x\n",
+					__func__, reg);
+
+	/*   CTRL SEL CFG1 */
+	reg = 0;
+	reg = reg | WCNSS_TSTBUS_CTRL_EN | WCNSS_TSTBUS_CTRL_CTRL |
+		WCNSS_TSTBUS_CTRL_CTRL_CFG1;
+	writel_relaxed(reg, tst_ctrl_addr);
+	reg = readl_relaxed(tst_addr);
+	pr_info_ratelimited("%s:  CTRL SEL CFG1 testbus %08x\n", __func__, reg);
+
 }
 EXPORT_SYMBOL(wcnss_pronto_log_debug_regs);
 
@@ -1071,11 +1169,19 @@
 			pr_err("%s: ioremap wcnss physical failed\n", __func__);
 			goto fail_ioremap;
 		}
+		penv->pronto_ccpu_base =  ioremap(MSM_PRONTO_CCPU_BASE, SZ_512);
+		if (!penv->pronto_ccpu_base) {
+			ret = -ENOMEM;
+			pr_err("%s: ioremap wcnss physical failed\n", __func__);
+			goto fail_ioremap2;
+		}
 	}
 	penv->cold_boot_done = 1;
 
 	return 0;
 
+fail_ioremap2:
+	iounmap(penv->pronto_a2xb_base);
 fail_ioremap:
 	iounmap(penv->msm_wcnss_base);
 fail_wake:
diff --git a/drivers/platform/msm/ipa/Makefile b/drivers/platform/msm/ipa/Makefile
index a25c799..b7eca61 100644
--- a/drivers/platform/msm/ipa/Makefile
+++ b/drivers/platform/msm/ipa/Makefile
@@ -1,4 +1,4 @@
 obj-$(CONFIG_IPA) += ipat.o
 ipat-y := ipa.o ipa_debugfs.o ipa_hdr.o ipa_flt.o ipa_rt.o ipa_dp.o ipa_client.o \
-	ipa_utils.o ipa_nat.o rmnet_bridge.o a2_service.o ipa_bridge.o ipa_intf.o \
+	ipa_utils.o ipa_nat.o rmnet_bridge.o a2_service.o ipa_bridge.o ipa_intf.o teth_bridge.o \
 	ipa_rm.o ipa_rm_dependency_graph.o ipa_rm_peers_list.o ipa_rm_resource.o ipa_rm_inactivity_timer.o
diff --git a/drivers/platform/msm/ipa/a2_service.c b/drivers/platform/msm/ipa/a2_service.c
index 2c5245c..4b5f0a2 100644
--- a/drivers/platform/msm/ipa/a2_service.c
+++ b/drivers/platform/msm/ipa/a2_service.c
@@ -53,6 +53,8 @@
 	spinlock_t		lock;
 	int			num_tx_pkts;
 	int			use_wm;
+	u32			v4_hdr_hdl;
+	u32			v6_hdr_hdl;
 };
 struct tx_pkt_info {
 	struct sk_buff		*skb;
@@ -70,6 +72,7 @@
 	u8			ch_id;
 	u16			pkt_len;
 };
+
 struct a2_mux_context_type {
 	u32 tethered_prod;
 	u32 tethered_cons;
@@ -515,6 +518,9 @@
 		goto bridge_tethered_dl_failed;
 	}
 	memset(&connect_params, 0, sizeof(struct ipa_sys_connect_params));
+	connect_params.ipa_ep_cfg.hdr.hdr_len = sizeof(struct bam_mux_hdr);
+	connect_params.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
+	connect_params.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 6;
 	connect_params.client = IPA_CLIENT_A2_EMBEDDED_CONS;
 	connect_params.notify = ipa_embedded_notify;
 	connect_params.desc_fifo_sz = 0x800;
@@ -527,6 +533,9 @@
 		goto bridge_embedded_ul_failed;
 	}
 	memset(&connect_params, 0, sizeof(struct ipa_sys_connect_params));
+	connect_params.ipa_ep_cfg.hdr.hdr_len = sizeof(struct bam_mux_hdr);
+	connect_params.ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
+	connect_params.ipa_ep_cfg.hdr.hdr_ofst_metadata = 4;
 	connect_params.client = IPA_CLIENT_A2_EMBEDDED_PROD;
 	connect_params.notify = ipa_embedded_notify;
 	connect_params.desc_fifo_sz = 0x800;
@@ -1006,6 +1015,176 @@
 }
 
 /**
+ * a2_mux_add_hdr() - called when MUX header should
+ *		be added
+ * @lcid: logical channel ID
+ *
+ * Returns: 0 on success, negative on failure
+ */
+static int a2_mux_add_hdr(enum a2_mux_logical_channel_id lcid)
+{
+	struct ipa_ioc_add_hdr *hdrs;
+	struct ipa_hdr_add *ipv4_hdr;
+	struct ipa_hdr_add *ipv6_hdr;
+	struct bam_mux_hdr *dmux_hdr;
+	int rc;
+
+	IPADBG("%s: ch %d\n", __func__, lcid);
+
+	if (lcid < A2_MUX_WWAN_0 || lcid > A2_MUX_WWAN_7) {
+		IPAERR("%s: non valid lcid passed: %d\n", __func__, lcid);
+		return -EINVAL;
+	}
+
+
+	hdrs = kzalloc(sizeof(struct ipa_ioc_add_hdr) +
+		       2 * sizeof(struct ipa_hdr_add), GFP_KERNEL);
+	if (!hdrs) {
+		IPAERR("%s: hdr allocation fail for ch %d\n", __func__, lcid);
+		return -ENOMEM;
+	}
+
+	ipv4_hdr = &hdrs->hdr[0];
+	ipv6_hdr = &hdrs->hdr[1];
+
+	dmux_hdr = (struct bam_mux_hdr *)ipv4_hdr->hdr;
+	snprintf(ipv4_hdr->name, IPA_RESOURCE_NAME_MAX, "%s%d",
+		 A2_MUX_HDR_NAME_V4_PREF, lcid);
+	dmux_hdr->magic_num = BAM_MUX_HDR_MAGIC_NO;
+	dmux_hdr->cmd = BAM_MUX_HDR_CMD_DATA;
+	dmux_hdr->reserved = 0;
+	dmux_hdr->ch_id = lcid;
+
+	/* Packet lenght is added by IPA */
+	dmux_hdr->pkt_len = 0;
+	dmux_hdr->pad_len = 0;
+
+	dmux_hdr->magic_num = htons(dmux_hdr->magic_num);
+	IPADBG("converted to network order magic_num=%d\n",
+		    dmux_hdr->magic_num);
+
+	ipv4_hdr->hdr_len = sizeof(struct bam_mux_hdr);
+	ipv4_hdr->is_partial = 0;
+
+	dmux_hdr = (struct bam_mux_hdr *)ipv6_hdr->hdr;
+	snprintf(ipv6_hdr->name, IPA_RESOURCE_NAME_MAX, "%s%d",
+		 A2_MUX_HDR_NAME_V6_PREF, lcid);
+	dmux_hdr->magic_num = BAM_MUX_HDR_MAGIC_NO;
+	dmux_hdr->cmd = BAM_MUX_HDR_CMD_DATA;
+	dmux_hdr->reserved = 0;
+	dmux_hdr->ch_id = lcid;
+
+	/* Packet lenght is added by IPA */
+	dmux_hdr->pkt_len = 0;
+	dmux_hdr->pad_len = 0;
+
+	dmux_hdr->magic_num = htons(dmux_hdr->magic_num);
+	IPADBG("converted to network order magic_num=%d\n",
+		    dmux_hdr->magic_num);
+
+	ipv6_hdr->hdr_len = sizeof(struct bam_mux_hdr);
+	ipv6_hdr->is_partial = 0;
+
+	hdrs->commit = 1;
+	hdrs->num_hdrs = 2;
+
+	rc = ipa_add_hdr(hdrs);
+	if (rc) {
+		IPAERR("Fail on Header-Insertion(%d)\n", rc);
+		goto bail;
+	}
+
+	if (ipv4_hdr->status) {
+		IPAERR("Fail on Header-Insertion ipv4(%d)\n",
+				ipv4_hdr->status);
+		rc = ipv4_hdr->status;
+		goto bail;
+	}
+
+	if (ipv6_hdr->status) {
+		IPAERR("%s: Fail on Header-Insertion ipv4(%d)\n", __func__,
+				ipv6_hdr->status);
+		rc = ipv6_hdr->status;
+		goto bail;
+	}
+
+	a2_mux_ctx->bam_ch[lcid].v4_hdr_hdl = ipv4_hdr->hdr_hdl;
+	a2_mux_ctx->bam_ch[lcid].v6_hdr_hdl = ipv6_hdr->hdr_hdl;
+
+	rc = 0;
+bail:
+	kfree(hdrs);
+	return rc;
+}
+
+/**
+ * a2_mux_del_hdr() - called when MUX header should
+ *		be removed
+ * @lcid: logical channel ID
+ *
+ * Returns: 0 on success, negative on failure
+ */
+static int a2_mux_del_hdr(enum a2_mux_logical_channel_id lcid)
+{
+	struct ipa_ioc_del_hdr *hdrs;
+	struct ipa_hdr_del *ipv4_hdl;
+	struct ipa_hdr_del *ipv6_hdl;
+	int rc;
+
+	IPADBG("%s: ch %d\n", __func__, lcid);
+
+	if (lcid < A2_MUX_WWAN_0 || lcid > A2_MUX_WWAN_7) {
+		IPAERR("invalid lcid passed: %d\n", lcid);
+		return -EINVAL;
+	}
+
+
+	hdrs = kzalloc(sizeof(struct ipa_ioc_del_hdr) +
+		       2 * sizeof(struct ipa_hdr_del), GFP_KERNEL);
+	if (!hdrs) {
+		IPAERR("hdr alloc fail for ch %d\n", lcid);
+		return -ENOMEM;
+	}
+
+	ipv4_hdl = &hdrs->hdl[0];
+	ipv6_hdl = &hdrs->hdl[1];
+
+	ipv4_hdl->hdl = a2_mux_ctx->bam_ch[lcid].v4_hdr_hdl;
+	ipv6_hdl->hdl = a2_mux_ctx->bam_ch[lcid].v6_hdr_hdl;
+
+	hdrs->commit = 1;
+	hdrs->num_hdls = 2;
+
+	rc = ipa_del_hdr(hdrs);
+	if (rc) {
+		IPAERR("Fail on Del Header-Insertion(%d)\n", rc);
+		goto bail;
+	}
+
+	if (ipv4_hdl->status) {
+		IPAERR("Fail on Del Header-Insertion ipv4(%d)\n",
+				ipv4_hdl->status);
+		rc = ipv4_hdl->status;
+		goto bail;
+	}
+	a2_mux_ctx->bam_ch[lcid].v4_hdr_hdl = 0;
+
+	if (ipv6_hdl->status) {
+		IPAERR("Fail on Del Header-Insertion ipv4(%d)\n",
+				ipv6_hdl->status);
+		rc = ipv6_hdl->status;
+		goto bail;
+	}
+	a2_mux_ctx->bam_ch[lcid].v6_hdr_hdl = 0;
+
+	rc = 0;
+bail:
+	kfree(hdrs);
+	return rc;
+
+}
+
+/**
  * a2_mux_open_channel() - opens logical channel
  *		to A2
  * @lcid: logical channel ID
@@ -1090,6 +1269,12 @@
 			kfree(hdr);
 			return rc;
 		}
+		rc = a2_mux_add_hdr(lcid);
+		if (rc) {
+			IPAERR("a2_mux_add_hdr failed %d; ch: %d\n",
+			       rc, lcid);
+			return rc;
+		}
 	}
 
 open_done:
@@ -1154,6 +1339,13 @@
 			kfree(hdr);
 			return rc;
 		}
+
+		rc = a2_mux_del_hdr(lcid);
+		if (rc) {
+			IPAERR("a2_mux_del_hdr failed %d; ch: %d\n",
+			       rc, lcid);
+			return rc;
+		}
 	}
 	IPADBG("%s: closed ch %d\n", __func__, lcid);
 	return 0;
@@ -1342,6 +1534,13 @@
 	}
 	if (smsm_get_state(SMSM_MODEM_STATE) & SMSM_A2_POWER_CONTROL)
 		bam_dmux_smsm_cb(NULL, 0, smsm_get_state(SMSM_MODEM_STATE));
+
+	/*
+	 * Set remote channel open for tethered channel since there is
+	 *  no actual remote tethered channel
+	 */
+	a2_mux_ctx->bam_ch[A2_MUX_TETHERED_0].status |= BAM_CH_REMOTE_OPEN;
+
 	rc = 0;
 	goto bail;
 
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index b07c653..edf3a60 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -806,7 +806,7 @@
 
 		/* check all the system pipes for tx comp and rx avail */
 		if (ipa_ctx->sys[IPA_A5_LAN_WAN_IN].ep->valid)
-			cnt |= ipa_handle_rx_core(false);
+			cnt |= ipa_handle_rx_core(false, true);
 
 		for (i = 0; i < num_tx_pipes; i++)
 			if (ipa_ctx->sys[tx_pipes[i]].ep->valid)
@@ -1578,6 +1578,10 @@
 
 	IPADBG("polling_mode=%u delay_ms=%u\n", polling_mode, polling_delay_ms);
 	ipa_ctx->polling_mode = polling_mode;
+	if (ipa_ctx->polling_mode)
+		atomic_set(&ipa_ctx->curr_polling_state, 1);
+	else
+		atomic_set(&ipa_ctx->curr_polling_state, 0);
 	IPADBG("hdr_lcl=%u ip4_rt=%u ip6_rt=%u ip4_flt=%u ip6_flt=%u\n",
 	       hdr_tbl_lcl, ip4_rt_tbl_lcl, ip6_rt_tbl_lcl, ip4_flt_tbl_lcl,
 	       ip6_flt_tbl_lcl);
@@ -1896,10 +1900,6 @@
 	ipa_ctx->aggregation_byte_limit = 1;
 	ipa_ctx->aggregation_time_limit = 0;
 
-	/* gate IPA clocks */
-	if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
-		ipa_disable_clks();
-
 	/* Initialize IPA RM (resource manager) */
 	result = ipa_rm_initialize();
 	if (result) {
@@ -1910,6 +1910,18 @@
 
 	a2_mux_init();
 
+	/* Initialize the tethering bridge driver */
+	result = teth_bridge_driver_init();
+	if (result) {
+		IPAERR(":teth_bridge_driver_init() failed\n");
+		result = -ENODEV;
+		goto fail_cdev_add;
+	}
+
+	/* gate IPA clocks */
+	if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
+		ipa_disable_clks();
+
 	IPADBG(":IPA driver init OK.\n");
 
 	return 0;
diff --git a/drivers/platform/msm/ipa/ipa_bridge.c b/drivers/platform/msm/ipa/ipa_bridge.c
index 56e9b0d..0227ee4 100644
--- a/drivers/platform/msm/ipa/ipa_bridge.c
+++ b/drivers/platform/msm/ipa/ipa_bridge.c
@@ -42,9 +42,6 @@
 	struct sps_connect connection;
 	struct sps_mem_buffer desc_mem_buf;
 	struct sps_register_event register_event;
-	spinlock_t spinlock;
-	u32 len;
-	u32 free_len;
 	struct list_head free_desc_list;
 };
 
@@ -162,12 +159,10 @@
 		goto fail_dma;
 	}
 
-	info->len = ~0;
-
 	list_add_tail(&info->link, &sys_rx->head_desc_list);
 	ret = sps_transfer_one(sys_rx->pipe, info->dma_address,
 			       IPA_RX_SKB_SIZE, info,
-			       SPS_IOVEC_FLAG_INT | SPS_IOVEC_FLAG_EOT);
+			       SPS_IOVEC_FLAG_INT);
 	if (ret) {
 		list_del(&info->link);
 		dma_unmap_single(NULL, info->dma_address, IPA_RX_SKB_SIZE,
@@ -176,7 +171,6 @@
 				type, dir);
 		goto fail_dma;
 	}
-	sys_rx->len++;
 	return 0;
 
 fail_dma:
@@ -206,9 +200,6 @@
 						  link);
 			list_move_tail(&tx_pkt->link,
 					&sys_tx->free_desc_list);
-			sys_tx->len--;
-			sys_tx->free_len++;
-			tx_pkt->len = ~0;
 			cnt++;
 		}
 	} while (all);
@@ -245,7 +236,6 @@
 						  struct ipa_pkt_info,
 						  link);
 			list_del(&rx_pkt->link);
-			sys_rx->len--;
 			rx_pkt->len = iov.size;
 
 retry_alloc_tx:
@@ -285,15 +275,12 @@
 
 				list_add_tail(&tmp_pkt->link,
 						&sys_tx->free_desc_list);
-				sys_tx->free_len++;
-				tmp_pkt->len = ~0;
 			}
 
 			tx_pkt = list_first_entry(&sys_tx->free_desc_list,
 						  struct ipa_pkt_info,
 						  link);
 			list_del(&tx_pkt->link);
-			sys_tx->free_len--;
 
 retry_add_rx:
 			list_add_tail(&tx_pkt->link,
@@ -302,8 +289,7 @@
 					tx_pkt->dma_address,
 					IPA_RX_SKB_SIZE,
 					tx_pkt,
-					SPS_IOVEC_FLAG_INT |
-					SPS_IOVEC_FLAG_EOT);
+					SPS_IOVEC_FLAG_INT);
 			if (ret) {
 				list_del(&tx_pkt->link);
 				pr_debug_ratelimited("%s: sps_transfer_one failed %d type=%d dir=%d\n",
@@ -312,7 +298,6 @@
 						polling_max_sleep[dir]);
 				goto retry_add_rx;
 			}
-			sys_rx->len++;
 
 retry_add_tx:
 			list_add_tail(&rx_pkt->link,
@@ -332,7 +317,6 @@
 						polling_max_sleep[dir]);
 				goto retry_add_tx;
 			}
-			sys_tx->len++;
 			IPA_STATS_INC_BRIDGE_CNT(ctx->type, dir,
 					ipa_ctx->stats.bridged_pkts);
 		}
@@ -444,7 +428,6 @@
 
 	INIT_LIST_HEAD(&sys->head_desc_list);
 	INIT_LIST_HEAD(&sys->free_desc_list);
-	spin_lock_init(&sys->spinlock);
 
 	memset(&ipa_ctx->ep[ipa_ep_idx], 0,
 	       sizeof(struct ipa_ep_context));
@@ -614,7 +597,6 @@
 
 	INIT_LIST_HEAD(&sys->head_desc_list);
 	INIT_LIST_HEAD(&sys->free_desc_list);
-	spin_lock_init(&sys->spinlock);
 
 	if (dir == IPA_BRIDGE_DIR_DL) {
 		sys->register_event.options = SPS_O_EOT;
@@ -663,32 +645,32 @@
 	int ret;
 	int i;
 
-	bridge[IPA_BRIDGE_TYPE_TETHERED].ul_wq = alloc_workqueue("ipa_ul_teth",
-			WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, 1);
+	bridge[IPA_BRIDGE_TYPE_TETHERED].ul_wq =
+		create_singlethread_workqueue("ipa_ul_teth");
 	if (!bridge[IPA_BRIDGE_TYPE_TETHERED].ul_wq) {
 		IPAERR("ipa ul teth wq alloc failed\n");
 		ret = -ENOMEM;
 		goto fail_ul_teth;
 	}
 
-	bridge[IPA_BRIDGE_TYPE_TETHERED].dl_wq = alloc_workqueue("ipa_dl_teth",
-			WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, 1);
+	bridge[IPA_BRIDGE_TYPE_TETHERED].dl_wq =
+		create_singlethread_workqueue("ipa_dl_teth");
 	if (!bridge[IPA_BRIDGE_TYPE_TETHERED].dl_wq) {
 		IPAERR("ipa dl teth wq alloc failed\n");
 		ret = -ENOMEM;
 		goto fail_dl_teth;
 	}
 
-	bridge[IPA_BRIDGE_TYPE_EMBEDDED].ul_wq = alloc_workqueue("ipa_ul_emb",
-					 WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, 1);
+	bridge[IPA_BRIDGE_TYPE_EMBEDDED].ul_wq =
+		create_singlethread_workqueue("ipa_ul_emb");
 	if (!bridge[IPA_BRIDGE_TYPE_EMBEDDED].ul_wq) {
 		IPAERR("ipa ul emb wq alloc failed\n");
 		ret = -ENOMEM;
 		goto fail_ul_emb;
 	}
 
-	bridge[IPA_BRIDGE_TYPE_EMBEDDED].dl_wq = alloc_workqueue("ipa_dl_emb",
-					 WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, 1);
+	bridge[IPA_BRIDGE_TYPE_EMBEDDED].dl_wq =
+		create_singlethread_workqueue("ipa_dl_emb");
 	if (!bridge[IPA_BRIDGE_TYPE_EMBEDDED].dl_wq) {
 		IPAERR("ipa dl emb wq alloc failed\n");
 		ret = -ENOMEM;
diff --git a/drivers/platform/msm/ipa/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_debugfs.c
index ec83653..1605ed2 100644
--- a/drivers/platform/msm/ipa/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_debugfs.c
@@ -45,6 +45,37 @@
 	__stringify(IPA_CLIENT_MAX),
 };
 
+const char *ipa_ic_name[] = {
+	__stringify_1(IPA_IP_CMD_INVALID),
+	__stringify_1(IPA_DECIPH_INIT),
+	__stringify_1(IPA_PPP_FRM_INIT),
+	__stringify_1(IPA_IP_V4_FILTER_INIT),
+	__stringify_1(IPA_IP_V6_FILTER_INIT),
+	__stringify_1(IPA_IP_V4_NAT_INIT),
+	__stringify_1(IPA_IP_V6_NAT_INIT),
+	__stringify_1(IPA_IP_V4_ROUTING_INIT),
+	__stringify_1(IPA_IP_V6_ROUTING_INIT),
+	__stringify_1(IPA_HDR_INIT_LOCAL),
+	__stringify_1(IPA_HDR_INIT_SYSTEM),
+	__stringify_1(IPA_DECIPH_SETUP),
+	__stringify_1(IPA_INSERT_NAT_RULE),
+	__stringify_1(IPA_DELETE_NAT_RULE),
+	__stringify_1(IPA_NAT_DMA),
+	__stringify_1(IPA_IP_PACKET_TAG),
+	__stringify_1(IPA_IP_PACKET_INIT),
+};
+
+const char *ipa_excp_name[] = {
+	__stringify_1(IPA_A5_MUX_HDR_EXCP_RSVD0),
+	__stringify_1(IPA_A5_MUX_HDR_EXCP_RSVD1),
+	__stringify_1(IPA_A5_MUX_HDR_EXCP_FLAG_IHL),
+	__stringify_1(IPA_A5_MUX_HDR_EXCP_FLAG_REPLICATED),
+	__stringify_1(IPA_A5_MUX_HDR_EXCP_FLAG_TAG),
+	__stringify_1(IPA_A5_MUX_HDR_EXCP_FLAG_SW_FLT),
+	__stringify_1(IPA_A5_MUX_HDR_EXCP_FLAG_NAT),
+	__stringify_1(IPA_A5_MUX_HDR_EXCP_FLAG_IP),
+};
+
 static struct dentry *dent;
 static struct dentry *dfile_gen_reg;
 static struct dentry *dfile_ep_reg;
@@ -489,33 +520,39 @@
 	nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
 			"sw_tx=%u\n"
 			"hw_tx=%u\n"
-			"rx=%u\n",
+			"rx=%u\n"
+			"rx_repl_repost=%u\n"
+			"x_intr_repost=%u\n"
+			"rx_q_len=%u\n",
 			ipa_ctx->stats.tx_sw_pkts,
 			ipa_ctx->stats.tx_hw_pkts,
-			ipa_ctx->stats.rx_pkts);
+			ipa_ctx->stats.rx_pkts,
+			ipa_ctx->stats.rx_repl_repost,
+			ipa_ctx->stats.x_intr_repost,
+			ipa_ctx->stats.rx_q_len);
 	cnt += nbytes;
 
 	for (i = 0; i < MAX_NUM_EXCP; i++) {
 		nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
-				"rx_excp[%u]=%u\n", i,
+				"rx_excp[%u:%35s]=%u\n", i, ipa_excp_name[i],
 				ipa_ctx->stats.rx_excp_pkts[i]);
 		cnt += nbytes;
 	}
 
 	for (i = 0; i < IPA_BRIDGE_TYPE_MAX; i++) {
 		nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
-				"bridged_pkt[%u][dl]=%u\n"
-				"bridged_pkt[%u][ul]=%u\n",
-				i,
+				"brg_pkt[%u:%s][dl]=%u\n"
+				"brg_pkt[%u:%s][ul]=%u\n",
+				i, (i == 0) ? "teth" : "embd",
 				ipa_ctx->stats.bridged_pkts[i][0],
-				i,
+				i, (i == 0) ? "teth" : "embd",
 				ipa_ctx->stats.bridged_pkts[i][1]);
 		cnt += nbytes;
 	}
 
 	for (i = 0; i < MAX_NUM_IMM_CMD; i++) {
 		nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
-				"IC[%u]=%u\n", i,
+				"IC[%2u:%22s]=%u\n", i, ipa_ic_name[i],
 				ipa_ctx->stats.imm_cmds[i]);
 		cnt += nbytes;
 	}
diff --git a/drivers/platform/msm/ipa/ipa_dp.c b/drivers/platform/msm/ipa/ipa_dp.c
index 52ed428..38690e9 100644
--- a/drivers/platform/msm/ipa/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_dp.c
@@ -10,6 +10,7 @@
  * GNU General Public License for more details.
  */
 
+#include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/dmapool.h>
 #include <linux/list.h>
@@ -19,6 +20,17 @@
 #define list_next_entry(pos, member) \
 	list_entry(pos->member.next, typeof(*pos), member)
 #define IPA_LAST_DESC_CNT 0xFFFF
+#define POLLING_INACTIVITY 40
+#define POLLING_MIN_SLEEP 950
+#define POLLING_MAX_SLEEP 1050
+
+static void replenish_rx_work_func(struct work_struct *work);
+static struct delayed_work replenish_rx_work;
+static void switch_to_intr_work_func(struct work_struct *work);
+static struct delayed_work switch_to_intr_work;
+static void ipa_wq_handle_rx(struct work_struct *work);
+static DECLARE_WORK(rx_work, ipa_wq_handle_rx);
+
 /**
  * ipa_write_done() - this function will be (eventually) called when a Tx
  * operation is complete
@@ -40,7 +52,7 @@
 	unsigned long irq_flags;
 	struct ipa_mem_buffer mult = { 0 };
 	int i;
-	u16 cnt;
+	u32 cnt;
 
 	tx_pkt = container_of(work, struct ipa_tx_pkt_wrapper, work);
 	cnt = tx_pkt->cnt;
@@ -66,9 +78,8 @@
 		}
 		next_pkt = list_next_entry(tx_pkt, link);
 		list_del(&tx_pkt->link);
-		tx_pkt->sys->len--;
 		spin_unlock_irqrestore(&tx_pkt->sys->spinlock, irq_flags);
-		if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0) {
+		if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0)) {
 			dma_pool_free(ipa_ctx->one_kb_no_straddle_pool,
 					tx_pkt->bounce,
 					tx_pkt->mem.phys_base);
@@ -114,10 +125,10 @@
 	u16 sps_flags = SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_INT;
 	dma_addr_t dma_address;
 	u16 len;
-	u32 mem_flag = GFP_KERNEL;
+	u32 mem_flag = GFP_ATOMIC;
 
-	if (in_atomic)
-		mem_flag = GFP_ATOMIC;
+	if (unlikely(!in_atomic))
+		mem_flag = GFP_KERNEL;
 
 	tx_pkt = kmem_cache_zalloc(ipa_ctx->tx_pkt_wrapper_cache, mem_flag);
 	if (!tx_pkt) {
@@ -125,7 +136,7 @@
 		goto fail_mem_alloc;
 	}
 
-	if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0) {
+	if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0)) {
 		WARN_ON(desc->len > 512);
 
 		/*
@@ -173,19 +184,15 @@
 	if (desc->type == IPA_IMM_CMD_DESC) {
 		sps_flags |= SPS_IOVEC_FLAG_IMME;
 		len = desc->opcode;
+		IPADBG("sending cmd=%d pyld_len=%d sps_flags=%x\n",
+				desc->opcode, desc->len, sps_flags);
+		IPA_DUMP_BUFF(desc->pyld, dma_address, desc->len);
 	} else {
 		len = desc->len;
 	}
 
-	if (desc->type == IPA_IMM_CMD_DESC) {
-		IPADBG("sending cmd=%d pyld_len=%d sps_flags=%x\n",
-				desc->opcode, desc->len, sps_flags);
-		IPA_DUMP_BUFF(desc->pyld, dma_address, desc->len);
-	}
-
 	spin_lock_irqsave(&sys->spinlock, irq_flags);
 	list_add_tail(&tx_pkt->link, &sys->head_desc_list);
-	sys->len++;
 	result = sps_transfer_one(sys->ep->ep_hdl, dma_address, len, tx_pkt,
 			sps_flags);
 	if (result) {
@@ -200,7 +207,7 @@
 fail_sps_send:
 	list_del(&tx_pkt->link);
 	spin_unlock_irqrestore(&sys->spinlock, irq_flags);
-	if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0)
+	if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0))
 		dma_pool_free(ipa_ctx->one_kb_no_straddle_pool, tx_pkt->bounce,
 				dma_address);
 	else
@@ -233,7 +240,7 @@
  *
  * Return codes: 0: success, -EFAULT: failure
  */
-int ipa_send(struct ipa_sys_context *sys, u16 num_desc, struct ipa_desc *desc,
+int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc,
 		bool in_atomic)
 {
 	struct ipa_tx_pkt_wrapper *tx_pkt;
@@ -247,17 +254,18 @@
 	int result;
 	int fail_dma_wrap = 0;
 	uint size = num_desc * sizeof(struct sps_iovec);
-	u32 mem_flag = GFP_KERNEL;
+	u32 mem_flag = GFP_ATOMIC;
 
-	if (likely(in_atomic))
-		mem_flag = GFP_ATOMIC;
+	if (unlikely(!in_atomic))
+		mem_flag = GFP_KERNEL;
 
 	transfer.iovec = dma_alloc_coherent(NULL, size, &dma_addr, 0);
 	transfer.iovec_phys = dma_addr;
 	transfer.iovec_count = num_desc;
+	spin_lock_irqsave(&sys->spinlock, irq_flags);
 	if (!transfer.iovec) {
 		IPAERR("fail to alloc DMA mem for sps xfr buff\n");
-		goto failure;
+		goto failure_coherent;
 	}
 
 	for (i = 0; i < num_desc; i++) {
@@ -274,24 +282,23 @@
 		 */
 		if (i == 0) {
 			transfer.user = tx_pkt;
-
 			tx_pkt->mult.phys_base = dma_addr;
 			tx_pkt->mult.base = transfer.iovec;
 			tx_pkt->mult.size = size;
 			tx_pkt->cnt = num_desc;
+			INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
 		}
 
 		iovec = &transfer.iovec[i];
 		iovec->flags = 0;
 
 		INIT_LIST_HEAD(&tx_pkt->link);
-		INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
 		tx_pkt->type = desc[i].type;
 
 		tx_pkt->mem.base = desc[i].pyld;
 		tx_pkt->mem.size = desc[i].len;
 
-		if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0) {
+		if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0)) {
 			WARN_ON(tx_pkt->mem.size > 512);
 
 			/*
@@ -334,10 +341,7 @@
 		 * add this packet to system pipe context.
 		 */
 		iovec->addr = tx_pkt->mem.phys_base;
-		spin_lock_irqsave(&sys->spinlock, irq_flags);
 		list_add_tail(&tx_pkt->link, &sys->head_desc_list);
-		sys->len++;
-		spin_unlock_irqrestore(&sys->spinlock, irq_flags);
 
 		/*
 		 * Special treatment for immediate commands, where the structure
@@ -364,16 +368,15 @@
 		goto failure;
 	}
 
+	spin_unlock_irqrestore(&sys->spinlock, irq_flags);
 	return 0;
 
 failure:
 	tx_pkt = transfer.user;
 	for (j = 0; j < i; j++) {
-		spin_lock_irqsave(&sys->spinlock, irq_flags);
 		next_pkt = list_next_entry(tx_pkt, link);
 		list_del(&tx_pkt->link);
-		spin_unlock_irqrestore(&sys->spinlock, irq_flags);
-		if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0)
+		if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0))
 			dma_pool_free(ipa_ctx->one_kb_no_straddle_pool,
 					tx_pkt->bounce,
 					tx_pkt->mem.phys_base);
@@ -391,7 +394,8 @@
 	if (transfer.iovec_phys)
 		dma_free_coherent(NULL, size, transfer.iovec,
 				  transfer.iovec_phys);
-
+failure_coherent:
+	spin_unlock_irqrestore(&sys->spinlock, irq_flags);
 	return -EFAULT;
 }
 
@@ -512,15 +516,14 @@
  *  - Call the endpoints notify function, passing the skb in the parameters
  *  - Replenish the rx cache
  */
-int ipa_handle_rx_core(bool process_all)
+int ipa_handle_rx_core(bool process_all, bool in_poll_state)
 {
 	struct ipa_a5_mux_hdr *mux_hdr;
 	struct ipa_rx_pkt_wrapper *rx_pkt;
 	struct sk_buff *rx_skb;
 	struct sps_iovec iov;
-	unsigned long irq_flags;
-	u16 pull_len;
-	u16 padding;
+	unsigned int pull_len;
+	unsigned int padding;
 	int ret;
 	struct ipa_sys_context *sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_IN];
 	struct ipa_ep_context *ep;
@@ -528,35 +531,35 @@
 	struct completion *compl;
 	struct ipa_tree_node *node;
 
-	do {
+	while ((in_poll_state ? atomic_read(&ipa_ctx->curr_polling_state) :
+				!atomic_read(&ipa_ctx->curr_polling_state))) {
+		if (cnt && !process_all)
+			break;
+
 		ret = sps_get_iovec(sys->ep->ep_hdl, &iov);
 		if (ret) {
 			IPAERR("sps_get_iovec failed %d\n", ret);
 			break;
 		}
 
-		/* Break the loop when there are no more packets to receive */
 		if (iov.addr == 0)
 			break;
 
-		spin_lock_irqsave(&sys->spinlock, irq_flags);
-		if (list_empty(&sys->head_desc_list))
-			WARN_ON(1);
+		if (unlikely(list_empty(&sys->head_desc_list)))
+			continue;
+
 		rx_pkt = list_first_entry(&sys->head_desc_list,
 					  struct ipa_rx_pkt_wrapper, link);
-		if (!rx_pkt)
-			WARN_ON(1);
+
 		rx_pkt->len = iov.size;
 		sys->len--;
 		list_del(&rx_pkt->link);
-		spin_unlock_irqrestore(&sys->spinlock, irq_flags);
 
 		IPADBG("--curr_cnt=%d\n", sys->len);
 
 		rx_skb = rx_pkt->skb;
 		dma_unmap_single(NULL, rx_pkt->dma_address, IPA_RX_SKB_SIZE,
 				 DMA_FROM_DEVICE);
-		kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt);
 
 		/*
 		 * make it look like a real skb, "data" was already set at
@@ -565,6 +568,7 @@
 		rx_skb->tail = rx_skb->data + rx_pkt->len;
 		rx_skb->len = rx_pkt->len;
 		rx_skb->truesize = rx_pkt->len + sizeof(struct sk_buff);
+		kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt);
 
 		mux_hdr = (struct ipa_a5_mux_hdr *)rx_skb->data;
 
@@ -601,20 +605,20 @@
 				}
 				mutex_unlock(&ipa_ctx->lock);
 			}
-			dev_kfree_skb_any(rx_skb);
+			dev_kfree_skb(rx_skb);
 			ipa_replenish_rx_cache();
 			++cnt;
 			continue;
 		}
 
-		if (mux_hdr->src_pipe_index >= IPA_NUM_PIPES ||
+		if (unlikely(mux_hdr->src_pipe_index >= IPA_NUM_PIPES ||
 			!ipa_ctx->ep[mux_hdr->src_pipe_index].valid ||
-			!ipa_ctx->ep[mux_hdr->src_pipe_index].client_notify) {
+			!ipa_ctx->ep[mux_hdr->src_pipe_index].client_notify)) {
 			IPAERR("drop pipe=%d ep_valid=%d client_notify=%p\n",
 			  mux_hdr->src_pipe_index,
 			  ipa_ctx->ep[mux_hdr->src_pipe_index].valid,
 			  ipa_ctx->ep[mux_hdr->src_pipe_index].client_notify);
-			dev_kfree_skb_any(rx_skb);
+			dev_kfree_skb(rx_skb);
 			ipa_replenish_rx_cache();
 			++cnt;
 			continue;
@@ -634,11 +638,11 @@
 
 		IPADBG("pulling %d bytes from skb\n", pull_len);
 		skb_pull(rx_skb, pull_len);
+		ipa_replenish_rx_cache();
 		ep->client_notify(ep->priv, IPA_RECEIVE,
 				(unsigned long)(rx_skb));
-		ipa_replenish_rx_cache();
 		cnt++;
-	} while (process_all);
+	};
 
 	return cnt;
 }
@@ -652,9 +656,9 @@
 	struct ipa_sys_context *sys;
 
 	IPADBG("Enter");
-	if (!ipa_ctx->curr_polling_state) {
+	if (!atomic_read(&ipa_ctx->curr_polling_state)) {
 		IPAERR("already in intr mode\n");
-		return;
+		goto fail;
 	}
 
 	sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_IN];
@@ -662,49 +666,28 @@
 	ret = sps_get_config(sys->ep->ep_hdl, &sys->ep->connect);
 	if (ret) {
 		IPAERR("sps_get_config() failed %d\n", ret);
-		return;
+		goto fail;
 	}
 	sys->event.options = SPS_O_EOT;
 	ret = sps_register_event(sys->ep->ep_hdl, &sys->event);
 	if (ret) {
 		IPAERR("sps_register_event() failed %d\n", ret);
-		return;
+		goto fail;
 	}
 	sys->ep->connect.options =
 		SPS_O_AUTO_ENABLE | SPS_O_ACK_TRANSFERS | SPS_O_EOT;
 	ret = sps_set_config(sys->ep->ep_hdl, &sys->ep->connect);
 	if (ret) {
 		IPAERR("sps_set_config() failed %d\n", ret);
-		return;
+		goto fail;
 	}
-	ipa_handle_rx_core(true);
-	ipa_ctx->curr_polling_state = 0;
-}
+	atomic_set(&ipa_ctx->curr_polling_state, 0);
+	ipa_handle_rx_core(true, false);
+	return;
 
-/**
- * ipa_rx_switch_to_poll_mode() - Operate the Rx data path in polling mode
- */
-static void ipa_rx_switch_to_poll_mode(void)
-{
-	int ret;
-	struct ipa_ep_context *ep;
-
-	IPADBG("Enter");
-	ep = ipa_ctx->sys[IPA_A5_LAN_WAN_IN].ep;
-
-	ret = sps_get_config(ep->ep_hdl, &ep->connect);
-	if (ret) {
-		IPAERR("sps_get_config() failed %d\n", ret);
-		return;
-	}
-	ep->connect.options =
-		SPS_O_AUTO_ENABLE | SPS_O_ACK_TRANSFERS | SPS_O_POLL;
-	ret = sps_set_config(ep->ep_hdl, &ep->connect);
-	if (ret) {
-		IPAERR("sps_set_config() failed %d\n", ret);
-		return;
-	}
-	ipa_ctx->curr_polling_state = 1;
+fail:
+	IPA_STATS_INC_CNT(ipa_ctx->stats.x_intr_repost);
+	schedule_delayed_work(&switch_to_intr_work, msecs_to_jiffies(1));
 }
 
 /**
@@ -722,16 +705,30 @@
  */
 static void ipa_sps_irq_rx_notify(struct sps_event_notify *notify)
 {
-	struct ipa_rx_pkt_wrapper *rx_pkt;
+	struct ipa_ep_context *ep;
+	int ret;
 
 	IPADBG("event %d notified\n", notify->event_id);
 
 	switch (notify->event_id) {
 	case SPS_EVENT_EOT:
-		if (!ipa_ctx->curr_polling_state) {
-			ipa_rx_switch_to_poll_mode();
-			rx_pkt = notify->data.transfer.user;
-			queue_work(ipa_ctx->rx_wq, &rx_pkt->work);
+		if (!atomic_read(&ipa_ctx->curr_polling_state)) {
+			ep = ipa_ctx->sys[IPA_A5_LAN_WAN_IN].ep;
+
+			ret = sps_get_config(ep->ep_hdl, &ep->connect);
+			if (ret) {
+				IPAERR("sps_get_config() failed %d\n", ret);
+				break;
+			}
+			ep->connect.options = SPS_O_AUTO_ENABLE |
+				SPS_O_ACK_TRANSFERS | SPS_O_POLL;
+			ret = sps_set_config(ep->ep_hdl, &ep->connect);
+			if (ret) {
+				IPAERR("sps_set_config() failed %d\n", ret);
+				break;
+			}
+			atomic_set(&ipa_ctx->curr_polling_state, 1);
+			queue_work(ipa_ctx->rx_wq, &rx_work);
 		}
 		break;
 	default:
@@ -861,6 +858,9 @@
 		/* fall through */
 	case 3:
 		sys_idx = ipa_ep_idx;
+		INIT_DELAYED_WORK(&replenish_rx_work, replenish_rx_work_func);
+		INIT_DELAYED_WORK(&switch_to_intr_work,
+				switch_to_intr_work_func);
 		break;
 	case WLAN_AMPDU_TX_EP:
 		sys_idx = IPA_A5_WLAN_AMPDU_OUT;
@@ -954,7 +954,7 @@
 		ipa_ctx->ep[ep_idx].client_notify(ipa_ctx->ep[ep_idx].priv,
 				IPA_WRITE_DONE, (unsigned long)skb);
 	else
-		dev_kfree_skb_any(skb);
+		dev_kfree_skb(skb);
 }
 
 static void ipa_tx_cmd_comp(void *user1, void *user2)
@@ -1066,6 +1066,24 @@
 }
 EXPORT_SYMBOL(ipa_tx_dp);
 
+static void ipa_handle_rx(void)
+{
+	int inactive_cycles = 0;
+	int cnt;
+
+	do {
+		cnt = ipa_handle_rx_core(true, true);
+		if (cnt == 0) {
+			inactive_cycles++;
+			usleep_range(POLLING_MIN_SLEEP, POLLING_MAX_SLEEP);
+		} else {
+			inactive_cycles = 0;
+		}
+	} while (inactive_cycles <= POLLING_INACTIVITY);
+
+	ipa_rx_switch_to_intr_mode();
+}
+
 /**
  * ipa_handle_rx() - handle packet reception. This function is executed in the
  * context of a work queue.
@@ -1074,10 +1092,9 @@
  * ipa_handle_rx_core() is run in polling mode. After all packets has been
  * received, the driver switches back to interrupt mode.
  */
-void ipa_wq_handle_rx(struct work_struct *work)
+static void ipa_wq_handle_rx(struct work_struct *work)
 {
-	ipa_handle_rx_core(true);
-	ipa_rx_switch_to_intr_mode();
+	ipa_handle_rx();
 }
 
 /**
@@ -1099,26 +1116,23 @@
 	void *ptr;
 	struct ipa_rx_pkt_wrapper *rx_pkt;
 	int ret;
-	int rx_len_cached;
-	unsigned long irq_flags;
+	int rx_len_cached = 0;
 	struct ipa_sys_context *sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_IN];
+	gfp_t flag = GFP_NOWAIT | __GFP_NOWARN;
 
-	spin_lock_irqsave(&sys->spinlock, irq_flags);
 	rx_len_cached = sys->len;
-	spin_unlock_irqrestore(&sys->spinlock, irq_flags);
 
 	while (rx_len_cached < IPA_RX_POOL_CEIL) {
 		rx_pkt = kmem_cache_zalloc(ipa_ctx->rx_pkt_wrapper_cache,
-					   GFP_KERNEL);
+					   flag);
 		if (!rx_pkt) {
 			IPAERR("failed to alloc rx wrapper\n");
-			return;
+			goto fail_kmem_cache_alloc;
 		}
 
 		INIT_LIST_HEAD(&rx_pkt->link);
-		INIT_WORK(&rx_pkt->work, ipa_wq_handle_rx);
 
-		rx_pkt->skb = __dev_alloc_skb(IPA_RX_SKB_SIZE, GFP_KERNEL);
+		rx_pkt->skb = __dev_alloc_skb(IPA_RX_SKB_SIZE, flag);
 		if (rx_pkt->skb == NULL) {
 			IPAERR("failed to alloc skb\n");
 			goto fail_skb_alloc;
@@ -1133,10 +1147,8 @@
 			goto fail_dma_mapping;
 		}
 
-		spin_lock_irqsave(&sys->spinlock, irq_flags);
 		list_add_tail(&rx_pkt->link, &sys->head_desc_list);
 		rx_len_cached = ++sys->len;
-		spin_unlock_irqrestore(&sys->spinlock, irq_flags);
 
 		ret = sps_transfer_one(sys->ep->ep_hdl, rx_pkt->dma_address,
 				       IPA_RX_SKB_SIZE, rx_pkt,
@@ -1146,27 +1158,41 @@
 			IPAERR("sps_transfer_one failed %d\n", ret);
 			goto fail_sps_transfer;
 		}
-
-		IPADBG("++curr_cnt=%d\n", sys->len);
 	}
 
+	ipa_ctx->stats.rx_q_len = sys->len;
+
 	return;
 
 fail_sps_transfer:
-	spin_lock_irqsave(&sys->spinlock, irq_flags);
 	list_del(&rx_pkt->link);
-	--sys->len;
-	spin_unlock_irqrestore(&sys->spinlock, irq_flags);
+	rx_len_cached = --sys->len;
 	dma_unmap_single(NULL, rx_pkt->dma_address, IPA_RX_SKB_SIZE,
 			 DMA_FROM_DEVICE);
 fail_dma_mapping:
-	dev_kfree_skb_any(rx_pkt->skb);
+	dev_kfree_skb(rx_pkt->skb);
 fail_skb_alloc:
 	kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt);
-
+fail_kmem_cache_alloc:
+	if (rx_len_cached == 0) {
+		IPA_STATS_INC_CNT(ipa_ctx->stats.rx_repl_repost);
+		schedule_delayed_work(&replenish_rx_work,
+				msecs_to_jiffies(100));
+	}
+	ipa_ctx->stats.rx_q_len = sys->len;
 	return;
 }
 
+static void replenish_rx_work_func(struct work_struct *work)
+{
+	ipa_replenish_rx_cache();
+}
+
+static void switch_to_intr_work_func(struct work_struct *work)
+{
+	ipa_handle_rx();
+}
+
 /**
  * ipa_cleanup_rx() - release RX queue resources
  *
@@ -1175,18 +1201,15 @@
 {
 	struct ipa_rx_pkt_wrapper *rx_pkt;
 	struct ipa_rx_pkt_wrapper *r;
-	unsigned long irq_flags;
 	struct ipa_sys_context *sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_IN];
 
-	spin_lock_irqsave(&sys->spinlock, irq_flags);
 	list_for_each_entry_safe(rx_pkt, r,
 				 &sys->head_desc_list, link) {
 		list_del(&rx_pkt->link);
 		dma_unmap_single(NULL, rx_pkt->dma_address, IPA_RX_SKB_SIZE,
 				 DMA_FROM_DEVICE);
-		dev_kfree_skb_any(rx_pkt->skb);
+		dev_kfree_skb(rx_pkt->skb);
 		kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt);
 	}
-	spin_unlock_irqrestore(&sys->spinlock, irq_flags);
 }
 
diff --git a/drivers/platform/msm/ipa/ipa_i.h b/drivers/platform/msm/ipa/ipa_i.h
index 14195d7..cb8c0f5 100644
--- a/drivers/platform/msm/ipa/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_i.h
@@ -110,7 +110,7 @@
 
 #define IPA_EVENT_THRESHOLD 0x10
 
-#define IPA_RX_POOL_CEIL 24
+#define IPA_RX_POOL_CEIL 32
 #define IPA_RX_SKB_SIZE 2048
 
 #define IPA_DFLT_HDR_NAME "ipa_excp_hdr"
@@ -422,7 +422,7 @@
 	void *user2;
 	struct ipa_sys_context *sys;
 	struct ipa_mem_buffer mult;
-	u16 cnt;
+	u32 cnt;
 	void *bounce;
 };
 
@@ -453,16 +453,14 @@
  * struct ipa_rx_pkt_wrapper - IPA Rx packet wrapper
  * @skb: skb
  * @dma_address: DMA address of this Rx packet
- * @work: work struct for current Rx packet
  * @link: linked to the Rx packets on that pipe
  * @len: how many bytes are copied into skb's flat buffer
  */
 struct ipa_rx_pkt_wrapper {
 	struct sk_buff *skb;
 	dma_addr_t dma_address;
-	struct work_struct work;
 	struct list_head link;
-	u16 len;
+	u32 len;
 };
 
 /**
@@ -527,6 +525,9 @@
 	u32 rx_pkts;
 	u32 rx_excp_pkts[MAX_NUM_EXCP];
 	u32 bridged_pkts[IPA_BRIDGE_TYPE_MAX][IPA_BRIDGE_DIR_MAX];
+	u32 rx_repl_repost;
+	u32 x_intr_repost;
+	u32 rx_q_len;
 };
 
 /**
@@ -629,7 +630,7 @@
 	uint aggregation_type;
 	uint aggregation_byte_limit;
 	uint aggregation_time_limit;
-	uint curr_polling_state;
+	atomic_t curr_polling_state;
 	struct delayed_work poll_work;
 	bool hdr_tbl_lcl;
 	struct ipa_mem_buffer hdr_mem;
@@ -742,7 +743,7 @@
 		u32 *consumer_handle);
 int ipa_send_one(struct ipa_sys_context *sys, struct ipa_desc *desc,
 		bool in_atomic);
-int ipa_send(struct ipa_sys_context *sys, u16 num_desc, struct ipa_desc *desc,
+int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc,
 		bool in_atomic);
 int ipa_get_ep_mapping(enum ipa_operating_mode mode,
 		       enum ipa_client_type client);
@@ -783,8 +784,7 @@
 void ipa_cleanup_rx(void);
 int ipa_cfg_filter(u32 disable);
 void ipa_wq_write_done(struct work_struct *work);
-void ipa_wq_handle_rx(struct work_struct *work);
-int ipa_handle_rx_core(bool process_all);
+int ipa_handle_rx_core(bool process_all, bool in_poll_state);
 int ipa_pipe_mem_init(u32 start_ofst, u32 size);
 int ipa_pipe_mem_alloc(u32 *ofst, u32 size);
 int ipa_pipe_mem_free(u32 ofst, u32 size);
@@ -823,4 +823,8 @@
 int a2_mux_init(void);
 int a2_mux_exit(void);
 
+void wwan_cleanup(void);
+
+int teth_bridge_driver_init(void);
+
 #endif /* _IPA_I_H_ */
diff --git a/drivers/platform/msm/ipa/teth_bridge.c b/drivers/platform/msm/ipa/teth_bridge.c
new file mode 100644
index 0000000..76e2eee
--- /dev/null
+++ b/drivers/platform/msm/ipa/teth_bridge.c
@@ -0,0 +1,1483 @@
+/* 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/completion.h>
+#include <linux/debugfs.h>
+#include <linux/export.h>
+#include <linux/fs.h>
+#include <linux/if_ether.h>
+#include <linux/ioctl.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/msm_ipa.h>
+#include <linux/mutex.h>
+#include <linux/skbuff.h>
+#include <linux/types.h>
+#include <mach/bam_dmux.h>
+#include <mach/ipa.h>
+#include <mach/sps.h>
+#include "ipa_i.h"
+
+#define TETH_BRIDGE_DRV_NAME "ipa_tethering_bridge"
+
+#ifdef TETH_DEBUG
+#define TETH_DBG(fmt, args...) \
+	pr_debug(TETH_BRIDGE_DRV_NAME " %s:%d " fmt, \
+		 __func__, __LINE__, ## args)
+#define TETH_DBG_FUNC_ENTRY() \
+	pr_debug(TETH_BRIDGE_DRV_NAME " %s:%d ENTRY\n", __func__, __LINE__)
+#define TETH_DBG_FUNC_EXIT() \
+	pr_debug(TETH_BRIDGE_DRV_NAME " %s:%d EXIT\n", __func__, __LINE__)
+#else
+#define TETH_DBG(fmt, args...)
+#define TETH_DBG_FUNC_ENTRY()
+#define TETH_DBG_FUNC_EXIT()
+#endif
+
+#define TETH_ERR(fmt, args...) \
+	pr_err(TETH_BRIDGE_DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args)
+
+#define USB_ETH_HDR_NAME_IPV4 "usb_bridge_ipv4"
+#define USB_ETH_HDR_NAME_IPV6 "usb_bridge_ipv6"
+#define A2_ETH_HDR_NAME_IPV4  "a2_bridge_ipv4"
+#define A2_ETH_HDR_NAME_IPV6  "a2_bridge_ipv6"
+
+#define USB_TO_A2_RT_TBL_NAME_IPV4 "usb_a2_rt_tbl_ipv4"
+#define A2_TO_USB_RT_TBL_NAME_IPV4 "a2_usb_rt_tbl_ipv4"
+#define USB_TO_A2_RT_TBL_NAME_IPV6 "usb_a2_rt_tbl_ipv6"
+#define A2_TO_USB_RT_TBL_NAME_IPV6 "a2_usb_rt_tbl_ipv6"
+
+#define MBIM_HEADER_NAME "mbim_header"
+#define TETH_DEFAULT_AGGR_TIME_LIMIT 1
+
+#define ETHERTYPE_IPV4 0x0800
+#define ETHERTYPE_IPV6 0x86DD
+
+struct mac_addresses_type {
+	u8 host_pc_mac_addr[ETH_ALEN];
+	bool host_pc_mac_addr_known;
+	u8 device_mac_addr[ETH_ALEN];
+	bool device_mac_addr_known;
+};
+
+struct teth_bridge_ctx {
+	struct class *class;
+	dev_t dev_num;
+	struct device *dev;
+	struct cdev cdev;
+	u32 usb_ipa_pipe_hdl;
+	u32 ipa_usb_pipe_hdl;
+	u32 a2_ipa_pipe_hdl;
+	u32 ipa_a2_pipe_hdl;
+	bool is_connected;
+	enum teth_link_protocol_type link_protocol;
+	struct mac_addresses_type mac_addresses;
+	bool is_hw_bridge_complete;
+	struct teth_aggr_params aggr_params;
+	bool aggr_params_known;
+	enum teth_tethering_mode tethering_mode;
+	struct completion is_bridge_prod_up;
+	struct completion is_bridge_prod_down;
+	struct work_struct comp_hw_bridge_work;
+	bool comp_hw_bridge_in_progress;
+	struct teth_aggr_capabilities *aggr_caps;
+};
+
+static struct teth_bridge_ctx *teth_ctx;
+
+#ifdef CONFIG_DEBUG_FS
+#define TETH_MAX_MSG_LEN 512
+static char dbg_buff[TETH_MAX_MSG_LEN];
+#endif
+
+static int add_eth_hdrs(char *hdr_name_ipv4, char *hdr_name_ipv6,
+			u8 *src_mac_addr, u8 *dst_mac_addr)
+{
+	int res;
+	struct ipa_ioc_add_hdr *hdrs;
+	struct ethhdr hdr_ipv4;
+	struct ethhdr hdr_ipv6;
+
+	TETH_DBG_FUNC_ENTRY();
+	memcpy(hdr_ipv4.h_source, src_mac_addr, ETH_ALEN);
+	memcpy(hdr_ipv4.h_dest, dst_mac_addr, ETH_ALEN);
+	hdr_ipv4.h_proto = htons(ETHERTYPE_IPV4);
+
+	memcpy(hdr_ipv6.h_source, src_mac_addr, ETH_ALEN);
+	memcpy(hdr_ipv6.h_dest, dst_mac_addr, ETH_ALEN);
+	hdr_ipv6.h_proto = htons(ETHERTYPE_IPV6);
+
+	/* Add headers to the header insertion tables */
+	hdrs = kzalloc(sizeof(struct ipa_ioc_add_hdr) +
+		       2 * sizeof(struct ipa_hdr_add), GFP_KERNEL);
+	if (hdrs == NULL) {
+		TETH_ERR("Failed allocating memory for headers !\n");
+		return -ENOMEM;
+	}
+
+	hdrs->commit = 0;
+	hdrs->num_hdrs = 2;
+
+	/* Ethernet IPv4 header */
+	strlcpy(hdrs->hdr[0].name, hdr_name_ipv4, IPA_RESOURCE_NAME_MAX);
+	hdrs->hdr[0].hdr_len = ETH_HLEN;
+	memcpy(hdrs->hdr[0].hdr, &hdr_ipv4, ETH_HLEN);
+
+	/* Ethernet IPv6 header */
+	strlcpy(hdrs->hdr[1].name, hdr_name_ipv6, IPA_RESOURCE_NAME_MAX);
+	hdrs->hdr[1].hdr_len = ETH_HLEN;
+	memcpy(hdrs->hdr[1].hdr, &hdr_ipv6, ETH_HLEN);
+
+	res = ipa_add_hdr(hdrs);
+	if (res || hdrs->hdr[0].status || hdrs->hdr[1].status)
+		TETH_ERR("Header insertion failed\n");
+	kfree(hdrs);
+	TETH_DBG_FUNC_EXIT();
+
+	return res;
+}
+
+static int configure_ipa_header_block_internal(u32 usb_ipa_hdr_len,
+					       u32 a2_ipa_hdr_len,
+					       u32 ipa_usb_hdr_len,
+					       u32 ipa_a2_hdr_len)
+{
+	struct ipa_ep_cfg_hdr hdr_cfg;
+	int res;
+
+	TETH_DBG_FUNC_ENTRY();
+	/* Configure header removal for the USB->IPA pipe and A2->IPA pipe */
+	memset(&hdr_cfg, 0, sizeof(hdr_cfg));
+	hdr_cfg.hdr_len = usb_ipa_hdr_len;
+	res = ipa_cfg_ep_hdr(teth_ctx->usb_ipa_pipe_hdl, &hdr_cfg);
+	if (res) {
+		TETH_ERR("Header removal config for USB->IPA pipe failed\n");
+		goto bail;
+	}
+
+	hdr_cfg.hdr_len = a2_ipa_hdr_len;
+	res = ipa_cfg_ep_hdr(teth_ctx->a2_ipa_pipe_hdl, &hdr_cfg);
+	if (res) {
+		TETH_ERR("Header removal config for A2->IPA pipe failed\n");
+		goto bail;
+	}
+
+	/* Configure header insertion for the IPA->USB pipe and IPA->A2 pipe */
+	hdr_cfg.hdr_len = ipa_usb_hdr_len;
+	res = ipa_cfg_ep_hdr(teth_ctx->ipa_usb_pipe_hdl, &hdr_cfg);
+	if (res) {
+		TETH_ERR("Header insertion config for IPA->USB pipe failed\n");
+		goto bail;
+	}
+
+	hdr_cfg.hdr_len = ipa_a2_hdr_len;
+	res = ipa_cfg_ep_hdr(teth_ctx->ipa_a2_pipe_hdl, &hdr_cfg);
+	if (res) {
+		TETH_ERR("Header insertion config for IPA->A2 pipe failed\n");
+		goto bail;
+	}
+	TETH_DBG_FUNC_EXIT();
+
+bail:
+	return res;
+}
+
+static int add_mbim_hdr(void)
+{
+	int res;
+	struct ipa_ioc_add_hdr *mbim_hdr;
+	u8 mbim_stream_id = 0;
+
+	TETH_DBG_FUNC_ENTRY();
+	mbim_hdr = kzalloc(sizeof(struct ipa_ioc_add_hdr) +
+			   sizeof(struct ipa_hdr_add),
+			   GFP_KERNEL);
+	if (!mbim_hdr) {
+		TETH_ERR("Failed allocating memory for MBIM header\n");
+		return -ENOMEM;
+	}
+
+	mbim_hdr->commit = 0;
+	mbim_hdr->num_hdrs = 1;
+	strlcpy(mbim_hdr->hdr[0].name, MBIM_HEADER_NAME, IPA_RESOURCE_NAME_MAX);
+	memcpy(mbim_hdr->hdr[0].hdr, &mbim_stream_id, sizeof(u8));
+	mbim_hdr->hdr[0].hdr_len = sizeof(u8);
+	mbim_hdr->hdr[0].is_partial = false;
+	res = ipa_add_hdr(mbim_hdr);
+	if (res || mbim_hdr->hdr[0].status) {
+		TETH_ERR("Failed adding MBIM header\n");
+		res = -EFAULT;
+	} else {
+		TETH_DBG("Added MBIM stream ID header\n");
+	}
+	kfree(mbim_hdr);
+	TETH_DBG_FUNC_EXIT();
+
+	return res;
+}
+
+static int configure_ipa_header_block(void)
+{
+	int res;
+	u32 hdr_len = 0;
+	u32 ipa_usb_hdr_len = 0;
+
+	TETH_DBG_FUNC_ENTRY();
+	if (teth_ctx->link_protocol == TETH_LINK_PROTOCOL_IP) {
+		/*
+		 * Create a new header for MBIM stream ID and associate it with
+		 * the IPA->USB routing table
+		 */
+		if (teth_ctx->aggr_params.dl.aggr_prot ==
+					TETH_AGGR_PROTOCOL_MBIM) {
+			ipa_usb_hdr_len = 1;
+			res = add_mbim_hdr();
+			if (res) {
+				TETH_ERR("Failed adding MBIM header\n");
+				goto bail;
+			}
+		}
+	} else if (teth_ctx->link_protocol == TETH_LINK_PROTOCOL_ETHERNET) {
+		/* Add a header entry for USB */
+		res = add_eth_hdrs(USB_ETH_HDR_NAME_IPV4,
+				   USB_ETH_HDR_NAME_IPV6,
+				   teth_ctx->mac_addresses.host_pc_mac_addr,
+				   teth_ctx->mac_addresses.device_mac_addr);
+		if (res) {
+			TETH_ERR("Failed adding USB Ethernet header\n");
+			goto bail;
+		}
+		TETH_DBG("Added USB Ethernet headers (IPv4 / IPv6)\n");
+
+		/* Add a header entry for A2 */
+		res = add_eth_hdrs(A2_ETH_HDR_NAME_IPV4,
+				   A2_ETH_HDR_NAME_IPV6,
+				   teth_ctx->mac_addresses.device_mac_addr,
+				   teth_ctx->mac_addresses.host_pc_mac_addr);
+		if (res) {
+			TETH_ERR("Failed adding A2 Ethernet header\n");
+			goto bail;
+		}
+		TETH_DBG("Added A2 Ethernet headers (IPv4 / IPv6\n");
+
+		hdr_len = ETH_HLEN;
+		ipa_usb_hdr_len = ETH_HLEN;
+	}
+
+	res = configure_ipa_header_block_internal(hdr_len,
+						  hdr_len,
+						  ipa_usb_hdr_len,
+						  hdr_len);
+	if (res) {
+		TETH_ERR("Configuration of header removal/insertion failed\n");
+		goto bail;
+	}
+
+	res = ipa_commit_hdr();
+	if (res) {
+		TETH_ERR("Failed committing headers\n");
+		goto bail;
+	}
+	TETH_DBG_FUNC_EXIT();
+
+bail:
+	return res;
+}
+
+static int configure_routing_by_ip(char *hdr_name,
+			    char *rt_tbl_name,
+			    enum ipa_client_type dst,
+			    enum ipa_ip_type ip_address_family)
+{
+
+	struct ipa_ioc_add_rt_rule *rt_rule;
+	struct ipa_ioc_get_hdr hdr_info;
+	int res;
+
+	TETH_DBG_FUNC_ENTRY();
+	/* Get the header handle */
+	memset(&hdr_info, 0, sizeof(hdr_info));
+	strlcpy(hdr_info.name, hdr_name, IPA_RESOURCE_NAME_MAX);
+	ipa_get_hdr(&hdr_info);
+
+	rt_rule = kzalloc(sizeof(struct ipa_ioc_add_rt_rule) +
+			  1 * sizeof(struct ipa_rt_rule_add),
+			  GFP_KERNEL);
+	if (!rt_rule) {
+		TETH_ERR("Memory allocation failure");
+		return -ENOMEM;
+	}
+
+	/* Match all, do not commit to HW*/
+	rt_rule->commit = 0;
+	rt_rule->num_rules = 1;
+	rt_rule->ip = ip_address_family;
+	strlcpy(rt_rule->rt_tbl_name, rt_tbl_name, IPA_RESOURCE_NAME_MAX);
+	rt_rule->rules[0].rule.dst = dst;
+	rt_rule->rules[0].rule.hdr_hdl = hdr_info.hdl;
+	rt_rule->rules[0].rule.attrib.attrib_mask = 0; /* Match all */
+	res = ipa_add_rt_rule(rt_rule);
+	if (res || rt_rule->rules[0].status)
+		TETH_ERR("Failed adding routing rule\n");
+	kfree(rt_rule);
+	TETH_DBG_FUNC_EXIT();
+
+	return res;
+}
+
+static int configure_routing(char *hdr_name_ipv4,
+			     char *rt_tbl_name_ipv4,
+			     char *hdr_name_ipv6,
+			     char *rt_tbl_name_ipv6,
+			     enum ipa_client_type dst)
+{
+	int res;
+
+	TETH_DBG_FUNC_ENTRY();
+	/* Configure IPv4 routing table */
+	res = configure_routing_by_ip(hdr_name_ipv4,
+				      rt_tbl_name_ipv4,
+				      dst,
+				      IPA_IP_v4);
+	if (res) {
+		TETH_ERR("Failed adding IPv4 routing table\n");
+		goto bail;
+	}
+
+	/* Configure IPv6 routing table */
+	res = configure_routing_by_ip(hdr_name_ipv6,
+				      rt_tbl_name_ipv6,
+				      dst,
+				      IPA_IP_v6);
+	if (res) {
+		TETH_ERR("Failed adding IPv6 routing table\n");
+		goto bail;
+	}
+	TETH_DBG_FUNC_EXIT();
+
+bail:
+	return res;
+}
+
+static int configure_ipa_routing_block(void)
+{
+	int res;
+	char hdr_name_ipv4[IPA_RESOURCE_NAME_MAX];
+	char hdr_name_ipv6[IPA_RESOURCE_NAME_MAX];
+
+	TETH_DBG_FUNC_ENTRY();
+	hdr_name_ipv4[0] = '\0';
+	hdr_name_ipv6[0] = '\0';
+
+	/* Configure USB -> A2 routing table */
+	if (teth_ctx->link_protocol == TETH_LINK_PROTOCOL_ETHERNET) {
+		strlcpy(hdr_name_ipv4,
+			A2_ETH_HDR_NAME_IPV4,
+			IPA_RESOURCE_NAME_MAX);
+		strlcpy(hdr_name_ipv6,
+			A2_ETH_HDR_NAME_IPV6,
+			IPA_RESOURCE_NAME_MAX);
+	}
+	res = configure_routing(hdr_name_ipv4,
+				USB_TO_A2_RT_TBL_NAME_IPV4,
+				hdr_name_ipv6,
+				USB_TO_A2_RT_TBL_NAME_IPV6,
+				IPA_CLIENT_A2_TETHERED_CONS);
+	if (res) {
+		TETH_ERR("USB to A2 routing block configuration failed\n");
+		goto bail;
+	}
+
+	/* Configure A2 -> USB routing table */
+	if (teth_ctx->link_protocol == TETH_LINK_PROTOCOL_ETHERNET) {
+		strlcpy(hdr_name_ipv4,
+			USB_ETH_HDR_NAME_IPV4,
+			IPA_RESOURCE_NAME_MAX);
+		strlcpy(hdr_name_ipv6,
+			USB_ETH_HDR_NAME_IPV6,
+			IPA_RESOURCE_NAME_MAX);
+	} else if (teth_ctx->aggr_params.dl.aggr_prot ==
+						TETH_AGGR_PROTOCOL_MBIM) {
+		strlcpy(hdr_name_ipv4,
+			MBIM_HEADER_NAME,
+			IPA_RESOURCE_NAME_MAX);
+		strlcpy(hdr_name_ipv6,
+			MBIM_HEADER_NAME,
+			IPA_RESOURCE_NAME_MAX);
+	}
+	res = configure_routing(hdr_name_ipv4,
+				A2_TO_USB_RT_TBL_NAME_IPV4,
+				hdr_name_ipv6,
+				A2_TO_USB_RT_TBL_NAME_IPV6,
+				IPA_CLIENT_USB_CONS);
+	if (res) {
+		TETH_ERR("A2 to USB routing block configuration failed\n");
+		goto bail;
+	}
+
+	/* Commit all the changes to HW in one shot */
+	res = ipa_commit_rt(IPA_IP_v4);
+	if (res) {
+		TETH_ERR("Failed commiting IPv4 routing tables\n");
+		goto bail;
+	}
+	res = ipa_commit_rt(IPA_IP_v6);
+	if (res) {
+		TETH_ERR("Failed commiting IPv6 routing tables\n");
+		goto bail;
+	}
+	TETH_DBG_FUNC_EXIT();
+
+bail:
+	return res;
+}
+
+static int configure_filtering_by_ip(char *rt_tbl_name,
+			      enum ipa_client_type src,
+			      enum ipa_ip_type ip_address_family)
+{
+	struct ipa_ioc_add_flt_rule *flt_tbl;
+	struct ipa_ioc_get_rt_tbl rt_tbl_info;
+	int res;
+
+	TETH_DBG_FUNC_ENTRY();
+	/* Get the needed routing table handle */
+	rt_tbl_info.ip = ip_address_family;
+	strlcpy(rt_tbl_info.name, rt_tbl_name, IPA_RESOURCE_NAME_MAX);
+	res = ipa_get_rt_tbl(&rt_tbl_info);
+	if (res) {
+		TETH_ERR("Failed getting routing table handle\n");
+		goto bail;
+	}
+
+	flt_tbl = kzalloc(sizeof(struct ipa_ioc_add_flt_rule) +
+			  1 * sizeof(struct ipa_flt_rule_add), GFP_KERNEL);
+	if (!flt_tbl) {
+		TETH_ERR("Filtering table memory allocation failure\n");
+		return -ENOMEM;
+	}
+
+	flt_tbl->commit = 0;
+	flt_tbl->ep = src;
+	flt_tbl->global = 0;
+	flt_tbl->ip = ip_address_family;
+	flt_tbl->num_rules = 1;
+	flt_tbl->rules[0].rule.action = IPA_PASS_TO_ROUTING;
+	flt_tbl->rules[0].rule.rt_tbl_hdl = rt_tbl_info.hdl;
+	flt_tbl->rules[0].rule.attrib.attrib_mask = 0; /* Match all */
+
+	res = ipa_add_flt_rule(flt_tbl);
+	if (res || flt_tbl->rules[0].status)
+		TETH_ERR("Failed adding filtering table\n");
+	kfree(flt_tbl);
+	TETH_DBG_FUNC_EXIT();
+
+bail:
+	return res;
+}
+
+static int configure_filtering(char *rt_tbl_name_ipv4,
+			char *rt_tbl_name_ipv6,
+			enum ipa_client_type src)
+{
+	int res;
+
+	TETH_DBG_FUNC_ENTRY();
+	res = configure_filtering_by_ip(rt_tbl_name_ipv4, src, IPA_IP_v4);
+	if (res) {
+		TETH_ERR("Failed adding IPv4 filtering table\n");
+		goto bail;
+	}
+
+	res = configure_filtering_by_ip(rt_tbl_name_ipv6, src, IPA_IP_v6);
+	if (res) {
+		TETH_ERR("Failed adding IPv4 filtering table\n");
+		goto bail;
+	}
+	TETH_DBG_FUNC_EXIT();
+
+bail:
+	return res;
+}
+
+static int configure_ipa_filtering_block(void)
+{
+	int res;
+
+	TETH_DBG_FUNC_ENTRY();
+	/* Filter all traffic coming from USB to A2 */
+	res = configure_filtering(USB_TO_A2_RT_TBL_NAME_IPV4,
+				  USB_TO_A2_RT_TBL_NAME_IPV6,
+				  IPA_CLIENT_USB_PROD);
+	if (res) {
+		TETH_ERR("USB_PROD ep filtering configuration failed\n");
+		goto bail;
+	}
+
+	/* Filter all traffic coming from A2 to USB */
+	res = configure_filtering(A2_TO_USB_RT_TBL_NAME_IPV4,
+				  A2_TO_USB_RT_TBL_NAME_IPV6,
+				  IPA_CLIENT_A2_TETHERED_PROD);
+	if (res) {
+		TETH_ERR("A2_PROD filtering configuration failed\n");
+		goto bail;
+	}
+
+	/* Commit all the changes to HW in one shot */
+	res = ipa_commit_flt(IPA_IP_v4);
+	if (res) {
+		TETH_ERR("Failed commiting IPv4 filtering tables\n");
+		goto bail;
+	}
+	res = ipa_commit_flt(IPA_IP_v6);
+	if (res) {
+		TETH_ERR("Failed commiting IPv6 filtering tables\n");
+		goto bail;
+	}
+	TETH_DBG_FUNC_EXIT();
+
+bail:
+	return res;
+}
+
+static int prepare_ipa_aggr_struct(
+	const struct teth_aggr_params_link *teth_aggr_params,
+	struct ipa_ep_cfg_aggr *ipa_aggr_params,
+	bool client_is_prod)
+{
+	TETH_DBG_FUNC_ENTRY();
+	memset(ipa_aggr_params, 0, sizeof(*ipa_aggr_params));
+
+	switch (teth_aggr_params->aggr_prot) {
+	case TETH_AGGR_PROTOCOL_NONE:
+		ipa_aggr_params->aggr_en = IPA_BYPASS_AGGR;
+		break;
+	case TETH_AGGR_PROTOCOL_MBIM:
+		 ipa_aggr_params->aggr = IPA_MBIM_16;
+		 ipa_aggr_params->aggr_en = (client_is_prod) ?
+			 IPA_ENABLE_DEAGGR : IPA_ENABLE_AGGR;
+		 break;
+	case TETH_AGGR_PROTOCOL_TLP:
+		ipa_aggr_params->aggr = IPA_TLP;
+		ipa_aggr_params->aggr_en = (client_is_prod) ?
+			IPA_ENABLE_DEAGGR : IPA_ENABLE_AGGR;
+		break;
+	default:
+		TETH_ERR("Unsupported aggregation protocol\n");
+		return -EFAULT;
+	}
+
+	ipa_aggr_params->aggr_byte_limit =
+		teth_aggr_params->max_transfer_size_byte / 1024;
+	ipa_aggr_params->aggr_time_limit = TETH_DEFAULT_AGGR_TIME_LIMIT;
+	TETH_DBG_FUNC_EXIT();
+
+	return 0;
+}
+
+static int teth_set_aggr_per_ep(
+	const struct teth_aggr_params_link *teth_aggr_params,
+	bool client_is_prod,
+	u32 pipe_hdl)
+{
+	struct ipa_ep_cfg_aggr agg_params;
+	struct ipa_ep_cfg_hdr hdr_params;
+	int res;
+
+	TETH_DBG_FUNC_ENTRY();
+	res = prepare_ipa_aggr_struct(teth_aggr_params,
+				      &agg_params,
+				      client_is_prod);
+	if (res) {
+		TETH_ERR("prepare_ipa_aggregation_struct() failed\n");
+		goto bail;
+	}
+
+	res = ipa_cfg_ep_aggr(pipe_hdl, &agg_params);
+	if (res) {
+		TETH_ERR("ipa_cfg_ep_aggr() failed\n");
+		goto bail;
+	}
+
+	if (!client_is_prod) {
+		memset(&hdr_params, 0, sizeof(hdr_params));
+		hdr_params.hdr_len = 1;
+		res = ipa_cfg_ep_hdr(pipe_hdl, &hdr_params);
+		if (res) {
+			TETH_ERR("ipa_cfg_ep_hdr() failed\n");
+			goto bail;
+		}
+	}
+	TETH_DBG_FUNC_EXIT();
+
+bail:
+	return res;
+}
+
+static void aggr_prot_to_str(enum teth_aggr_protocol_type aggr_prot,
+			     char *buff,
+			     uint buff_size)
+{
+	switch (aggr_prot) {
+	case TETH_AGGR_PROTOCOL_NONE:
+		strlcpy(buff, "NONE", buff_size);
+		break;
+	case TETH_AGGR_PROTOCOL_MBIM:
+		strlcpy(buff, "MBIM", buff_size);
+		break;
+	case TETH_AGGR_PROTOCOL_TLP:
+		strlcpy(buff, "TLP", buff_size);
+		break;
+	default:
+		strlcpy(buff, "ERROR", buff_size);
+		break;
+	}
+}
+
+static int teth_set_aggregation(void)
+{
+	int res;
+	char aggr_prot_str[20];
+
+	TETH_DBG_FUNC_ENTRY();
+	if (teth_ctx->aggr_params.ul.aggr_prot == TETH_AGGR_PROTOCOL_MBIM ||
+	    teth_ctx->aggr_params.dl.aggr_prot == TETH_AGGR_PROTOCOL_MBIM) {
+		res = ipa_set_aggr_mode(IPA_MBIM);
+		if (res) {
+			TETH_ERR("ipa_set_aggr_mode() failed\n");
+			goto bail;
+		}
+		res = ipa_set_single_ndp_per_mbim(false);
+		if (res) {
+			TETH_ERR("ipa_set_single_ndp_per_mbim() failed\n");
+			goto bail;
+		}
+	}
+
+	aggr_prot_to_str(teth_ctx->aggr_params.ul.aggr_prot,
+			 aggr_prot_str,
+			 sizeof(aggr_prot_str)-1);
+	TETH_DBG("Setting %s aggregation on UL\n", aggr_prot_str);
+	aggr_prot_to_str(teth_ctx->aggr_params.dl.aggr_prot,
+			 aggr_prot_str,
+			 sizeof(aggr_prot_str)-1);
+	TETH_DBG("Setting %s aggregation on DL\n", aggr_prot_str);
+
+	/* Configure aggregation on UL producer (USB->IPA) */
+	res = teth_set_aggr_per_ep(&teth_ctx->aggr_params.ul,
+				   true,
+				   teth_ctx->usb_ipa_pipe_hdl);
+	if (res) {
+		TETH_ERR("teth_set_aggregation_per_ep() failed\n");
+		goto bail;
+	}
+
+	/* Configure aggregation on DL consumer (IPA->USB) */
+	res = teth_set_aggr_per_ep(&teth_ctx->aggr_params.dl,
+				   false,
+				   teth_ctx->ipa_usb_pipe_hdl);
+	if (res) {
+		TETH_ERR("teth_set_aggregation_per_ep() failed\n");
+		goto bail;
+	}
+	TETH_DBG_FUNC_EXIT();
+bail:
+	return res;
+}
+
+static void complete_hw_bridge(struct work_struct *work)
+{
+	int res;
+	static DEFINE_MUTEX(f_lock);
+
+	mutex_lock(&f_lock);
+
+	TETH_DBG_FUNC_ENTRY();
+	TETH_DBG("Completing HW bridge in %s mode\n",
+		 (teth_ctx->link_protocol == TETH_LINK_PROTOCOL_ETHERNET) ?
+		 "ETHERNET" :
+		 "IP");
+
+	res = teth_set_aggregation();
+	if (res) {
+		TETH_ERR("Failed setting aggregation params\n");
+		goto bail;
+	}
+
+	/*
+	 * Reset the Header, Routing and Filtering blocks.
+	 * Resetting the Header block will also reset the other blocks.
+	 * This reset is not comitted to HW.
+	 */
+	res = ipa_reset_hdr();
+	if (res) {
+		TETH_ERR("Failed resetting IPA\n");
+		goto bail;
+	}
+
+	res = configure_ipa_header_block();
+	if (res) {
+		TETH_ERR("Configuration of IPA header block Failed\n");
+		goto bail;
+	}
+
+	res = configure_ipa_routing_block();
+	if (res) {
+		TETH_ERR("Configuration of IPA routing block Failed\n");
+		goto bail;
+	}
+
+	res = configure_ipa_filtering_block();
+	if (res) {
+		TETH_ERR("Configuration of IPA filtering block Failed\n");
+		goto bail;
+	}
+
+	teth_ctx->is_hw_bridge_complete = true;
+	teth_ctx->comp_hw_bridge_in_progress = false;
+bail:
+	mutex_unlock(&f_lock);
+	TETH_DBG_FUNC_EXIT();
+
+	return;
+}
+
+static void mac_addr_to_str(u8 mac_addr[ETH_ALEN],
+		     char *buff,
+		     uint buff_size)
+{
+	scnprintf(buff, buff_size, "%02x-%02x-%02x-%02x-%02x-%02x",
+		  mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3],
+		  mac_addr[4], mac_addr[5]);
+}
+
+static void check_to_complete_hw_bridge(struct sk_buff *skb,
+					u8 *my_mac_addr,
+					bool *my_mac_addr_known,
+					bool *peer_mac_addr_known)
+{
+	bool both_mac_addresses_known;
+	char mac_addr_str[20];
+
+	if ((teth_ctx->link_protocol == TETH_LINK_PROTOCOL_ETHERNET) &&
+	    (!(*my_mac_addr_known))) {
+		memcpy(my_mac_addr, &skb->data[ETH_ALEN], ETH_ALEN);
+		mac_addr_to_str(my_mac_addr,
+				mac_addr_str,
+				sizeof(mac_addr_str)-1);
+		TETH_DBG("Extracted MAC addr: %s\n", mac_addr_str);
+		*my_mac_addr_known = true;
+	}
+
+	both_mac_addresses_known = *my_mac_addr_known && *peer_mac_addr_known;
+	if ((both_mac_addresses_known ||
+	    (teth_ctx->link_protocol == TETH_LINK_PROTOCOL_IP)) &&
+	    (!teth_ctx->comp_hw_bridge_in_progress) &&
+	    (teth_ctx->aggr_params_known)) {
+		INIT_WORK(&teth_ctx->comp_hw_bridge_work, complete_hw_bridge);
+		teth_ctx->comp_hw_bridge_in_progress = true;
+		schedule_work(&teth_ctx->comp_hw_bridge_work);
+	}
+}
+
+static void usb_notify_cb(void *priv,
+			  enum ipa_dp_evt_type evt,
+			  unsigned long data)
+{
+	struct sk_buff *skb = (struct sk_buff *)data;
+	int res;
+
+	switch (evt) {
+	case IPA_RECEIVE:
+		if (!teth_ctx->is_hw_bridge_complete)
+			check_to_complete_hw_bridge(
+				skb,
+				teth_ctx->mac_addresses.host_pc_mac_addr,
+				&teth_ctx->mac_addresses.host_pc_mac_addr_known,
+				&teth_ctx->mac_addresses.device_mac_addr_known);
+
+		/* Send the packet to A2, using a2_service driver API */
+		res = a2_mux_write(A2_MUX_TETHERED_0, skb);
+		if (res) {
+			TETH_ERR("Packet send failure, dropping packet !\n");
+			dev_kfree_skb(skb);
+		}
+		break;
+
+	case IPA_WRITE_DONE:
+		dev_kfree_skb(skb);
+		break;
+
+	default:
+		TETH_ERR("Unsupported IPA event !\n");
+		WARN_ON(1);
+	}
+
+	return;
+}
+
+static void a2_notify_cb(void *user_data,
+			 enum a2_mux_event_type event,
+			 unsigned long data)
+{
+	struct sk_buff *skb = (struct sk_buff *)data;
+	int res;
+
+	switch (event) {
+	case A2_MUX_RECEIVE:
+		if (!teth_ctx->is_hw_bridge_complete)
+			check_to_complete_hw_bridge(
+				skb,
+				teth_ctx->mac_addresses.device_mac_addr,
+				&teth_ctx->mac_addresses.device_mac_addr_known,
+				&teth_ctx->
+				mac_addresses.host_pc_mac_addr_known);
+
+		/* Send the packet to USB */
+		res = ipa_tx_dp(IPA_CLIENT_USB_CONS, skb, NULL);
+		if (res) {
+			TETH_ERR("Packet send failure, dropping packet !\n");
+			dev_kfree_skb(skb);
+		}
+		break;
+
+	case A2_MUX_WRITE_DONE:
+		dev_kfree_skb(skb);
+		break;
+
+	default:
+		TETH_ERR("Unsupported IPA event !\n");
+		WARN_ON(1);
+	}
+
+	return;
+}
+
+static void bridge_prod_notify_cb(void *notify_cb_data,
+				  enum ipa_rm_event event,
+				  unsigned long data)
+{
+	switch (event) {
+	case IPA_RM_RESOURCE_GRANTED:
+		complete(&teth_ctx->is_bridge_prod_up);
+		break;
+
+	case IPA_RM_RESOURCE_RELEASED:
+		complete(&teth_ctx->is_bridge_prod_down);
+		break;
+
+	default:
+		TETH_ERR("Unsupported notification!\n");
+		WARN_ON(1);
+		break;
+	}
+
+	return;
+}
+
+/**
+* teth_bridge_init() - Initialize the Tethering bridge driver
+* @usb_notify_cb_ptr:	Callback function which should be used
+*			by the caller. Output parameter.
+* @private_data_ptr:	Data for the callback function. Should
+*			be used by the caller. Output parameter.
+* Return codes: 0: success,
+*		-EINVAL - Bad parameter
+*		Other negative value - Failure
+*/
+int teth_bridge_init(ipa_notify_cb *usb_notify_cb_ptr, void **private_data_ptr)
+{
+	int res = 0;
+	struct ipa_rm_create_params bridge_prod_params;
+
+	TETH_DBG_FUNC_ENTRY();
+	if (usb_notify_cb_ptr == NULL) {
+		TETH_ERR("Bad parameter\n");
+		res = -EINVAL;
+		goto bail;
+	}
+
+	*usb_notify_cb_ptr = usb_notify_cb;
+	*private_data_ptr = NULL;
+
+	/* Build IPA Resource manager dependency graph */
+	bridge_prod_params.name = IPA_RM_RESOURCE_BRIDGE_PROD;
+	bridge_prod_params.reg_params.user_data = NULL;
+	bridge_prod_params.reg_params.notify_cb = bridge_prod_notify_cb;
+	res = ipa_rm_create_resource(&bridge_prod_params);
+	if (res) {
+		TETH_ERR("ipa_rm_create_resource() failed\n");
+		goto bail;
+	}
+
+	res = ipa_rm_add_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
+				    IPA_RM_RESOURCE_USB_CONS);
+	if (res) {
+		TETH_ERR("ipa_rm_add_dependency() failed\n");
+		goto bail;
+	}
+
+	res = ipa_rm_add_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
+				    IPA_RM_RESOURCE_A2_CONS);
+	if (res) {
+		TETH_ERR("ipa_rm_add_dependency() failed\n");
+		goto fail_add_dependency_1;
+	}
+
+	res = ipa_rm_add_dependency(IPA_RM_RESOURCE_USB_PROD,
+				    IPA_RM_RESOURCE_A2_CONS);
+	if (res) {
+		TETH_ERR("ipa_rm_add_dependency() failed\n");
+		goto fail_add_dependency_2;
+	}
+
+	res = ipa_rm_add_dependency(IPA_RM_RESOURCE_A2_PROD,
+				    IPA_RM_RESOURCE_USB_CONS);
+	if (res) {
+		TETH_ERR("ipa_rm_add_dependency() failed\n");
+		goto fail_add_dependency_3;
+	}
+
+	init_completion(&teth_ctx->is_bridge_prod_up);
+	init_completion(&teth_ctx->is_bridge_prod_down);
+
+	/* The default link protocol is Ethernet */
+	teth_ctx->link_protocol = TETH_LINK_PROTOCOL_ETHERNET;
+	goto bail;
+
+fail_add_dependency_3:
+	ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD,
+				 IPA_RM_RESOURCE_A2_CONS);
+fail_add_dependency_2:
+	ipa_rm_delete_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
+				 IPA_RM_RESOURCE_A2_CONS);
+fail_add_dependency_1:
+	ipa_rm_delete_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
+				 IPA_RM_RESOURCE_USB_CONS);
+bail:
+	TETH_DBG_FUNC_EXIT();
+	return res;
+}
+EXPORT_SYMBOL(teth_bridge_init);
+
+/**
+* teth_bridge_disconnect() - Disconnect tethering bridge module
+*
+* Return codes:	0: success
+*		-EPERM: Operation not permitted as the bridge is already
+*		disconnected
+*/
+int teth_bridge_disconnect(void)
+{
+	int res = -EPERM;
+
+	TETH_DBG_FUNC_ENTRY();
+	if (!teth_ctx->is_connected) {
+		TETH_ERR(
+		"Trying to disconnect an already disconnected bridge\n");
+		goto bail;
+	}
+
+	teth_ctx->is_connected = false;
+
+	res = ipa_rm_release_resource(IPA_RM_RESOURCE_BRIDGE_PROD);
+	if (res == -EINPROGRESS)
+		wait_for_completion(&teth_ctx->is_bridge_prod_down);
+
+bail:
+	TETH_DBG_FUNC_EXIT();
+	return res;
+}
+EXPORT_SYMBOL(teth_bridge_disconnect);
+
+/**
+* teth_bridge_connect() - Connect bridge for a tethered Rmnet / MBIM call
+* @connect_params:	Connection info
+*
+* Return codes: 0: success
+*		-EINVAL: invalid parameters
+*		-EPERM: Operation not permitted as the bridge is already
+*		connected
+*/
+int teth_bridge_connect(struct teth_bridge_connect_params *connect_params)
+{
+	int res;
+	struct ipa_ep_cfg ipa_ep_cfg;
+
+	TETH_DBG_FUNC_ENTRY();
+	if (teth_ctx->is_connected) {
+		TETH_ERR("Trying to connect an already connected bridge !\n");
+		return -EPERM;
+	}
+	if (connect_params == NULL ||
+	    connect_params->ipa_usb_pipe_hdl <= 0 ||
+	    connect_params->usb_ipa_pipe_hdl <= 0 ||
+	    connect_params->tethering_mode >= TETH_TETHERING_MODE_MAX ||
+	    connect_params->tethering_mode < 0)
+		return -EINVAL;
+
+	teth_ctx->ipa_usb_pipe_hdl = connect_params->ipa_usb_pipe_hdl;
+	teth_ctx->usb_ipa_pipe_hdl = connect_params->usb_ipa_pipe_hdl;
+	teth_ctx->tethering_mode = connect_params->tethering_mode;
+
+	res = ipa_rm_request_resource(IPA_RM_RESOURCE_BRIDGE_PROD);
+	if (res < 0) {
+		if (res == -EINPROGRESS)
+			wait_for_completion(&teth_ctx->is_bridge_prod_up);
+		else
+			goto bail;
+	}
+
+	res = a2_mux_open_channel(A2_MUX_TETHERED_0,
+				  NULL,
+				  a2_notify_cb);
+	if (res) {
+		TETH_ERR("a2_mux_open_channel() failed\n");
+		goto bail;
+	}
+
+	res = a2_mux_get_tethered_client_handles(A2_MUX_TETHERED_0,
+						 &teth_ctx->ipa_a2_pipe_hdl,
+						 &teth_ctx->a2_ipa_pipe_hdl);
+	if (res) {
+		TETH_ERR(
+		"a2_mux_get_tethered_client_handles() failed, res = %d\n", res);
+		goto bail;
+	}
+
+	/* Reset the various endpoints configuration */
+	memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+	ipa_cfg_ep(teth_ctx->ipa_usb_pipe_hdl, &ipa_ep_cfg);
+	ipa_cfg_ep(teth_ctx->usb_ipa_pipe_hdl, &ipa_ep_cfg);
+	ipa_cfg_ep(teth_ctx->ipa_a2_pipe_hdl, &ipa_ep_cfg);
+	ipa_cfg_ep(teth_ctx->a2_ipa_pipe_hdl, &ipa_ep_cfg);
+
+	teth_ctx->is_connected = true;
+
+	if (teth_ctx->tethering_mode == TETH_TETHERING_MODE_MBIM)
+		teth_ctx->link_protocol = TETH_LINK_PROTOCOL_IP;
+	TETH_DBG_FUNC_EXIT();
+bail:
+	if (res)
+		ipa_rm_release_resource(IPA_RM_RESOURCE_BRIDGE_PROD);
+	return res;
+}
+EXPORT_SYMBOL(teth_bridge_connect);
+
+static void set_aggr_default_params(struct teth_aggr_params_link *params)
+{
+	if (params->max_datagrams == 0)
+		params->max_datagrams = 16;
+	if (params->max_transfer_size_byte == 0)
+		params->max_transfer_size_byte = 16*1024;
+}
+
+static void teth_set_bridge_mode(enum teth_link_protocol_type link_protocol)
+{
+	teth_ctx->link_protocol = link_protocol;
+	teth_ctx->is_hw_bridge_complete = false;
+	memset(&teth_ctx->mac_addresses, 0, sizeof(teth_ctx->mac_addresses));
+}
+
+static long teth_bridge_ioctl(struct file *filp,
+			      unsigned int cmd,
+			      unsigned long arg)
+{
+	int res = 0;
+
+	TETH_DBG("cmd=%x nr=%d\n", cmd, _IOC_NR(cmd));
+
+	if ((_IOC_TYPE(cmd) != TETH_BRIDGE_IOC_MAGIC) ||
+	    (_IOC_NR(cmd) >= TETH_BRIDGE_IOCTL_MAX)) {
+		TETH_ERR("Invalid ioctl\n");
+		return -ENOIOCTLCMD;
+	}
+
+	switch (cmd) {
+	case TETH_BRIDGE_IOC_SET_BRIDGE_MODE:
+		TETH_DBG("TETH_BRIDGE_IOC_SET_BRIDGE_MODE ioctl called\n");
+		if (teth_ctx->link_protocol != arg)
+			teth_set_bridge_mode(arg);
+		break;
+
+	case TETH_BRIDGE_IOC_SET_AGGR_PARAMS:
+		TETH_DBG("TETH_BRIDGE_IOC_SET_AGGR_PARAMS ioctl called\n");
+		res = copy_from_user(&teth_ctx->aggr_params,
+				   (struct teth_aggr_params *)arg,
+				   sizeof(struct teth_aggr_params));
+		if (res) {
+			TETH_ERR("Error, res = %d\n", res);
+			res = -EFAULT;
+			break;
+		}
+		set_aggr_default_params(&teth_ctx->aggr_params.dl);
+		set_aggr_default_params(&teth_ctx->aggr_params.ul);
+		teth_ctx->aggr_params_known = true;
+		break;
+
+	case TETH_BRIDGE_IOC_GET_AGGR_PARAMS:
+		TETH_DBG("TETH_BRIDGE_IOC_GET_AGGR_PARAMS ioctl called\n");
+		if (copy_to_user((u8 *)arg, (u8 *)&teth_ctx->aggr_params,
+				   sizeof(struct teth_aggr_params))) {
+			res = -EFAULT;
+			break;
+		}
+		break;
+
+	case TETH_BRIDGE_IOC_GET_AGGR_CAPABILITIES:
+	{
+		u16 sz;
+		u16 pyld_sz;
+		struct teth_aggr_capabilities caps;
+
+		TETH_DBG("GET_AGGR_CAPABILITIES ioctl called\n");
+		sz = sizeof(struct teth_aggr_capabilities);
+		if (copy_from_user(&caps,
+				   (struct teth_aggr_capabilities *)arg,
+				   sz)) {
+			res = -EFAULT;
+			break;
+		}
+
+		if (caps.num_protocols < teth_ctx->aggr_caps->num_protocols) {
+			caps.num_protocols = teth_ctx->aggr_caps->num_protocols;
+			if (copy_to_user((struct teth_aggr_capabilities *)arg,
+					 &caps,
+					 sz)) {
+				res = -EFAULT;
+				break;
+			}
+			TETH_DBG("Not enough space allocated.\n");
+			res = -EAGAIN;
+			break;
+		}
+
+		pyld_sz = sz + caps.num_protocols *
+			sizeof(struct teth_aggr_params_link);
+
+		if (copy_to_user((u8 *)arg,
+				 (u8 *)(teth_ctx->aggr_caps),
+				 pyld_sz)) {
+			res = -EFAULT;
+			break;
+		}
+	}
+	break;
+	}
+
+	return res;
+}
+
+static void set_aggr_capabilities(void)
+{
+	u16 NUM_PROTOCOLS = 2;
+
+	teth_ctx->aggr_caps = kzalloc(sizeof(struct teth_aggr_capabilities) +
+				      NUM_PROTOCOLS *
+				      sizeof(struct teth_aggr_params_link),
+				      GFP_KERNEL);
+	if (teth_ctx->aggr_caps == NULL) {
+		TETH_ERR("Memory alloc failed for aggregation capabilities.\n");
+		return;
+	}
+
+	teth_ctx->aggr_caps->num_protocols = NUM_PROTOCOLS;
+
+	teth_ctx->aggr_caps->prot_caps[0].aggr_prot = TETH_AGGR_PROTOCOL_MBIM;
+	teth_ctx->aggr_caps->prot_caps[0].max_datagrams = 16;
+	teth_ctx->aggr_caps->prot_caps[0].max_transfer_size_byte = 16*1024;
+
+	teth_ctx->aggr_caps->prot_caps[1].aggr_prot = TETH_AGGR_PROTOCOL_TLP;
+	teth_ctx->aggr_caps->prot_caps[1].max_datagrams = 16;
+	teth_ctx->aggr_caps->prot_caps[1].max_transfer_size_byte = 16*1024;
+}
+
+void teth_bridge_get_client_handles(u32 *producer_handle,
+		u32 *consumer_handle)
+{
+	if (producer_handle == NULL || consumer_handle == NULL)
+		return;
+
+	*producer_handle = teth_ctx->usb_ipa_pipe_hdl;
+	*consumer_handle = teth_ctx->ipa_usb_pipe_hdl;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *dent;
+static struct dentry *dfile_link_protocol;
+static struct dentry *dfile_get_aggr_params;
+static struct dentry *dfile_set_aggr_protocol;
+
+static ssize_t teth_debugfs_read_link_protocol(struct file *file,
+					       char __user *ubuf,
+					       size_t count,
+					       loff_t *ppos)
+{
+	int nbytes;
+
+	nbytes = scnprintf(dbg_buff, TETH_MAX_MSG_LEN, "Link protocol = %s\n",
+			   (teth_ctx->link_protocol ==
+				TETH_LINK_PROTOCOL_ETHERNET) ?
+			   "ETHERNET" :
+			   "IP");
+
+	return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
+}
+
+static ssize_t teth_debugfs_write_link_protocol(struct file *file,
+					const char __user *ubuf,
+					size_t count,
+					loff_t *ppos)
+{
+	unsigned long missing;
+	enum teth_link_protocol_type link_protocol;
+
+	if (sizeof(dbg_buff) < count + 1)
+		return -EFAULT;
+
+	missing = copy_from_user(dbg_buff, ubuf, count);
+	if (missing)
+		return -EFAULT;
+
+	if (count > 0)
+		dbg_buff[count-1] = '\0';
+
+	if (strcmp(dbg_buff, "ETHERNET") == 0) {
+		link_protocol = TETH_LINK_PROTOCOL_ETHERNET;
+	} else if (strcmp(dbg_buff, "IP") == 0) {
+		link_protocol = TETH_LINK_PROTOCOL_IP;
+	} else {
+		TETH_ERR("Bad link protocol, got %s,\n"
+			 "Use <ETHERNET> or <IP>.\n", dbg_buff);
+		return count;
+	}
+
+	teth_set_bridge_mode(link_protocol);
+
+	return count;
+}
+
+static ssize_t teth_debugfs_read_aggr_params(struct file *file,
+					     char __user *ubuf,
+					     size_t count,
+					     loff_t *ppos)
+{
+	int nbytes = 0;
+	char aggr_str[20];
+
+	aggr_prot_to_str(teth_ctx->aggr_params.ul.aggr_prot,
+			 aggr_str,
+			 sizeof(aggr_str)-1);
+	nbytes += scnprintf(&dbg_buff[nbytes], TETH_MAX_MSG_LEN,
+			   "Aggregation parameters for uplink:\n");
+	nbytes += scnprintf(&dbg_buff[nbytes], TETH_MAX_MSG_LEN - nbytes,
+			    "  Aggregation protocol: %s\n",
+			    aggr_str);
+	nbytes += scnprintf(&dbg_buff[nbytes], TETH_MAX_MSG_LEN - nbytes,
+			    "  Max transfer size [byte]: %d\n",
+			    teth_ctx->aggr_params.ul.max_transfer_size_byte);
+	nbytes += scnprintf(&dbg_buff[nbytes], TETH_MAX_MSG_LEN - nbytes,
+			    "  Max datagrams: %d\n",
+			    teth_ctx->aggr_params.ul.max_datagrams);
+
+	aggr_prot_to_str(teth_ctx->aggr_params.dl.aggr_prot,
+			 aggr_str,
+			 sizeof(aggr_str)-1);
+	nbytes += scnprintf(&dbg_buff[nbytes], TETH_MAX_MSG_LEN,
+			   "Aggregation parameters for downlink:\n");
+	nbytes += scnprintf(&dbg_buff[nbytes], TETH_MAX_MSG_LEN - nbytes,
+			    "  Aggregation protocol: %s\n",
+			    aggr_str);
+	nbytes += scnprintf(&dbg_buff[nbytes], TETH_MAX_MSG_LEN - nbytes,
+			    "  Max transfer size [byte]: %d\n",
+			    teth_ctx->aggr_params.dl.max_transfer_size_byte);
+	nbytes += scnprintf(&dbg_buff[nbytes], TETH_MAX_MSG_LEN - nbytes,
+			    "  Max datagrams: %d\n",
+			    teth_ctx->aggr_params.dl.max_datagrams);
+
+	return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
+}
+
+static ssize_t teth_debugfs_set_aggr_protocol(struct file *file,
+				      const char __user *ubuf,
+				      size_t count, loff_t *ppos)
+{
+	unsigned long missing;
+	enum teth_aggr_protocol_type aggr_prot;
+	int res;
+
+	if (sizeof(dbg_buff) < count + 1)
+		return -EFAULT;
+
+	missing = copy_from_user(dbg_buff, ubuf, count);
+	if (missing)
+		return -EFAULT;
+
+	if (count > 0)
+		dbg_buff[count-1] = '\0';
+
+	set_aggr_default_params(&teth_ctx->aggr_params.dl);
+	set_aggr_default_params(&teth_ctx->aggr_params.ul);
+
+	if (strcmp(dbg_buff, "NONE") == 0) {
+		aggr_prot = TETH_AGGR_PROTOCOL_NONE;
+	} else if (strcmp(dbg_buff, "MBIM") == 0) {
+		aggr_prot = TETH_AGGR_PROTOCOL_MBIM;
+	} else if (strcmp(dbg_buff, "TLP") == 0) {
+		aggr_prot = TETH_AGGR_PROTOCOL_TLP;
+	} else {
+		TETH_ERR("Bad aggregation protocol, got %s,\n"
+			 "Use <NONE>, <MBIM> or <TLP>.\n", dbg_buff);
+		return count;
+	}
+
+	teth_ctx->aggr_params.dl.aggr_prot = aggr_prot;
+	teth_ctx->aggr_params.ul.aggr_prot = aggr_prot;
+	teth_ctx->aggr_params_known = true;
+
+	res = teth_set_aggregation();
+	if (res)
+		TETH_ERR("Failed setting aggregation params\n");
+
+	return count;
+}
+
+const struct file_operations teth_link_protocol_ops = {
+	.read = teth_debugfs_read_link_protocol,
+	.write = teth_debugfs_write_link_protocol,
+};
+
+const struct file_operations teth_get_aggr_params_ops = {
+	.read = teth_debugfs_read_aggr_params,
+};
+
+const struct file_operations teth_set_aggr_protocol_ops = {
+	.write = teth_debugfs_set_aggr_protocol,
+};
+
+void teth_debugfs_init(void)
+{
+	const mode_t read_only_mode = S_IRUSR | S_IRGRP | S_IROTH;
+	const mode_t read_write_mode = S_IRUSR | S_IRGRP | S_IROTH |
+			S_IWUSR | S_IWGRP | S_IWOTH;
+
+	dent = debugfs_create_dir("ipa_teth", 0);
+	if (IS_ERR(dent)) {
+		IPAERR("fail to create folder ipa_teth debug_fs.\n");
+		return;
+	}
+
+	dfile_link_protocol =
+		debugfs_create_file("link_protocol", read_write_mode, dent, 0,
+				    &teth_link_protocol_ops);
+	if (!dfile_link_protocol || IS_ERR(dfile_link_protocol)) {
+		IPAERR("fail to create file link_protocol\n");
+		goto fail;
+	}
+
+	dfile_get_aggr_params =
+		debugfs_create_file("get_aggr_params", read_only_mode, dent, 0,
+				    &teth_get_aggr_params_ops);
+	if (!dfile_get_aggr_params || IS_ERR(dfile_get_aggr_params)) {
+		IPAERR("fail to create file get_aggr_params\n");
+		goto fail;
+	}
+
+	dfile_set_aggr_protocol =
+		debugfs_create_file("set_aggr_protocol", read_only_mode, dent,
+				    0, &teth_set_aggr_protocol_ops);
+	if (!dfile_set_aggr_protocol || IS_ERR(dfile_set_aggr_protocol)) {
+		IPAERR("fail to create file set_aggr_protocol\n");
+		goto fail;
+	}
+
+	return;
+fail:
+	debugfs_remove_recursive(dent);
+}
+#else
+void teth_debugfs_init(void) {}
+#endif /* CONFIG_DEBUG_FS */
+
+
+static const struct file_operations teth_bridge_drv_fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = teth_bridge_ioctl,
+};
+
+/**
+* teth_bridge_driver_init() - Initialize tethering bridge driver
+*
+*/
+int teth_bridge_driver_init(void)
+{
+	int res;
+
+	TETH_DBG("Tethering bridge driver init\n");
+	teth_ctx = kzalloc(sizeof(*teth_ctx), GFP_KERNEL);
+	if (!teth_ctx) {
+		TETH_ERR("kzalloc err.\n");
+		return -ENOMEM;
+	}
+
+	set_aggr_capabilities();
+
+	teth_ctx->class = class_create(THIS_MODULE, TETH_BRIDGE_DRV_NAME);
+
+	res = alloc_chrdev_region(&teth_ctx->dev_num, 0, 1,
+				  TETH_BRIDGE_DRV_NAME);
+	if (res) {
+		TETH_ERR("alloc_chrdev_region err.\n");
+		res = -ENODEV;
+		goto fail_alloc_chrdev_region;
+	}
+
+	teth_ctx->dev = device_create(teth_ctx->class, NULL, teth_ctx->dev_num,
+				      teth_ctx, TETH_BRIDGE_DRV_NAME);
+	if (IS_ERR(teth_ctx->dev)) {
+		TETH_ERR(":device_create err.\n");
+		res = -ENODEV;
+		goto fail_device_create;
+	}
+
+	cdev_init(&teth_ctx->cdev, &teth_bridge_drv_fops);
+	teth_ctx->cdev.owner = THIS_MODULE;
+	teth_ctx->cdev.ops = &teth_bridge_drv_fops;
+
+	res = cdev_add(&teth_ctx->cdev, teth_ctx->dev_num, 1);
+	if (res) {
+		TETH_ERR(":cdev_add err=%d\n", -res);
+		res = -ENODEV;
+		goto fail_cdev_add;
+	}
+
+	teth_ctx->comp_hw_bridge_in_progress = false;
+
+	teth_debugfs_init();
+	TETH_DBG("Tethering bridge driver init OK\n");
+
+	return 0;
+fail_cdev_add:
+	device_destroy(teth_ctx->class, teth_ctx->dev_num);
+fail_device_create:
+	unregister_chrdev_region(teth_ctx->dev_num, 1);
+fail_alloc_chrdev_region:
+	kfree(teth_ctx->aggr_caps);
+	kfree(teth_ctx);
+	teth_ctx = NULL;
+
+	return res;
+}
+EXPORT_SYMBOL(teth_bridge_driver_init);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Tethering bridge driver");
diff --git a/drivers/platform/msm/ssbi.c b/drivers/platform/msm/ssbi.c
index a08eb48..e0bbdd1 100644
--- a/drivers/platform/msm/ssbi.c
+++ b/drivers/platform/msm/ssbi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
  * Copyright (c) 2010, Google Inc.
  *
  * Original authors: Code Aurora Forum
@@ -362,7 +362,7 @@
 
 	ssbi->base = ioremap(mem_res->start, resource_size(mem_res));
 	if (!ssbi->base) {
-		pr_err("ioremap of 0x%p failed\n", (void *)mem_res->start);
+		pr_err("ioremap failed: %pr\n", mem_res);
 		ret = -EINVAL;
 		goto err_ioremap;
 	}
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index f87a443..03b3e0d 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -255,12 +255,9 @@
 	struct dentry			*dent;
 	struct bms_notify		bms_notify;
 	int				*usb_trim_table;
-	struct regulator		*vreg_xoadc;
 	bool				ext_charging;
 	bool				ext_charge_done;
 	bool				iusb_fine_res;
-	bool				final_kickstart;
-	bool				lockup_lpm_wrkarnd;
 	DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS);
 	struct work_struct		battery_id_valid_work;
 	int64_t				batt_id_min;
@@ -296,6 +293,7 @@
 	int				stop_chg_upon_expiry;
 	bool				disable_aicl;
 	int				usb_type;
+	bool				disable_chg_rmvl_wrkarnd;
 };
 
 /* user space parameter to limit usb current */
@@ -311,7 +309,6 @@
 
 static struct pm8921_chg_chip *the_chip;
 
-static DEFINE_SPINLOCK(lpm_lock);
 #define LPM_ENABLE_BIT	BIT(2)
 static int pm8921_chg_set_lpm(struct pm8921_chg_chip *chip, int enable)
 {
@@ -340,66 +337,11 @@
 static int pm_chg_write(struct pm8921_chg_chip *chip, u16 addr, u8 reg)
 {
 	int rc;
-	unsigned long flags = 0;
-	u8 temp;
 
-	/* Disable LPM */
-	if (chip->lockup_lpm_wrkarnd) {
-		spin_lock_irqsave(&lpm_lock, flags);
+	rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
+	if (rc)
+		pr_err("failed: addr=%03X, rc=%d\n", addr, rc);
 
-		/*
-		 * This delay is to prevent exit out of 32khz mode within
-		 * 200uS. It could be that chg was removed just few uS before
-		 * this gets called.
-		 */
-		udelay(200);
-		/* no clks */
-		temp = 0xD1;
-		rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
-		if (rc) {
-			pr_err("Error %d writing %d to CHG_TEST\n", rc, temp);
-			goto release_lpm_lock;
-		}
-
-		/* force 19.2Mhz before reading */
-		temp = 0xD3;
-		rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
-		if (rc) {
-			pr_err("Error %d writing %d to CHG_TEST\n", rc, temp);
-			goto release_lpm_lock;
-		}
-
-		rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
-		if (rc) {
-			pr_err("failed: addr=%03X, rc=%d\n", addr, rc);
-			goto release_lpm_lock;
-		}
-
-		/* no clks */
-		temp = 0xD1;
-		rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
-		if (rc) {
-			pr_err("Error %d writing %d to CHG_TEST\n", rc, temp);
-			goto release_lpm_lock;
-		}
-
-		/* switch to hw clk selection */
-		temp = 0xD0;
-		rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
-		if (rc) {
-			pr_err("Error %d writing %d to CHG_TEST\n", rc, temp);
-			goto release_lpm_lock;
-		}
-
-		udelay(200);
-
-release_lpm_lock:
-		spin_unlock_irqrestore(&lpm_lock, flags);
-	} else {
-		rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
-		if (rc)
-			pr_err("failed: addr=%03X, rc=%d\n", addr, rc);
-	}
 	return rc;
 }
 
@@ -430,23 +372,6 @@
 					chip->pmic_chg_irq[irq_id]);
 }
 
-static int is_chg_on_bat(struct pm8921_chg_chip *chip)
-{
-	return !(pm_chg_get_rt_status(chip, DCIN_VALID_IRQ)
-			|| pm_chg_get_rt_status(chip, USBIN_VALID_IRQ));
-}
-
-static void pm8921_chg_bypass_bat_gone_debounce(struct pm8921_chg_chip *chip,
-		int bypass)
-{
-	int rc;
-
-	rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, bypass ? 0x89 : 0x88);
-	if (rc) {
-		pr_err("Failed to set bypass bit to %d rc=%d\n", bypass, rc);
-	}
-}
-
 /* Treat OverVoltage/UnderVoltage as source missing */
 static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
 {
@@ -469,35 +394,8 @@
 static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip)
 {
 	u8 temp;
-	unsigned long flags = 0;
 	int err = 0, ret = 0;
 
-	if (chip->lockup_lpm_wrkarnd) {
-		spin_lock_irqsave(&lpm_lock, flags);
-
-		/*
-		 * This delay is to prevent exit out of 32khz mode within
-		 * 200uS. It could be that chg was removed just few uS before
-		 * this gets called.
-		 */
-		udelay(200);
-		/* no clks */
-		temp = 0xD1;
-		err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
-		if (err) {
-			pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
-			goto err_out;
-		}
-
-		/* force 19.2Mhz before reading */
-		temp = 0xD3;
-		err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
-		if (err) {
-			pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
-			goto err_out;
-		}
-	}
-
 	temp = CAPTURE_FSM_STATE_CMD;
 	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
 	if (err) {
@@ -535,29 +433,7 @@
 	/* get the upper 1 bit */
 	ret |= (temp & 0x1) << 4;
 
-	if (chip->lockup_lpm_wrkarnd) {
-		/* no clks */
-		temp = 0xD1;
-		err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
-		if (err) {
-			pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
-			goto err_out;
-		}
-
-		/* switch to hw clk selection */
-		temp = 0xD0;
-		err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
-		if (err) {
-			pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
-			goto err_out;
-		}
-
-		udelay(200);
-	}
-
 err_out:
-	if (chip->lockup_lpm_wrkarnd)
-		spin_unlock_irqrestore(&lpm_lock, flags);
 	if (err)
 		return err;
 
@@ -568,35 +444,8 @@
 static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip)
 {
 	u8 temp, data;
-	unsigned long flags = 0;
 	int err = 0;
 
-	if (chip->lockup_lpm_wrkarnd) {
-		spin_lock_irqsave(&lpm_lock, flags);
-
-		/*
-		 * This delay is to prevent exit out of 32khz mode within
-		 * 200uS. It could be that chg was removed just few uS before
-		 * this gets called.
-		 */
-		udelay(200);
-		/* no clks */
-		temp = 0xD1;
-		err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
-		if (err) {
-			pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
-			goto err_out;
-		}
-
-		/* force 19.2Mhz before reading */
-		temp = 0xD3;
-		err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
-		if (err) {
-			pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
-			goto err_out;
-		}
-	}
-
 	temp = READ_BANK_6;
 	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
 	if (err) {
@@ -610,29 +459,7 @@
 		goto err_out;
 	}
 
-	if (chip->lockup_lpm_wrkarnd) {
-		/* no clks */
-		temp = 0xD1;
-		err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
-		if (err) {
-			pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
-			goto err_out;
-		}
-
-		/* switch to hw clk selection */
-		temp = 0xD0;
-		err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
-		if (err) {
-			pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
-			goto err_out;
-		}
-
-		udelay(200);
-	}
-
 err_out:
-	if (chip->lockup_lpm_wrkarnd)
-		spin_unlock_irqrestore(&lpm_lock, flags);
 	if (err)
 		return err;
 
@@ -2099,10 +1926,10 @@
 	 * This would also apply when the battery has been
 	 * removed from the running system.
 	 */
-	if (the_chip && !get_prop_batt_present(the_chip)
+	if (mA == 0 && the_chip && !get_prop_batt_present(the_chip)
 		&& !is_dc_chg_plugged_in(the_chip)) {
 		if (!the_chip->has_dc_supply) {
-			pr_err("rejected: no other power source connected\n");
+			pr_err("rejected: no other power source mA = %d\n", mA);
 			return;
 		}
 	}
@@ -2377,96 +2204,9 @@
 	return get_prop_batt_temp(the_chip);
 }
 
-static int __pm8921_apply_19p2mhz_kickstart(struct pm8921_chg_chip *chip)
-{
-	int err;
-	u8 temp;
-
-
-	temp  = 0xD1;
-	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
-	if (err) {
-		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
-		return err;
-	}
-
-	temp  = 0xD3;
-	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
-	if (err) {
-		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
-		return err;
-	}
-
-	temp  = 0xD1;
-	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
-	if (err) {
-		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
-		return err;
-	}
-
-	temp  = 0xD5;
-	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
-	if (err) {
-		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
-		return err;
-	}
-
-	/* Wait a few clock cycles before re-enabling hw clock switching */
-	udelay(183);
-
-	temp  = 0xD1;
-	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
-	if (err) {
-		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
-		return err;
-	}
-
-	temp  = 0xD0;
-	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
-	if (err) {
-		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
-		return err;
-	}
-
-	/* Wait for few clock cycles before re-enabling LPM */
-	udelay(32);
-
-	return 0;
-}
-
-static int pm8921_apply_19p2mhz_kickstart(struct pm8921_chg_chip *chip)
-{
-	int err;
-	unsigned long flags = 0;
-
-	spin_lock_irqsave(&lpm_lock, flags);
-	err = pm8921_chg_set_lpm(chip, 0);
-	if (err) {
-		pr_err("Error settig LPM rc=%d\n", err);
-		goto kick_err;
-	}
-
-	__pm8921_apply_19p2mhz_kickstart(chip);
-
-kick_err:
-	err = pm8921_chg_set_lpm(chip, 1);
-	if (err)
-		pr_err("Error settig LPM rc=%d\n", err);
-
-	spin_unlock_irqrestore(&lpm_lock, flags);
-
-	return err;
-}
-
 static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
 {
-	int usb_present, rc = 0;
-
-	if (chip->lockup_lpm_wrkarnd) {
-		rc = pm8921_apply_19p2mhz_kickstart(chip);
-		if (rc)
-			pr_err("Failed to apply kickstart rc=%d\n", rc);
-	}
+	int usb_present;
 
 	pm_chg_failed_clear(chip, 1);
 	usb_present = is_usb_chg_plugged_in(chip);
@@ -2476,11 +2216,6 @@
 		power_supply_changed(&chip->usb_psy);
 		power_supply_changed(&chip->batt_psy);
 		pm8921_bms_calibrate_hkadc();
-
-		/* Enable/disable bypass if charger is on battery */
-		if (chip->lockup_lpm_wrkarnd)
-			pm8921_chg_bypass_bat_gone_debounce(chip,
-				is_chg_on_bat(chip));
 	}
 	if (usb_present) {
 		schedule_delayed_work(&chip->unplug_check_work,
@@ -2496,10 +2231,6 @@
 
 static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
 {
-	if (chip->lockup_lpm_wrkarnd)
-		/* Enable bypass if charger is on battery */
-		pm8921_chg_bypass_bat_gone_debounce(chip, is_chg_on_bat(chip));
-
 	if (!chip->ext_psy) {
 		pr_debug("external charger not registered.\n");
 		return;
@@ -2529,10 +2260,6 @@
 	unsigned long delay =
 		round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
 
-	/* Disable bypass if charger connected and not running on bat */
-	if (chip->lockup_lpm_wrkarnd)
-		pm8921_chg_bypass_bat_gone_debounce(chip, is_chg_on_bat(chip));
-
 	if (!chip->ext_psy) {
 		pr_debug("external charger not registered.\n");
 		return;
@@ -3014,28 +2741,12 @@
 				pm_chg_get_fsm_state(chip),
 				get_prop_batt_current(chip)
 				);
-			if (chip->lockup_lpm_wrkarnd) {
-				rc = pm8921_apply_19p2mhz_kickstart(chip);
-				if (rc)
-					pr_err("Failed kickstart rc=%d\n", rc);
-
-				/*
-				 * Make sure kickstart happens at least 200 ms
-				 * after charger has been removed.
-				 */
-				if (chip->final_kickstart) {
-					chip->final_kickstart = false;
-					goto check_again_later;
-				}
-			}
 			return;
 		} else {
 			goto check_again_later;
 		}
 	}
 
-	chip->final_kickstart = true;
-
 	/* AICL only for usb wall charger */
 	if ((active_path & USB_ACTIVE_BIT) && usb_target_ma > 0 &&
 		!chip->disable_aicl) {
@@ -3057,7 +2768,7 @@
 	pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
 
 	ibat = get_prop_batt_current(chip);
-	if (reg_loop & VIN_ACTIVE_BIT) {
+	if ((reg_loop & VIN_ACTIVE_BIT) && !chip->disable_chg_rmvl_wrkarnd) {
 		if (ibat > 0) {
 			pr_debug("revboost ibat = %d fsm = %d loop = 0x%x\n",
 				ibat, pm_chg_get_fsm_state(chip), reg_loop);
@@ -3077,7 +2788,8 @@
 			active_path, active_chg_plugged_in);
 	chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
 
-	if (chg_gone == 1  && active_chg_plugged_in == 1) {
+	if (chg_gone == 1  && active_chg_plugged_in == 1 &&
+					!chip->disable_chg_rmvl_wrkarnd) {
 		pr_debug("chg_gone=%d, active_chg_plugged_in = %d\n",
 					chg_gone, active_chg_plugged_in);
 		unplug_ovp_fet_open(chip);
@@ -3328,11 +3040,6 @@
 		else
 			handle_stop_ext_chg(chip);
 	} else {
-		if (chip->lockup_lpm_wrkarnd)
-			/* if no external supply call bypass debounce here */
-			pm8921_chg_bypass_bat_gone_debounce(chip,
-				is_chg_on_bat(chip));
-
 		if (dc_present)
 			schedule_delayed_work(&chip->unplug_check_work,
 				msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
@@ -4164,6 +3871,91 @@
 	return -EINVAL;
 }
 
+static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
+{
+	int err;
+	u8 temp;
+
+	temp  = 0xD1;
+	err = pm_chg_write(chip, CHG_TEST, temp);
+	if (err) {
+		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+		return;
+	}
+
+	temp  = 0xD3;
+	err = pm_chg_write(chip, CHG_TEST, temp);
+	if (err) {
+		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+		return;
+	}
+
+	temp  = 0xD1;
+	err = pm_chg_write(chip, CHG_TEST, temp);
+	if (err) {
+		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+		return;
+	}
+
+	temp  = 0xD5;
+	err = pm_chg_write(chip, CHG_TEST, temp);
+	if (err) {
+		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+		return;
+	}
+
+	udelay(183);
+
+	temp  = 0xD1;
+	err = pm_chg_write(chip, CHG_TEST, temp);
+	if (err) {
+		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+		return;
+	}
+
+	temp  = 0xD0;
+	err = pm_chg_write(chip, CHG_TEST, temp);
+	if (err) {
+		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+		return;
+	}
+	udelay(32);
+
+	temp  = 0xD1;
+	err = pm_chg_write(chip, CHG_TEST, temp);
+	if (err) {
+		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+		return;
+	}
+
+	temp  = 0xD3;
+	err = pm_chg_write(chip, CHG_TEST, temp);
+	if (err) {
+		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+		return;
+	}
+}
+
+static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
+{
+	int err;
+	u8 temp;
+
+	temp  = 0xD1;
+	err = pm_chg_write(chip, CHG_TEST, temp);
+	if (err) {
+		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+		return;
+	}
+
+	temp  = 0xD0;
+	err = pm_chg_write(chip, CHG_TEST, temp);
+	if (err) {
+		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
+		return;
+	}
+}
+
 #define VREF_BATT_THERM_FORCE_ON	BIT(7)
 static void detect_battery_removal(struct pm8921_chg_chip *chip)
 {
@@ -4195,15 +3987,8 @@
 	u8 subrev;
 	int rc, vdd_safe, fcc_uah, safety_time = DEFAULT_SAFETY_MINUTES;
 
-	spin_lock_init(&lpm_lock);
-
-	if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
-		rc = __pm8921_apply_19p2mhz_kickstart(chip);
-		if (rc) {
-			pr_err("Failed to apply kickstart rc=%d\n", rc);
-			return rc;
-		}
-	}
+	/* forcing 19p2mhz before accessing any charger registers */
+	pm8921_chg_force_19p2mhz_clk(chip);
 
 	detect_battery_removal(chip);
 
@@ -4451,45 +4236,6 @@
 		return rc;
 	}
 
-	if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
-		/* Clear kickstart */
-		rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, 0xD0);
-		if (rc) {
-			pr_err("Failed to clear kickstart rc=%d\n", rc);
-			return rc;
-		}
-
-		/* From here the lpm_workaround will be active */
-		chip->lockup_lpm_wrkarnd = true;
-
-		/* Enable LPM */
-		pm8921_chg_set_lpm(chip, 1);
-	}
-
-	if (chip->lockup_lpm_wrkarnd) {
-		chip->vreg_xoadc = regulator_get(chip->dev, "vreg_xoadc");
-		if (IS_ERR(chip->vreg_xoadc))
-			return -ENODEV;
-
-		rc = regulator_set_optimum_mode(chip->vreg_xoadc, 10000);
-		if (rc < 0) {
-			pr_err("Failed to set configure HPM rc=%d\n", rc);
-			return rc;
-		}
-
-		rc = regulator_set_voltage(chip->vreg_xoadc, 1800000, 1800000);
-		if (rc) {
-			pr_err("Failed to set L14 voltage rc=%d\n", rc);
-			return rc;
-		}
-
-		rc = regulator_enable(chip->vreg_xoadc);
-		if (rc) {
-			pr_err("Failed to enable L14 rc=%d\n", rc);
-			return rc;
-		}
-	}
-
 	return 0;
 }
 
@@ -4740,19 +4486,16 @@
 	int rc;
 	struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
 
-	if (chip->lockup_lpm_wrkarnd) {
-		rc = regulator_disable(chip->vreg_xoadc);
-		if (rc)
-			pr_err("Failed to disable L14 rc=%d\n", rc);
-
-		rc = pm8921_apply_19p2mhz_kickstart(chip);
-		if (rc)
-			pr_err("Failed to apply kickstart rc=%d\n", rc);
-	}
-
 	rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
 	if (rc)
 		pr_err("Failed to Force Vref therm off rc=%d\n", rc);
+
+	rc = pm8921_chg_set_lpm(chip, 1);
+	if (rc)
+		pr_err("Failed to set lpm rc=%d\n", rc);
+
+	pm8921_chg_set_hw_clk_switching(chip);
+
 	return 0;
 }
 
@@ -4761,15 +4504,11 @@
 	int rc;
 	struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
 
-	if (chip->lockup_lpm_wrkarnd) {
-		rc = regulator_enable(chip->vreg_xoadc);
-		if (rc)
-			pr_err("Failed to enable L14 rc=%d\n", rc);
+	pm8921_chg_force_19p2mhz_clk(chip);
 
-		rc = pm8921_apply_19p2mhz_kickstart(chip);
-		if (rc)
-			pr_err("Failed to apply kickstart rc=%d\n", rc);
-	}
+	rc = pm8921_chg_set_lpm(chip, 0);
+	if (rc)
+		pr_err("Failed to set lpm rc=%d\n", rc);
 
 	rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
 						VREF_BATT_THERM_FORCE_ON);
@@ -4869,6 +4608,7 @@
 	chip->vin_min = pdata->vin_min;
 	chip->thermal_mitigation = pdata->thermal_mitigation;
 	chip->thermal_levels = pdata->thermal_levels;
+	chip->disable_chg_rmvl_wrkarnd = pdata->disable_chg_rmvl_wrkarnd;
 
 	chip->cold_thr = pdata->cold_thr;
 	chip->hot_thr = pdata->hot_thr;
@@ -5000,7 +4740,6 @@
 {
 	struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
 
-	regulator_put(chip->vreg_xoadc);
 	free_irqs(chip);
 	platform_set_drvdata(pdev, NULL);
 	the_chip = NULL;
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index eb75475..ec0b0e7 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -1095,60 +1095,6 @@
 	return 1;
 }
 
-#define BMS_OVERRIDE_MODE_EN_BIT	BIT(7)
-#define EN_VBAT_BIT			BIT(0)
-#define OVERRIDE_MODE_DELAY_MS		20
-static int override_mode_batt_v_and_i(
-		struct qpnp_bms_chip *chip, int *ibat_ua, int *vbat_uv)
-{
-	int16_t vsense_raw, vbat_raw;
-	int vsense_uv, rc;
-	u8 delay;
-
-	mutex_lock(&chip->bms_output_lock);
-
-	delay = 0x00;
-	rc = qpnp_write_wrapper(chip, &delay,
-			chip->base + BMS1_S1_DELAY_CTL, 1);
-	if (rc)
-		pr_err("unable to write into BMS1_S1_DELAY, rc: %d\n", rc);
-
-	rc = qpnp_masked_write(chip, BMS1_MODE_CTL,
-			BMS_OVERRIDE_MODE_EN_BIT | EN_VBAT_BIT,
-			BMS_OVERRIDE_MODE_EN_BIT | EN_VBAT_BIT);
-	if (rc)
-		pr_err("unable to write into BMS1_MODE_CTL, rc: %d\n", rc);
-
-	msleep(OVERRIDE_MODE_DELAY_MS);
-
-	lock_output_data(chip);
-	qpnp_read_wrapper(chip, (u8 *)&vsense_raw,
-			chip->base + BMS1_VSENSE_AVG_DATA0, 2);
-	qpnp_read_wrapper(chip, (u8 *)&vbat_raw,
-			chip->base + BMS1_VBAT_AVG_DATA0, 2);
-	unlock_output_data(chip);
-
-	rc = qpnp_masked_write(chip, BMS1_MODE_CTL,
-			BMS_OVERRIDE_MODE_EN_BIT | EN_VBAT_BIT, 0);
-
-	delay = 0x0B;
-	rc = qpnp_write_wrapper(chip, &delay,
-			chip->base + BMS1_S1_DELAY_CTL, 1);
-	if (rc)
-		pr_err("unable to write into BMS1_S1_DELAY, rc: %d\n", rc);
-
-	mutex_unlock(&chip->bms_output_lock);
-
-	*vbat_uv = convert_vbatt_raw_to_uv(chip, vbat_raw);
-	vsense_uv = convert_vsense_to_uv(chip, vsense_raw);
-	*ibat_ua = div_s64(vsense_uv * 1000000LL, (int)chip->r_sense_uohm);
-
-	pr_debug("vsense_raw = 0x%x vbat_raw = 0x%x ibat_ua = %d vbat_uv = %d\n",
-			(uint16_t)vsense_raw, (uint16_t)vbat_raw,
-			*ibat_ua, *vbat_uv);
-	return 0;
-}
-
 static bool is_battery_charging(struct qpnp_bms_chip *chip)
 {
 	union power_supply_propval ret = {0,};
@@ -1188,23 +1134,21 @@
 static int get_simultaneous_batt_v_and_i(struct qpnp_bms_chip *chip,
 					int *ibat_ua, int *vbat_uv)
 {
+	struct qpnp_iadc_result i_result;
+	struct qpnp_vadc_result v_result;
+	enum qpnp_iadc_channels iadc_channel;
 	int rc;
 
-	if (is_batfet_open(chip)) {
-		pr_debug("batfet is open using separate vbat and ibat meas\n");
-		rc = get_battery_voltage(vbat_uv);
-		if (rc < 0) {
-			pr_err("adc vbat failed err = %d\n", rc);
-			return rc;
-		}
-		rc = get_battery_current(chip, ibat_ua);
-		if (rc < 0) {
-			pr_err("bms ibat failed err = %d\n", rc);
-			return rc;
-		}
-	} else {
-		return override_mode_batt_v_and_i(chip, ibat_ua, vbat_uv);
+	iadc_channel = chip->use_external_rsense ?
+				EXTERNAL_RSENSE : INTERNAL_RSENSE;
+	rc = qpnp_iadc_vadc_sync_read(iadc_channel, &i_result,
+				VBAT_SNS, &v_result);
+	if (rc) {
+		pr_err("vadc read failed with rc: %d\n", rc);
+		return rc;
 	}
+	*ibat_ua = (int)i_result.result_ua;
+	*vbat_uv = (int)v_result.physical;
 
 	return 0;
 }
@@ -1231,7 +1175,7 @@
 
 static int reset_bms_for_test(struct qpnp_bms_chip *chip)
 {
-	int ibat_ua, vbat_uv, rc;
+	int ibat_ua = 0, vbat_uv = 0, rc;
 	int ocv_est_uv;
 
 	if (!chip) {
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index e2ba042..7833afa 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -86,8 +86,8 @@
 #define USB_OVP_CTL				0x42
 #define SEC_ACCESS				0xD0
 
-/* SMBB peripheral subtype values */
 #define REG_OFFSET_PERP_SUBTYPE			0x05
+/* SMBB peripheral subtype values */
 #define SMBB_CHGR_SUBTYPE			0x01
 #define SMBB_BUCK_SUBTYPE			0x02
 #define SMBB_BAT_IF_SUBTYPE			0x03
@@ -96,6 +96,14 @@
 #define SMBB_BOOST_SUBTYPE			0x06
 #define SMBB_MISC_SUBTYPE			0x07
 
+/* SMBB peripheral subtype values */
+#define SMBBP_CHGR_SUBTYPE			0x31
+#define SMBBP_BUCK_SUBTYPE			0x32
+#define SMBBP_BAT_IF_SUBTYPE			0x33
+#define SMBBP_USB_CHGPTH_SUBTYPE		0x34
+#define SMBBP_BOOST_SUBTYPE			0x36
+#define SMBBP_MISC_SUBTYPE			0x37
+
 #define QPNP_CHARGER_DEV_NAME	"qcom,qpnp-charger"
 
 /* Status bits and masks */
@@ -341,6 +349,9 @@
 	u8 dcin_valid_rt_sts;
 	int rc;
 
+	if (!chip->dc_chgpth_base)
+		return 0;
+
 	rc = qpnp_chg_read(chip, &dcin_valid_rt_sts,
 				 INT_RT_STS(chip->dc_chgpth_base), 1);
 	if (rc) {
@@ -1212,6 +1223,7 @@
 
 	switch (subtype) {
 	case SMBB_CHGR_SUBTYPE:
+	case SMBBP_CHGR_SUBTYPE:
 		chip->chg_done_irq = spmi_get_irq_byname(chip->spmi,
 						spmi_resource, "chg-done");
 		if (chip->chg_done_irq < 0) {
@@ -1289,6 +1301,7 @@
 		enable_irq_wake(chip->chg_done_irq);
 		break;
 	case SMBB_BUCK_SUBTYPE:
+	case SMBBP_BUCK_SUBTYPE:
 		rc = qpnp_chg_masked_write(chip,
 			chip->chgr_base + CHGR_BUCK_BCK_VBAT_REG_MODE,
 			BUCK_VBAT_REG_NODE_SEL_BIT,
@@ -1299,8 +1312,10 @@
 		}
 		break;
 	case SMBB_BAT_IF_SUBTYPE:
+	case SMBBP_BAT_IF_SUBTYPE:
 		break;
 	case SMBB_USB_CHGPTH_SUBTYPE:
+	case SMBBP_USB_CHGPTH_SUBTYPE:
 		chip->usbin_valid_irq = spmi_get_irq_byname(chip->spmi,
 						spmi_resource, "usbin-valid");
 		if (chip->usbin_valid_irq < 0) {
@@ -1361,8 +1376,10 @@
 		enable_irq_wake(chip->dcin_valid_irq);
 		break;
 	case SMBB_BOOST_SUBTYPE:
+	case SMBBP_BOOST_SUBTYPE:
 		break;
 	case SMBB_MISC_SUBTYPE:
+	case SMBBP_MISC_SUBTYPE:
 		pr_debug("Setting BOOT_DONE\n");
 		rc = qpnp_chg_masked_write(chip,
 			chip->misc_base + CHGR_MISC_BOOT_DONE,
@@ -1397,10 +1414,6 @@
 		return -ENOMEM;
 	}
 
-	rc = qpnp_vadc_is_ready();
-	if (rc)
-		goto fail_chg_enable;
-
 	chip->dev = &(spmi->dev);
 	chip->spmi = spmi;
 
@@ -1557,6 +1570,7 @@
 
 		switch (subtype) {
 		case SMBB_CHGR_SUBTYPE:
+		case SMBBP_CHGR_SUBTYPE:
 			chip->chgr_base = resource->start;
 			rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
 			if (rc) {
@@ -1566,6 +1580,7 @@
 			}
 			break;
 		case SMBB_BUCK_SUBTYPE:
+		case SMBBP_BUCK_SUBTYPE:
 			chip->buck_base = resource->start;
 			rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
 			if (rc) {
@@ -1575,6 +1590,7 @@
 			}
 			break;
 		case SMBB_BAT_IF_SUBTYPE:
+		case SMBBP_BAT_IF_SUBTYPE:
 			chip->bat_if_base = resource->start;
 			rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
 			if (rc) {
@@ -1584,6 +1600,7 @@
 			}
 			break;
 		case SMBB_USB_CHGPTH_SUBTYPE:
+		case SMBBP_USB_CHGPTH_SUBTYPE:
 			chip->usb_chgpth_base = resource->start;
 			rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
 			if (rc) {
@@ -1602,6 +1619,7 @@
 			}
 			break;
 		case SMBB_BOOST_SUBTYPE:
+		case SMBBP_BOOST_SUBTYPE:
 			chip->boost_base = resource->start;
 			rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
 			if (rc) {
@@ -1611,6 +1629,7 @@
 			}
 			break;
 		case SMBB_MISC_SUBTYPE:
+		case SMBBP_MISC_SUBTYPE:
 			chip->misc_base = resource->start;
 			rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
 			if (rc) {
@@ -1628,34 +1647,44 @@
 	dev_set_drvdata(&spmi->dev, chip);
 	device_init_wakeup(&spmi->dev, 1);
 
-	chip->dc_psy.name = "qpnp-dc";
-	chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
-	chip->dc_psy.supplied_to = pm_power_supplied_to;
-	chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
-	chip->dc_psy.properties = pm_power_props_mains;
-	chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains);
-	chip->dc_psy.get_property = qpnp_power_get_property_mains;
+	if (chip->bat_if_base) {
+		rc = qpnp_vadc_is_ready();
+		if (rc)
+			goto fail_chg_enable;
 
-	chip->batt_psy.name = "battery";
-	chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
-	chip->batt_psy.properties = msm_batt_power_props;
-	chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props);
-	chip->batt_psy.get_property = qpnp_batt_power_get_property;
-	chip->batt_psy.set_property = qpnp_batt_power_set_property;
-	chip->batt_psy.property_is_writeable = qpnp_batt_property_is_writeable;
-	chip->batt_psy.external_power_changed =
+		chip->batt_psy.name = "battery";
+		chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
+		chip->batt_psy.properties = msm_batt_power_props;
+		chip->batt_psy.num_properties =
+			ARRAY_SIZE(msm_batt_power_props);
+		chip->batt_psy.get_property = qpnp_batt_power_get_property;
+		chip->batt_psy.set_property = qpnp_batt_power_set_property;
+		chip->batt_psy.property_is_writeable =
+				qpnp_batt_property_is_writeable;
+		chip->batt_psy.external_power_changed =
 				qpnp_batt_external_power_changed;
 
-	rc = power_supply_register(chip->dev, &chip->batt_psy);
-	if (rc < 0) {
-		pr_err("power_supply_register batt failed rc = %d\n", rc);
-		goto fail_chg_enable;
+		rc = power_supply_register(chip->dev, &chip->batt_psy);
+		if (rc < 0) {
+			pr_err("batt failed to register rc = %d\n", rc);
+			goto fail_chg_enable;
+		}
 	}
 
-	rc = power_supply_register(chip->dev, &chip->dc_psy);
-	if (rc < 0) {
-		pr_err("power_supply_register usb failed rc = %d\n", rc);
-		goto unregister_batt;
+	if (chip->dc_chgpth_base) {
+		chip->dc_psy.name = "qpnp-dc";
+		chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
+		chip->dc_psy.supplied_to = pm_power_supplied_to;
+		chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
+		chip->dc_psy.properties = pm_power_props_mains;
+		chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains);
+		chip->dc_psy.get_property = qpnp_power_get_property_mains;
+
+		rc = power_supply_register(chip->dev, &chip->dc_psy);
+		if (rc < 0) {
+			pr_err("power_supply_register dc failed rc=%d\n", rc);
+			goto unregister_batt;
+		}
 	}
 
 	/* Turn on appropriate workaround flags */
@@ -1664,11 +1693,11 @@
 	power_supply_set_present(chip->usb_psy,
 			qpnp_chg_is_usb_chg_plugged_in(chip));
 
-	if (chip->maxinput_dc_ma) {
+	if (chip->maxinput_dc_ma && chip->dc_chgpth_base) {
 		rc = qpnp_chg_idcmax_set(chip, chip->maxinput_dc_ma);
 		if (rc) {
 			pr_err("Error setting idcmax property %d\n", rc);
-			goto fail_chg_enable;
+			goto unregister_batt;
 		}
 	}
 
@@ -1684,7 +1713,8 @@
 	return 0;
 
 unregister_batt:
-	power_supply_unregister(&chip->batt_psy);
+	if (chip->bat_if_base)
+		power_supply_unregister(&chip->batt_psy);
 fail_chg_enable:
 	kfree(chip->thermal_mitigation);
 	kfree(chip);
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index 9b0b8b4..9a864aa 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -263,6 +263,17 @@
 			 */
 			mb();
 			complete(&dev->rx_msgq_notify);
+		} else if (mt == SLIM_MSG_MT_CORE &&
+			mc == SLIM_MSG_MC_REPORT_ABSENT) {
+			writel_relaxed(MGR_INT_RX_MSG_RCVD, dev->base +
+						MGR_INT_CLR);
+			/*
+			 * Guarantee that CLR bit write goes through
+			 * before signalling completion
+			 */
+			mb();
+			complete(&dev->rx_msgq_notify);
+
 		} else if (mc == SLIM_MSG_MC_REPLY_INFORMATION ||
 				mc == SLIM_MSG_MC_REPLY_VALUE) {
 			msm_slim_rx_enqueue(dev, rx_buf, len);
@@ -975,6 +986,10 @@
 			txn.wbuf = wbuf;
 			gen_ack = true;
 			ret = msm_xfer_msg(&dev->ctrl, &txn);
+			break;
+		case SLIM_MSG_MC_REPORT_ABSENT:
+			dev_info(dev->dev, "Received Report Absent Message\n");
+			break;
 		default:
 			break;
 		}
@@ -1087,7 +1102,8 @@
 				laddr = (u8)((buffer[0] >> 16) & 0xff);
 				sat = addr_to_sat(dev, laddr);
 			}
-		} else if ((index * 4) >= msg_len) {
+		}
+		if ((index * 4) >= msg_len) {
 			index = 0;
 			if (sat) {
 				msm_sat_enqueue(sat, buffer, msg_len);
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 482d383..b04213c 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -616,7 +616,8 @@
 	calib_data[5] = readl_relaxed(
 			(TSENS_EEPROM_8X26_2(tmdev->tsens_calib_addr)) + 0x8);
 
-	tsens_calibration_mode = calib_data[5] & TSENS_8X26_TSENS_CAL_SEL;
+	tsens_calibration_mode = (calib_data[5] & TSENS_8X26_TSENS_CAL_SEL)
+			>> TSENS_8X26_CAL_SEL_SHIFT;
 
 	if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB) ||
 		(tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2)) {
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index f38de0c..65b2199 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -1963,7 +1963,7 @@
 		    (mdwc->ext_xceiv.otg_capability || !init)) {
 			mdwc->ext_xceiv.bsv = val->intval;
 			queue_delayed_work(system_nrt_wq,
-							&mdwc->resume_work, 0);
+							&mdwc->resume_work, 20);
 
 			if (!init)
 				init = true;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 5694999..f060718 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1567,6 +1567,8 @@
 	return ret;
 }
 
+static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc);
+
 static int dwc3_gadget_vbus_session(struct usb_gadget *_gadget, int is_active)
 {
 	struct dwc3 *dwc = gadget_to_dwc(_gadget);
@@ -1597,17 +1599,18 @@
 		} else {
 			ret = dwc3_gadget_run_stop(dwc, 0);
 		}
-	} else if (dwc->gadget_driver && !dwc->softconnect &&
-						!dwc->vbus_active) {
-		if (dwc->gadget_driver->disconnect) {
-			spin_unlock_irqrestore(&dwc->lock, flags);
-			dwc->gadget_driver->disconnect(&dwc->gadget);
-			return 0;
-		}
+	}
+
+	/*
+	 * Clearing run/stop bit might occur before disconnect event is seen.
+	 * Make sure to let gadget driver know in that case.
+	 */
+	if (!dwc->vbus_active && dwc->start_config_issued) {
+		dev_dbg(dwc->dev, "calling disconnect from %s\n", __func__);
+		dwc3_gadget_disconnect_interrupt(dwc);
 	}
 
 	spin_unlock_irqrestore(&dwc->lock, flags);
-
 	return ret;
 }
 
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index a2997e9..5a6faf2 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -667,7 +667,7 @@
 		if (ret)
 			pr_err("%s: usb_bam_disconnect_ipa failed: err:%d\n",
 				__func__, ret);
-		rmnet_bridge_disconnect();
+		teth_bridge_disconnect();
 	}
 }
 
@@ -707,8 +707,11 @@
 static void gbam2bam_connect_work(struct work_struct *w)
 {
 	struct gbam_port *port = container_of(w, struct gbam_port, connect_w);
+	struct teth_bridge_connect_params connect_params;
 	struct bam_ch_info *d = &port->data_ch;
 	u32 sps_params;
+	ipa_notify_cb usb_notify_cb;
+	void *priv;
 	int ret;
 
 	if (d->trans == USB_GADGET_XPORT_BAM2BAM) {
@@ -720,6 +723,15 @@
 			return;
 		}
 	} else if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+		ret = teth_bridge_init(&usb_notify_cb, &priv);
+		if (ret) {
+			pr_err("%s:teth_bridge_init() failed\n", __func__);
+			return;
+		}
+		d->ipa_params.notify = usb_notify_cb;
+		d->ipa_params.priv = priv;
+		d->ipa_params.ipa_ep_cfg.mode.mode = IPA_BASIC;
+
 		d->ipa_params.client = IPA_CLIENT_USB_CONS;
 		d->ipa_params.dir = PEER_PERIPHERAL_TO_USB;
 		ret = usb_bam_connect_ipa(&d->ipa_params);
@@ -731,18 +743,21 @@
 
 		d->ipa_params.client = IPA_CLIENT_USB_PROD;
 		d->ipa_params.dir = USB_TO_PEER_PERIPHERAL;
-		/* Currently only DMA mode is supported */
-		d->ipa_params.ipa_ep_cfg.mode.mode = IPA_DMA;
-		d->ipa_params.ipa_ep_cfg.mode.dst =
-				IPA_CLIENT_A2_TETHERED_CONS;
 		ret = usb_bam_connect_ipa(&d->ipa_params);
 		if (ret) {
 			pr_err("%s: usb_bam_connect_ipa failed: err:%d\n",
 				__func__, ret);
 			return;
 		}
-		rmnet_bridge_connect(d->ipa_params.prod_clnt_hdl,
-				d->ipa_params.cons_clnt_hdl, 0);
+
+		connect_params.ipa_usb_pipe_hdl = d->ipa_params.prod_clnt_hdl;
+		connect_params.usb_ipa_pipe_hdl = d->ipa_params.cons_clnt_hdl;
+		connect_params.tethering_mode = TETH_TETHERING_MODE_RMNET;
+		ret = teth_bridge_connect(&connect_params);
+		if (ret) {
+			pr_err("%s:teth_bridge_connect() failed\n", __func__);
+			return;
+		}
 	}
 
 	d->rx_req = usb_ep_alloc_request(port->port_usb->out, GFP_KERNEL);
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 8e32aa9..f1f6962 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -1059,6 +1059,7 @@
 	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
 	struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
 	u32 __iomem *status_reg = &ehci->regs->port_status[0];
+	u32 cmd;
 	unsigned long flags;
 	int retries = 0, ret, cnt = RESET_SIGNAL_TIME_USEC;
 
@@ -1067,6 +1068,19 @@
 			pdata->swfi_latency + 1);
 
 	mehci->bus_reset = 1;
+
+	/* Halt the controller */
+	cmd = ehci_readl(ehci, &ehci->regs->command);
+	cmd &= ~CMD_RUN;
+	ehci_writel(ehci, cmd, &ehci->regs->command);
+	ret = handshake(ehci, &ehci->regs->status, STS_HALT,
+			STS_HALT, 16 * 125);
+	if (ret) {
+		pr_err("halt handshake fatal error\n");
+		dbg_log_event(NULL, "HALT: fatal", 0);
+		goto fail;
+	}
+
 retry:
 	retries++;
 	dbg_log_event(NULL, "RESET: start", retries);
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index 40e1eea..faa5625 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -45,6 +45,7 @@
 	struct ehci_hcd				ehci;
 	spinlock_t				wakeup_lock;
 	struct device				*dev;
+	struct clk				*xo_clk;
 	struct clk				*iface_clk;
 	struct clk				*core_clk;
 	struct clk				*alt_core_clk;
@@ -659,10 +660,14 @@
 	clk_disable_unprepare(mhcd->core_clk);
 
 	/* usb phy does not require TCXO clock, hence vote for TCXO disable */
-	ret = msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_OFF);
-	if (ret)
-		dev_err(mhcd->dev, "%s failed to devote for "
-			"TCXO D0 buffer%d\n", __func__, ret);
+	if (!IS_ERR(mhcd->xo_clk)) {
+		clk_disable_unprepare(mhcd->xo_clk);
+	} else {
+		ret = msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_OFF);
+		if (ret)
+			dev_err(mhcd->dev, "%s failed to devote for TCXO %d\n",
+								__func__, ret);
+	}
 
 	msm_ehci_config_vddcx(mhcd, 0);
 
@@ -714,10 +719,14 @@
 	wake_lock(&mhcd->wlock);
 
 	/* Vote for TCXO when waking up the phy */
-	ret = msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_ON);
-	if (ret)
-		dev_err(mhcd->dev, "%s failed to vote for "
-			"TCXO D0 buffer%d\n", __func__, ret);
+	if (!IS_ERR(mhcd->xo_clk)) {
+		clk_prepare_enable(mhcd->xo_clk);
+	} else {
+		ret = msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_ON);
+		if (ret)
+			dev_err(mhcd->dev, "%s failed to vote for TCXO D0 %d\n",
+								__func__, ret);
+	}
 
 	clk_prepare_enable(mhcd->core_clk);
 	clk_prepare_enable(mhcd->iface_clk);
@@ -1091,18 +1100,23 @@
 	}
 
 	snprintf(pdev_name, PDEV_NAME_LEN, "%s.%d", pdev->name, pdev->id);
-	mhcd->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, pdev_name);
-	if (IS_ERR(mhcd->xo_handle)) {
-		dev_err(&pdev->dev, "%s not able to get the handle "
-			"to vote for TCXO D0 buffer\n", __func__);
-		ret = PTR_ERR(mhcd->xo_handle);
-		goto free_async_irq;
+	mhcd->xo_clk = clk_get(&pdev->dev, "xo");
+	if (!IS_ERR(mhcd->xo_clk)) {
+		ret = clk_prepare_enable(mhcd->xo_clk);
+	} else {
+		mhcd->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, pdev_name);
+		if (IS_ERR(mhcd->xo_handle)) {
+			dev_err(&pdev->dev, "%s fail to get handle for X0 D0\n",
+								__func__);
+			ret = PTR_ERR(mhcd->xo_handle);
+			goto free_async_irq;
+		} else {
+			ret = msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_ON);
+		}
 	}
-
-	ret = msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_ON);
 	if (ret) {
-		dev_err(&pdev->dev, "%s failed to vote for TCXO "
-			"D0 buffer%d\n", __func__, ret);
+		dev_err(&pdev->dev, "%s failed to vote for TCXO %d\n",
+								__func__, ret);
 		goto free_xo_handle;
 	}
 
@@ -1202,9 +1216,15 @@
 deinit_clocks:
 	msm_ehci_init_clocks(mhcd, 0);
 devote_xo_handle:
-	msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_OFF);
+	if (!IS_ERR(mhcd->xo_clk))
+		clk_disable_unprepare(mhcd->xo_clk);
+	else
+		msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_OFF);
 free_xo_handle:
-	msm_xo_put(mhcd->xo_handle);
+	if (!IS_ERR(mhcd->xo_clk))
+		clk_put(mhcd->xo_clk);
+	else
+		msm_xo_put(mhcd->xo_handle);
 free_async_irq:
 	if (mhcd->async_irq)
 		free_irq(mhcd->async_irq, mhcd);
@@ -1236,7 +1256,12 @@
 
 	usb_remove_hcd(hcd);
 
-	msm_xo_put(mhcd->xo_handle);
+	if (!IS_ERR(mhcd->xo_clk)) {
+		clk_disable_unprepare(mhcd->xo_clk);
+		clk_put(mhcd->xo_clk);
+	} else {
+		msm_xo_put(mhcd->xo_handle);
+	}
 	msm_ehci_vbus_power(mhcd, 0);
 	msm_ehci_init_vbus(mhcd, 0);
 	msm_ehci_ldo_enable(mhcd, 0);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index bd1423d..b35d904 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -95,7 +95,7 @@
 
 static struct regulator *hsusb_3p3;
 static struct regulator *hsusb_1p8;
-static struct regulator *hsusb_vddcx;
+static struct regulator *hsusb_vdd;
 static struct regulator *vbus_otg;
 static struct regulator *mhl_usb_hs_switch;
 static struct power_supply *psy;
@@ -111,7 +111,7 @@
 #endif
 }
 
-static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
+static int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
 		{  /* VDD_CX CORNER Voting */
 			[VDD_NONE]	= RPM_VREG_CORNER_NONE,
 			[VDD_MIN]	= RPM_VREG_CORNER_NOMINAL,
@@ -175,7 +175,7 @@
 	int ret;
 
 	min_vol = vdd_val[vdd_type][!!high];
-	ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol);
+	ret = regulator_set_voltage(hsusb_vdd, min_vol, max_vol);
 	if (ret) {
 		pr_err("%s: unable to set the voltage for regulator "
 			"HSUSB_VDDCX\n", __func__);
@@ -3038,7 +3038,7 @@
 		set_bit(A_SRP_DET, &motg->inputs);
 		set_bit(A_BUS_REQ, &motg->inputs);
 		work = 1;
-	} else if (otgsc & OTGSC_BSVIS) {
+	} else if ((otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) {
 		writel_relaxed(otgsc, USB_OTGSC);
 		/*
 		 * BSV interrupt comes when operating as an A-device
@@ -3157,7 +3157,15 @@
 	static bool init;
 	struct msm_otg *motg = the_msm_otg;
 
-	/* Ignore received BSV interrupts, if ID pin is GND */
+	if (online) {
+		pr_debug("PMIC: BSV set\n");
+		set_bit(B_SESS_VLD, &motg->inputs);
+	} else {
+		pr_debug("PMIC: BSV clear\n");
+		clear_bit(B_SESS_VLD, &motg->inputs);
+	}
+
+	/* do not queue state m/c work if id is grounded */
 	if (!test_bit(ID, &motg->inputs)) {
 		/*
 		 * state machine work waits for initial VBUS
@@ -3166,17 +3174,8 @@
 		 */
 		if (init)
 			return;
-		goto complete;
 	}
 
-	if (online) {
-		pr_debug("PMIC: BSV set\n");
-		set_bit(B_SESS_VLD, &motg->inputs);
-	} else {
-		pr_debug("PMIC: BSV clear\n");
-		clear_bit(B_SESS_VLD, &motg->inputs);
-	}
-complete:
 	if (!init) {
 		init = true;
 		complete(&pmic_vbus_init);
@@ -3795,6 +3794,8 @@
 				"qcom,hsusb-otg-lpm-on-dev-suspend");
 	pdata->core_clk_always_on_workaround = of_property_read_bool(node,
 				"qcom,hsusb-otg-clk-always-on-workaround");
+	pdata->delay_lpm_on_disconnect = of_property_read_bool(node,
+				"qcom,hsusb-otg-delay-lpm");
 
 	return pdata;
 }
@@ -3802,6 +3803,8 @@
 static int __init msm_otg_probe(struct platform_device *pdev)
 {
 	int ret = 0;
+	int len = 0;
+	u32 tmp[3];
 	struct resource *res;
 	struct msm_otg *motg;
 	struct usb_phy *phy;
@@ -3958,24 +3961,40 @@
 	clk_prepare_enable(motg->pclk);
 
 	motg->vdd_type = VDDCX_CORNER;
-	hsusb_vddcx = devm_regulator_get(motg->phy.dev, "hsusb_vdd_dig");
-	if (IS_ERR(hsusb_vddcx)) {
-		hsusb_vddcx = devm_regulator_get(motg->phy.dev, "HSUSB_VDDCX");
-		if (IS_ERR(hsusb_vddcx)) {
+	hsusb_vdd = devm_regulator_get(motg->phy.dev, "hsusb_vdd_dig");
+	if (IS_ERR(hsusb_vdd)) {
+		hsusb_vdd = devm_regulator_get(motg->phy.dev, "HSUSB_VDDCX");
+		if (IS_ERR(hsusb_vdd)) {
 			dev_err(motg->phy.dev, "unable to get hsusb vddcx\n");
-			ret = PTR_ERR(hsusb_vddcx);
+			ret = PTR_ERR(hsusb_vdd);
 			goto devote_xo_handle;
 		}
 		motg->vdd_type = VDDCX;
 	}
 
+	if (pdev->dev.of_node) {
+		of_get_property(pdev->dev.of_node,
+				"qcom,vdd-voltage-level",
+				&len);
+		if (len == sizeof(tmp)) {
+			of_property_read_u32_array(pdev->dev.of_node,
+					"qcom,vdd-voltage-level",
+					tmp, len/sizeof(*tmp));
+			vdd_val[motg->vdd_type][0] = tmp[0];
+			vdd_val[motg->vdd_type][1] = tmp[1];
+			vdd_val[motg->vdd_type][2] = tmp[2];
+		} else {
+			dev_dbg(&pdev->dev, "Using default hsusb vdd config.\n");
+		}
+	}
+
 	ret = msm_hsusb_config_vddcx(1);
 	if (ret) {
 		dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
 		goto devote_xo_handle;
 	}
 
-	ret = regulator_enable(hsusb_vddcx);
+	ret = regulator_enable(hsusb_vdd);
 	if (ret) {
 		dev_err(&pdev->dev, "unable to enable the hsusb vddcx\n");
 		goto free_config_vddcx;
@@ -3984,7 +4003,7 @@
 	ret = msm_hsusb_ldo_init(motg, 1);
 	if (ret) {
 		dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
-		goto free_hsusb_vddcx;
+		goto free_hsusb_vdd;
 	}
 
 	if (pdata->mhl_enable) {
@@ -4167,10 +4186,10 @@
 	msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
 free_ldo_init:
 	msm_hsusb_ldo_init(motg, 0);
-free_hsusb_vddcx:
-	regulator_disable(hsusb_vddcx);
+free_hsusb_vdd:
+	regulator_disable(hsusb_vdd);
 free_config_vddcx:
-	regulator_set_voltage(hsusb_vddcx,
+	regulator_set_voltage(hsusb_vdd,
 		vdd_val[motg->vdd_type][VDD_NONE],
 		vdd_val[motg->vdd_type][VDD_MAX]);
 devote_xo_handle:
@@ -4264,8 +4283,8 @@
 	}
 	msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
 	msm_hsusb_ldo_init(motg, 0);
-	regulator_disable(hsusb_vddcx);
-	regulator_set_voltage(hsusb_vddcx,
+	regulator_disable(hsusb_vdd);
+	regulator_set_voltage(hsusb_vdd,
 		vdd_val[motg->vdd_type][VDD_NONE],
 		vdd_val[motg->vdd_type][VDD_MAX]);
 
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index ed0a385..a3d8d7e 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, The Linux Foundation. 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
@@ -276,6 +276,7 @@
 	struct mdp4_overlay_pipe *solidfill_pipe;
 };
 
+
 struct mdp4_overlay_pipe {
 	uint32 pipe_used;
 	uint32 pipe_type;		/* rgb, video/graphic */
@@ -983,6 +984,8 @@
 void mdp4_overlay_mdp_perf_upd(struct msm_fb_data_type *mfd, int flag);
 int mdp4_update_base_blend(struct msm_fb_data_type *mfd,
 				struct mdp_blend_cfg *mdp_blend_cfg);
+int mdp4_update_writeback_format(struct msm_fb_data_type *mfd,
+			struct mdp_mixer_cfg *mdp_mixer_cfg);
 u32 mdp4_get_mixer_num(u32 panel_type);
 
 #ifndef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index fbae011..bfd8238 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -49,6 +49,7 @@
 	struct mdp4_overlay_pipe *baselayer[MDP4_MIXER_MAX];
 	struct blend_cfg blend[MDP4_MIXER_MAX][MDP4_MIXER_STAGE_MAX];
 	struct mdp4_overlay_pipe sf_plist[MDP4_MIXER_MAX][OVERLAY_PIPE_MAX];
+	struct mdp_mixer_cfg mdp_mixer_cfg[MDP4_MIXER_MAX];
 	uint32 mixer_cfg[MDP4_MIXER_MAX];
 	uint32 flush[MDP4_MIXER_MAX];
 	struct iommu_free_list iommu_free[MDP4_MIXER_MAX];
@@ -1456,6 +1457,87 @@
 			(pipe->element1 << 8) | pipe->element0;
 }
 
+static uint32 mdp4_overlayproc_cfg_wb_panel(struct mdp4_overlay_pipe *pipe,
+					char *overlay_base, uint32 curr)
+{
+	int off, bpp;
+	uint32 flag;
+	bool is_rgb = false;
+	struct mdp_mixer_cfg *mixer_cfg;
+
+	off = 0;
+	mixer_cfg = &ctrl->mdp_mixer_cfg[MDP4_MIXER2];
+
+	switch (mixer_cfg->writeback_format) {
+	case WB_FORMAT_RGB_888:
+		bpp = 3; /* RGB888 */
+		flag = 0x0;
+		is_rgb = true;
+		break;
+	case WB_FORMAT_RGB_565:
+		bpp = 2; /* RGB565 */
+		flag = 0x1;
+		is_rgb = true;
+		break;
+	case WB_FORMAT_xRGB_8888:
+		bpp = 4; /* xRGB8888 */
+		flag = 0x3;
+		is_rgb = true;
+		break;
+	case WB_FORMAT_ARGB_8888:
+		bpp = 4; /* ARGB8888 */
+		flag = 0x80000003;
+		is_rgb = true;
+		break;
+	case WB_FORMAT_ARGB_8888_INPUT_ALPHA:
+		pr_warn("currently not supported ARGB_8888_INPUT_ALPHA\n");
+	default:
+		bpp = 1; /* NV12 */
+		is_rgb = false;
+		break;
+	}
+
+	if (is_rgb == true) {
+		if (pipe->ov_cnt & 0x01)
+			off = pipe->src_height * pipe->src_width * bpp;
+
+		outpdw(overlay_base + 0x000c, pipe->ov_blt_addr + off);
+		/* overlay ouput is RGB888 */
+		outpdw(overlay_base + 0x0010, pipe->src_width * bpp);
+		outpdw(overlay_base + 0x001c, pipe->ov_blt_addr + off);
+		/* MDDI - BLT + on demand */
+		outpdw(overlay_base + 0x0004, 0x08);
+
+		curr = inpdw(overlay_base + 0x0014);
+		curr &= 0x4;
+
+		outpdw(overlay_base + 0x0014, curr | flag);
+	} else {
+		if (pipe->ov_cnt & 0x01)
+			off = pipe->src_height * pipe->src_width * bpp;
+
+		outpdw(overlay_base + 0x000c, pipe->ov_blt_addr + off);
+		/* overlay ouput is RGB888 */
+		outpdw(overlay_base + 0x0010, ((pipe->src_width << 16) |
+				pipe->src_width));
+		outpdw(overlay_base + 0x001c, pipe->ov_blt_addr + off);
+		off = pipe->src_height * pipe->src_width;
+		/* align chroma to 2k address */
+		off = (off + 2047) & ~2047;
+		/* UV plane adress */
+		outpdw(overlay_base + 0x0020, pipe->ov_blt_addr + off);
+		/* MDDI - BLT + on demand */
+		outpdw(overlay_base + 0x0004, 0x08);
+		/* pseudo planar + writeback */
+		curr = inpdw(overlay_base + 0x0014);
+		curr &= 0x4;
+		outpdw(overlay_base + 0x0014, curr | 0x012);
+		/* rgb->yuv */
+		outpdw(overlay_base + 0x0200, 0x05);
+	}
+	return curr;
+}
+
 /*
  * mdp4_overlayproc_cfg: only be called from base layer
  */
@@ -1515,34 +1597,8 @@
 #endif
 		} else if (pipe->mixer_num == MDP4_MIXER2) {
 			if (ctrl->panel_mode & MDP4_PANEL_WRITEBACK) {
-				off = 0;
-				bpp = 1;
-				if (pipe->ov_cnt & 0x01)
-					off = pipe->src_height *
-							pipe->src_width * bpp;
-
-				outpdw(overlay_base + 0x000c,
-						pipe->ov_blt_addr + off);
-				/* overlay ouput is RGB888 */
-				outpdw(overlay_base + 0x0010,
-					((pipe->src_width << 16) |
-					 pipe->src_width));
-				outpdw(overlay_base + 0x001c,
-						pipe->ov_blt_addr + off);
-				off = pipe->src_height * pipe->src_width;
-				/* align chroma to 2k address */
-				off = (off + 2047) & ~2047;
-				/* UV plane adress */
-				outpdw(overlay_base + 0x0020,
-						pipe->ov_blt_addr + off);
-				/* MDDI - BLT + on demand */
-				outpdw(overlay_base + 0x0004, 0x08);
-				/* pseudo planar + writeback */
-				curr = inpdw(overlay_base + 0x0014);
-				curr &= 0x4;
-				outpdw(overlay_base + 0x0014, curr | 0x012);
-				/* rgb->yuv */
-				outpdw(overlay_base + 0x0200, 0x05);
+				curr = mdp4_overlayproc_cfg_wb_panel(pipe,
+							overlay_base, curr);
 			}
 		}
 	} else {
@@ -3865,6 +3921,42 @@
 	mutex_unlock(&mfd->dma->ov_mutex);
 	return err;
 }
+
+int mdp4_update_writeback_format(struct msm_fb_data_type *mfd,
+				struct mdp_mixer_cfg *mdp_mixer_cfg)
+{
+	int ret = 0;
+	u32 mixer_num;
+	struct mdp_mixer_cfg *mixer;
+
+	mixer_num = mdp4_get_mixer_num(mfd->panel_info.type);
+	if (!ctrl) {
+		pr_warn("mdp4_overlay_ctrl is NULL\n");
+		return -EPERM;
+	}
+	mixer = &ctrl->mdp_mixer_cfg[mixer_num];
+
+	switch (mdp_mixer_cfg->writeback_format) {
+	case WB_FORMAT_RGB_888:
+	case WB_FORMAT_RGB_565:
+	case WB_FORMAT_NV12:
+	case WB_FORMAT_xRGB_8888:
+	case WB_FORMAT_ARGB_8888:
+		mixer->writeback_format = mdp_mixer_cfg->writeback_format;
+		break;
+	case WB_FORMAT_ARGB_8888_INPUT_ALPHA:
+		mixer->writeback_format = mdp_mixer_cfg->writeback_format;
+		mixer->alpha = mdp_mixer_cfg->alpha;
+		break;
+	default:
+		mixer->writeback_format = WB_FORMAT_NV12;
+		pr_warn("Unsupported format request, setting to NV12\n");
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
 int mdp4_update_base_blend(struct msm_fb_data_type *mfd,
 			struct mdp_blend_cfg *mdp_blend_cfg)
 {
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index ea0eb7b..1e0de89 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -1069,7 +1069,15 @@
 	int i, ret = 0;
 	/* buf sync */
 	for (i = 0; i < mfd->acq_fen_cnt; i++) {
-		ret = sync_fence_wait(mfd->acq_fen[i], WAIT_FENCE_TIMEOUT);
+		ret = sync_fence_wait(mfd->acq_fen[i],
+				WAIT_FENCE_FIRST_TIMEOUT);
+		if (ret == -ETIME) {
+			pr_warn("sync_fence_wait timed out! ");
+			pr_cont("Waiting %ld more seconds\n",
+					WAIT_FENCE_FINAL_TIMEOUT/MSEC_PER_SEC);
+			ret = sync_fence_wait(mfd->acq_fen[i],
+					WAIT_FENCE_FINAL_TIMEOUT);
+		}
 		if (ret < 0) {
 			pr_err("%s: sync_fence_wait failed! ret = %x\n",
 				__func__, ret);
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index c4e837e..db2e305 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -27,10 +27,11 @@
 #define MSM_FB_MAX_DEV_LIST 32
 
 #define MSM_FB_ENABLE_DBGFS
-/* 900 ms for fence time out */
-#define WAIT_FENCE_TIMEOUT 900
-/* 950 ms for display operation time out */
-#define WAIT_DISP_OP_TIMEOUT 950
+#define WAIT_FENCE_FIRST_TIMEOUT MSEC_PER_SEC
+#define WAIT_FENCE_FINAL_TIMEOUT (10 * MSEC_PER_SEC)
+/* Display op timeout should be greater than total timeout */
+#define WAIT_DISP_OP_TIMEOUT ((WAIT_FENCE_FIRST_TIMEOUT + \
+		WAIT_FENCE_FINAL_TIMEOUT) * MDP_MAX_FENCE_FD)
 
 #ifndef MAX
 #define  MAX(x, y) (((x) > (y)) ? (x) : (y))
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 5404000..4f95aee 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -378,8 +378,9 @@
 	} else if (1 == hpd && !hdmi_ctrl->hpd_feature_on) {
 		rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, true);
 	} else {
-		rc = -EPERM;
-		ret = rc;
+		DEV_DBG("%s: hpd is already '%s'. return\n", __func__,
+			hdmi_ctrl->hpd_feature_on ? "enabled" : "disabled");
+		return ret;
 	}
 
 	if (!rc) {
@@ -387,8 +388,9 @@
 			(~hdmi_ctrl->hpd_feature_on) & BIT(0);
 		DEV_DBG("%s: '%d'\n", __func__, hdmi_ctrl->hpd_feature_on);
 	} else {
-		DEV_DBG("%s: '%d' (unchanged)\n", __func__,
-			hdmi_ctrl->hpd_feature_on);
+		DEV_ERR("%s: failed to '%s' hpd. rc = %d\n", __func__,
+			hpd ? "enable" : "disable", rc);
+		ret = rc;
 	}
 
 	return ret;
@@ -426,9 +428,6 @@
 	hdmi_ctrl->kobj = &fbi->dev->kobj;
 	DEV_DBG("%s: sysfs group %p\n", __func__, hdmi_ctrl->kobj);
 
-	kobject_uevent(hdmi_ctrl->kobj, KOBJ_ADD);
-	DEV_DBG("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
-
 	return 0;
 } /* hdmi_tx_sysfs_create */
 
@@ -695,17 +694,13 @@
 
 	if (hdmi_ctrl->hpd_state) {
 		hdmi_tx_read_sink_info(hdmi_ctrl);
-		DEV_INFO("HDMI HPD: sense CONNECTED: send ONLINE\n");
-		kobject_uevent(hdmi_ctrl->kobj, KOBJ_ONLINE);
 		switch_set_state(&hdmi_ctrl->sdev, 1);
-		DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
-			hdmi_ctrl->sdev.state);
+		DEV_INFO("%s: sense cable CONNECTED: state switch to %d\n",
+			__func__, hdmi_ctrl->sdev.state);
 	} else {
-		DEV_INFO("HDMI HPD: sense DISCONNECTED: send OFFLINE\n");
-		kobject_uevent(hdmi_ctrl->kobj, KOBJ_OFFLINE);
 		switch_set_state(&hdmi_ctrl->sdev, 0);
-		DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
-			hdmi_ctrl->sdev.state);
+		DEV_INFO("%s: sense cable DISCONNECTED: state switch to %d\n",
+			__func__, hdmi_ctrl->sdev.state);
 	}
 
 	if (!completion_done(&hdmi_ctrl->hpd_done))
@@ -2265,8 +2260,6 @@
 			switch_set_state(&hdmi_ctrl->sdev, 0);
 			DEV_DBG("%s: Hdmi state switch to %d\n", __func__,
 				hdmi_ctrl->sdev.state);
-			DEV_DBG("HDMI HPD: sent fake OFFLINE event\n");
-			kobject_uevent(hdmi_ctrl->kobj, KOBJ_OFFLINE);
 		}
 	}
 
@@ -2486,10 +2479,7 @@
 			if (!timeout & !hdmi_ctrl->hpd_state) {
 				DEV_INFO("%s: cable removed during suspend\n",
 					__func__);
-
-				kobject_uevent(hdmi_ctrl->kobj, KOBJ_OFFLINE);
 				switch_set_state(&hdmi_ctrl->sdev, 0);
-
 				rc = -EPERM;
 			} else {
 				DEV_DBG("%s: cable present after resume\n",
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index e4099ad..977fc63 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -124,6 +124,7 @@
 				      char *prop_name, u32 *offsets, int len);
 static int mdss_mdp_parse_dt_prop_len(struct platform_device *pdev,
 				       char *prop_name);
+static int mdss_mdp_parse_dt_smp(struct platform_device *pdev);
 
 static inline int mdss_irq_dispatch(u32 hw_ndx, int irq, void *ptr)
 {
@@ -808,10 +809,6 @@
 	mdata->clk_ctrl_wq = create_singlethread_workqueue("mdp_clk_wq");
 	INIT_WORK(&mdata->clk_ctrl_worker, mdss_mdp_clk_ctrl_workqueue_handler);
 
-	mdata->smp_mb_cnt = MDSS_MDP_SMP_MMB_BLOCKS;
-	mdata->smp_mb_size = MDSS_MDP_SMP_MMB_SIZE;
-
-
 	mdata->iclient = msm_ion_client_create(-1, mdata->pdev->name);
 	if (IS_ERR_OR_NULL(mdata->iclient)) {
 		pr_err("msm_ion_client_create() return error (%p)\n",
@@ -1045,6 +1042,12 @@
 		return rc;
 	}
 
+	rc = mdss_mdp_parse_dt_smp(pdev);
+	if (rc) {
+		pr_err("Error in device tree : smp\n");
+		return rc;
+	}
+
 	return 0;
 }
 
@@ -1305,6 +1308,30 @@
 	return rc;
 }
 
+static int mdss_mdp_parse_dt_smp(struct platform_device *pdev)
+{
+	struct mdss_data_type *mdata = platform_get_drvdata(pdev);
+	u32 num;
+	u32 data[2];
+	int rc;
+
+	num = mdss_mdp_parse_dt_prop_len(pdev, "qcom,mdss-smp-data");
+
+	if (num != 2)
+		return -EINVAL;
+
+	rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-smp-data", data, num);
+	if (rc)
+		return rc;
+
+	rc = mdss_mdp_smp_setup(mdata, data[0], data[1]);
+
+	if (rc)
+		pr_err("unable to setup smp data\n");
+
+	return rc;
+}
+
 static int mdss_mdp_parse_dt_handler(struct platform_device *pdev,
 		char *prop_name, u32 *offsets, int len)
 {
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 4c70770..efd93c0 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -323,6 +323,7 @@
 
 struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata,
 				       struct msm_fb_data_type *mfd);
+int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_ctl_split_display_setup(struct mdss_mdp_ctl *ctl,
 		struct mdss_panel_data *pdata);
 int mdss_mdp_ctl_destroy(struct mdss_mdp_ctl *ctl);
@@ -354,6 +355,7 @@
 int mdss_mdp_pipe_pp_setup(struct mdss_mdp_pipe *pipe, u32 *op);
 int mdss_mdp_pipe_sspp_setup(struct mdss_mdp_pipe *pipe, u32 *op);
 void mdss_mdp_pipe_sspp_term(struct mdss_mdp_pipe *pipe);
+int mdss_mdp_smp_setup(struct mdss_data_type *mdata, u32 cnt, u32 size);
 
 int mdss_hw_init(struct mdss_data_type *mdata);
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index c640c73..8515782 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -39,6 +39,8 @@
 
 static DEFINE_MUTEX(mdss_mdp_ctl_lock);
 
+static int mdss_mdp_mixer_free(struct mdss_mdp_mixer *mixer);
+
 static inline void mdp_mixer_write(struct mdss_mdp_mixer *mixer,
 				   u32 reg, u32 val)
 {
@@ -265,8 +267,14 @@
 
 	mutex_lock(&mdss_mdp_ctl_lock);
 	ctl->ref_cnt--;
-	ctl->mixer_left = NULL;
-	ctl->mixer_right = NULL;
+	if (ctl->mixer_left) {
+		mdss_mdp_mixer_free(ctl->mixer_left);
+		ctl->mixer_left = NULL;
+	}
+	if (ctl->mixer_right) {
+		mdss_mdp_mixer_free(ctl->mixer_right);
+		ctl->mixer_right = NULL;
+	}
 	ctl->power_on = false;
 	ctl->start_fnc = NULL;
 	ctl->stop_fnc = NULL;
@@ -443,7 +451,7 @@
 	return NULL;
 }
 
-static int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl)
+int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl)
 {
 	struct mdss_mdp_ctl *split_ctl;
 	u32 width, height;
@@ -517,6 +525,50 @@
 	return 0;
 }
 
+static int mdss_mdp_ctl_setup_wfd(struct mdss_mdp_ctl *ctl)
+{
+	struct mdss_data_type *mdata = ctl->mdata;
+	struct mdss_mdp_mixer *mixer;
+	int mixer_type;
+
+	/* if WB2 is supported, try to allocate it first */
+	if (mdata->nmixers_intf >= MDSS_MDP_INTF_LAYERMIXER2)
+		mixer_type = MDSS_MDP_MIXER_TYPE_INTF;
+	else
+		mixer_type = MDSS_MDP_MIXER_TYPE_WRITEBACK;
+
+	mixer = mdss_mdp_mixer_alloc(ctl, mixer_type, false);
+	if (!mixer && mixer_type == MDSS_MDP_MIXER_TYPE_INTF)
+		mixer = mdss_mdp_mixer_alloc(ctl, MDSS_MDP_MIXER_TYPE_WRITEBACK,
+				false);
+
+	if (!mixer) {
+		pr_err("Unable to allocate writeback mixer\n");
+		return -ENOMEM;
+	}
+
+	if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
+		ctl->opmode = MDSS_MDP_CTL_OP_WFD_MODE;
+	} else {
+		switch (mixer->num) {
+		case MDSS_MDP_WB_LAYERMIXER0:
+			ctl->opmode = MDSS_MDP_CTL_OP_WB0_MODE;
+			break;
+		case MDSS_MDP_WB_LAYERMIXER1:
+			ctl->opmode = MDSS_MDP_CTL_OP_WB1_MODE;
+			break;
+		default:
+			pr_err("Incorrect writeback config num=%d\n",
+					mixer->num);
+			mdss_mdp_mixer_free(mixer);
+			return -EINVAL;
+		}
+	}
+	ctl->mixer_left = mixer;
+
+	return 0;
+}
+
 struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata,
 				       struct msm_fb_data_type *mfd)
 {
@@ -555,8 +607,10 @@
 		break;
 	case WRITEBACK_PANEL:
 		ctl->intf_num = MDSS_MDP_NO_INTF;
-		ctl->opmode = MDSS_MDP_CTL_OP_WFD_MODE;
 		ctl->start_fnc = mdss_mdp_writeback_start;
+		ret = mdss_mdp_ctl_setup_wfd(ctl);
+		if (ret)
+			goto ctl_init_fail;
 		break;
 	default:
 		pr_err("unsupported panel type (%d)\n", pdata->panel_info.type);
@@ -566,12 +620,6 @@
 
 	ctl->opmode |= (ctl->intf_num << 4);
 
-	ret = mdss_mdp_ctl_setup(ctl);
-	if (ret) {
-		pr_err("unable to setup control path %d\n", ctl->num);
-		goto ctl_init_fail;
-	}
-
 	if (ctl->intf_num == MDSS_MDP_NO_INTF) {
 		ctl->dst_format = pdata->panel_info.out_format;
 	} else {
@@ -972,9 +1020,13 @@
 
 	ctl->flush_bits |= BIT(6) << mixer->num;	/* LAYER_MIXER */
 
-	off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
 	mdp_mixer_write(mixer, MDSS_MDP_REG_LM_OP_MODE, blend_color_out);
-	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_LAYER(mixer->num), mixercfg);
+	if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF)
+		off = MDSS_MDP_REG_CTL_LAYER(mixer->num);
+	else
+		off = MDSS_MDP_REG_CTL_LAYER(mixer->num +
+				MDSS_MDP_INTF_MAX_LAYERMIXER);
+	mdss_mdp_ctl_write(ctl, off, mixercfg);
 
 	return 0;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index d4ffaff..f8cd0ce 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -447,8 +447,7 @@
 #define MDSS_MDP_REG_SMP_ALLOC_W0			0x00180
 #define MDSS_MDP_REG_SMP_ALLOC_R0			0x00230
 
-#define MDSS_MDP_SMP_MMB_SIZE		4096
-#define MDSS_MDP_SMP_MMB_BLOCKS		22
+#define MDSS_MDP_SMP_MMB_BLOCKS			22
 
 enum mdss_mdp_smp_client_index {
 	MDSS_MDP_SMP_CLIENT_UNUSED,
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index c1dcc18..dcefc09 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -654,10 +654,8 @@
 		ret = mdss_mdp_display_commit(ctl, NULL);
 	mutex_unlock(&mfd->lock);
 
-	if (IS_ERR_VALUE(ret)) {
-		mutex_unlock(&mfd->ov_lock);
-		return ret;
-	}
+	if (IS_ERR_VALUE(ret))
+		goto commit_fail;
 
 	ret = mdss_mdp_display_wait4comp(ctl);
 
@@ -670,6 +668,7 @@
 	add_timer(&mfd->no_update.timer);
 	mutex_unlock(&mfd->no_update.lock);
 
+commit_fail:
 	ret = mdss_mdp_overlay_cleanup(mfd);
 
 	mutex_unlock(&mfd->ov_lock);
@@ -1017,6 +1016,12 @@
 		return;
 	}
 
+	ret = mdss_mdp_overlay_start(mfd);
+	if (ret) {
+		pr_err("unable to start overlay %d (%d)\n", mfd->index, ret);
+		return;
+	}
+
 	if (is_mdss_iommu_attached())
 		data.p[0].addr = mfd->iova;
 	else
@@ -1454,6 +1459,10 @@
 		rc = mdss_mdp_overlay_start(mfd);
 		if (!IS_ERR_VALUE(rc))
 			rc = mdss_mdp_overlay_kickoff(mfd->ctl);
+	} else {
+		rc = mdss_mdp_ctl_setup(mfd->ctl);
+		if (rc)
+			return rc;
 	}
 
 	if (!IS_ERR_VALUE(rc) && mfd->vsync_pending) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 8c88646..d51b144 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -130,6 +130,17 @@
 	return 0;
 }
 
+int mdss_mdp_smp_setup(struct mdss_data_type *mdata, u32 cnt, u32 size)
+{
+	if (!mdata)
+		return -EINVAL;
+
+	mdata->smp_mb_cnt = cnt;
+	mdata->smp_mb_size = size;
+
+	return 0;
+}
+
 void mdss_mdp_pipe_unmap(struct mdss_mdp_pipe *pipe)
 {
 	int tmp;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 59d760b..aa223a1 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -193,17 +193,24 @@
 				   struct mdp_csc_cfg *data)
 {
 	int i, ret = 0;
-	u32 *off, base, val = 0;
+	char __iomem *base, *off;
+	u32 val = 0;
+	struct mdss_data_type *mdata;
+	struct mdss_mdp_pipe *pipe;
+	struct mdss_mdp_ctl *ctl;
+
 
 	if (data == NULL) {
 		pr_err("no csc matrix specified\n");
 		return -EINVAL;
 	}
 
+	mdata = mdss_mdp_get_mdata();
 	switch (block) {
 	case MDSS_MDP_BLOCK_SSPP:
-		if (blk_idx < MDSS_MDP_SSPP_RGB0) {
-			base = MDSS_MDP_REG_SSPP_OFFSET(blk_idx);
+		if (blk_idx < mdata->nvig_pipes) {
+			pipe = mdata->vig_pipes + blk_idx;
+			base = pipe->base;
 			if (tbl_idx == 1)
 				base += MDSS_MDP_REG_VIG_CSC_1_BASE;
 			else
@@ -213,9 +220,9 @@
 		}
 		break;
 	case MDSS_MDP_BLOCK_WB:
-		if (blk_idx < MDSS_MDP_MAX_WRITEBACK) {
-			base = MDSS_MDP_REG_WB_OFFSET(blk_idx) +
-			       MDSS_MDP_REG_WB_CSC_BASE;
+		if (blk_idx < mdata->nctl) {
+			ctl = mdata->ctl_off + blk_idx;
+			base = ctl->wb_base + MDSS_MDP_REG_WB_CSC_BASE;
 		} else {
 			ret = -EINVAL;
 		}
@@ -229,34 +236,33 @@
 		return ret;
 	}
 
-	off = (u32 *) (base + CSC_MV_OFF);
+	off = base + CSC_MV_OFF;
 	for (i = 0; i < 9; i++) {
 		if (i & 0x1) {
 			val |= data->csc_mv[i] << 16;
-			MDSS_MDP_REG_WRITE(off, val);
-			off++;
+			writel_relaxed(val, off);
+			off += sizeof(u32 *);
 		} else {
 			val = data->csc_mv[i];
 		}
 	}
-	MDSS_MDP_REG_WRITE(off, val); /* COEFF_33 */
+	writel_relaxed(val, off); /* COEFF_33 */
 
-	off = (u32 *) (base + CSC_BV_OFF);
+	off = base + CSC_BV_OFF;
 	for (i = 0; i < 3; i++) {
-		MDSS_MDP_REG_WRITE(off, data->csc_pre_bv[i]);
-		MDSS_MDP_REG_WRITE((u32 *)(((u32)off) + CSC_POST_OFF),
-				   data->csc_post_bv[i]);
-		off++;
+		writel_relaxed(data->csc_pre_bv[i], off);
+		writel_relaxed(data->csc_post_bv[i], off + CSC_POST_OFF);
+		off += sizeof(u32 *);
 	}
 
-	off = (u32 *) (base + CSC_LV_OFF);
+	off = base + CSC_LV_OFF;
 	for (i = 0; i < 6; i += 2) {
 		val = (data->csc_pre_lv[i] << 8) | data->csc_pre_lv[i+1];
-		MDSS_MDP_REG_WRITE(off, val);
+		writel_relaxed(val, off);
 
 		val = (data->csc_post_lv[i] << 8) | data->csc_post_lv[i+1];
-		MDSS_MDP_REG_WRITE((u32 *)(((u32)off) + CSC_POST_OFF), val);
-		off++;
+		writel_relaxed(val, off + CSC_POST_OFF);
+		off += sizeof(u32 *);
 	}
 
 	return ret;
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 5f994a0..b96e093 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -3301,6 +3301,10 @@
 		ret = mdp4_update_base_blend(mfd,
 						&metadata_ptr->data.blend_cfg);
 		break;
+	case metadata_op_wb_format:
+		ret = mdp4_update_writeback_format(mfd,
+					&metadata_ptr->data.mixer_cfg);
+		break;
 #endif
 	default:
 		pr_warn("Unsupported request to MDP META IOCTL.\n");
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index b8231ed..f6ca334 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -451,3 +451,4 @@
 header-y += ci-bridge-spi.h
 header-y += msm_audio_amrwbplus.h
 header-y += avtimer.h
+header-y += msm_ipa.h
diff --git a/include/linux/bif/consumer.h b/include/linux/bif/consumer.h
new file mode 100644
index 0000000..e4c190e
--- /dev/null
+++ b/include/linux/bif/consumer.h
@@ -0,0 +1,613 @@
+/* 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.
+ */
+
+#ifndef _LINUX_BIF_CONSUMER_H_
+#define _LINUX_BIF_CONSUMER_H_
+
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/notifier.h>
+
+#define BIF_DEVICE_ID_BYTE_LENGTH	8
+#define BIF_UNIQUE_ID_BYTE_LENGTH	10
+#define BIF_UNIQUE_ID_BIT_LENGTH	80
+
+#define BIF_PRIMARY_SLAVE_DEV_ADR	0x01
+
+/**
+ * enum bif_transaction - BIF master bus transaction types
+ * %BIF_TRANS_WD:	Write data
+ * %BIF_TRANS_ERA:	Extended register address
+ * %BIF_TRANS_WRA:	Write register address
+ * %BIF_TRANS_RRA:	Read register address
+ * %BIF_TRANS_BC:	Bus command
+ * %BIF_TRANS_EDA:	Extended device address
+ * %BIF_TRANS_SDA:	Slave device address
+ *
+ * These values correspond to BIF word bits: BCF, bit 9, bit 8.
+ * BCF_n bit is inserted automatically.
+ */
+enum bif_transaction {
+	BIF_TRANS_WD	= 0x00,
+	BIF_TRANS_ERA	= 0x01,
+	BIF_TRANS_WRA	= 0x02,
+	BIF_TRANS_RRA	= 0x03,
+	BIF_TRANS_BC	= 0x04,
+	BIF_TRANS_EDA	= 0x05,
+	BIF_TRANS_SDA	= 0x06,
+};
+
+/* BIF slave response components */
+#define BIF_SLAVE_RD_ACK		0x200
+#define BIF_SLAVE_RD_EOT		0x100
+#define BIF_SLAVE_RD_DATA		0x0FF
+#define BIF_SLAVE_RD_ERR		0x0FF
+#define BIF_SLAVE_TACK_ACK		0x200
+#define BIF_SLAVE_TACK_WCNT		0x0FF
+#define BIF_SLAVE_TACK_ERR		0x0FF
+
+/**
+ * enum bif_bus_command - MIPI defined bus commands to use in BC transaction
+ * %BIF_CMD_BRES:	Bus reset of all slaves
+ * %BIF_CMD_PDWN:	Put all slaves into power down mode
+ * %BIF_CMD_STBY:	Put all slaves into standby mode
+ * %BIF_CMD_EINT:	Enable interrupts for all slaves
+ * %BIF_CMD_ISTS:	Poll interrupt status for all slaves.  Expects BQ
+ *			response if any slave has a pending interrupt.
+ * %BIF_CMD_RBL:	Specify the burst read length for the next read
+ *			transaction.  Bits 3 to 0 should also be ORed on in
+ *			order to specify the number of bytes to read.
+ * %BIF_CMD_RBE:	Specify the extended burst read length for the next read
+ *			transaction.  Bits 3 to 0 should also be ORed on in
+ *			order to specify the number of bytes to read.  The burst
+ *			read length for RBEy and RBLx = 16 * y + x.
+ * %BIF_CMD_DASM:	Device activation stick mode.  This keeps a slave
+ *			selected if it would otherwise become unselected by the
+ *			next transaction.
+ * %BIF_CMD_DISS:	UID search start
+ * %BIF_CMD_DILC:	UID length check.  Expects BQ response if all 80 UID
+ *			bits for a given slave have been entered.
+ * %BIF_CMD_DIE0:	UID search enter 0
+ * %BIF_CMD_DIE1:	UID search enter 1
+ * %BIF_CMD_DIP0:	UID search probe 0
+ * %BIF_CMD_DIP1:	UID search probe 1
+ * %BIF_CMD_DRES:	Device reset of selected slaves
+ * %BIF_CMD_TQ:		Transaction query; expects TACK response
+ * %BIF_CMD_AIO:	Address increment off for the next transaction
+ *
+ * These values correspond to BIF word bits 7 to 0.
+ */
+enum bif_bus_command {
+	BIF_CMD_BRES	= 0x00,
+	BIF_CMD_PDWN	= 0x02,
+	BIF_CMD_STBY	= 0x03,
+	BIF_CMD_EINT	= 0x10,
+	BIF_CMD_ISTS	= 0x11,
+	BIF_CMD_RBL	= 0x20,
+	BIF_CMD_RBE	= 0x30,
+	BIF_CMD_DASM	= 0x40,
+	BIF_CMD_DISS	= 0x80,
+	BIF_CMD_DILC	= 0x81,
+	BIF_CMD_DIE0	= 0x84,
+	BIF_CMD_DIE1	= 0x85,
+	BIF_CMD_DIP0	= 0x86,
+	BIF_CMD_DIP1	= 0x87,
+	BIF_CMD_DRES	= 0xC0,
+	BIF_CMD_TQ	= 0xC2,
+	BIF_CMD_AIO	= 0xC4,
+};
+
+/**
+ * struct bif_ddb_l1_data - MIPI defined L1 DDB data structure
+ * @revision:		DDB version; should be 0x10 for DDB v1.0
+ * @level:		DDB level support; should be 0x03 for DDB L1 and L2
+ * @device_class:	MIPI device class; should be 0x0800
+ * @manufacturer_id:	Manufacturer ID number allocated by MIPI
+ * @product_id:		Manufacturer specified product ID number
+ * @length:		Size of L2 function directory in bytes
+ */
+struct bif_ddb_l1_data {
+	u8	revision;
+	u8	level;
+	u16	device_class;
+	u16	manufacturer_id;
+	u16	product_id;
+	u16	length;
+};
+
+/**
+ * struct bif_ddb_l2_data - MIPI defined L2 DDB function data structure
+ * @function_type:	Defines the type of the function.  The type may be
+ *			either MIPI or manufacturer defined.
+ * @function_version:	Defines the version of the function.  The version may
+ *			be either MIPI or manufacturer defined.
+ * @function_pointer:	Address in BIF slave memory where the register map for
+ *			the function begins.
+ */
+struct bif_ddb_l2_data {
+	u8	function_type;
+	u8	function_version;
+	u16	function_pointer;
+};
+
+/**
+ * enum bif_mipi_function_type - MIPI defined DDB L2 function types
+ * %BIF_FUNC_PROTOCOL:		Protocol function which provides access to core
+ *				BIF communication features.
+ * %BIF_FUNC_SLAVE_CONTROL:	Slave control function which provides control
+ *				for BIF slave interrupts and tasks.
+ * %BIF_FUNC_TEMPERATURE:	Temperature sensor function which provides a
+ *				means to accurately read the battery temperature
+ *				in a single-shot or periodic fashion.
+ * %BIF_FUNC_NVM:		Non-volatile memory function which provides a
+ *				means to store data onto a BIF slave that is
+ *				non-volatile.  Secondary slave objects are also
+ *				found through the NVM function.
+ * %BIF_FUNC_AUTHENTICATION:	Authentication function which provides a means
+ *				to authenticate batteries.  This function does
+ *				not have a MIPI defined implimentation.  Instead
+ *				all aspects of the authentication function are
+ *				left to the discretion of the manufacturer.
+ */
+enum bif_mipi_function_type {
+	BIF_FUNC_PROTOCOL	= 0x01,
+	BIF_FUNC_SLAVE_CONTROL	= 0x02,
+	BIF_FUNC_TEMPERATURE	= 0x03,
+	BIF_FUNC_NVM		= 0x04,
+	BIF_FUNC_AUTHENTICATION	= 0x05,
+};
+
+#define BIF_DDB_L1_BASE_ADDR	0x0000
+#define BIF_DDB_L2_BASE_ADDR	0x000A
+
+/**
+ * enum bif_slave_error_code - MIPI defined BIF slave error codes
+ * %BIF_ERR_NONE:		No error occurred
+ * %BIF_ERR_GENERAL:		An unenumerated error occurred
+ * %BIF_ERR_PARITY:		A Hamming-15 parity check failed for a word
+ *				sent on the bus
+ * %BIF_ERR_INVERSION:		More than 8 bits in a word were 1
+ * %BIF_ERR_BAD_LENGTH:		Word had more or less than 17 bits
+ * %BIF_ERR_TIMING:		Bit timing was violated in a word
+ * %BIF_ERR_UNKNOWN_CMD:	Bus command was unknown to the slave
+ * %BIF_ERR_CMD_SEQ:		Commands with ordering dependency were not
+ *				sent in the right order
+ * %BIF_ERR_BUS_COLLISION:	BCL was already low at the beginning of a new
+ *				transaction
+ * %BIF_ERR_SLAVE_BUSY:		Slave is busy and cannot respond
+ * %BIF_ERR_FATAL:		Slave is in an unrecoverable error state and
+ *				must be reset
+ *
+ * These values are present in the ERR portion of an RD or TACK slave response
+ * word.  These values can also be found in the ERR_CODE register of the
+ * protocol function.
+ */
+enum bif_slave_error_code {
+	BIF_ERR_NONE		= 0x00,
+	BIF_ERR_GENERAL		= 0x10,
+	BIF_ERR_PARITY		= 0x11,
+	BIF_ERR_INVERSION	= 0x12,
+	BIF_ERR_BAD_LENGTH	= 0x13,
+	BIF_ERR_TIMING		= 0x14,
+	BIF_ERR_UNKNOWN_CMD	= 0x15,
+	BIF_ERR_CMD_SEQ		= 0x16,
+	BIF_ERR_BUS_COLLISION	= 0x1F,
+	BIF_ERR_SLAVE_BUSY	= 0x20,
+	BIF_ERR_FATAL		= 0x7F,
+};
+
+/**
+ * struct bif_protocol_function - constant data present in protocol function
+ * @l2_entry:		Pointer to protocol function L2 DDB data struct
+ * @protocol_pointer:	BIF slave address where protocol registers begin
+ * @device_id_pointer:	BIF slave address where device ID begins
+ * @device_id:		The 8-byte unique device ID in MSB to LSB order
+ */
+struct bif_protocol_function {
+	struct bif_ddb_l2_data *l2_entry;
+	u16	protocol_pointer;
+	u16	device_id_pointer;
+	u8	device_id[BIF_DEVICE_ID_BYTE_LENGTH]; /* Unique ID */
+};
+
+#define PROTOCOL_FUNC_DEV_ADR_ADDR(protocol_pointer)	((protocol_pointer) + 0)
+#define PROTOCOL_FUNC_ERR_CODE_ADDR(protocol_pointer)	((protocol_pointer) + 2)
+#define PROTOCOL_FUNC_ERR_CNT_ADDR(protocol_pointer)	((protocol_pointer) + 3)
+#define PROTOCOL_FUNC_WORD_CNT_ADDR(protocol_pointer)	((protocol_pointer) + 4)
+
+/**
+ * struct bif_slave_control_function - constant data present in slave control
+ *			function as well internal software state parameters
+ * @l2_entry:		Pointer to slave control function L2 DDB data struct
+ * @slave_ctrl_pointer:	BIF slave address where slave control registers begin
+ * @task_count:		Number of tasks supported by the slave
+ * @irq_notifier_list:	List of notifiers for consumers drivers that wish to be
+ *			notified when any given interrupt triggers.  This list
+ *			is dynamically allocated with length task_count.
+ */
+struct bif_slave_control_function {
+	struct bif_ddb_l2_data		*l2_entry;
+	u16				slave_ctrl_pointer;
+	unsigned int			task_count;
+	struct blocking_notifier_head	*irq_notifier_list;
+};
+
+#define SLAVE_CTRL_TASKS_PER_SET	8
+
+/**
+ * bif_slave_control_task_is_valid() - returns true if the specified task
+ *		is supported by the slave or false if it isn't
+ * @func:	Pointer to slave's slave control function structure
+ * @task:	Slave task number to check
+ */
+static inline bool
+bif_slave_control_task_is_valid(struct bif_slave_control_function *func,
+				unsigned int task)
+{
+	return func ? task < func->task_count : false;
+}
+
+#define SLAVE_CTRL_FUNC_IRQ_EN_ADDR(slave_ctrl_pointer, task) \
+	((slave_ctrl_pointer) + 4 * ((task) / SLAVE_CTRL_TASKS_PER_SET) + 0)
+
+#define SLAVE_CTRL_FUNC_IRQ_STATUS_ADDR(slave_ctrl_pointer, task) \
+	((slave_ctrl_pointer) + 4 * ((task) / SLAVE_CTRL_TASKS_PER_SET) + 1)
+#define SLAVE_CTRL_FUNC_IRQ_CLEAR_ADDR(slave_ctrl_pointer, task) \
+	SLAVE_CTRL_FUNC_IRQ_STATUS_ADDR(slave_ctrl_pointer, task)
+
+#define SLAVE_CTRL_FUNC_TASK_TRIGGER_ADDR(slave_ctrl_pointer, task) \
+	((slave_ctrl_pointer) + 4 * ((task) / SLAVE_CTRL_TASKS_PER_SET) + 2)
+#define SLAVE_CTRL_FUNC_TASK_BUSY_ADDR(slave_ctrl_pointer, task) \
+	SLAVE_CTRL_FUNC_TASK_TRIGGER_ADDR(slave_ctrl_pointer, task)
+
+#define SLAVE_CTRL_FUNC_TASK_AUTO_TRIGGER_ADDR(slave_ctrl_pointer, task) \
+	((slave_ctrl_pointer) + 4 * ((task) / SLAVE_CTRL_TASKS_PER_SET) + 3)
+
+/**
+ * struct bif_temperature_function - constant data present in temperature
+ *				sensor function
+ * @temperatuer_pointer:	BIF slave address where temperature sensor
+ *				control registers begin
+ * @slave_control_channel:	Slave control channel associated with the
+ *				temperature sensor function.  This channel is
+ *				also the task number.
+ * @accuracy_pointer:		BIF slave address where temperature accuracy
+ *				registers begin
+ */
+struct bif_temperature_function {
+	u16	temperature_pointer;
+	u8	slave_control_channel;
+	u16	accuracy_pointer;
+};
+
+/**
+ * enum bif_mipi_object_type - MIPI defined BIF object types
+ * %BIF_OBJ_END_OF_LIST:	Indicates that the end of the object list in
+ *				NVM has been reached
+ * %BIF_OBJ_SEC_SLAVE:		Specifies the UIDs of secondary slaves found
+ *				inside of the battery pack
+ * %BIF_OBJ_BATT_PARAM:		Specifies some variety of battery parameter.
+ *				There is no MIPI defined format for this object
+ *				type so parsing is manufacturer specific.
+ */
+enum bif_mipi_object_type {
+	BIF_OBJ_END_OF_LIST	= 0x00,
+	BIF_OBJ_SEC_SLAVE	= 0x01,
+	BIF_OBJ_BATT_PARAM	= 0x02,
+};
+
+/**
+ * struct bif_object - contains all header and data information for a slave
+ *			data object
+ * @type:		Object type
+ * @version:		Object version
+ * @manufacturer_id:	Manufacturer ID number allocated by MIPI
+ * @length:		Length of the entire object including header and CRC
+ * @data:		Raw byte data found in the object
+ * @crc:		CRC of the object calculated using CRC-CCITT
+ * @list:		Linked-list connection parameter
+ * @addr:		BIF slave address correspond to the start of the object
+ *
+ * manufacturer_id == 0x0000 if MIPI type and version.
+ */
+struct bif_object {
+	u8			type;
+	u8			version;
+	u16			manufacturer_id;
+	u16			length;
+	u8			*data;
+	u16			crc;
+	struct list_head	list;
+	u16			addr;
+};
+
+/**
+ * struct bif_nvm_function - constant data present in non-volatile memory
+ *				function as well internal software state
+ *				parameters
+ * @nvm_pointer:		BIF slave address where NVM registers begin
+ * @slave_control_channel:	Slave control channel associated with the
+ *				NVM function.  This channel is also the task
+ *				number.
+ * @write_buffer_size:		Size in bytes of the NVM write buffer.  0x00
+ *				is used to denote a 256 byte buffer.
+ * @nvm_base_address:		BIF slave address where NVM begins
+ * @nvm_size:			NVM size in bytes
+ * @object_count:		Number of BIF objects read from NVM
+ * @object_list:		List of BIF objects read from NVM
+ */
+struct bif_nvm_function {
+	u16			nvm_pointer;
+	u8			slave_control_channel;
+	u8			write_buffer_size;
+	u16			nvm_base_address;
+	u16			nvm_size;
+	int			object_count;
+	struct list_head	object_list;
+};
+
+/**
+ * struct bif_ctrl - Opaque handle for a BIF controller to be used in bus
+ *			oriented BIF function calls.
+ */
+struct bif_ctrl;
+
+/**
+ * struct bif_slave - Opaque handle for a BIF slave to be used in slave oriented
+ *			BIF function calls.
+ */
+struct bif_slave;
+
+/**
+ * enum bif_bus_state - indicates the current or desired state of the BIF bus
+ * %BIF_BUS_STATE_MASTER_DISABLED:	BIF host hardware is disabled
+ * %BIF_BUS_STATE_POWER_DOWN:		BIF bus is in power down state and
+ *					BCL is not being pulled high
+ * %BIF_BUS_STATE_STANDBY:		BIF slaves are in standby state in which
+ *					less power is drawn
+ * %BIF_BUS_STATE_ACTIVE:		BIF slaves are ready for immediate
+ *					communications
+ * %BIF_BUS_STATE_INTERRUPT:		BIF bus is active, but no communication
+ *					is possible.  Instead, either one of the
+ *					slaves or the master must transition to
+ *					active state by pulling BCL low for 1
+ *					tau bif period.
+ */
+enum bif_bus_state {
+	BIF_BUS_STATE_MASTER_DISABLED,
+	BIF_BUS_STATE_POWER_DOWN,
+	BIF_BUS_STATE_STANDBY,
+	BIF_BUS_STATE_ACTIVE,
+	BIF_BUS_STATE_INTERRUPT,
+};
+
+/**
+ * enum bif_bus_event - events that the BIF framework may send to BIF consumers
+ * %BIF_BUS_EVENT_BATTERY_INSERTED:	Indicates that a battery was just
+ *					inserted physically or that the BIF
+ *					host controller for the battery just
+ *					probed and a battery was already
+ *					present.
+ * %BIF_BUS_EVENT_BATTERY_REMOVED:	Indicates that a battery was just
+ *					removed and thus its slaves are no
+ *					longer accessible.
+ */
+enum bif_bus_event {
+	BIF_BUS_EVENT_BATTERY_INSERTED,
+	BIF_BUS_EVENT_BATTERY_REMOVED,
+};
+
+/* Mask values to be ORed together for use in bif_match_criteria.match_mask. */
+#define BIF_MATCH_MANUFACTURER_ID	BIT(0)
+#define BIF_MATCH_PRODUCT_ID		BIT(1)
+#define BIF_MATCH_FUNCTION_TYPE		BIT(2)
+#define BIF_MATCH_FUNCTION_VERSION	BIT(3)
+#define BIF_MATCH_IGNORE_PRESENCE	BIT(4)
+
+/**
+ * struct bif_match_criteria - specifies the matching criteria that a BIF
+ *			consumer uses to find an appropriate BIF slave
+ * @match_mask:		Mask value specifying which parameters to match upon.
+ *			This value should be some ORed combination of
+ *			BIF_MATCH_* specified above.
+ * @manufacturer_id:	Manufacturer ID number allocated by MIPI
+ * @product_id:		Manufacturer specified product ID number
+ * @function_type:	Defines the type of the function.  The type may be
+ *			either MIPI or manufacturer defined.
+ * @function_version:	Defines the version of the function.  The version may
+ *			be either MIPI or manufacturer defined.
+ * @ignore_presence:	If true, then slaves that are currently not present
+ *			will be successfully matched against.  By default, only
+ *			present slaves can be matched.
+ */
+struct bif_match_criteria {
+	u32	match_mask;
+	u16	manufacturer_id;
+	u16	product_id;
+	u8	function_type;
+	u8	function_version;
+	bool	ignore_presence;
+};
+
+/**
+ * bif_battery_rid_ranges - MIPI-BIF defined Rid battery pack resistance ranges
+ * %BIF_BATT_RID_SPECIAL1_MIN:	Minimum Rid for special case 1
+ * %BIF_BATT_RID_SPECIAL1_MAX:	Maximum Rid for special case 1
+ * %BIF_BATT_RID_SPECIAL2_MIN:	Minimum Rid for special case 2
+ * %BIF_BATT_RID_SPECIAL2_MAX:	Maximum Rid for special case 2
+ * %BIF_BATT_RID_SPECIAL3_MIN:	Minimum Rid for special case 3
+ * %BIF_BATT_RID_SPECIAL3_MAX:	Maximum Rid for special case 3
+ * %BIF_BATT_RID_LOW_COST_MIN:	Minimum Rid for a low cost battery pack
+ * %BIF_BATT_RID_LOW_COST_MAX:	Maximum Rid for a low cost battery pack
+ * %BIF_BATT_RID_SMART_MIN:	Minimum Rid for a smart battery pack
+ * %BIF_BATT_RID_SMART_MAX:	Maximum Rid for a smart battery pack
+ */
+enum bif_battery_rid_ranges {
+	BIF_BATT_RID_SPECIAL1_MIN	= 0,
+	BIF_BATT_RID_SPECIAL1_MAX	= 1,
+	BIF_BATT_RID_SPECIAL2_MIN	= 7350,
+	BIF_BATT_RID_SPECIAL2_MAX	= 7650,
+	BIF_BATT_RID_SPECIAL3_MIN	= 12740,
+	BIF_BATT_RID_SPECIAL3_MAX	= 13260,
+	BIF_BATT_RID_LOW_COST_MIN	= 19600,
+	BIF_BATT_RID_LOW_COST_MAX	= 140000,
+	BIF_BATT_RID_SMART_MIN		= 240000,
+	BIF_BATT_RID_SMART_MAX		= 450000,
+};
+
+#ifdef CONFIG_BIF
+
+int bif_request_irq(struct bif_slave *slave, unsigned int task,
+			struct notifier_block *nb);
+int bif_free_irq(struct bif_slave *slave, unsigned int task,
+			struct notifier_block *nb);
+
+int bif_trigger_task(struct bif_slave *slave, unsigned int task);
+int bif_task_is_busy(struct bif_slave *slave, unsigned int task);
+
+int bif_ctrl_count(void);
+struct bif_ctrl *bif_ctrl_get_by_id(unsigned int id);
+struct bif_ctrl *bif_ctrl_get(struct device *consumer_dev);
+void bif_ctrl_put(struct bif_ctrl *ctrl);
+
+int bif_ctrl_signal_battery_changed(struct bif_ctrl *ctrl);
+
+int bif_slave_match_count(const struct bif_ctrl *ctrl,
+			const struct bif_match_criteria *match_criteria);
+
+struct bif_slave *bif_slave_match_get(const struct bif_ctrl *ctrl,
+	unsigned int id, const struct bif_match_criteria *match_criteria);
+
+void bif_slave_put(struct bif_slave *slave);
+
+int bif_ctrl_notifier_register(struct bif_ctrl *ctrl,
+				struct notifier_block *nb);
+
+int bif_ctrl_notifier_unregister(struct bif_ctrl *ctrl,
+				struct notifier_block *nb);
+
+struct bif_ctrl *bif_get_ctrl_handle(struct bif_slave *slave);
+
+int bif_slave_find_function(struct bif_slave *slave, u8 function, u8 *version,
+				u16 *function_pointer);
+
+int bif_slave_read(struct bif_slave *slave, u16 addr, u8 *buf, int len);
+int bif_slave_write(struct bif_slave *slave, u16 addr, u8 *buf, int len);
+
+int bif_slave_is_present(struct bif_slave *slave);
+
+int bif_slave_is_selected(struct bif_slave *slave);
+int bif_slave_select(struct bif_slave *slave);
+
+int bif_ctrl_raw_transaction(struct bif_ctrl *ctrl, int transaction, u8 data);
+int bif_ctrl_raw_transaction_read(struct bif_ctrl *ctrl, int transaction,
+					u8 data, int *response);
+int bif_ctrl_raw_transaction_query(struct bif_ctrl *ctrl, int transaction,
+		u8 data, bool *query_response);
+
+void bif_ctrl_bus_lock(struct bif_ctrl *ctrl);
+void bif_ctrl_bus_unlock(struct bif_ctrl *ctrl);
+
+u16 bif_crc_ccitt(const u8 *buffer, unsigned int len);
+
+int bif_ctrl_measure_rid(struct bif_ctrl *ctrl);
+int bif_ctrl_get_bus_period(struct bif_ctrl *ctrl);
+int bif_ctrl_set_bus_period(struct bif_ctrl *ctrl, int period_ns);
+int bif_ctrl_get_bus_state(struct bif_ctrl *ctrl);
+int bif_ctrl_set_bus_state(struct bif_ctrl *ctrl, enum bif_bus_state state);
+
+#else
+
+static inline int bif_request_irq(struct bif_slave *slave, unsigned int task,
+			struct notifier_block *nb) { return -EPERM; }
+static inline int bif_free_irq(struct bif_slave *slave, unsigned int task,
+			struct notifier_block *nb) { return -EPERM; }
+
+static inline int bif_trigger_task(struct bif_slave *slave, unsigned int task)
+{ return -EPERM; }
+static inline int bif_task_is_busy(struct bif_slave *slave, unsigned int task)
+{ return -EPERM; }
+
+static inline int bif_ctrl_count(void) { return -EPERM; }
+static inline struct bif_ctrl *bif_ctrl_get_by_id(unsigned int id)
+{ return ERR_PTR(-EPERM); }
+struct bif_ctrl *bif_ctrl_get(struct device *consumer_dev)
+{ return ERR_PTR(-EPERM); }
+static inline void bif_ctrl_put(struct bif_ctrl *ctrl) { return; }
+
+int bif_ctrl_signal_battery_changed(struct bif_ctrl *ctrl) { return -EPERM; }
+
+static inline int bif_slave_match_count(const struct bif_ctrl *ctrl,
+			const struct bif_match_criteria *match_criteria)
+{ return -EPERM; }
+
+static inline struct bif_slave *bif_slave_match_get(const struct bif_ctrl *ctrl,
+	unsigned int id, const struct bif_match_criteria *match_criteria)
+{ return ERR_PTR(-EPERM); }
+
+static inline void bif_slave_put(struct bif_slave *slave) { return; }
+
+static inline int bif_ctrl_notifier_register(struct bif_ctrl *ctrl,
+				struct notifier_block *nb)
+{ return -EPERM; }
+
+static inline int bif_ctrl_notifier_unregister(struct bif_ctrl *ctrl,
+				struct notifier_block *nb)
+{ return -EPERM; }
+
+static inline struct bif_ctrl *bif_get_ctrl_handle(struct bif_slave *slave)
+{ return ERR_PTR(-EPERM); }
+
+static inline int bif_slave_find_function(struct bif_slave *slave, u8 function,
+				u8 *version, u16 *function_pointer)
+{ return -EPERM; }
+
+static inline int bif_slave_read(struct bif_slave *slave, u16 addr, u8 *buf,
+				int len)
+{ return -EPERM; }
+static inline int bif_slave_write(struct bif_slave *slave, u16 addr, u8 *buf,
+				int len)
+{ return -EPERM; }
+
+int bif_slave_is_present(struct bif_slave *slave) { return -EPERM; }
+
+int bif_slave_is_selected(struct bif_slave *slave) { return -EPERM; }
+int bif_slave_select(struct bif_slave *slave) { return -EPERM; }
+
+int bif_ctrl_raw_transaction(struct bif_ctrl *ctrl, int transaction, u8 data)
+{ return -EPERM; }
+int bif_ctrl_raw_transaction_read(struct bif_ctrl *ctrl, int transaction,
+					u8 data, int *response)
+{ return -EPERM; }
+int bif_ctrl_raw_transaction_query(struct bif_ctrl *ctrl, int transaction,
+		u8 data, bool *query_response)
+{ return -EPERM; }
+
+static inline void bif_ctrl_bus_lock(struct bif_ctrl *ctrl)
+{ return -EPERM; }
+static inline void bif_ctrl_bus_unlock(struct bif_ctrl *ctrl)
+{ return -EPERM; }
+
+static inline u16 bif_crc_ccitt(const u8 *buffer, unsigned int len)
+{ return 0; }
+
+static inline int bif_ctrl_measure_rid(struct bif_ctrl *ctrl) { return -EPERM; }
+int bif_ctrl_get_bus_period(struct bif_ctrl *ctrl) { return -EPERM; }
+int bif_ctrl_set_bus_period(struct bif_ctrl *ctrl, int period_ns)
+{ return -EPERM; }
+int bif_ctrl_get_bus_state(struct bif_ctrl *ctrl) { return -EPERM; }
+int bif_ctrl_set_bus_state(struct bif_ctrl *ctrl, enum bif_bus_state state)
+{ return -EPERM; }
+
+#endif
+
+#endif
diff --git a/include/linux/bif/driver.h b/include/linux/bif/driver.h
new file mode 100644
index 0000000..184d46f
--- /dev/null
+++ b/include/linux/bif/driver.h
@@ -0,0 +1,161 @@
+/* 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.
+ */
+
+#ifndef _LINUX_BIF_DRIVER_H_
+#define _LINUX_BIF_DRIVER_H_
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/types.h>
+#include <linux/bif/consumer.h>
+
+/**
+ * struct bif_ctrl_dev - opaque handle used to identify a given BIF controller
+ *			device
+ */
+struct bif_ctrl_dev;
+
+/**
+ * struct bif_ctrl_ops - BIF operations which may be implemented by BIF
+ *				controller drivers
+ * @bus_transaction:		Perform the specified BIF transaction which does
+ *				not result in any slave response.
+ * @bus_transaction_query:	Perform the specified BIF transaction which
+ *				expects a BQ response in the case of slave
+ *				positive acknowledgement.
+ * @bus_transaction_read:	Perform the specified BIF transaction which
+ *				expects an RD or TACK response from the selected
+ *				slave.
+ * @read_slave_registers:	Perform all BIF transactions necessary to read
+ *				the specified set of contiguous registers from
+ *				the previously selected slave.  This operation
+ *				is used to optimize the common case of slave
+ *				register reads since the a BIF controller driver
+ *				can take advantage of BIF burst reads while the
+ *				BIF core driver cannot due to the inherient
+ *				tight timing requirements.
+ * @write_slave_registers:	Perform all BIF transactions necessary to write
+ *				the specified set of contiguous registers to
+ *				the previously selected slave.  This operation
+ *				is used to optimize the common case of slave
+ *				register writes since the a BIF controller
+ *				driver can remove redundant steps when
+ *				performing several WD commands in a row.
+ * @get_bus_period:		Return the tau_bif BIF bus clock period in
+ *				nanoseconds.
+ * @set_bus_period:		Set the tau_bif BIF bus clock period in
+ *				nanoseconds.  If the exact period is not
+ *				supported by the BIF controller hardware, then
+ *				the next larger supported period should be used.
+ * @get_battery_presence:	Return the current state of the battery pack.
+ *				If a battery pack is present, then return >= 1.
+ *				If a battery pack is not present, then return 0.
+ *				If an error occurs during presence detection,
+ *				then return errno.
+ * @get_battery_rid:		Return the measured value of the Rid battery
+ *				pack pull-down resistor in ohms.
+ * @get_bus_state:		Return the current bus state as defined by one
+ *				of the enum bif_bus_state values.
+ * @set_bus_state:		Set the BIF bus state to the specified enum
+ *				bif_bus_state value.
+ *
+ * The following operations must be defined by every BIF controller driver in
+ * order to ensure baseline functionality:
+ * bus_transaction, bus_transaction_query, get_bus_state, and set_bus_state.
+ *
+ * The BIF core driver is unaware of BIF transaction timing constraints.  A
+ * given BIF controller driver must ensure that all timing constraints in the
+ * MIPI-BIF specification are met as transactions are carried out.
+ *
+ * Conversion between 11-bit and 17-bit BIF words (i.e. the insertion of BCF_n,
+ * parity bits, and the inversion bit) must be handled inside of the BIF
+ * controller driver (either in software or hardware).  This guarantees maximum
+ * performance if hardware support is available.
+ *
+ * The bus_transaction_read operation must return -ETIMEDOUT in the case of no
+ * RD or TACK word received.  This allows the transaction query, TQ, command
+ * to be used for slave selection verification.
+ *
+ * It is acceptable for the BIF bus state to be changed autonomously by a BIF
+ * controller driver in response to low level bus actions without a call to
+ * set_bus_state.  One example is the case of receiving a slave interrupt
+ * while in interrupt state as this intrinsically causes the bus to enter the
+ * active communication state.
+ */
+struct bif_ctrl_ops {
+	int (*bus_transaction) (struct bif_ctrl_dev *bdev, int transaction,
+					u8 data);
+	int (*bus_transaction_query) (struct bif_ctrl_dev *bdev,
+					int transaction, u8 data,
+					bool *query_response);
+	int (*bus_transaction_read) (struct bif_ctrl_dev *bdev,
+					int transaction, u8 data,
+					int *response);
+	int (*read_slave_registers) (struct bif_ctrl_dev *bdev, u16 addr,
+					u8 *data, int len);
+	int (*write_slave_registers) (struct bif_ctrl_dev *bdev, u16 addr,
+					const u8 *data, int len);
+	int (*get_bus_period) (struct bif_ctrl_dev *bdev);
+	int (*set_bus_period) (struct bif_ctrl_dev *bdev, int period_ns);
+	int (*get_battery_presence) (struct bif_ctrl_dev *bdev);
+	int (*get_battery_rid) (struct bif_ctrl_dev *bdev);
+	int (*get_bus_state) (struct bif_ctrl_dev *bdev);
+	int (*set_bus_state) (struct bif_ctrl_dev *bdev, int state);
+};
+
+/**
+ * struct bif_ctrl_desc - BIF bus controller descriptor
+ * @name:		Name used to identify the BIF controller
+ * @ops:		BIF operations supported by the BIF controller
+ * @bus_clock_min_ns:	Minimum tau_bif BIF bus clock period supported by the
+ *			BIF controller
+ * @bus_clock_max_ns:	Maximum tau_bif BIF bus clock period supported by the
+ *			BIF controller
+ *
+ * Each BIF controller registered with the BIF core is described with a
+ * structure of this type.
+ */
+struct bif_ctrl_desc {
+	const char *name;
+	struct bif_ctrl_ops *ops;
+	int bus_clock_min_ns;
+	int bus_clock_max_ns;
+};
+
+#ifdef CONFIG_BIF
+
+struct bif_ctrl_dev *bif_ctrl_register(struct bif_ctrl_desc *bif_desc,
+	struct device *dev, void *driver_data, struct device_node *of_node);
+
+void bif_ctrl_unregister(struct bif_ctrl_dev *bdev);
+
+void *bdev_get_drvdata(struct bif_ctrl_dev *bdev);
+
+int bif_ctrl_notify_battery_changed(struct bif_ctrl_dev *bdev);
+int bif_ctrl_notify_slave_irq(struct bif_ctrl_dev *bdev);
+
+#else
+
+static inline struct bif_ctrl_dev *bif_ctrl_register(
+	struct bif_ctrl_desc *bif_desc, struct device *dev, void *driver_data,
+	struct device_node *of_node)
+{ return ERR_PTR(-EINVAL); }
+
+static inline void bif_ctrl_unregister(struct bif_ctrl_dev *bdev) { }
+
+static inline void *bdev_get_drvdata(struct bif_ctrl_dev *bdev) { return NULL; }
+
+int bif_ctrl_notify_slave_irq(struct bif_ctrl_dev *bdev) { return -EINVAL; }
+
+#endif
+
+#endif
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index d3ee879..7a5ab0d 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -112,10 +112,10 @@
 /* This needs to be modified manually now, when we add
  a new RANGE of SSIDs to the msg_mask_tbl */
 #define MSG_MASK_TBL_CNT		24
-#define EVENT_LAST_ID			0x099F
+#define EVENT_LAST_ID			0x09AB
 
 #define MSG_SSID_0			0
-#define MSG_SSID_0_LAST			93
+#define MSG_SSID_0_LAST			94
 #define MSG_SSID_1			500
 #define MSG_SSID_1_LAST			506
 #define MSG_SSID_2			1000
@@ -278,6 +278,9 @@
 	MSG_LVL_LOW,
 	MSG_LVL_MED,
 	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_HIGH,
 	MSG_LVL_LOW
 };
 
@@ -713,7 +716,7 @@
 /* LOG CODES */
 
 #define LOG_0	0x0
-#define LOG_1	0x1750
+#define LOG_1	0x1755
 #define LOG_2	0x0
 #define LOG_3	0x0
 #define LOG_4	0x4910
diff --git a/include/linux/dma-contiguous.h b/include/linux/dma-contiguous.h
index 285b593..8a1b3a1 100644
--- a/include/linux/dma-contiguous.h
+++ b/include/linux/dma-contiguous.h
@@ -70,7 +70,7 @@
 void dma_contiguous_reserve(phys_addr_t addr_limit);
 
 int dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t *res_base,
-				  phys_addr_t limit);
+				  phys_addr_t limit, const char *name);
 
 int dma_contiguous_add_device(struct device *dev, phys_addr_t base);
 
@@ -91,7 +91,7 @@
 					 phys_addr_t base, phys_addr_t limit)
 {
 	int ret;
-	ret = dma_contiguous_reserve_area(size, &base, limit);
+	ret = dma_contiguous_reserve_area(size, &base, limit, NULL);
 	if (ret == 0)
 		ret = dma_contiguous_add_device(dev, base);
 	return ret;
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index 785a33a..1c67b1e 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.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
@@ -188,6 +188,7 @@
 	int				btc_delay_ms;
 	int				btc_panic_if_cant_stop_chg;
 	int				stop_chg_upon_expiry;
+	bool				disable_chg_rmvl_wrkarnd;
 };
 
 enum pm8921_charger_source {
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index e9051e1..565d6b5 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -91,6 +91,20 @@
 	unsigned int quirks2;	/* More deviations from spec. */
 
 #define SDHCI_QUIRK2_HOST_OFF_CARD_ON			(1<<0)
+/*
+ * Read Transfer Active/ Write Transfer Active may be not
+ * de-asserted after end of transaction. Issue reset for DAT line.
+ */
+#define SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT			(1<<1)
+/*
+ * Slow interrupt clearance at 400KHz may cause
+ * host controller driver interrupt handler to
+ * be called twice.
+ */
+#define SDHCI_QUIRK2_SLOW_INT_CLR			(1<<2)
+/* Ignore CMD CRC errors for tuning commands */
+#define SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING		(1<<3)
+
 
 	int irq;		/* Device IRQ */
 	void __iomem *ioaddr;	/* Mapped address */
diff --git a/include/linux/msm_ipa.h b/include/linux/msm_ipa.h
index 1b869b1..30bf4f2 100644
--- a/include/linux/msm_ipa.h
+++ b/include/linux/msm_ipa.h
@@ -155,6 +155,10 @@
  * wlan client normal: wlan client moved out of power save
  * sw routing enable: ipa routing is disabled
  * sw routing disable: ipa routing is enabled
+ * wlan ap connect: wlan AP(access point) is up
+ * wlan ap disconnect: wlan AP(access point) is down
+ * wlan sta connect: wlan STA(station) is up
+ * wlan sta disconnect: wlan STA(station) is down
  */
 enum ipa_wlan_event {
 	WLAN_CLIENT_CONNECT,
@@ -163,6 +167,10 @@
 	WLAN_CLIENT_NORMAL_MODE,
 	SW_ROUTING_ENABLE,
 	SW_ROUTING_DISABLE,
+	WLAN_AP_CONNECT,
+	WLAN_AP_DISCONNECT,
+	WLAN_STA_CONNECT,
+	WLAN_STA_DISCONNECT,
 };
 
 
@@ -761,4 +769,87 @@
 				IPA_IOCTL_PULL_MSG, \
 				struct ipa_msg_meta *)
 
+/*
+ * unique magic number of the Tethering bridge ioctls
+ */
+#define TETH_BRIDGE_IOC_MAGIC 0xCE
+
+/*
+ * Ioctls supported by Tethering bridge driver
+ */
+#define TETH_BRIDGE_IOCTL_SET_BRIDGE_MODE	0
+#define TETH_BRIDGE_IOCTL_SET_AGGR_PARAMS	1
+#define TETH_BRIDGE_IOCTL_GET_AGGR_PARAMS	2
+#define TETH_BRIDGE_IOCTL_GET_AGGR_CAPABILITIES	3
+#define TETH_BRIDGE_IOCTL_MAX			4
+
+
+/**
+ * enum teth_link_protocol_type - link protocol (IP / Ethernet)
+ */
+enum teth_link_protocol_type {
+	TETH_LINK_PROTOCOL_IP,
+	TETH_LINK_PROTOCOL_ETHERNET,
+	TETH_LINK_PROTOCOL_MAX,
+};
+
+/**
+ * enum teth_aggr_protocol_type - Aggregation protocol (MBIM / TLP)
+ */
+enum teth_aggr_protocol_type {
+	TETH_AGGR_PROTOCOL_NONE,
+	TETH_AGGR_PROTOCOL_MBIM,
+	TETH_AGGR_PROTOCOL_TLP,
+	TETH_AGGR_PROTOCOL_MAX,
+};
+
+/**
+ * struct teth_aggr_params_link - Aggregation parameters for uplink/downlink
+ * @aggr_prot:			Aggregation protocol (MBIM / TLP)
+ * @max_transfer_size_byte:	Maximal size of aggregated packet in bytes.
+ *				Default value is 16*1024.
+ * @max_datagrams:		Maximal number of IP packets in an aggregated
+ *				packet. Default value is 16
+ */
+struct teth_aggr_params_link {
+	enum teth_aggr_protocol_type aggr_prot;
+	uint32_t max_transfer_size_byte;
+	uint32_t max_datagrams;
+};
+
+
+/**
+ * struct teth_aggr_params - Aggregation parmeters
+ * @ul:	Uplink parameters
+ * @dl: Downlink parmaeters
+ */
+struct teth_aggr_params {
+	struct teth_aggr_params_link ul;
+	struct teth_aggr_params_link dl;
+};
+
+/**
+ * struct teth_aggr_capabilities - Aggregation capabilities
+ * @num_protocols:		Number of protocols described in the array
+ * @prot_caps[]:		Array of aggregation capabilities per protocol
+ */
+struct teth_aggr_capabilities {
+	uint16_t num_protocols;
+	struct teth_aggr_params_link prot_caps[0];
+};
+
+
+#define TETH_BRIDGE_IOC_SET_BRIDGE_MODE _IOW(TETH_BRIDGE_IOC_MAGIC, \
+				TETH_BRIDGE_IOCTL_SET_BRIDGE_MODE, \
+				enum teth_link_protocol_type)
+#define TETH_BRIDGE_IOC_SET_AGGR_PARAMS _IOW(TETH_BRIDGE_IOC_MAGIC, \
+				TETH_BRIDGE_IOCTL_SET_AGGR_PARAMS, \
+				struct teth_aggr_params *)
+#define TETH_BRIDGE_IOC_GET_AGGR_PARAMS _IOR(TETH_BRIDGE_IOC_MAGIC, \
+				TETH_BRIDGE_IOCTL_GET_AGGR_PARAMS, \
+				struct teth_aggr_params *)
+#define TETH_BRIDGE_IOC_GET_AGGR_CAPABILITIES _IOWR(TETH_BRIDGE_IOC_MAGIC, \
+				TETH_BRIDGE_IOCTL_GET_AGGR_CAPABILITIES, \
+				struct teth_aggr_capabilities *)
+
 #endif /* _MSM_IPA_H_ */
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 404ea52..45bc0ea 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -564,6 +564,15 @@
 	mdp_op_max,
 };
 
+enum {
+	WB_FORMAT_NV12,
+	WB_FORMAT_RGB_565,
+	WB_FORMAT_RGB_888,
+	WB_FORMAT_xRGB_8888,
+	WB_FORMAT_ARGB_8888,
+	WB_FORMAT_ARGB_8888_INPUT_ALPHA /* Need to support */
+};
+
 struct msmfb_mdp_pp {
 	uint32_t op;
 	union {
@@ -585,6 +594,7 @@
 	metadata_op_base_blend,
 	metadata_op_frame_rate,
 	metadata_op_vic,
+	metadata_op_wb_format,
 	metadata_op_max
 };
 
@@ -592,11 +602,17 @@
 	uint32_t is_premultiplied;
 };
 
+struct mdp_mixer_cfg {
+	uint32_t writeback_format;
+	uint32_t alpha;
+};
+
 struct msmfb_metadata {
 	uint32_t op;
 	uint32_t flags;
 	union {
 		struct mdp_blend_cfg blend_cfg;
+		struct mdp_mixer_cfg mixer_cfg;
 		uint32_t panel_frame_rate;
 		uint32_t video_info_code;
 	} data;
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index c6ee4f0..6e4b7a6 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -365,8 +365,8 @@
  *	requests to connect to a specified network but without separating
  *	auth and assoc steps. For this, you need to specify the SSID in a
  *	%NL80211_ATTR_SSID attribute, and can optionally specify the association
- *	IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC,
- *	%NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
+ *	IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP,
+ *	%NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
  *	%NL80211_ATTR_CONTROL_PORT_ETHERTYPE and
  *	%NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT.
  *	Background scan period can optionally be
@@ -554,14 +554,6 @@
  * @NL80211_CMD_SET_NOACK_MAP: sets a bitmap for the individual TIDs whether
  *      No Acknowledgement Policy should be applied.
  *
- * @NL80211_CMD_UPDATE_FT_IES: Pass down the most up-to-date Fast Transition
- *	Information Element to the WLAN driver
- *
- * @NL80211_CMD_FT_EVENT: Send a Fast transition event from the WLAN driver
- *	to the supplicant. This will carry the target AP's MAC address along
- *	with the relevant Information Elements. This event to report received
- *	FT IEs( MDIE, FTIE,RSN IE, TIE, RICIE).
- *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -703,9 +695,6 @@
 
 	NL80211_CMD_SET_NOACK_MAP,
 
-	NL80211_CMD_UPDATE_FT_IES,
-	NL80211_CMD_FT_EVENT,
-
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -906,7 +895,7 @@
  * @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is
  *	used for the association (&enum nl80211_mfp, represented as a u32);
  *	this attribute can be used
- *	with %NL80211_CMD_ASSOCIATE request
+ *	with %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests
  *
  * @NL80211_ATTR_STA_FLAGS2: Attribute containing a
  *	&struct nl80211_sta_flag_update.
@@ -1281,10 +1270,6 @@
  * @NL80211_ATTR_BG_SCAN_PERIOD: Background scan period in seconds
  *      or 0 to disable background scan.
  *
- * @NL80211_ATTR_MDID: Mobility Domain Identifier
- *
- * @NL80211_ATTR_IE_RIC: Resource Information Container Information Element
- *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1536,9 +1521,6 @@
 
 	NL80211_ATTR_BG_SCAN_PERIOD,
 
-	NL80211_ATTR_MDID,
-	NL80211_ATTR_IE_RIC,
-
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
diff --git a/include/linux/regulator/krait-regulator.h b/include/linux/regulator/krait-regulator.h
index 836f9d6..b784531 100644
--- a/include/linux/regulator/krait-regulator.h
+++ b/include/linux/regulator/krait-regulator.h
@@ -13,7 +13,8 @@
 #ifndef __KRAIT_REGULATOR_H__
 #define __KRAIT_REGULATOR_H__
 
-#define KRAIT_REGULATOR_DRIVER_NAME "krait-power-regulator"
+#define KRAIT_REGULATOR_DRIVER_NAME	"krait-power-regulator"
+#define KRAIT_PDN_DRIVER_NAME		"krait-pdn"
 
 /**
  * krait_power_init - driver initialization function
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index fae1efa..c53d604 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -17,20 +17,6 @@
 	MSM_VIDC_MAX_DEVICES,
 };
 
-struct msm_vidc_iommu_info {
-	u32 addr_range[2];
-	char name[64];
-	char ctx[64];
-	int domain;
-	int partition;
-};
-
-enum msm_vidc_io_maps {
-	CP_MAP,
-	NS_MAP,
-	MAX_MAP
-};
-
 void *msm_vidc_open(int core_id, int session_type);
 int msm_vidc_close(void *instance);
 int msm_vidc_querycap(void *instance, struct v4l2_capability *cap);
@@ -50,8 +36,8 @@
 int msm_vidc_encoder_cmd(void *instance, struct v4l2_encoder_cmd *enc);
 int msm_vidc_poll(void *instance, struct file *filp,
 		struct poll_table_struct *pt);
-int msm_vidc_get_iommu_maps(void *instance,
-		struct msm_vidc_iommu_info maps[MAX_MAP]);
+int msm_vidc_get_iommu_domain_partition(void *instance, u32 flags,
+		enum v4l2_buf_type, int *domain, int *partition);
 int msm_vidc_subscribe_event(void *instance,
 		struct v4l2_event_subscription *sub);
 int msm_vidc_unsubscribe_event(void *instance,
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
index 6bac1d6..56c257d 100644
--- a/include/media/msmb_pproc.h
+++ b/include/media/msmb_pproc.h
@@ -89,10 +89,9 @@
 	struct ion_handle *dest_ion_handle;
 };
 
-struct msm_ver_num_info {
-	uint32_t main;
-	uint32_t minor;
-	uint32_t rev;
+struct cpp_hw_info {
+	uint32_t cpp_hw_version;
+	uint32_t cpp_hw_caps;
 };
 
 #define VIDIOC_MSM_CPP_CFG \
@@ -107,6 +106,9 @@
 #define VIDIOC_MSM_CPP_LOAD_FIRMWARE \
 	_IOWR('V', BASE_VIDIOC_PRIVATE + 3, struct msm_camera_v4l2_ioctl_t)
 
+#define VIDIOC_MSM_CPP_GET_HW_INFO \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct msm_camera_v4l2_ioctl_t)
+
 #define V4L2_EVENT_CPP_FRAME_DONE  (V4L2_EVENT_PRIVATE_START + 0)
 
 struct msm_camera_v4l2_ioctl_t {
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 5e32ff7..3a7edf3 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1199,6 +1199,7 @@
  * @ie: IEs for association request
  * @ie_len: Length of assoc_ie in octets
  * @privacy: indicates whether privacy-enabled APs should be used
+ * @mfp: indicate whether management frame protection is used
  * @crypto: crypto settings
  * @key_len: length of WEP key for shared key authentication
  * @key_idx: index of WEP key for shared key authentication
@@ -1219,6 +1220,7 @@
 	u8 *ie;
 	size_t ie_len;
 	bool privacy;
+	enum nl80211_mfp mfp;
 	struct cfg80211_crypto_settings crypto;
 	const u8 *key;
 	u8 key_len, key_idx;
@@ -1318,21 +1320,6 @@
 };
 
 /**
- * struct cfg80211_update_ft_ies_params - FT IE Information
- *
- * This structure provides information needed to update the fast transition IE
- *
- * @md: The Mobility Domain ID, 2 Octet value
- * @ie: Fast Transition IEs
- * @ie_len: Length of ft_ie in octets
- */
-struct cfg80211_update_ft_ies_params {
-	u16 md;
-	u8 *ie;
-	size_t ie_len;
-};
-
-/**
  * struct cfg80211_ops - backend description for wireless configuration
  *
  * This struct is registered by fullmac card drivers and/or wireless stacks
@@ -1712,8 +1699,6 @@
 				  u16 noack_map);
 
 	struct ieee80211_channel *(*get_channel)(struct wiphy *wiphy);
-	int	(*update_ft_ies)(struct wiphy *wiphy, struct net_device *dev,
-				 struct cfg80211_update_ft_ies_params *ftie);
 };
 
 /*
@@ -3384,32 +3369,6 @@
  */
 u16 cfg80211_calculate_bitrate(struct rate_info *rate);
 
-/**
- * struct cfg80211_ft_event - FT Information Elements
- * @dev: network device
- * @ies: FT IEs
- * @ies_len: length of the FT IE in bytes
- * @target_ap: target AP's MAC address
- * @ric_ies: RIC IE
- * @ric_ies_len: length of the RIC IE in bytes
- */
-struct cfg80211_ft_event_params {
-	u8 *ies;
-	size_t ies_len;
-	u8 target_ap[ETH_ALEN];
-	u8 *ric_ies;
-	size_t ric_ies_len;
-};
-
-/**
- * cfg80211_ft_event - notify userspace about FT IE and RIC IE
- * @dev: network device
- * @cfg80211_ft_event_params: IE information
- */
-int cfg80211_ft_event(struct net_device *dev,
-			struct cfg80211_ft_event_params ft_event);
-
-
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
diff --git a/kernel/sys.c b/kernel/sys.c
index e7006eb..39791be 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1179,15 +1179,16 @@
  * Work around broken programs that cannot handle "Linux 3.0".
  * Instead we map 3.x to 2.6.40+x, so e.g. 3.0 would be 2.6.40
  */
-static int override_release(char __user *release, int len)
+static int override_release(char __user *release, size_t len)
 {
 	int ret = 0;
-	char buf[65];
 
 	if (current->personality & UNAME26) {
-		char *rest = UTS_RELEASE;
+		const char *rest = UTS_RELEASE;
+		char buf[65] = { 0 };
 		int ndots = 0;
 		unsigned v;
+		size_t copy;
 
 		while (*rest) {
 			if (*rest == '.' && ++ndots >= 3)
@@ -1197,8 +1198,9 @@
 			rest++;
 		}
 		v = ((LINUX_VERSION_CODE >> 8) & 0xff) + 40;
-		snprintf(buf, len, "2.6.%u%s", v, rest);
-		ret = copy_to_user(release, buf, len);
+		copy = min(sizeof(buf), max_t(size_t, 1, len));
+		copy = scnprintf(buf, copy, "2.6.%u%s", v, rest);
+		ret = copy_to_user(release, buf, copy + 1);
 	}
 	return ret;
 }
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index dd99041..f5a7ac3 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -954,16 +954,3 @@
 	return nl80211_unexpected_4addr_frame(dev, addr, gfp);
 }
 EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
-
-int cfg80211_ft_event(struct net_device *dev,
-			struct cfg80211_ft_event_params ft_event)
-{
-	int err = 0;
-	struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
-	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
-	nl80211_ft_event(rdev, dev, ft_event);
-
-	return err;
-}
-EXPORT_SYMBOL(cfg80211_ft_event);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 5c2e805..68a6b17 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -206,9 +206,6 @@
 	[NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 },
 	[NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 },
 	[NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
-	[NL80211_ATTR_MDID] = { .type = NLA_U16 },
-	[NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY,
-					 .len = IEEE80211_MAX_DATA_LEN },
 };
 
 /* policy for the key attributes */
@@ -5173,6 +5170,15 @@
 		connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
 	}
 
+	if (info->attrs[NL80211_ATTR_USE_MFP]) {
+		connect.mfp = nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
+		if (connect.mfp != NL80211_MFP_REQUIRED &&
+		    connect.mfp != NL80211_MFP_NO)
+			return -EINVAL;
+	} else {
+		connect.mfp = NL80211_MFP_NO;
+	}
+
 	if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
 		connect.channel =
 			ieee80211_get_channel(wiphy,
@@ -6302,26 +6308,6 @@
 	return 0;
 }
 
-static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info)
-{
-	struct cfg80211_registered_device *rdev = info->user_ptr[0];
-	struct cfg80211_update_ft_ies_params ft_params;
-	struct net_device *dev = info->user_ptr[1];
-
-	if (!info->attrs[NL80211_ATTR_MDID])
-		return -EINVAL;
-
-	ft_params.md = nla_get_u16(info->attrs[NL80211_ATTR_MDID]);
-
-	if (!info->attrs[NL80211_ATTR_IE])
-		return -EINVAL;
-
-	ft_params.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
-	ft_params.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
-
-	return rdev->ops->update_ft_ies(&rdev->wiphy, dev, &ft_params);
-}
-
 #define NL80211_FLAG_NEED_WIPHY		0x01
 #define NL80211_FLAG_NEED_NETDEV	0x02
 #define NL80211_FLAG_NEED_RTNL		0x04
@@ -6910,14 +6896,6 @@
 		.internal_flags = NL80211_FLAG_NEED_NETDEV |
 				  NL80211_FLAG_NEED_RTNL,
 	},
-	{
-		.cmd = NL80211_CMD_UPDATE_FT_IES,
-		.doit = nl80211_update_ft_ies,
-		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
-		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-				  NL80211_FLAG_NEED_RTNL,
-	},
 
 };
 
@@ -8155,47 +8133,6 @@
 	.notifier_call = nl80211_netlink_notify,
 };
 
-void nl80211_ft_event(struct cfg80211_registered_device *rdev,
-	struct net_device *netdev, struct cfg80211_ft_event_params ft_event)
-{
-	struct sk_buff *msg;
-	void *hdr;
-
-	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-	if (!msg)
-		return;
-
-	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FT_EVENT);
-	if (!hdr) {
-		nlmsg_free(msg);
-		return;
-	}
-
-	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
-	if (ft_event.target_ap)
-		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, ft_event.target_ap);
-	if (ft_event.ies)
-		NLA_PUT(msg, NL80211_ATTR_IE, ft_event.ies_len, ft_event.ies);
-	if (ft_event.ric_ies)
-		NLA_PUT(msg, NL80211_ATTR_IE_RIC, ft_event.ric_ies_len,
-					ft_event.ric_ies);
-
-	if (genlmsg_end(msg, hdr) < 0) {
-		nlmsg_free(msg);
-		return;
-	}
-
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_mlme_mcgrp.id, GFP_KERNEL);
-	return;
-
- nla_put_failure:
-	genlmsg_cancel(msg, hdr);
-	nlmsg_free(msg);
-}
-
-
 /* initialisation/exit functions */
 
 int nl80211_init(void)
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index ffd4c8a..4ffe50d 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -123,8 +123,4 @@
 bool nl80211_unexpected_4addr_frame(struct net_device *dev,
 				    const u8 *addr, gfp_t gfp);
 
-void nl80211_ft_event(struct cfg80211_registered_device *rdev,
-			struct net_device *netdev,
-			struct cfg80211_ft_event_params ft_event);
-
 #endif /* __NET_WIRELESS_NL80211_H */
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index bbbed73..ab91446 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -190,7 +190,8 @@
 					    prev_bssid,
 					    params->ssid, params->ssid_len,
 					    params->ie, params->ie_len,
-					    false, &params->crypto,
+					    params->mfp != NL80211_MFP_NO,
+					    &params->crypto,
 					    params->flags, &params->ht_capa,
 					    &params->ht_capa_mask);
 		if (err)
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index 0b26a56..25d3f56 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -487,16 +487,16 @@
 	SOC_ENUM_SINGLE(TAPAN_A_CDC_TX4_MUX_CTL, 4, 3, cf_text);
 
 static const struct soc_enum cf_rxmix1_enum =
-	SOC_ENUM_SINGLE(TAPAN_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_RX1_B4_CTL, 0, 3, cf_text);
 
 static const struct soc_enum cf_rxmix2_enum =
-	SOC_ENUM_SINGLE(TAPAN_A_CDC_RX2_B4_CTL, 1, 3, cf_text);
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_RX2_B4_CTL, 0, 3, cf_text);
 
 static const struct soc_enum cf_rxmix3_enum =
-	SOC_ENUM_SINGLE(TAPAN_A_CDC_RX3_B4_CTL, 1, 3, cf_text);
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_RX3_B4_CTL, 0, 3, cf_text);
 
 static const struct soc_enum cf_rxmix4_enum =
-	SOC_ENUM_SINGLE(TAPAN_A_CDC_RX4_B4_CTL, 1, 3, cf_text);
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_RX4_B4_CTL, 0, 3, cf_text);
 
 static const struct snd_kcontrol_new tapan_snd_controls[] = {
 
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index f48dbf1..af268bd 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -829,25 +829,25 @@
 	SOC_ENUM_SINGLE(TAIKO_A_CDC_TX10_MUX_CTL, 4, 3, cf_text);
 
 static const struct soc_enum cf_rxmix1_enum =
-	SOC_ENUM_SINGLE(TAIKO_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
+	SOC_ENUM_SINGLE(TAIKO_A_CDC_RX1_B4_CTL, 0, 3, cf_text);
 
 static const struct soc_enum cf_rxmix2_enum =
-	SOC_ENUM_SINGLE(TAIKO_A_CDC_RX2_B4_CTL, 1, 3, cf_text);
+	SOC_ENUM_SINGLE(TAIKO_A_CDC_RX2_B4_CTL, 0, 3, cf_text);
 
 static const struct soc_enum cf_rxmix3_enum =
-	SOC_ENUM_SINGLE(TAIKO_A_CDC_RX3_B4_CTL, 1, 3, cf_text);
+	SOC_ENUM_SINGLE(TAIKO_A_CDC_RX3_B4_CTL, 0, 3, cf_text);
 
 static const struct soc_enum cf_rxmix4_enum =
-	SOC_ENUM_SINGLE(TAIKO_A_CDC_RX4_B4_CTL, 1, 3, cf_text);
+	SOC_ENUM_SINGLE(TAIKO_A_CDC_RX4_B4_CTL, 0, 3, cf_text);
 
 static const struct soc_enum cf_rxmix5_enum =
-	SOC_ENUM_SINGLE(TAIKO_A_CDC_RX5_B4_CTL, 1, 3, cf_text)
+	SOC_ENUM_SINGLE(TAIKO_A_CDC_RX5_B4_CTL, 0, 3, cf_text)
 ;
 static const struct soc_enum cf_rxmix6_enum =
-	SOC_ENUM_SINGLE(TAIKO_A_CDC_RX6_B4_CTL, 1, 3, cf_text);
+	SOC_ENUM_SINGLE(TAIKO_A_CDC_RX6_B4_CTL, 0, 3, cf_text);
 
 static const struct soc_enum cf_rxmix7_enum =
-	SOC_ENUM_SINGLE(TAIKO_A_CDC_RX7_B4_CTL, 1, 3, cf_text);
+	SOC_ENUM_SINGLE(TAIKO_A_CDC_RX7_B4_CTL, 0, 3, cf_text);
 
 static const char * const class_h_dsm_text[] = {
 	"ZERO", "DSM_HPHL_RX1", "DSM_SPKR_RX7"
@@ -932,12 +932,6 @@
 	SOC_SINGLE_TLV("ADC5 Volume", TAIKO_A_TX_5_6_EN, 5, 3, 0, analog_gain),
 	SOC_SINGLE_TLV("ADC6 Volume", TAIKO_A_TX_5_6_EN, 1, 3, 0, analog_gain),
 
-
-	SOC_SINGLE("MICBIAS1 CAPLESS Switch", TAIKO_A_MICB_1_CTL, 4, 1, 1),
-	SOC_SINGLE("MICBIAS2 CAPLESS Switch", TAIKO_A_MICB_2_CTL, 4, 1, 1),
-	SOC_SINGLE("MICBIAS3 CAPLESS Switch", TAIKO_A_MICB_3_CTL, 4, 1, 1),
-	SOC_SINGLE("MICBIAS4 CAPLESS Switch", TAIKO_A_MICB_4_CTL, 4, 1, 1),
-
 	SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, taiko_get_anc_slot,
 		taiko_put_anc_slot),
 	SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
@@ -1813,28 +1807,61 @@
 	struct snd_soc_codec *codec = w->codec;
 	u16 adc_reg;
 	u8 init_bit_shift;
+	struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
 
 	pr_debug("%s %d\n", __func__, event);
 
-	if (w->reg == TAIKO_A_TX_1_2_EN)
-		adc_reg = TAIKO_A_TX_1_2_TEST_CTL;
-	else if (w->reg == TAIKO_A_TX_3_4_EN)
-		adc_reg = TAIKO_A_TX_3_4_TEST_CTL;
-	else if (w->reg == TAIKO_A_TX_5_6_EN)
-		adc_reg = TAIKO_A_TX_5_6_TEST_CTL;
-	else {
-		pr_err("%s: Error, invalid adc register\n", __func__);
-		return -EINVAL;
-	}
+	if (TAIKO_IS_1_0(core->version)) {
+		if (w->reg == TAIKO_A_TX_1_2_EN) {
+			adc_reg = TAIKO_A_TX_1_2_TEST_CTL;
+		} else if (w->reg == TAIKO_A_TX_3_4_EN) {
+			adc_reg = TAIKO_A_TX_3_4_TEST_CTL;
+		} else if (w->reg == TAIKO_A_TX_5_6_EN) {
+			adc_reg = TAIKO_A_TX_5_6_TEST_CTL;
+		} else {
+			pr_err("%s: Error, invalid adc register\n", __func__);
+			return -EINVAL;
+		}
 
-	if (w->shift == 3)
-		init_bit_shift = 6;
-	else if  (w->shift == 7)
-		init_bit_shift = 7;
-	else {
-		pr_err("%s: Error, invalid init bit postion adc register\n",
-				__func__);
-		return -EINVAL;
+		if (w->shift == 3) {
+			init_bit_shift = 6;
+		} else if  (w->shift == 7) {
+			init_bit_shift = 7;
+		} else {
+			pr_err("%s: Error, invalid init bit postion adc register\n",
+			       __func__);
+			return -EINVAL;
+		}
+	} else {
+		switch (w->reg) {
+		case TAIKO_A_CDC_TX_1_GAIN:
+			adc_reg = TAIKO_A_TX_1_2_TEST_CTL;
+			init_bit_shift = 7;
+			break;
+		case TAIKO_A_CDC_TX_2_GAIN:
+			adc_reg = TAIKO_A_TX_1_2_TEST_CTL;
+			init_bit_shift = 6;
+			break;
+		case TAIKO_A_CDC_TX_3_GAIN:
+			adc_reg = TAIKO_A_TX_3_4_TEST_CTL;
+			init_bit_shift = 7;
+			break;
+		case TAIKO_A_CDC_TX_4_GAIN:
+			adc_reg = TAIKO_A_TX_3_4_TEST_CTL;
+			init_bit_shift = 6;
+			break;
+		case TAIKO_A_CDC_TX_5_GAIN:
+			adc_reg = TAIKO_A_TX_5_6_TEST_CTL;
+			init_bit_shift = 7;
+			break;
+		case TAIKO_A_CDC_TX_6_GAIN:
+			adc_reg = TAIKO_A_TX_5_6_TEST_CTL;
+			init_bit_shift = 6;
+			break;
+		default:
+			pr_err("%s: Error, invalid adc register\n", __func__);
+			return -EINVAL;
+		}
 	}
 
 	switch (event) {
@@ -1844,9 +1871,7 @@
 				1 << init_bit_shift);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
-
 		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
-
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		taiko_codec_enable_adc_block(codec, 0);
@@ -2157,14 +2182,14 @@
 		e_post_on = WCD9XXX_EVENT_POST_MICBIAS_2_ON;
 		e_post_off = WCD9XXX_EVENT_POST_MICBIAS_2_OFF;
 	} else if (strnstr(w->name, "MIC BIAS3", sizeof("MIC BIAS3"))) {
-		micb_ctl_reg = TAIKO_A_MICB_2_CTL;
+		micb_ctl_reg = TAIKO_A_MICB_3_CTL;
 		micb_int_reg = TAIKO_A_MICB_3_INT_RBIAS;
 		cfilt_sel_val = taiko->resmgr.pdata->micbias.bias3_cfilt_sel;
 		e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_3_ON;
 		e_post_on = WCD9XXX_EVENT_POST_MICBIAS_3_ON;
 		e_post_off = WCD9XXX_EVENT_POST_MICBIAS_3_OFF;
 	} else if (strnstr(w->name, "MIC BIAS4", sizeof("MIC BIAS4"))) {
-		micb_ctl_reg = TAIKO_A_MICB_2_CTL;
+		micb_ctl_reg = TAIKO_A_MICB_4_CTL;
 		micb_int_reg = taiko->resmgr.reg_addr->micb_4_int_rbias;
 		cfilt_sel_val = taiko->resmgr.pdata->micbias.bias4_cfilt_sel;
 		e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_4_ON;
@@ -2190,14 +2215,12 @@
 		else if (strnstr(w->name, internal3_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
 
-		if (micb_ctl_reg == TAIKO_A_MICB_2_CTL) {
-			WCD9XXX_BCL_LOCK(&taiko->resmgr);
+		if (micb_ctl_reg == TAIKO_A_MICB_2_CTL)
 			wcd9xxx_resmgr_add_cond_update_bits(&taiko->resmgr,
 						  WCD9XXX_COND_HPH_MIC,
 						  micb_ctl_reg, w->shift,
 						  false);
-			WCD9XXX_BCL_UNLOCK(&taiko->resmgr);
-		} else
+		else
 			snd_soc_update_bits(codec, micb_ctl_reg, 1 << w->shift,
 					    1 << w->shift);
 		break;
@@ -2207,13 +2230,11 @@
 		wcd9xxx_resmgr_notifier_call(&taiko->resmgr, e_post_on);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		if (micb_ctl_reg == TAIKO_A_MICB_2_CTL) {
-			WCD9XXX_BCL_LOCK(&taiko->resmgr);
+		if (micb_ctl_reg == TAIKO_A_MICB_2_CTL)
 			wcd9xxx_resmgr_rm_cond_update_bits(&taiko->resmgr,
 						  WCD9XXX_COND_HPH_MIC,
 						  micb_ctl_reg, 7, false);
-			WCD9XXX_BCL_UNLOCK(&taiko->resmgr);
-		} else
+		else
 			snd_soc_update_bits(codec, micb_ctl_reg, 1 << w->shift,
 					    0);
 
@@ -4305,27 +4326,14 @@
 			       taiko_codec_enable_micbias,
 			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
 			       SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_ADC_E("ADC1", NULL, TAIKO_A_TX_1_2_EN, 7, 0,
-		taiko_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_INPUT("AMIC3"),
-	SND_SOC_DAPM_ADC_E("ADC3", NULL, TAIKO_A_TX_3_4_EN, 7, 0,
-		taiko_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_INPUT("AMIC4"),
-	SND_SOC_DAPM_ADC_E("ADC4", NULL, TAIKO_A_TX_3_4_EN, 3, 0,
-		taiko_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_INPUT("AMIC5"),
-	SND_SOC_DAPM_ADC_E("ADC5", NULL, TAIKO_A_TX_5_6_EN, 7, 0,
-		taiko_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
 
 	SND_SOC_DAPM_INPUT("AMIC6"),
-	SND_SOC_DAPM_ADC_E("ADC6", NULL, TAIKO_A_TX_5_6_EN, 3, 0,
-		taiko_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
 
 	SND_SOC_DAPM_MUX_E("DEC1 MUX", TAIKO_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
 		&dec1_mux, taiko_codec_enable_dec,
@@ -4420,10 +4428,6 @@
 			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
 			       SND_SOC_DAPM_POST_PMD),
 
-	SND_SOC_DAPM_ADC_E("ADC2", NULL, TAIKO_A_TX_1_2_EN, 3, 0,
-		taiko_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
 	SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
 		AIF1_CAP, 0, taiko_codec_enable_slimtx,
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
@@ -5073,6 +5077,56 @@
 	return buck_volt;
 }
 
+static const struct snd_soc_dapm_widget taiko_1_dapm_widgets[] = {
+	SND_SOC_DAPM_ADC_E("ADC1", NULL, TAIKO_A_TX_1_2_EN, 7, 0,
+			   taiko_codec_enable_adc,
+			   SND_SOC_DAPM_PRE_PMU |
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("ADC2", NULL, TAIKO_A_TX_1_2_EN, 3, 0,
+			   taiko_codec_enable_adc,
+			   SND_SOC_DAPM_PRE_PMU |
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("ADC3", NULL, TAIKO_A_TX_3_4_EN, 7, 0,
+			   taiko_codec_enable_adc,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("ADC4", NULL, TAIKO_A_TX_3_4_EN, 3, 0,
+			   taiko_codec_enable_adc,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("ADC5", NULL, TAIKO_A_TX_5_6_EN, 7, 0,
+			   taiko_codec_enable_adc,
+			   SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_ADC_E("ADC6", NULL, TAIKO_A_TX_5_6_EN, 3, 0,
+			   taiko_codec_enable_adc,
+			   SND_SOC_DAPM_POST_PMU),
+};
+
+static const struct snd_soc_dapm_widget taiko_2_dapm_widgets[] = {
+	SND_SOC_DAPM_ADC_E("ADC1", NULL, TAIKO_A_CDC_TX_1_GAIN, 7, 0,
+			   taiko_codec_enable_adc,
+			   SND_SOC_DAPM_PRE_PMU |
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("ADC2", NULL, TAIKO_A_CDC_TX_2_GAIN, 7, 0,
+			   taiko_codec_enable_adc,
+			   SND_SOC_DAPM_PRE_PMU |
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("ADC3", NULL, TAIKO_A_CDC_TX_3_GAIN, 7, 0,
+			   taiko_codec_enable_adc,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("ADC4", NULL, TAIKO_A_CDC_TX_4_GAIN, 7, 0,
+			   taiko_codec_enable_adc,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("ADC5", NULL, TAIKO_A_CDC_TX_5_GAIN, 7, 0,
+			   taiko_codec_enable_adc,
+			   SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_ADC_E("ADC6", NULL, TAIKO_A_CDC_TX_6_GAIN, 7, 0,
+			   taiko_codec_enable_adc,
+			   SND_SOC_DAPM_POST_PMU),
+};
+
 static int taiko_codec_probe(struct snd_soc_codec *codec)
 {
 	struct wcd9xxx *control;
@@ -5119,7 +5173,7 @@
 	}
 
 	taiko->clsh_d.buck_mv = taiko_codec_get_buck_mv(codec);
-	wcd9xxx_clsh_init(&taiko->clsh_d);
+	wcd9xxx_clsh_init(&taiko->clsh_d, &taiko->resmgr);
 
 	/* init and start mbhc */
 	ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec);
@@ -5185,6 +5239,13 @@
 		}
 	}
 
+	if (TAIKO_IS_1_0(control->version))
+		snd_soc_dapm_new_controls(dapm, taiko_1_dapm_widgets,
+					  ARRAY_SIZE(taiko_1_dapm_widgets));
+	else
+		snd_soc_dapm_new_controls(dapm, taiko_2_dapm_widgets,
+					  ARRAY_SIZE(taiko_2_dapm_widgets));
+
 	control->num_rx_port = TAIKO_RX_MAX;
 	control->rx_chs = ptr;
 	memcpy(control->rx_chs, taiko_rx_chs, sizeof(taiko_rx_chs));
diff --git a/sound/soc/codecs/wcd9xxx-common.c b/sound/soc/codecs/wcd9xxx-common.c
index dbf2e39..f1b6203 100644
--- a/sound/soc/codecs/wcd9xxx-common.c
+++ b/sound/soc/codecs/wcd9xxx-common.c
@@ -165,33 +165,38 @@
 	}
 }
 
-static inline void wcd9xxx_clsh_computation_request(
-	struct snd_soc_codec *codec, int compute_pa, bool on)
+static void wcd9xxx_clsh_comp_req(struct snd_soc_codec *codec,
+				  struct wcd9xxx_clsh_cdc_data *clsh_d,
+				  int compute_pa, bool on)
 {
-	u8 reg_val, reg_mask;
+	u8 shift;
 
-	switch (compute_pa) {
-	case CLSH_COMPUTE_EAR:
-		reg_mask = 0x10;
-		reg_val = (on ? 0x10 : 0x00);
-		break;
-	case CLSH_COMPUTE_HPH_L:
-		reg_mask = 0x08;
-		reg_val = (on ? 0x08 : 0x00);
-		break;
-	case CLSH_COMPUTE_HPH_R:
-		reg_mask = 0x04;
-		reg_val = (on ? 0x04 : 0x00);
-		break;
-	default:
-		dev_dbg(codec->dev, "%s: class h computation PA request incorrect\n",
-			   __func__);
-		return;
+	if (compute_pa == CLSH_COMPUTE_EAR) {
+		snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL, 0x10,
+				    (on ? 0x10 : 0));
+	} else {
+		if (compute_pa == CLSH_COMPUTE_HPH_L) {
+			shift = 3;
+		} else if (compute_pa == CLSH_COMPUTE_HPH_R) {
+			shift = 2;
+		} else {
+			dev_dbg(codec->dev,
+				"%s: classh computation request is incorrect\n",
+				__func__);
+			return;
+		}
+
+		if (on)
+			wcd9xxx_resmgr_add_cond_update_bits(clsh_d->resmgr,
+						  WCD9XXX_COND_HPH,
+						  WCD9XXX_A_CDC_CLSH_B1_CTL,
+						  shift, false);
+		else
+			wcd9xxx_resmgr_rm_cond_update_bits(clsh_d->resmgr,
+						  WCD9XXX_COND_HPH,
+						  WCD9XXX_A_CDC_CLSH_B1_CTL,
+						  shift, false);
 	}
-
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
-						reg_mask, reg_val);
-
 }
 
 static void wcd9xxx_enable_buck_mode(struct snd_soc_codec *codec,
@@ -355,12 +360,12 @@
 		if (req_state == WCD9XXX_CLSH_STATE_EAR) {
 			wcd9xxx_clsh_turnoff_postpa(codec);
 		} else if (req_state == WCD9XXX_CLSH_STATE_HPHL) {
-			wcd9xxx_clsh_computation_request(codec,
-				CLSH_COMPUTE_HPH_L, false);
+			wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L,
+					      false);
 			wcd9xxx_clsh_turnoff_postpa(codec);
 		} else if (req_state == WCD9XXX_CLSH_STATE_HPHR) {
-			wcd9xxx_clsh_computation_request(codec,
-				CLSH_COMPUTE_HPH_R, false);
+			wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R,
+					      false);
 			wcd9xxx_clsh_turnoff_postpa(codec);
 		} else if (req_state == WCD9XXX_CLSH_STATE_LO) {
 			wcd9xxx_enable_ncp(codec, false);
@@ -380,8 +385,7 @@
 		wcd9xxx_enable_clsh_block(codec, true);
 		wcd9xxx_chargepump_request(codec, true);
 		wcd9xxx_enable_anc_delay(codec, true);
-		wcd9xxx_clsh_computation_request(codec,
-				CLSH_COMPUTE_EAR, true);
+		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_EAR, true);
 		wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
 		wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
 
@@ -402,16 +406,15 @@
 		wcd9xxx_enable_clsh_block(codec, true);
 		wcd9xxx_chargepump_request(codec, true);
 		wcd9xxx_enable_anc_delay(codec, true);
-		wcd9xxx_clsh_computation_request(codec,
-				CLSH_COMPUTE_HPH_L, true);
+		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, true);
 		wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
 		wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
 
 		dev_dbg(codec->dev, "%s: Done\n", __func__);
 	} else {
 		if (req_state == WCD9XXX_CLSH_STATE_HPHR) {
-			wcd9xxx_clsh_computation_request(codec,
-				CLSH_COMPUTE_HPH_R, false);
+			wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R,
+					      false);
 		} else {
 			dev_dbg(codec->dev, "%s: stub fallback to hph_l\n",
 					__func__);
@@ -431,16 +434,15 @@
 		wcd9xxx_enable_clsh_block(codec, true);
 		wcd9xxx_chargepump_request(codec, true);
 		wcd9xxx_enable_anc_delay(codec, true);
-		wcd9xxx_clsh_computation_request(codec,
-				CLSH_COMPUTE_HPH_R, true);
+		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, true);
 		wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
 		wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
 
 		dev_dbg(codec->dev, "%s: Done\n", __func__);
 	} else {
 		if (req_state == WCD9XXX_CLSH_STATE_HPHL) {
-			wcd9xxx_clsh_computation_request(codec,
-				CLSH_COMPUTE_HPH_L, false);
+			wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L,
+					      false);
 		} else {
 			dev_dbg(codec->dev, "%s: stub fallback to hph_r\n",
 					__func__);
@@ -453,10 +455,8 @@
 		u8 req_state, bool is_enable)
 {
 	if (is_enable) {
-		wcd9xxx_clsh_computation_request(codec,
-				CLSH_COMPUTE_HPH_L, true);
-		wcd9xxx_clsh_computation_request(codec,
-				CLSH_COMPUTE_HPH_R, true);
+		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, true);
+		wcd9xxx_clsh_comp_req(codec, clsh_d,  CLSH_COMPUTE_HPH_R, true);
 	} else {
 		dev_dbg(codec->dev, "%s: stub fallback to hph_st\n", __func__);
 	}
@@ -566,10 +566,12 @@
 }
 EXPORT_SYMBOL_GPL(wcd9xxx_clsh_fsm);
 
-void wcd9xxx_clsh_init(struct wcd9xxx_clsh_cdc_data *clsh)
+void wcd9xxx_clsh_init(struct wcd9xxx_clsh_cdc_data *clsh,
+		       struct wcd9xxx_resmgr *resmgr)
 {
 	int i;
 	clsh->state = WCD9XXX_CLSH_STATE_IDLE;
+	clsh->resmgr = resmgr;
 
 	for (i = 0; i < NUM_CLSH_STATES; i++)
 		clsh_state_fp[i] = wcd9xxx_clsh_state_err;
diff --git a/sound/soc/codecs/wcd9xxx-common.h b/sound/soc/codecs/wcd9xxx-common.h
index 743ab0c..dc00ec6 100644
--- a/sound/soc/codecs/wcd9xxx-common.h
+++ b/sound/soc/codecs/wcd9xxx-common.h
@@ -14,6 +14,8 @@
 
 #define WCD9XXX_CODEC_COMMON
 
+#include "wcd9xxx-resmgr.h"
+
 #define WCD9XXX_CLSH_REQ_ENABLE true
 #define WCD9XXX_CLSH_REQ_DISABLE false
 
@@ -50,6 +52,7 @@
 struct wcd9xxx_clsh_cdc_data {
 	u8 state;
 	int buck_mv;
+	struct wcd9xxx_resmgr *resmgr;
 };
 
 
@@ -63,6 +66,7 @@
 		struct wcd9xxx_clsh_cdc_data *cdc_clsh_d,
 		u8 req_state, bool req_type, u8 clsh_event);
 
-extern void wcd9xxx_clsh_init(struct wcd9xxx_clsh_cdc_data *clsh);
+extern void wcd9xxx_clsh_init(struct wcd9xxx_clsh_cdc_data *clsh,
+			      struct wcd9xxx_resmgr *resmgr);
 
 #endif
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index b3549cc..88f0567 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -85,6 +85,8 @@
 #define WCD9XXX_HPHL_STATUS_READY_WAIT_US 1000
 #define WCD9XXX_MUX_SWITCH_READY_WAIT_US 100
 #define WCD9XXX_MEAS_DELTA_MAX_MV 50
+#define WCD9XXX_MEAS_INVALD_RANGE_LOW_MV 20
+#define WCD9XXX_MEAS_INVALD_RANGE_HIGH_MV 80
 #define WCD9XXX_GM_SWAP_THRES_MIN_MV 150
 #define WCD9XXX_GM_SWAP_THRES_MAX_MV 500
 
@@ -377,10 +379,14 @@
 static void wcd9xxx_jack_report(struct wcd9xxx_mbhc *mbhc,
 				struct snd_soc_jack *jack, int status, int mask)
 {
-	if (jack == &mbhc->headset_jack)
+	if (jack == &mbhc->headset_jack) {
 		wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
 						WCD9XXX_COND_HPH_MIC,
 						status & SND_JACK_MICROPHONE);
+		wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
+						WCD9XXX_COND_HPH,
+						status & SND_JACK_HEADPHONE);
+	}
 
 	snd_soc_jack_report_no_dapm(jack, status, mask);
 }
@@ -1012,6 +1018,20 @@
 			 __func__, i, d->dce, vdce, d->_vdces,
 			 d->swap_gnd, d->vddio, d->hphl_status & 0x01,
 			 d->_type);
+
+
+		/*
+		 * If GND and MIC prongs are aligned to HPHR and GND of
+		 * headphone, codec measures the voltage based on
+		 * impedance between HPHR and GND which results in ~80mv.
+		 * Avoid this.
+		 */
+		if (d->_vdces >= WCD9XXX_MEAS_INVALD_RANGE_LOW_MV &&
+		    d->_vdces <= WCD9XXX_MEAS_INVALD_RANGE_HIGH_MV) {
+			pr_debug("%s: within invalid range\n", __func__);
+			type = PLUG_TYPE_INVALID;
+			goto exit;
+		}
 	}
 	if (ch != size && ch > 0) {
 		pr_debug("%s: Invalid, inconsistent HPHL\n", __func__);
@@ -1616,9 +1636,15 @@
 	 * While we don't know whether MIC is there or not, let the resmgr know
 	 * so micbias can be disabled temporarily
 	 */
-	if (mbhc->current_plug == PLUG_TYPE_HEADSET)
+	if (mbhc->current_plug == PLUG_TYPE_HEADSET) {
 		wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
 						WCD9XXX_COND_HPH_MIC, false);
+		wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
+						WCD9XXX_COND_HPH, false);
+	} else if (mbhc->current_plug == PLUG_TYPE_HEADPHONE) {
+		wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
+						WCD9XXX_COND_HPH, false);
+	}
 
 	vddio = (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
 		 mbhc->mbhc_micbias_switched);
@@ -1639,9 +1665,15 @@
 	if (vddio && (mbhc->current_plug == PLUG_TYPE_HEADSET))
 		__wcd9xxx_switch_micbias(mbhc, 1, true, true);
 
-	if (mbhc->current_plug == PLUG_TYPE_HEADSET)
+	if (mbhc->current_plug == PLUG_TYPE_HEADSET) {
+		wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
+						WCD9XXX_COND_HPH, true);
 		wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
 						WCD9XXX_COND_HPH_MIC, true);
+	} else if (mbhc->current_plug == PLUG_TYPE_HEADPHONE) {
+		wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
+						WCD9XXX_COND_HPH, true);
+	}
 	WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
 
 	return IRQ_HANDLED;
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c
index 2011346..18614d8 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr.c
@@ -688,7 +688,6 @@
 {
 	struct wcd9xxx_resmgr_cond_entry *entry;
 
-	WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
 	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
 	if (!entry)
 		return -ENOMEM;
@@ -697,9 +696,12 @@
 	entry->reg = reg;
 	entry->shift = shift;
 	entry->invert = invert;
+
+	WCD9XXX_BCL_LOCK(resmgr);
 	list_add_tail(&entry->list, &resmgr->update_bit_cond_h);
 
 	wcd9xxx_resmgr_cond_trigger_cond(resmgr, cond);
+	WCD9XXX_BCL_UNLOCK(resmgr);
 
 	return 0;
 }
@@ -717,7 +719,7 @@
 	struct wcd9xxx_resmgr_cond_entry *e = NULL;
 
 	pr_debug("%s: enter\n", __func__);
-	WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
+	WCD9XXX_BCL_LOCK(resmgr);
 	list_for_each_safe(l, next, &resmgr->update_bit_cond_h) {
 		e = list_entry(l, struct wcd9xxx_resmgr_cond_entry, list);
 		if (e->reg == reg && e->shift == shift && e->invert == invert) {
@@ -725,10 +727,12 @@
 					    1 << e->shift,
 					    e->invert << e->shift);
 			list_del(&e->list);
+			WCD9XXX_BCL_UNLOCK(resmgr);
 			kfree(e);
 			return 0;
 		}
 	}
+	WCD9XXX_BCL_UNLOCK(resmgr);
 	pr_err("%s: Cannot find update bit entry reg 0x%x, shift %d\n",
 	       __func__, e ? e->reg : 0, e ? e->shift : 0);
 
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.h b/sound/soc/codecs/wcd9xxx-resmgr.h
index 53c48f6..8acc816 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.h
+++ b/sound/soc/codecs/wcd9xxx-resmgr.h
@@ -193,7 +193,8 @@
 				  const enum wcd9xxx_notify_event e);
 
 enum wcd9xxx_resmgr_cond {
-	WCD9XXX_COND_HPH_MIC = 1,
+	WCD9XXX_COND_HPH = 0x01, /* Headphone */
+	WCD9XXX_COND_HPH_MIC = 0x02, /* Microphone on the headset */
 };
 int wcd9xxx_resmgr_rm_cond_update_bits(struct wcd9xxx_resmgr *resmgr,
 				       enum wcd9xxx_resmgr_cond cond,
diff --git a/sound/soc/msm/mdm9625.c b/sound/soc/msm/mdm9625.c
index eb7366c..2bef1b7 100644
--- a/sound/soc/msm/mdm9625.c
+++ b/sound/soc/msm/mdm9625.c
@@ -749,7 +749,7 @@
 		.name = "MDM9625 Media1",
 		.stream_name = "MultiMedia1",
 		.cpu_dai_name = "MultiMedia1",
-		.platform_name  = "msm-pcm-dsp",
+		.platform_name  = "msm-pcm-dsp.0",
 		.dynamic = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			    SND_SOC_DPCM_TRIGGER_POST},
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index c5cfa11..4462213 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -133,6 +133,7 @@
 struct msm8974_asoc_mach_data {
 	int mclk_gpio;
 	u32 mclk_freq;
+	int us_euro_gpio;
 	struct msm_auxpcm_ctrl *pri_auxpcm_ctrl;
 };
 
@@ -1040,6 +1041,16 @@
 			slim0_rx_sample_rate_get, slim0_rx_sample_rate_put),
 };
 
+static bool msm8974_swap_gnd_mic(struct snd_soc_codec *codec)
+{
+	struct snd_soc_card *card = codec->card;
+	struct msm8974_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	int value = gpio_get_value_cansleep(pdata->us_euro_gpio);
+	pr_debug("%s: swap select switch %d to %d\n", __func__, value, !value);
+	gpio_set_value_cansleep(pdata->us_euro_gpio, !value);
+	return true;
+}
+
 static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
 {
 	int err;
@@ -1984,6 +1995,25 @@
 	return 0;
 }
 
+static int msm8974_prepare_us_euro(struct snd_soc_card *card)
+{
+	struct msm8974_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	int ret;
+	if (pdata->us_euro_gpio) {
+		dev_dbg(card->dev, "%s : us_euro gpio request %d", __func__,
+			pdata->us_euro_gpio);
+		ret = gpio_request(pdata->us_euro_gpio, "TAIKO_CODEC_US_EURO");
+		if (ret) {
+			dev_err(card->dev,
+				"%s: Failed to request taiko US/EURO gpio %d error %d\n",
+				__func__, pdata->us_euro_gpio, ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
 static __devinit int msm8974_asoc_machine_probe(struct platform_device *pdev)
 {
 	struct snd_soc_card *card = &snd_soc_card_msm8974;
@@ -2073,6 +2103,23 @@
 		card->num_links	= ARRAY_SIZE(msm8974_common_dai_links);
 	}
 
+	pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
+				"qcom,us-euro-gpios", 0);
+	if (pdata->us_euro_gpio < 0) {
+		dev_err(&pdev->dev, "Looking up %s property in node %s failed",
+			"qcom,us-euro-gpios",
+			pdev->dev.of_node->full_name);
+	} else {
+		dev_dbg(&pdev->dev, "%s detected %d",
+			"qcom,us-euro-gpios", pdata->us_euro_gpio);
+		mbhc_cfg.swap_gnd_mic = msm8974_swap_gnd_mic;
+	}
+
+	ret = msm8974_prepare_us_euro(card);
+	if (ret)
+		dev_err(&pdev->dev, "msm8974_prepare_us_euro failed (%d)\n",
+			ret);
+
 	mutex_init(&cdc_mclk_mutex);
 	atomic_set(&auxpcm_rsc_ref, 0);
 	spdev = pdev;
@@ -2094,6 +2141,18 @@
 	}
 	return 0;
 err:
+	if (pdata->mclk_gpio > 0) {
+		dev_dbg(&pdev->dev, "%s free gpio %d\n",
+			__func__, pdata->mclk_gpio);
+		gpio_free(pdata->mclk_gpio);
+		pdata->mclk_gpio = 0;
+	}
+	if (pdata->us_euro_gpio > 0) {
+		dev_dbg(&pdev->dev, "%s free us_euro gpio %d\n",
+			__func__, pdata->us_euro_gpio);
+		gpio_free(pdata->us_euro_gpio);
+		pdata->us_euro_gpio = 0;
+	}
 	devm_kfree(&pdev->dev, pdata);
 	return ret;
 }
@@ -2107,6 +2166,7 @@
 		regulator_put(ext_spk_amp_regulator);
 
 	gpio_free(pdata->mclk_gpio);
+	gpio_free(pdata->us_euro_gpio);
 	if (ext_spk_amp_gpio >= 0)
 		gpio_free(ext_spk_amp_gpio);
 
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index 4c50b53..f030d3c 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -1354,10 +1354,17 @@
 	for (i = 0; i < num_copps; i++)
 		send_adm_cal(port_id[i], path);
 
-	for (i = 0; i < num_copps; i++)
-		rtac_add_adm_device(port_id[i],	atomic_read(&this_adm.copp_id
-			[afe_get_port_index(port_id[i])]),
-			path, session_id);
+	for (i = 0; i < num_copps; i++) {
+		int tmp;
+		tmp = afe_get_port_index(port_id[i]);
+		if (tmp >= 0 && tmp < AFE_MAX_PORTS)
+			rtac_add_adm_device(port_id[i],
+				atomic_read(&this_adm.copp_id[tmp]),
+				path, session_id);
+		else
+			pr_debug("%s: Invalid port index %d",
+				__func__, tmp);
+	}
 	return 0;
 
 fail_cmd:
diff --git a/sound/soc/msm/qdsp6v2/audio_ocmem.c b/sound/soc/msm/qdsp6v2/audio_ocmem.c
index 1969fe8..c14cb74 100644
--- a/sound/soc/msm/qdsp6v2/audio_ocmem.c
+++ b/sound/soc/msm/qdsp6v2/audio_ocmem.c
@@ -503,6 +503,7 @@
 		rc = -EINVAL;
 	}
 
+	kfree(voice_ocm_work);
 	return;
 }
 /**
@@ -614,6 +615,7 @@
 		rc = -EINVAL;
 	}
 
+	kfree(audio_ocm_work);
 	return;
 }
 
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index 2d2fe31..d0b5500 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -148,7 +148,6 @@
 		 */
 		snd_pcm_stream_lock_irq(substream);
 		if (snd_pcm_playback_empty(substream)) {
-			atomic_set(&prtd->pending_buffer, 1);
 			runtime->render_flag |= SNDRV_RENDER_STOPPED;
 			stop_playback = 1;
 		}
@@ -1038,7 +1037,6 @@
 				(prtd->out_head + 1) & (runtime->periods - 1);
 
 		runtime->render_flag &= ~SNDRV_RENDER_STOPPED;
-		atomic_set(&prtd->pending_buffer, 0);
 		return 0;
 	}
 	return 0;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
index ae7e76c..3a4a674 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
@@ -536,8 +536,8 @@
 		memset(&tstamp, 0x0, sizeof(struct snd_compr_tstamp));
 		rc = q6asm_get_session_time(prtd->audio_client, &timestamp);
 		if (rc < 0) {
-			pr_err("%s: Get Session Time return value =%lld\n",
-				__func__, timestamp);
+			pr_err("%s: Fail to get session time stamp, rc:%d\n",
+							__func__, rc);
 			return -EAGAIN;
 		}
 		temp = (timestamp * 2 * runtime->channels);
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 913dded..b32daaa 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -223,6 +223,12 @@
 	adm_params->hdr.dest_svc = APR_SVC_ADM;
 	adm_params->hdr.dest_domain = APR_DOMAIN_ADSP;
 	index = afe_get_port_index(port_id);
+	if (index < 0 || index >= AFE_MAX_PORTS) {
+		pr_err("%s: invalid port idx %d portid %#x\n",
+				__func__, index, port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
 	adm_params->hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
 	adm_params->hdr.token = port_id;
 	adm_params->hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
@@ -1011,10 +1017,17 @@
 	for (i = 0; i < num_copps; i++)
 		send_adm_cal(port_id[i], path);
 
-	for (i = 0; i < num_copps; i++)
-		rtac_add_adm_device(port_id[i],	atomic_read(&this_adm.copp_id
-			[afe_get_port_index(port_id[i])]),
-			path, session_id);
+	for (i = 0; i < num_copps; i++) {
+		int tmp;
+		tmp = afe_get_port_index(port_id[i]);
+		if (tmp >= 0 && tmp < AFE_MAX_PORTS)
+			rtac_add_adm_device(port_id[i],
+				atomic_read(&this_adm.copp_id[tmp]),
+				path, session_id);
+		else
+			pr_debug("%s: Invalid port index %d",
+				__func__, tmp);
+	}
 
 fail_cmd:
 	kfree(matrix_map);