Merge "msm: ipc: Change IPC log file name for IPC Router"
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/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index 6aa4ee7..24b6b36 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -44,10 +44,18 @@
 	- 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 {
@@ -79,3 +87,21 @@
 			<&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 c783ac8..aaa731e 100644
--- a/Documentation/devicetree/bindings/regulator/krait-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
@@ -9,6 +9,10 @@
 [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
@@ -42,7 +46,9 @@
 binding, defined in regulator.txt, can also be used.
 
 Example:
-	krait_pdn: krait-pdn {
+	krait_pdn: krait-pdn@f9011000 {
+		reg = <0xf9011000 0x1000>;
+		reg-names = "apcs_gcc";
 		compatible = "qcom,krait-pdn";
 		qcom,use-phase-switching;
 		#address-cells = <1>;
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 2cdc7ff..a1510f3 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -52,6 +52,8 @@
 - 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),
@@ -107,6 +109,8 @@
 
 Optional properties :
 - qcom,usb2-enable-hsphy2: If present, select second PHY for USB operation.
+- qcom,pool-64-bit-align: If present then the pool's memory will be aligned
+  to 64 bits
 
 Example MSM HSUSB EHCI controller device node :
 	ehci: qcom,ehci-host@f9a55000 {
diff --git a/Documentation/hid/uhid.txt b/Documentation/hid/uhid.txt
new file mode 100644
index 0000000..4627c42
--- /dev/null
+++ b/Documentation/hid/uhid.txt
@@ -0,0 +1,169 @@
+      UHID - User-space I/O driver support for HID subsystem
+     ========================================================
+
+The HID subsystem needs two kinds of drivers. In this document we call them:
+
+ 1. The "HID I/O Driver" is the driver that performs raw data I/O to the
+    low-level device. Internally, they register an hid_ll_driver structure with
+    the HID core. They perform device setup, read raw data from the device and
+    push it into the HID subsystem and they provide a callback so the HID
+    subsystem can send data to the device.
+
+ 2. The "HID Device Driver" is the driver that parses HID reports and reacts on
+    them. There are generic drivers like "generic-usb" and "generic-bluetooth"
+    which adhere to the HID specification and provide the standardizes features.
+    But there may be special drivers and quirks for each non-standard device out
+    there. Internally, they use the hid_driver structure.
+
+Historically, the USB stack was the first subsystem to provide an HID I/O
+Driver. However, other standards like Bluetooth have adopted the HID specs and
+may provide HID I/O Drivers, too. The UHID driver allows to implement HID I/O
+Drivers in user-space and feed the data into the kernel HID-subsystem.
+
+This allows user-space to operate on the same level as USB-HID, Bluetooth-HID
+and similar. It does not provide a way to write HID Device Drivers, though. Use
+hidraw for this purpose.
+
+There is an example user-space application in ./samples/uhid/uhid-example.c
+
+The UHID API
+------------
+
+UHID is accessed through a character misc-device. The minor-number is allocated
+dynamically so you need to rely on udev (or similar) to create the device node.
+This is /dev/uhid by default.
+
+If a new device is detected by your HID I/O Driver and you want to register this
+device with the HID subsystem, then you need to open /dev/uhid once for each
+device you want to register. All further communication is done by read()'ing or
+write()'ing "struct uhid_event" objects. Non-blocking operations are supported
+by setting O_NONBLOCK.
+
+struct uhid_event {
+        __u32 type;
+        union {
+                struct uhid_create_req create;
+                struct uhid_data_req data;
+                ...
+        } u;
+};
+
+The "type" field contains the ID of the event. Depending on the ID different
+payloads are sent. You must not split a single event across multiple read()'s or
+multiple write()'s. A single event must always be sent as a whole. Furthermore,
+only a single event can be sent per read() or write(). Pending data is ignored.
+If you want to handle multiple events in a single syscall, then use vectored
+I/O with readv()/writev().
+
+The first thing you should do is sending an UHID_CREATE event. This will
+register the device. UHID will respond with an UHID_START event. You can now
+start sending data to and reading data from UHID. However, unless UHID sends the
+UHID_OPEN event, the internally attached HID Device Driver has no user attached.
+That is, you might put your device asleep unless you receive the UHID_OPEN
+event. If you receive the UHID_OPEN event, you should start I/O. If the last
+user closes the HID device, you will receive an UHID_CLOSE event. This may be
+followed by an UHID_OPEN event again and so on. There is no need to perform
+reference-counting in user-space. That is, you will never receive multiple
+UHID_OPEN events without an UHID_CLOSE event. The HID subsystem performs
+ref-counting for you.
+You may decide to ignore UHID_OPEN/UHID_CLOSE, though. I/O is allowed even
+though the device may have no users.
+
+If you want to send data to the HID subsystem, you send an HID_INPUT event with
+your raw data payload. If the kernel wants to send data to the device, you will
+read an UHID_OUTPUT or UHID_OUTPUT_EV event.
+
+If your device disconnects, you should send an UHID_DESTROY event. This will
+unregister the device. You can now send UHID_CREATE again to register a new
+device.
+If you close() the fd, the device is automatically unregistered and destroyed
+internally.
+
+write()
+-------
+write() allows you to modify the state of the device and feed input data into
+the kernel. The following types are supported: UHID_CREATE, UHID_DESTROY and
+UHID_INPUT. The kernel will parse the event immediately and if the event ID is
+not supported, it will return -EOPNOTSUPP. If the payload is invalid, then
+-EINVAL is returned, otherwise, the amount of data that was read is returned and
+the request was handled successfully.
+
+  UHID_CREATE:
+  This creates the internal HID device. No I/O is possible until you send this
+  event to the kernel. The payload is of type struct uhid_create_req and
+  contains information about your device. You can start I/O now.
+
+  UHID_DESTROY:
+  This destroys the internal HID device. No further I/O will be accepted. There
+  may still be pending messages that you can receive with read() but no further
+  UHID_INPUT events can be sent to the kernel.
+  You can create a new device by sending UHID_CREATE again. There is no need to
+  reopen the character device.
+
+  UHID_INPUT:
+  You must send UHID_CREATE before sending input to the kernel! This event
+  contains a data-payload. This is the raw data that you read from your device.
+  The kernel will parse the HID reports and react on it.
+
+  UHID_FEATURE_ANSWER:
+  If you receive a UHID_FEATURE request you must answer with this request. You
+  must copy the "id" field from the request into the answer. Set the "err" field
+  to 0 if no error occured or to EIO if an I/O error occurred.
+  If "err" is 0 then you should fill the buffer of the answer with the results
+  of the feature request and set "size" correspondingly.
+
+read()
+------
+read() will return a queued ouput report. These output reports can be of type
+UHID_START, UHID_STOP, UHID_OPEN, UHID_CLOSE, UHID_OUTPUT or UHID_OUTPUT_EV. No
+reaction is required to any of them but you should handle them according to your
+needs. Only UHID_OUTPUT and UHID_OUTPUT_EV have payloads.
+
+  UHID_START:
+  This is sent when the HID device is started. Consider this as an answer to
+  UHID_CREATE. This is always the first event that is sent.
+
+  UHID_STOP:
+  This is sent when the HID device is stopped. Consider this as an answer to
+  UHID_DESTROY.
+  If the kernel HID device driver closes the device manually (that is, you
+  didn't send UHID_DESTROY) then you should consider this device closed and send
+  an UHID_DESTROY event. You may want to reregister your device, though. This is
+  always the last message that is sent to you unless you reopen the device with
+  UHID_CREATE.
+
+  UHID_OPEN:
+  This is sent when the HID device is opened. That is, the data that the HID
+  device provides is read by some other process. You may ignore this event but
+  it is useful for power-management. As long as you haven't received this event
+  there is actually no other process that reads your data so there is no need to
+  send UHID_INPUT events to the kernel.
+
+  UHID_CLOSE:
+  This is sent when there are no more processes which read the HID data. It is
+  the counterpart of UHID_OPEN and you may as well ignore this event.
+
+  UHID_OUTPUT:
+  This is sent if the HID device driver wants to send raw data to the I/O
+  device. You should read the payload and forward it to the device. The payload
+  is of type "struct uhid_data_req".
+  This may be received even though you haven't received UHID_OPEN, yet.
+
+  UHID_OUTPUT_EV:
+  Same as UHID_OUTPUT but this contains a "struct input_event" as payload. This
+  is called for force-feedback, LED or similar events which are received through
+  an input device by the HID subsystem. You should convert this into raw reports
+  and send them to your device similar to events of type UHID_OUTPUT.
+
+  UHID_FEATURE:
+  This event is sent if the kernel driver wants to perform a feature request as
+  described in the HID specs. The report-type and report-number are available in
+  the payload.
+  The kernel serializes feature requests so there will never be two in parallel.
+  However, if you fail to respond with a UHID_FEATURE_ANSWER in a time-span of 5
+  seconds, then the requests will be dropped and a new one might be sent.
+  Therefore, the payload also contains an "id" field that identifies every
+  request.
+
+Document by:
+  David Herrmann <dh.herrmann@googlemail.com>
diff --git a/MAINTAINERS b/MAINTAINERS
index b362709..5f8ab49 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6855,6 +6855,13 @@
 F:	Documentation/filesystems/ufs.txt
 F:	fs/ufs/
 
+UHID USERSPACE HID IO DRIVER:
+M:	David Herrmann <dh.herrmann@googlemail.com>
+L:	linux-input@vger.kernel.org
+S:	Maintained
+F:	drivers/hid/uhid.c
+F:	include/linux/uhid.h
+
 ULTRA-WIDEBAND (UWB) SUBSYSTEM:
 L:	linux-usb@vger.kernel.org
 S:	Orphan
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/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 6a07bad..44ece9e 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -49,6 +49,109 @@
 			};
 		};
 
+		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";
@@ -498,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-cdp.dts b/arch/arm/boot/dts/msm8226-cdp.dts
index f01491f..a2707ee 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-cdp.dts
@@ -85,3 +85,79 @@
 
 	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-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 0242540..43f6685 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-mtp.dts
@@ -82,3 +82,79 @@
 
 	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 65d4b33..482a5da 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-qrd.dts
@@ -85,3 +85,79 @@
 
 	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 741ffbd..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";
@@ -92,7 +94,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";
@@ -346,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";
 
@@ -592,6 +594,12 @@
 		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 {
@@ -709,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-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-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 6e2719b..4dd92b98 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -738,3 +738,40 @@
 		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 2dad8e7..5eff79c 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -423,7 +423,9 @@
 };
 
 / {
-	krait_pdn: krait-pdn {
+	krait_pdn: krait-pdn@f9011000 {
+		reg = <0xf9011000 0x1000>;
+		reg-names = "apcs_gcc";
 		compatible = "qcom,krait-pdn";
 		#address-cells = <1>;
 		#size-cells = <1>;
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 64014b3..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 {
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 3dda20f..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 {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 7c6a9d1..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,10 @@
 	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 {
@@ -333,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>,
@@ -1170,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";
 
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 8517605..e1501ac 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -91,6 +91,7 @@
 		qcom,hsusb-otg-disable-reset;
 		qcom,hsusb-otg-lpm-on-dev-suspend;
 		qcom,hsusb-otg-clk-always-on-workaround;
+		qcom,hsusb-otg-delay-lpm;
 
 		qcom,msm-bus,name = "usb2";
 		qcom,msm-bus,num-cases = <2>;
@@ -104,8 +105,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>;
 
@@ -634,7 +635,7 @@
 	qcom,smem@fa00000 {
 		compatible = "qcom,smem";
 		reg = <0xfa00000 0x200000>,
-			<0xfa006000 0x1000>,
+			<0xf9011000 0x1000>,
 			<0xfc428000 0x4000>;
 		reg-names = "smem", "irq-reg-base", "aux-mem1";
 
@@ -718,6 +719,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/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 df4ae19..14bd1b4 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -114,6 +114,8 @@
 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
@@ -151,6 +153,9 @@
 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
 CONFIG_REGULATOR=y
@@ -160,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
@@ -185,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
@@ -238,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 d36d5a2..c6be3c5 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -393,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
@@ -429,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
@@ -442,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 df0b5f0..f77f04f 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -401,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
@@ -438,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/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/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index b10212e..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
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/board-8064.c b/arch/arm/mach-msm/board-8064.c
index f3d648e..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")
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-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 3df0b38..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();
@@ -3556,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/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 119eeb2..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
 
@@ -1801,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),
 	},
@@ -1990,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),
 	},
@@ -3197,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"),
@@ -3463,6 +3478,12 @@
 	enable_rpm_scaling();
 
 	reg_init();
+
+	/*
+	 * 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 msm8226_clock_late_init(void)
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 4cef377..3587df6 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -3030,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,
@@ -3324,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,
@@ -3385,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,
@@ -5525,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) {
@@ -5693,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/ipa.h b/arch/arm/mach-msm/include/mach/ipa.h
index f2a4427..2010abb 100644
--- a/arch/arm/mach-msm/include/mach/ipa.h
+++ b/arch/arm/mach-msm/include/mach/ipa.h
@@ -355,36 +355,6 @@
 };
 
 /**
- * enum ipa_rm_resource_name - IPA RM clients identification names
- *
- * Add new mapping to ipa_rm_dep_prod_index() / ipa_rm_dep_cons_index()
- * when adding new entry to this enum.
- */
-enum ipa_rm_resource_name {
-	IPA_RM_RESOURCE_PROD = 0,
-	IPA_RM_RESOURCE_BRIDGE_PROD = IPA_RM_RESOURCE_PROD,
-	IPA_RM_RESOURCE_A2_PROD,
-	IPA_RM_RESOURCE_USB_PROD,
-	IPA_RM_RESOURCE_HSIC_PROD,
-	IPA_RM_RESOURCE_STD_ECM_PROD,
-	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,
-	IPA_RM_RESOURCE_WLAN_PROD,
-	IPA_RM_RESOURCE_PROD_MAX,
-
-	IPA_RM_RESOURCE_A2_CONS = IPA_RM_RESOURCE_PROD_MAX,
-	IPA_RM_RESOURCE_USB_CONS,
-	IPA_RM_RESOURCE_HSIC_CONS,
-	IPA_RM_RESOURCE_MAX
-};
-
-/**
  * enum ipa_rm_event - IPA RM events
  *
  * Indicate the resource state change
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/include/mach/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
index a7f052e..b3fb8af 100644
--- a/arch/arm/mach-msm/include/mach/usb_bam.h
+++ b/arch/arm/mach-msm/include/mach/usb_bam.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -163,12 +163,6 @@
  */
 int usb_bam_client_ready(bool ready);
 
-/**
- * Returns QDSS BAM connection number
- *
- */
-u8 usb_bam_get_qdss_num(void);
-
 #else
 static inline int usb_bam_connect(u8 idx, u32 *src_pipe_idx, u32 *dst_pipe_idx)
 {
@@ -222,10 +216,5 @@
 	return -ENODEV;
 }
 
-static inline u8 usb_bam_get_qdss_num(void)
-{
-	return -ENODEV;
-}
-
 #endif
 #endif				/* _USB_BAM_H_ */
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index dc0b755..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;
@@ -156,6 +157,7 @@
 	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;
@@ -890,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);
 }
 
@@ -1117,6 +1119,7 @@
 	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");
@@ -1132,6 +1135,18 @@
 		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;
@@ -1146,7 +1161,7 @@
 	pr_debug("name=%s inited\n", pvreg->name);
 
 	/* global initializtion */
-	glb_init(pdev);
+	glb_init(pvreg->apcs_gcc_base);
 
 	rc = of_platform_populate(node, NULL, NULL, dev);
 	if (rc) {
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/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/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/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/init.c b/arch/arm/mm/init.c
index bf59a9d..38da432 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -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/mmu.c b/arch/arm/mm/mmu.c
index 25cb67c..0e31910 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -940,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];
diff --git a/drivers/bif/Kconfig b/drivers/bif/Kconfig
index 502b92b..d9828c5 100644
--- a/drivers/bif/Kconfig
+++ b/drivers/bif/Kconfig
@@ -10,3 +10,17 @@
 	  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
index 02528c1..7604ca7 100644
--- a/drivers/bif/Makefile
+++ b/drivers/bif/Makefile
@@ -2,3 +2,4 @@
 # Makefile for kernel BIF framework.
 #
 obj-$(CONFIG_BIF)			+= bif-core.o
+obj-$(CONFIG_BIF_QPNP)			+= qpnp-bsi.o
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..1c9f968 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
@@ -107,92 +107,102 @@
 			break;
 		}
 	}
-	if (index == -1)
+	if (index == -1) {
 		pr_alert("diag: No matching PID for DCI data\n");
+		return;
+	}
 	/* Using PID of client process, find client buffer */
-	for (i = 0; i < MAX_DCI_CLIENTS; i++) {
-		if (driver->dci_client_tbl[i].client != NULL) {
-			if (curr_client_pid ==
-				driver->dci_client_tbl[i].client->tgid) {
-				/* copy pkt rsp in client buf */
-				entry = &(driver->dci_client_tbl[i]);
-				if (DCI_CHK_CAPACITY(entry, 8+write_len)) {
-					pr_alert("diag: create capacity for pkt rsp\n");
-					entry->total_capacity += 8+write_len;
-					temp_buf = krealloc(entry->dci_data,
-					entry->total_capacity, GFP_KERNEL);
-					if (!temp_buf) {
-						pr_err("diag: DCI realloc failed\n");
-						break;
-					} else {
-						entry->dci_data = temp_buf;
-					}
-				}
-				*(int *)(entry->dci_data+entry->data_len) =
-							DCI_PKT_RSP_TYPE;
-				entry->data_len += 4;
-				*(int *)(entry->dci_data+entry->data_len)
-								= write_len;
-				entry->data_len += 4;
-				memcpy(entry->dci_data+entry->data_len,
-					buf+4+cmd_code_len, write_len);
-				entry->data_len += write_len;
-				/* delete immediate response entry */
-				if (driver->smd_dci[MODEM_DATA].
-					buf_in_1[8+cmd_code_len] != 0x80)
-					driver->req_tracking_tbl[index].pid = 0;
-				break;
+	i = diag_dci_find_client_index(curr_client_pid);
+	if (i != DCI_CLIENT_INDEX_INVALID) {
+		/* copy pkt rsp in client buf */
+		entry = &(driver->dci_client_tbl[i]);
+		if (DCI_CHK_CAPACITY(entry, 8+write_len)) {
+			pr_alert("diag: create capacity for pkt rsp\n");
+			entry->total_capacity += 8+write_len;
+			temp_buf = krealloc(entry->dci_data,
+			entry->total_capacity, GFP_KERNEL);
+			if (!temp_buf) {
+				pr_err("diag: DCI realloc failed\n");
+				return;
+			} else {
+				entry->dci_data = temp_buf;
 			}
 		}
+		*(int *)(entry->dci_data+entry->data_len) =
+					DCI_PKT_RSP_TYPE;
+		entry->data_len += 4;
+		*(int *)(entry->dci_data+entry->data_len)
+						= write_len;
+		entry->data_len += 4;
+		memcpy(entry->dci_data+entry->data_len,
+			buf+4+cmd_code_len, write_len);
+		entry->data_len += write_len;
+		/* delete immediate response entry */
+		if (driver->smd_dci[MODEM_DATA].
+			buf_in_1[8+cmd_code_len] != 0x80)
+			driver->req_tracking_tbl[index].pid = 0;
 	}
 }
 
 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 +215,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 +224,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 +240,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 +278,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);
 			}
 		}
 	}
@@ -519,16 +524,8 @@
 		}
 	} else if (*(int *)temp == DCI_LOG_TYPE) {
 		/* find client id and table */
-		for (i = 0; i < MAX_DCI_CLIENTS; i++) {
-			if (driver->dci_client_tbl[i].client != NULL) {
-				if (driver->dci_client_tbl[i].client->tgid ==
-							current->tgid) {
-					found = 1;
-					break;
-				}
-			}
-		}
-		if (!found) {
+		i = diag_dci_find_client_index(current->tgid);
+		if (i == DCI_CLIENT_INDEX_INVALID) {
 			pr_err("diag: dci client not registered/found\n");
 			return ret;
 		}
@@ -602,16 +599,8 @@
 		ret = diag_send_dci_log_mask(driver->smd_cntl[MODEM_DATA].ch);
 	} else if (*(int *)temp == DCI_EVENT_TYPE) {
 		/* find client id and table */
-		for (i = 0; i < MAX_DCI_CLIENTS; i++) {
-			if (driver->dci_client_tbl[i].client != NULL) {
-				if (driver->dci_client_tbl[i].client->tgid ==
-							current->tgid) {
-					found = 1;
-					break;
-				}
-			}
-		}
-		if (!found) {
+		i = diag_dci_find_client_index(current->tgid);
+		if (i == DCI_CLIENT_INDEX_INVALID) {
 			pr_err("diag: dci client not registered/found\n");
 			return ret;
 		}
@@ -664,6 +653,22 @@
 	return ret;
 }
 
+int diag_dci_find_client_index(int client_id)
+{
+	int i, ret = DCI_CLIENT_INDEX_INVALID;
+
+	for (i = 0; i < MAX_DCI_CLIENTS; i++) {
+		if (driver->dci_client_tbl[i].client != NULL) {
+			if (driver->dci_client_tbl[i].client->tgid ==
+					client_id) {
+				ret = i;
+				break;
+			}
+		}
+	}
+	return ret;
+}
+
 void update_dci_cumulative_event_mask(int offset, uint8_t byte_mask)
 {
 	int i;
@@ -690,6 +695,69 @@
 	mutex_unlock(&dci_event_mask_mutex);
 }
 
+void clear_client_dci_cumulative_event_mask(int client_index)
+{
+	int i, j;
+	uint8_t *update_ptr = dci_cumulative_event_mask;
+	uint8_t *event_mask_ptr, *client_event_mask_ptr, byte_mask = 0;
+	bool is_set = false;
+
+	event_mask_ptr =
+		(driver->dci_client_tbl[client_index].dci_event_mask);
+
+	mutex_lock(&dci_event_mask_mutex);
+	for (i = 0; i < DCI_EVENT_MASK_SIZE; i++) {
+		is_set = false;
+		/* Already cleared event masks need not to be considered */
+		if (*event_mask_ptr != 0) {
+			byte_mask = *event_mask_ptr;
+		} else {
+			update_ptr++;
+			event_mask_ptr++;
+			continue;
+		}
+		for (j = 0; j < MAX_DCI_CLIENTS; j++) {
+			/* continue searching for valid client */
+			if (driver->dci_client_tbl[j].client == NULL ||
+				client_index == j)
+				continue;
+			client_event_mask_ptr =
+				(driver->dci_client_tbl[j].dci_event_mask);
+			client_event_mask_ptr += i;
+			if (*client_event_mask_ptr & byte_mask) {
+				/*
+				* Break if another client has same
+				* event mask set
+				*/
+				if ((*client_event_mask_ptr &
+					byte_mask) == byte_mask) {
+					is_set = true;
+					break;
+				} else {
+					byte_mask =
+					(~(*client_event_mask_ptr) &
+					byte_mask);
+					is_set = false;
+				}
+			}
+		}
+		/*
+		* Clear only if this client has event mask set else
+		* don't update cumulative event mask ptr
+		*/
+		if (is_set == false)
+			*update_ptr &= ~byte_mask;
+
+		update_ptr++;
+		event_mask_ptr++;
+	}
+	event_mask_ptr =
+		(driver->dci_client_tbl[client_index].dci_event_mask);
+	memset(event_mask_ptr, 0, DCI_EVENT_MASK_SIZE);
+	mutex_unlock(&dci_event_mask_mutex);
+}
+
+
 int diag_send_dci_event_mask(smd_channel_t *ch)
 {
 	void *buf = driver->buf_event_mask_update;
@@ -769,6 +837,87 @@
 	mutex_unlock(&dci_log_mask_mutex);
 }
 
+void clear_client_dci_cumulative_log_mask(int client_index)
+{
+	int i, j, k;
+	uint8_t *update_ptr = dci_cumulative_log_mask;
+	uint8_t *log_mask_ptr, *client_log_mask_ptr, byte_mask = 0;
+	bool is_set = false;
+
+	log_mask_ptr = driver->dci_client_tbl[client_index].dci_log_mask;
+
+	mutex_lock(&dci_log_mask_mutex);
+	*update_ptr = 0;
+	/* set the equipment IDs */
+	for (i = 0; i < 16; i++)
+		*(update_ptr + (i*514)) = i;
+
+	/* update cumulative log mask ptr*/
+	update_ptr += 2;
+	log_mask_ptr += 2;
+	for (i = 0; i < 16; i++) {
+		for (j = 0; j < 512; j++) {
+			is_set = false;
+			/*
+			* Already cleared log masks need
+			* not to be considered
+			*/
+			if (*log_mask_ptr != 0) {
+				byte_mask = *log_mask_ptr;
+			} else {
+				update_ptr++;
+				log_mask_ptr++;
+				continue;
+			}
+			for (k = 0; k < MAX_DCI_CLIENTS; k++) {
+				/* continue searching for valid client */
+				if (driver->dci_client_tbl[k].client == NULL ||
+					client_index == k)
+					continue;
+				client_log_mask_ptr =
+				 (driver->dci_client_tbl[k].dci_log_mask);
+				client_log_mask_ptr += (i*514) + 2 + j;
+				if (*client_log_mask_ptr & byte_mask) {
+					/*
+					* Break if another client has same
+					* log mask set
+					*/
+					if ((*client_log_mask_ptr &
+						byte_mask) == byte_mask) {
+						is_set = true;
+						break;
+					} else {
+						byte_mask =
+						 (~(*client_log_mask_ptr) &
+						 byte_mask);
+						is_set = false;
+					}
+				}
+			}
+			/*
+			* Clear only if this client has log mask set else
+			* don't update cumulative log mask ptr
+			*/
+			if (is_set == false) {
+				/*
+				* Update the dirty bit for the equipment
+				* whose mask is changing
+				*/
+				dci_cumulative_log_mask[1+(i*514)] = 1;
+				*update_ptr &= ~byte_mask;
+			}
+
+			update_ptr++;
+			log_mask_ptr++;
+		}
+		update_ptr += 2;
+		log_mask_ptr += 2;
+	}
+	log_mask_ptr = driver->dci_client_tbl[client_index].dci_log_mask;
+	memset(log_mask_ptr, 0, DCI_LOG_MASK_SIZE);
+	mutex_unlock(&dci_log_mask_mutex);
+}
+
 int diag_send_dci_log_mask(smd_channel_t *ch)
 {
 	void *buf = driver->buf_log_mask_update;
@@ -878,10 +1027,12 @@
 	mutex_init(&driver->dci_mutex);
 	mutex_init(&dci_log_mask_mutex);
 	mutex_init(&dci_event_mask_mutex);
-	success = diag_smd_constructor(&driver->smd_dci[MODEM_DATA],
-					MODEM_DATA, SMD_DCI_TYPE);
-	if (!success)
-		goto err;
+	for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
+		success = diag_smd_constructor(&driver->smd_dci[i],
+					i, SMD_DCI_TYPE);
+		if (!success)
+			goto err;
+	}
 
 	if (driver->req_tracking_tbl == NULL) {
 		driver->req_tracking_tbl = kzalloc(dci_max_reg *
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 56d1b91..9187516 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,9 @@
 #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
+#define DCI_CLIENT_INDEX_INVALID -1
+
 
 /* 16 log code categories, each has:
  * 1 bytes equip id + 1 dirty byte + 512 byte max log mask
@@ -86,14 +88,17 @@
 int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
 							 int len, int index);
 void extract_dci_pkt_rsp(unsigned char *buf);
+int diag_dci_find_client_index(int client_id);
 /* DCI Log streaming functions */
 void create_dci_log_mask_tbl(unsigned char *tbl_buf);
 void update_dci_cumulative_log_mask(int offset, unsigned int byte_index,
 						uint8_t byte_mask);
+void clear_client_dci_cumulative_log_mask(int client_index);
 int diag_send_dci_log_mask(smd_channel_t *ch);
 void extract_dci_log(unsigned char *buf);
 /* DCI event streaming functions */
 void update_dci_cumulative_event_mask(int offset, uint8_t byte_mask);
+void clear_client_dci_cumulative_event_mask(int client_index);
 int diag_send_dci_event_mask(smd_channel_t *ch);
 void extract_dci_events(unsigned char *buf);
 void create_dci_event_mask_tbl(unsigned char *tbl_buf);
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 13e52df..2809900 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -245,7 +245,7 @@
 
 static int diagchar_close(struct inode *inode, struct file *file)
 {
-	int i = 0;
+	int i = -1;
 	struct diagchar_priv *diagpriv_data = file->private_data;
 
 	pr_debug("diag: process exit %s\n", current->comm);
@@ -261,14 +261,9 @@
 	* This will specially help in case of ungraceful exit of any DCI client
 	* This call will remove any pending registrations of such client
 	*/
-	for (i = 0; i < MAX_DCI_CLIENTS; i++) {
-		if (driver->dci_client_tbl[i].client &&
-			driver->dci_client_tbl[i].client->tgid ==
-							 current->tgid) {
-			diagchar_ioctl(NULL, DIAG_IOCTL_DCI_DEINIT, 0);
-			break;
-		}
-	}
+	if (diag_dci_find_client_index(current->tgid) !=
+		 DCI_CLIENT_INDEX_INVALID)
+		diagchar_ioctl(NULL, DIAG_IOCTL_DCI_DEINIT, 0);
 	/* If the exiting process is the socket process */
 	if (driver->socket_process &&
 		(driver->socket_process->tgid == current->tgid)) {
@@ -530,7 +525,7 @@
 long diagchar_ioctl(struct file *filp,
 			   unsigned int iocmd, unsigned long ioarg)
 {
-	int i, j, temp, success = -1, status;
+	int i, j, temp, success = -1, status, index = -1;
 	unsigned int count_entries = 0, interim_count = 0;
 	void *temp_buf;
 	uint16_t support_list = 0;
@@ -731,19 +726,40 @@
 		return driver->dci_client_id;
 	} else if (iocmd == DIAG_IOCTL_DCI_DEINIT) {
 		success = -1;
-		/* Delete this process from DCI table */
+		/*
+		* Clear log/event masks and send updated
+		* masks to peripherals
+		*/
 		mutex_lock(&driver->dci_mutex);
+		index = diag_dci_find_client_index(current->tgid);
+		if (index != DCI_CLIENT_INDEX_INVALID) {
+			/* clear respective cumulative log masks */
+			clear_client_dci_cumulative_log_mask(index);
+			/* send updated log mask to peripherals */
+			success =
+			diag_send_dci_log_mask(driver->smd_cntl[MODEM_DATA].ch);
+			if (success != DIAG_DCI_NO_ERROR) {
+				mutex_unlock(&driver->dci_mutex);
+				return success;
+			}
+			/* clear respective cumulative event masks */
+			clear_client_dci_cumulative_event_mask(index);
+			/* send updated event mask to peripherals */
+			success =
+			diag_send_dci_event_mask(
+				driver->smd_cntl[MODEM_DATA].ch);
+			if (success != DIAG_DCI_NO_ERROR) {
+				mutex_unlock(&driver->dci_mutex);
+				return success;
+			}
+		}
+		/* Delete this process from DCI table */
 		for (i = 0; i < dci_max_reg; i++)
 			if (driver->req_tracking_tbl[i].pid == current->tgid)
 				driver->req_tracking_tbl[i].pid = 0;
-		for (i = 0; i < MAX_DCI_CLIENTS; i++) {
-			if (driver->dci_client_tbl[i].client &&
-			driver->dci_client_tbl[i].client->tgid ==
-							 current->tgid) {
-				driver->dci_client_tbl[i].client = NULL;
-				success = i;
-				break;
-			}
+		if (index != DCI_CLIENT_INDEX_INVALID) {
+			driver->dci_client_tbl[index].client = NULL;
+			success = index;
 		}
 		if (success >= 0)
 			driver->num_dci_client--;
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/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/hid/uhid.c b/drivers/hid/uhid.c
index 05ef4b0..714cd8c 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -28,13 +28,26 @@
 #define UHID_BUFSIZE	32
 
 struct uhid_device {
+	struct mutex devlock;
+	bool running;
+
+	__u8 *rd_data;
+	uint rd_size;
+
 	struct hid_device *hid;
+	struct uhid_event input_buf;
 
 	wait_queue_head_t waitq;
 	spinlock_t qlock;
 	__u8 head;
 	__u8 tail;
 	struct uhid_event *outq[UHID_BUFSIZE];
+
+	struct mutex report_lock;
+	wait_queue_head_t report_wait;
+	atomic_t report_done;
+	atomic_t report_id;
+	struct uhid_event report_buf;
 };
 
 static struct miscdevice uhid_misc;
@@ -73,6 +86,316 @@
 	return 0;
 }
 
+static int uhid_hid_start(struct hid_device *hid)
+{
+	struct uhid_device *uhid = hid->driver_data;
+
+	return uhid_queue_event(uhid, UHID_START);
+}
+
+static void uhid_hid_stop(struct hid_device *hid)
+{
+	struct uhid_device *uhid = hid->driver_data;
+
+	hid->claimed = 0;
+	uhid_queue_event(uhid, UHID_STOP);
+}
+
+static int uhid_hid_open(struct hid_device *hid)
+{
+	struct uhid_device *uhid = hid->driver_data;
+
+	return uhid_queue_event(uhid, UHID_OPEN);
+}
+
+static void uhid_hid_close(struct hid_device *hid)
+{
+	struct uhid_device *uhid = hid->driver_data;
+
+	uhid_queue_event(uhid, UHID_CLOSE);
+}
+
+static int uhid_hid_input(struct input_dev *input, unsigned int type,
+			  unsigned int code, int value)
+{
+	struct hid_device *hid = input_get_drvdata(input);
+	struct uhid_device *uhid = hid->driver_data;
+	unsigned long flags;
+	struct uhid_event *ev;
+
+	ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+	if (!ev)
+		return -ENOMEM;
+
+	ev->type = UHID_OUTPUT_EV;
+	ev->u.output_ev.type = type;
+	ev->u.output_ev.code = code;
+	ev->u.output_ev.value = value;
+
+	spin_lock_irqsave(&uhid->qlock, flags);
+	uhid_queue(uhid, ev);
+	spin_unlock_irqrestore(&uhid->qlock, flags);
+
+	return 0;
+}
+
+static int uhid_hid_parse(struct hid_device *hid)
+{
+	struct uhid_device *uhid = hid->driver_data;
+
+	return hid_parse_report(hid, uhid->rd_data, uhid->rd_size);
+}
+
+static int uhid_hid_get_raw(struct hid_device *hid, unsigned char rnum,
+			    __u8 *buf, size_t count, unsigned char rtype)
+{
+	struct uhid_device *uhid = hid->driver_data;
+	__u8 report_type;
+	struct uhid_event *ev;
+	unsigned long flags;
+	int ret;
+	size_t uninitialized_var(len);
+	struct uhid_feature_answer_req *req;
+
+	if (!uhid->running)
+		return -EIO;
+
+	switch (rtype) {
+	case HID_FEATURE_REPORT:
+		report_type = UHID_FEATURE_REPORT;
+		break;
+	case HID_OUTPUT_REPORT:
+		report_type = UHID_OUTPUT_REPORT;
+		break;
+	case HID_INPUT_REPORT:
+		report_type = UHID_INPUT_REPORT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = mutex_lock_interruptible(&uhid->report_lock);
+	if (ret)
+		return ret;
+
+	ev = kzalloc(sizeof(*ev), GFP_KERNEL);
+	if (!ev) {
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	spin_lock_irqsave(&uhid->qlock, flags);
+	ev->type = UHID_FEATURE;
+	ev->u.feature.id = atomic_inc_return(&uhid->report_id);
+	ev->u.feature.rnum = rnum;
+	ev->u.feature.rtype = report_type;
+
+	atomic_set(&uhid->report_done, 0);
+	uhid_queue(uhid, ev);
+	spin_unlock_irqrestore(&uhid->qlock, flags);
+
+	ret = wait_event_interruptible_timeout(uhid->report_wait,
+				atomic_read(&uhid->report_done), 5 * HZ);
+
+	/*
+	 * Make sure "uhid->running" is cleared on shutdown before
+	 * "uhid->report_done" is set.
+	 */
+	smp_rmb();
+	if (!ret || !uhid->running) {
+		ret = -EIO;
+	} else if (ret < 0) {
+		ret = -ERESTARTSYS;
+	} else {
+		spin_lock_irqsave(&uhid->qlock, flags);
+		req = &uhid->report_buf.u.feature_answer;
+
+		if (req->err) {
+			ret = -EIO;
+		} else {
+			ret = 0;
+			len = min(count,
+				min_t(size_t, req->size, UHID_DATA_MAX));
+			memcpy(buf, req->data, len);
+		}
+
+		spin_unlock_irqrestore(&uhid->qlock, flags);
+	}
+
+	atomic_set(&uhid->report_done, 1);
+
+unlock:
+	mutex_unlock(&uhid->report_lock);
+	return ret ? ret : len;
+}
+
+static int uhid_hid_output_raw(struct hid_device *hid, __u8 *buf, size_t count,
+			       unsigned char report_type)
+{
+	struct uhid_device *uhid = hid->driver_data;
+	__u8 rtype;
+	unsigned long flags;
+	struct uhid_event *ev;
+
+	switch (report_type) {
+	case HID_FEATURE_REPORT:
+		rtype = UHID_FEATURE_REPORT;
+		break;
+	case HID_OUTPUT_REPORT:
+		rtype = UHID_OUTPUT_REPORT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (count < 1 || count > UHID_DATA_MAX)
+		return -EINVAL;
+
+	ev = kzalloc(sizeof(*ev), GFP_KERNEL);
+	if (!ev)
+		return -ENOMEM;
+
+	ev->type = UHID_OUTPUT;
+	ev->u.output.size = count;
+	ev->u.output.rtype = rtype;
+	memcpy(ev->u.output.data, buf, count);
+
+	spin_lock_irqsave(&uhid->qlock, flags);
+	uhid_queue(uhid, ev);
+	spin_unlock_irqrestore(&uhid->qlock, flags);
+
+	return count;
+}
+
+static struct hid_ll_driver uhid_hid_driver = {
+	.start = uhid_hid_start,
+	.stop = uhid_hid_stop,
+	.open = uhid_hid_open,
+	.close = uhid_hid_close,
+	.hidinput_input_event = uhid_hid_input,
+	.parse = uhid_hid_parse,
+};
+
+static int uhid_dev_create(struct uhid_device *uhid,
+			   const struct uhid_event *ev)
+{
+	struct hid_device *hid;
+	int ret;
+
+	if (uhid->running)
+		return -EALREADY;
+
+	uhid->rd_size = ev->u.create.rd_size;
+	if (uhid->rd_size <= 0 || uhid->rd_size > HID_MAX_DESCRIPTOR_SIZE)
+		return -EINVAL;
+
+	uhid->rd_data = kmalloc(uhid->rd_size, GFP_KERNEL);
+	if (!uhid->rd_data)
+		return -ENOMEM;
+
+	if (copy_from_user(uhid->rd_data, ev->u.create.rd_data,
+			   uhid->rd_size)) {
+		ret = -EFAULT;
+		goto err_free;
+	}
+
+	hid = hid_allocate_device();
+	if (IS_ERR(hid)) {
+		ret = PTR_ERR(hid);
+		goto err_free;
+	}
+
+	strncpy(hid->name, ev->u.create.name, 127);
+	hid->name[127] = 0;
+	strncpy(hid->phys, ev->u.create.phys, 63);
+	hid->phys[63] = 0;
+	strncpy(hid->uniq, ev->u.create.uniq, 63);
+	hid->uniq[63] = 0;
+
+	hid->ll_driver = &uhid_hid_driver;
+	hid->hid_get_raw_report = uhid_hid_get_raw;
+	hid->hid_output_raw_report = uhid_hid_output_raw;
+	hid->bus = ev->u.create.bus;
+	hid->vendor = ev->u.create.vendor;
+	hid->product = ev->u.create.product;
+	hid->version = ev->u.create.version;
+	hid->country = ev->u.create.country;
+	hid->driver_data = uhid;
+	hid->dev.parent = uhid_misc.this_device;
+
+	uhid->hid = hid;
+	uhid->running = true;
+
+	ret = hid_add_device(hid);
+	if (ret) {
+		hid_err(hid, "Cannot register HID device\n");
+		goto err_hid;
+	}
+
+	return 0;
+
+err_hid:
+	hid_destroy_device(hid);
+	uhid->hid = NULL;
+	uhid->running = false;
+err_free:
+	kfree(uhid->rd_data);
+	return ret;
+}
+
+static int uhid_dev_destroy(struct uhid_device *uhid)
+{
+	if (!uhid->running)
+		return -EINVAL;
+
+	/* clear "running" before setting "report_done" */
+	uhid->running = false;
+	smp_wmb();
+	atomic_set(&uhid->report_done, 1);
+	wake_up_interruptible(&uhid->report_wait);
+
+	hid_destroy_device(uhid->hid);
+	kfree(uhid->rd_data);
+
+	return 0;
+}
+
+static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev)
+{
+	if (!uhid->running)
+		return -EINVAL;
+
+	hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input.data,
+			 min_t(size_t, ev->u.input.size, UHID_DATA_MAX), 0);
+
+	return 0;
+}
+
+static int uhid_dev_feature_answer(struct uhid_device *uhid,
+				   struct uhid_event *ev)
+{
+	unsigned long flags;
+
+	if (!uhid->running)
+		return -EINVAL;
+
+	spin_lock_irqsave(&uhid->qlock, flags);
+
+	/* id for old report; drop it silently */
+	if (atomic_read(&uhid->report_id) != ev->u.feature_answer.id)
+		goto unlock;
+	if (atomic_read(&uhid->report_done))
+		goto unlock;
+
+	memcpy(&uhid->report_buf, ev, sizeof(*ev));
+	atomic_set(&uhid->report_done, 1);
+	wake_up_interruptible(&uhid->report_wait);
+
+unlock:
+	spin_unlock_irqrestore(&uhid->qlock, flags);
+	return 0;
+}
+
 static int uhid_char_open(struct inode *inode, struct file *file)
 {
 	struct uhid_device *uhid;
@@ -81,8 +404,13 @@
 	if (!uhid)
 		return -ENOMEM;
 
+	mutex_init(&uhid->devlock);
+	mutex_init(&uhid->report_lock);
 	spin_lock_init(&uhid->qlock);
 	init_waitqueue_head(&uhid->waitq);
+	init_waitqueue_head(&uhid->report_wait);
+	uhid->running = false;
+	atomic_set(&uhid->report_done, 1);
 
 	file->private_data = uhid;
 	nonseekable_open(inode, file);
@@ -95,6 +423,8 @@
 	struct uhid_device *uhid = file->private_data;
 	unsigned int i;
 
+	uhid_dev_destroy(uhid);
+
 	for (i = 0; i < UHID_BUFSIZE; ++i)
 		kfree(uhid->outq[i]);
 
@@ -106,17 +436,106 @@
 static ssize_t uhid_char_read(struct file *file, char __user *buffer,
 				size_t count, loff_t *ppos)
 {
-	return 0;
+	struct uhid_device *uhid = file->private_data;
+	int ret;
+	unsigned long flags;
+	size_t len;
+
+	/* they need at least the "type" member of uhid_event */
+	if (count < sizeof(__u32))
+		return -EINVAL;
+
+try_again:
+	if (file->f_flags & O_NONBLOCK) {
+		if (uhid->head == uhid->tail)
+			return -EAGAIN;
+	} else {
+		ret = wait_event_interruptible(uhid->waitq,
+						uhid->head != uhid->tail);
+		if (ret)
+			return ret;
+	}
+
+	ret = mutex_lock_interruptible(&uhid->devlock);
+	if (ret)
+		return ret;
+
+	if (uhid->head == uhid->tail) {
+		mutex_unlock(&uhid->devlock);
+		goto try_again;
+	} else {
+		len = min(count, sizeof(**uhid->outq));
+		if (copy_to_user(buffer, uhid->outq[uhid->tail], len)) {
+			ret = -EFAULT;
+		} else {
+			kfree(uhid->outq[uhid->tail]);
+			uhid->outq[uhid->tail] = NULL;
+
+			spin_lock_irqsave(&uhid->qlock, flags);
+			uhid->tail = (uhid->tail + 1) % UHID_BUFSIZE;
+			spin_unlock_irqrestore(&uhid->qlock, flags);
+		}
+	}
+
+	mutex_unlock(&uhid->devlock);
+	return ret ? ret : len;
 }
 
 static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
 				size_t count, loff_t *ppos)
 {
-	return 0;
+	struct uhid_device *uhid = file->private_data;
+	int ret;
+	size_t len;
+
+	/* we need at least the "type" member of uhid_event */
+	if (count < sizeof(__u32))
+		return -EINVAL;
+
+	ret = mutex_lock_interruptible(&uhid->devlock);
+	if (ret)
+		return ret;
+
+	memset(&uhid->input_buf, 0, sizeof(uhid->input_buf));
+	len = min(count, sizeof(uhid->input_buf));
+	if (copy_from_user(&uhid->input_buf, buffer, len)) {
+		ret = -EFAULT;
+		goto unlock;
+	}
+
+	switch (uhid->input_buf.type) {
+	case UHID_CREATE:
+		ret = uhid_dev_create(uhid, &uhid->input_buf);
+		break;
+	case UHID_DESTROY:
+		ret = uhid_dev_destroy(uhid);
+		break;
+	case UHID_INPUT:
+		ret = uhid_dev_input(uhid, &uhid->input_buf);
+		break;
+	case UHID_FEATURE_ANSWER:
+		ret = uhid_dev_feature_answer(uhid, &uhid->input_buf);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+	}
+
+unlock:
+	mutex_unlock(&uhid->devlock);
+
+	/* return "count" not "len" to not confuse the caller */
+	return ret ? ret : count;
 }
 
 static unsigned int uhid_char_poll(struct file *file, poll_table *wait)
 {
+	struct uhid_device *uhid = file->private_data;
+
+	poll_wait(file, &uhid->waitq, wait);
+
+	if (uhid->head != uhid->tail)
+		return POLLIN | POLLRDNORM;
+
 	return 0;
 }
 
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/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/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 6974cb4..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;
 	}
 
@@ -588,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;
 		}
@@ -710,7 +710,7 @@
 
 	*event = cmd->event;
 
-	kfree(cmd);
+	kzfree(cmd);
 	return rc;
 }
 
@@ -1002,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 22131f8..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 = {
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/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index 0641162..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
@@ -4454,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;
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h
index 5b91436..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 {
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index f23c0aa..c8599d5 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -184,18 +184,12 @@
 	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;
diff --git a/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c
index 5b5c121..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,26 +168,20 @@
 	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);
 	}
@@ -153,21 +190,18 @@
 	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 8cce310..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:
@@ -1462,7 +1462,6 @@
 	struct internal_buf *binfo;
 	struct vidc_buffer_addr_info buffer_info;
 	u32 smem_flags = 0;
-	int domain;
 	struct hal_buffer_requirements *scratch_buf;
 	int i;
 	struct hfi_device *hdev;
@@ -1481,20 +1480,15 @@
 		scratch_buf->buffer_count_actual,
 		scratch_buf->buffer_size);
 
-	if (inst->mode == VIDC_SECURE) {
-		domain = call_hfi_op(hdev, get_domain,
-				hdev->hfi_device_data, CP_MAP);
+	if (inst->mode == VIDC_SECURE)
 		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);
+				buffer_type, 0);
 			if (!handle) {
 				dprintk(VIDC_ERR,
 					"Failed to allocate scratch memory\n");
@@ -1550,7 +1544,6 @@
 	struct internal_buf *binfo;
 	struct vidc_buffer_addr_info buffer_info;
 	u32 smem_flags = 0;
-	int domain;
 	struct hal_buffer_requirements *persist_buf;
 	int i;
 	struct hfi_device *hdev;
@@ -1575,19 +1568,14 @@
 		return rc;
 	}
 
-	if (inst->mode == VIDC_SECURE) {
-		domain = call_hfi_op(hdev, get_domain,
-				hdev->hfi_device_data, CP_MAP);
+	if (inst->mode == VIDC_SECURE)
 		smem_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);
+				buffer_type, 0);
 			if (!handle) {
 				dprintk(VIDC_ERR,
 					"Failed to allocate persist memory\n");
@@ -2310,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_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_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index a057303..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,21 +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_SCRATCH_1,
-	HAL_BUFFER_INTERNAL_SCRATCH_2,
-	HAL_BUFFER_INTERNAL_PERSIST,
-	HAL_BUFFER_INTERNAL_PERSIST_1,
-	HAL_BUFFER_MAX
-};
-
 struct hal_frame_rate {
 	enum hal_buffer buffer_type;
 	u32 frame_rate;
@@ -1061,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/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..1f3dc2f 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;
 }
@@ -3744,6 +3749,31 @@
 	return retval;
 }
 
+static int iris_fops_release(struct file *file)
+{
+	struct iris_device *radio = video_get_drvdata(video_devdata(file));
+	int retval = 0;
+
+	FMDBG("Enter %s ", __func__);
+	if (radio == NULL)
+		return -EINVAL;
+
+	if (radio->mode == FM_OFF)
+		return 0;
+
+	if (radio->mode == FM_RECV)
+		retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
+						radio->fm_hdev);
+	else if (radio->mode == FM_TRANS)
+		retval = hci_cmd(HCI_FM_DISABLE_TRANS_CMD,
+					radio->fm_hdev);
+	if (retval < 0)
+		FMDERR("Err on disable FM %d\n", retval);
+
+	radio->mode = FM_OFF;
+	return retval;
+}
+
 static int iris_vidioc_dqbuf(struct file *file, void *priv,
 				struct v4l2_buffer *buffer)
 {
@@ -3838,6 +3868,7 @@
 static const struct v4l2_file_operations iris_fops = {
 	.owner = THIS_MODULE,
 	.unlocked_ioctl = video_ioctl2,
+	.release        = iris_fops_release,
 };
 
 static struct video_device iris_viddev_template = {
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/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/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 14038ed..07850b9 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -27,9 +27,16 @@
 #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
 
@@ -52,6 +59,43 @@
 #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)
+
+/* 8KB descriptors */
+#define SDHCI_MSM_MAX_SEGMENTS  (1 << 13)
+
+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 {
@@ -96,13 +140,43 @@
 	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 {
@@ -142,6 +216,403 @@
 	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;
@@ -180,20 +651,88 @@
 	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);
 
-	ret = sdhci_msm_setup_gpio(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)
@@ -261,11 +800,164 @@
 	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, cnt, i;
+	int ret = 0, id = 0, cnt, i;
 	struct sdhci_msm_pin_data *pin_data;
 	struct device_node *np = dev->of_node;
 
@@ -278,6 +970,7 @@
 
 	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) {
@@ -294,7 +987,6 @@
 			ret = -ENOMEM;
 			goto out;
 		}
-
 		for (i = 0; i < cnt; i++) {
 			const char *name = NULL;
 			char result[GPIO_NAME_MAX_LEN];
@@ -306,12 +998,39 @@
 					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);
-			pdata->pin_data = pin_data;
+				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);
@@ -665,7 +1384,9 @@
 
 static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
 {
-	struct sdhci_msm_host *msm_host = (struct sdhci_msm_host *)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;
@@ -731,6 +1452,16 @@
 	 */
 	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);
@@ -771,8 +1502,28 @@
 		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 unsigned int sdhci_msm_max_segs(void)
+{
+	return SDHCI_MSM_MAX_SEGMENTS;
+}
+
 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,
+	.get_max_segments = sdhci_msm_max_segs,
 };
 
 static int __devinit sdhci_msm_probe(struct platform_device *pdev)
@@ -783,6 +1534,7 @@
 	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),
@@ -880,7 +1632,27 @@
 	 */
 	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",
@@ -889,7 +1661,7 @@
 	}
 	ret = devm_request_threaded_irq(&pdev->dev, pwr_irq, NULL,
 					sdhci_msm_pwr_irq, IRQF_ONESHOT,
-					dev_name(&pdev->dev), msm_host);
+					dev_name(&pdev->dev), host);
 	if (ret) {
 		dev_err(&pdev->dev, "Request threaded irq(%d) failed (%d)\n",
 				pwr_irq, ret);
@@ -918,6 +1690,7 @@
 					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;
@@ -990,7 +1763,7 @@
 	if (!IS_ERR_OR_NULL(msm_host->bus_clk))
 		clk_disable_unprepare(msm_host->bus_clk);
 	if (pdata->pin_data)
-		sdhci_msm_setup_gpio(pdata, false);
+		sdhci_msm_setup_pins(pdata, false);
 	return 0;
 }
 
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 8c2bea09..326f220 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -483,9 +483,10 @@
 	 * The ADMA descriptor table is mapped further down as we
 	 * need to fill it with data first.
 	 */
-
 	host->align_addr = dma_map_single(mmc_dev(host->mmc),
-		host->align_buffer, 128 * 4, direction);
+					  host->align_buffer,
+					  host->align_buf_sz,
+					  direction);
 	if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr))
 		goto fail;
 	BUG_ON(host->align_addr & 0x3);
@@ -544,7 +545,8 @@
 		 * If this triggers then we have a calculation bug
 		 * somewhere. :/
 		 */
-		WARN_ON((desc - host->adma_desc) > (128 * 2 + 1) * 4);
+		WARN_ON((desc - host->adma_desc) > host->adma_desc_sz);
+
 	}
 
 	if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) {
@@ -569,11 +571,15 @@
 	 */
 	if (data->flags & MMC_DATA_WRITE) {
 		dma_sync_single_for_device(mmc_dev(host->mmc),
-			host->align_addr, 128 * 4, direction);
+					   host->align_addr,
+					   host->align_buf_sz,
+					   direction);
 	}
 
 	host->adma_addr = dma_map_single(mmc_dev(host->mmc),
-		host->adma_desc, (128 * 2 + 1) * 4, DMA_TO_DEVICE);
+					 host->adma_desc,
+					 host->adma_desc_sz,
+					 DMA_TO_DEVICE);
 	if (dma_mapping_error(mmc_dev(host->mmc), host->adma_addr))
 		goto unmap_entries;
 	BUG_ON(host->adma_addr & 0x3);
@@ -585,7 +591,7 @@
 		data->sg_len, direction);
 unmap_align:
 	dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
-		128 * 4, direction);
+			 host->align_buf_sz, direction);
 fail:
 	return -EINVAL;
 }
@@ -607,10 +613,10 @@
 		direction = DMA_TO_DEVICE;
 
 	dma_unmap_single(mmc_dev(host->mmc), host->adma_addr,
-		(128 * 2 + 1) * 4, DMA_TO_DEVICE);
+			 host->adma_desc_sz, DMA_TO_DEVICE);
 
 	dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
-		128 * 4, direction);
+			 host->align_buf_sz, direction);
 
 	if (data->flags & MMC_DATA_READ) {
 		dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg,
@@ -721,7 +727,7 @@
 		return;
 
 	/* Sanity checks */
-	BUG_ON(data->blksz * data->blocks > 524288);
+	BUG_ON(data->blksz * data->blocks > host->mmc->max_req_size);
 	BUG_ON(data->blksz > host->mmc->max_blk_size);
 	BUG_ON(data->blocks > 65535);
 
@@ -2049,6 +2055,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 +2144,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 +2181,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 +2378,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);
 	}
 
@@ -2686,11 +2721,23 @@
 	if (host->flags & SDHCI_USE_ADMA) {
 		/*
 		 * We need to allocate descriptors for all sg entries
-		 * (128) and potentially one alignment transfer for
+		 * (128/max_segments) and potentially one alignment transfer for
 		 * each of those entries.
 		 */
-		host->adma_desc = kmalloc((128 * 2 + 1) * 4, GFP_KERNEL);
-		host->align_buffer = kmalloc(128 * 4, GFP_KERNEL);
+		if (host->ops->get_max_segments)
+			host->adma_max_desc = host->ops->get_max_segments();
+		else
+			host->adma_max_desc = 128;
+
+		host->adma_desc_sz = (host->adma_max_desc * 2 + 1) * 4;
+		host->align_buf_sz = host->adma_max_desc * 4;
+
+		pr_debug("%s: %s: dma_desc_size: %d\n",
+			mmc_hostname(host->mmc), __func__, host->adma_desc_sz);
+		host->adma_desc = kmalloc(host->adma_desc_sz,
+					  GFP_KERNEL);
+		host->align_buffer = kmalloc(host->align_buf_sz,
+					     GFP_KERNEL);
 		if (!host->adma_desc || !host->align_buffer) {
 			kfree(host->adma_desc);
 			kfree(host->align_buffer);
@@ -2944,17 +2991,21 @@
 	 * can do scatter/gather or not.
 	 */
 	if (host->flags & SDHCI_USE_ADMA)
-		mmc->max_segs = 128;
+		mmc->max_segs = host->adma_max_desc;
 	else if (host->flags & SDHCI_USE_SDMA)
 		mmc->max_segs = 1;
-	else /* PIO */
-		mmc->max_segs = 128;
+	else/* PIO */
+		mmc->max_segs = host->adma_max_desc;
 
 	/*
 	 * Maximum number of sectors in one transfer. Limited by DMA boundary
-	 * size (512KiB).
+	 * size (512KiB), unless specified by platform specific driver. Each
+	 * descriptor can transfer a maximum of 64KB.
 	 */
-	mmc->max_req_size = 524288;
+	if (host->ops->get_max_segments)
+		mmc->max_req_size = (host->adma_max_desc * 65536);
+	else
+		mmc->max_req_size = 524288;
 
 	/*
 	 * Maximum segment size. Could be one segment with the maximum number
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 4f8d01d..c0ae39f 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -280,6 +280,7 @@
 	void	(*check_power_status)(struct sdhci_host *host);
 	int	(*execute_tuning)(struct sdhci_host *host, u32 opcode);
 	void	(*toggle_cdr)(struct sdhci_host *host, bool enable);
+	unsigned int	(*get_max_segments)(void);
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
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/ipa.c b/drivers/platform/msm/ipa/ipa.c
index edf3a60..1142094 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -161,6 +161,7 @@
 	struct ipa_ioc_nat_alloc_mem nat_mem;
 	struct ipa_ioc_v4_nat_init nat_init;
 	struct ipa_ioc_v4_nat_del nat_del;
+	struct ipa_ioc_rm_dependency rm_depend;
 	size_t sz;
 
 	IPADBG("cmd=%x nr=%d\n", cmd, _IOC_NR(cmd));
@@ -593,6 +594,24 @@
 			break;
 		}
 		break;
+	case IPA_IOC_RM_ADD_DEPENDENCY:
+		if (copy_from_user((u8 *)&rm_depend, (u8 *)arg,
+				sizeof(struct ipa_ioc_rm_dependency))) {
+			retval = -EFAULT;
+			break;
+		}
+		retval = ipa_rm_add_dependency(rm_depend.resource_name,
+						rm_depend.depends_on_name);
+		break;
+	case IPA_IOC_RM_DEL_DEPENDENCY:
+		if (copy_from_user((u8 *)&rm_depend, (u8 *)arg,
+				sizeof(struct ipa_ioc_rm_dependency))) {
+			retval = -EFAULT;
+			break;
+		}
+		retval = ipa_rm_delete_dependency(rm_depend.resource_name,
+						rm_depend.depends_on_name);
+		break;
 	default:        /* redundant, as cmd was checked against MAXNR */
 		return -ENOTTY;
 	}
diff --git a/drivers/platform/msm/ipa/ipa_rm.c b/drivers/platform/msm/ipa/ipa_rm.c
index 99b19cc..1fdd300 100644
--- a/drivers/platform/msm/ipa/ipa_rm.c
+++ b/drivers/platform/msm/ipa/ipa_rm.c
@@ -48,7 +48,7 @@
 	if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
 					  create_params->name,
 					  &resource) == 0) {
-		result = -EPERM;
+		result = -EEXIST;
 		goto bail;
 	}
 	result = ipa_rm_resource_create(create_params,
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.c b/drivers/platform/msm/ipa/ipa_rm_resource.c
index 3ba8e84..0a6771c 100644
--- a/drivers/platform/msm/ipa/ipa_rm_resource.c
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.c
@@ -451,7 +451,7 @@
 			resource->name,
 			depends_on->peers_list,
 			depends_on->name))
-		return -EINVAL;
+		return -EEXIST;
 	ipa_rm_peers_list_add_peer(resource->peers_list, depends_on);
 	ipa_rm_peers_list_add_peer(depends_on->peers_list, resource);
 	spin_lock_irqsave(&resource->state_lock, flags);
@@ -507,7 +507,7 @@
 	unsigned long flags;
 	if (!resource || !depends_on)
 		return -EINVAL;
-	if (ipa_rm_peers_list_check_dependency(resource->peers_list,
+	if (!ipa_rm_peers_list_check_dependency(resource->peers_list,
 			resource->name,
 			depends_on->peers_list,
 			depends_on->name))
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index c841575..a9a850c 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -472,6 +472,63 @@
 	return 0;
 }
 
+static void usb_prod_notify_cb(void *user_data, enum ipa_rm_event event,
+	unsigned long data)
+{
+	switch (event) {
+	case IPA_RM_RESOURCE_GRANTED:
+		pr_debug("USB_PROD resource granted\n");
+		break;
+	case IPA_RM_RESOURCE_RELEASED:
+		pr_debug("USB_PROD resource released\n");
+		break;
+	default:
+		break;
+	}
+	return;
+}
+
+static int usb_cons_request_resource(void)
+{
+	pr_debug(": Requesting USB_CONS resource\n");
+	return 0;
+}
+
+static int usb_cons_release_resource(void)
+{
+	pr_debug(": Releasing USB_CONS resource\n");
+	return 0;
+}
+
+static void usb_bam_ipa_create_resources(void)
+{
+	struct ipa_rm_create_params usb_prod_create_params;
+	struct ipa_rm_create_params usb_cons_create_params;
+	int ret;
+
+	/* Create USB_PROD entity */
+	memset(&usb_prod_create_params, 0, sizeof(usb_prod_create_params));
+	usb_prod_create_params.name = IPA_RM_RESOURCE_USB_PROD;
+	usb_prod_create_params.reg_params.notify_cb = usb_prod_notify_cb;
+	usb_prod_create_params.reg_params.user_data = NULL;
+	ret = ipa_rm_create_resource(&usb_prod_create_params);
+	if (ret) {
+		pr_err("%s: Failed to create USB_PROD resource\n", __func__);
+		return;
+	}
+
+	/* Create USB_CONS entity */
+	memset(&usb_cons_create_params, 0, sizeof(usb_cons_create_params));
+	usb_cons_create_params.name = IPA_RM_RESOURCE_USB_CONS;
+	usb_cons_create_params.request_resource = usb_cons_request_resource;
+	usb_cons_create_params.release_resource = usb_cons_release_resource;
+	ret = ipa_rm_create_resource(&usb_cons_create_params);
+	if (ret) {
+		pr_err("%s: Failed to create USB_CONS resource\n", __func__);
+		return ;
+	}
+}
+
 int usb_bam_connect_ipa(struct usb_bam_connect_ipa_params *ipa_params)
 {
 	u8 idx = ipa_params->idx;
@@ -500,6 +557,8 @@
 
 	connection->idx = idx;
 
+	ipa_rm_request_resource(IPA_CLIENT_USB_PROD);
+
 	ret = connect_pipe_ipa(ipa_params);
 	if (ret) {
 		pr_err("%s: dst pipe connection failure\n", __func__);
@@ -779,6 +838,7 @@
 		}
 	}
 
+	ipa_rm_release_resource(IPA_CLIENT_USB_PROD);
 	return 0;
 
 }
@@ -925,14 +985,6 @@
 	return 0;
 }
 
-static u8 qdss_conn_num;
-
-u8 usb_bam_get_qdss_num(void)
-{
-	return qdss_conn_num;
-}
-EXPORT_SYMBOL(usb_bam_get_qdss_num);
-
 static struct msm_usb_bam_platform_data *usb_bam_dt_to_pdata(
 	struct platform_device *pdev)
 {
@@ -1055,11 +1107,6 @@
 			!strcmp(str, "usb-to-peri-qdss-hsusb") ||
 			!strcmp(str, "peri-to-usb-qdss-hsusb"))
 				conn_num = 0;
-		else if (!strcmp(str, "usb-to-qdss-hsusb") ||
-			!strcmp(str, "qdss-to-usb-hsusb")) {
-				conn_num = 1;
-				qdss_conn_num = 1;
-		}
 		else
 			goto err;
 
@@ -1094,8 +1141,6 @@
 	struct resource *res, *ram_resource;
 	int irq;
 
-	qdss_conn_num = 0;
-
 	res = platform_get_resource_byname(usb_bam_pdev, IORESOURCE_MEM,
 				bam_enable_strings[pdata->usb_active_bam]);
 	if (!res) {
@@ -1276,6 +1321,8 @@
 		return -ENOMEM;
 	}
 
+	usb_bam_ipa_create_resources();
+
 	return ret;
 }
 
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/gadget/u_qdss.c b/drivers/usb/gadget/u_qdss.c
index 2931ace..028d5e6 100644
--- a/drivers/usb/gadget/u_qdss.c
+++ b/drivers/usb/gadget/u_qdss.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -15,6 +15,8 @@
 #include <linux/usb/msm_hsusb.h>
 #include <mach/usb_bam.h>
 
+#define BAM_CONNC_IDX 0 /* USB bam connection index */
+
 struct  usb_qdss_bam_connect_info {
 	u32 usb_bam_pipe_idx;
 	u32 peer_pipe_idx;
@@ -55,18 +57,17 @@
 		pr_err("send_sps_req: usb_ep_queue error\n");
 		return -EIO;
 	}
-
 	return 0;
 }
 
 int set_qdss_data_connection(struct usb_ep *data_ep, u8 data_addr, int enable)
 {
 	int res = 0;
-	u8 conn_num = usb_bam_get_qdss_num();
+
 	pr_debug("set_qdss_data_connection\n");
 
 	if (enable) {
-		res = usb_bam_connect(conn_num, NULL,
+		res = usb_bam_connect(BAM_CONNC_IDX, NULL,
 			&(bam_info.usb_bam_pipe_idx));
 		if (res) {
 			pr_err("usb_bam_connection error\n");
@@ -79,7 +80,7 @@
 			pr_err("qdss_data_connection: memory alloc failed\n");
 			return -ENOMEM;
 		}
-		get_bam2bam_connection_info(conn_num,
+		get_bam2bam_connection_info(BAM_CONNC_IDX,
 			PEER_PERIPHERAL_TO_USB, &bam_info.usb_bam_handle,
 			&bam_info.usb_bam_pipe_idx, &bam_info.peer_pipe_idx,
 			NULL, bam_info.data_fifo);
@@ -88,7 +89,7 @@
 			bam_info.data_fifo->size, bam_info.usb_bam_pipe_idx);
 	} else {
 		kfree(bam_info.data_fifo);
-		res = usb_bam_disconnect_pipe(conn_num);
+		res = usb_bam_disconnect_pipe(BAM_CONNC_IDX);
 		if (res) {
 			pr_err("usb_bam_disconnection error\n");
 			return res;
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index f1f6962..ea5484b 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -1776,6 +1776,9 @@
 
 	pdata->bus_scale_table = msm_bus_cl_get_pdata(pdev);
 
+	pdata->pool_64_bit_align = of_property_read_bool(node,
+				"qcom,pool-64-bit-align");
+
 	return pdata;
 }
 
@@ -1853,6 +1856,7 @@
 	mehci->ehci.reset_sof_bug = 1;
 
 	mehci->ehci.resume_sof_bug = 1;
+	mehci->ehci.pool_64_bit_align = pdata->pool_64_bit_align;
 
 	if (pdata)
 		mehci->ehci.log2_irq_thresh = pdata->log2_irq_thresh;
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index 07a232a..d238b4e2 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -30,7 +30,6 @@
 
 	hcd->has_tt = pdata->has_tt;
 	ehci->has_synopsys_hc_bug = pdata->has_synopsys_hc_bug;
-	ehci->pool_64_bit_align = pdata->pool_64_bit_align;
 	ehci->big_endian_desc = pdata->big_endian_desc;
 	ehci->big_endian_mmio = pdata->big_endian_mmio;
 
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index c03ca69..b35d904 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -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;
 }
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index bde7340..1c8664c 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -379,7 +379,7 @@
 		list_add_tail(&urb->urb_list, &portdata->in_urb_list);
 		spin_unlock_irqrestore(&portdata->in_lock, flags);
 
-		schedule_work(&portdata->in_work);
+		queue_work(system_nrt_wq, &portdata->in_work);
 
 		return;
 	}
@@ -498,7 +498,7 @@
 	port->throttle_req = false;
 	port->throttled = false;
 
-	schedule_work(&portdata->in_work);
+	queue_work(system_nrt_wq, &portdata->in_work);
 }
 EXPORT_SYMBOL(usb_wwan_unthrottle);
 
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 e4f78ad..efd93c0 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -355,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 cabb183..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;
@@ -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);
@@ -966,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 daa2499..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);
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/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index e9051e1..9fb01f4 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 */
@@ -147,6 +161,10 @@
 	u8 *adma_desc;		/* ADMA descriptor table */
 	u8 *align_buffer;	/* Bounce buffer */
 
+	unsigned int adma_desc_sz; /* ADMA descriptor table size */
+	unsigned int align_buf_sz; /* Bounce buffer size */
+	unsigned int adma_max_desc; /* Max ADMA descriptos (max sg segments) */
+
 	dma_addr_t adma_addr;	/* Mapped ADMA descr. table */
 	dma_addr_t align_addr;	/* Mapped bounce buffer */
 
diff --git a/include/linux/msm_ipa.h b/include/linux/msm_ipa.h
index 30bf4f2..b377a6c 100644
--- a/include/linux/msm_ipa.h
+++ b/include/linux/msm_ipa.h
@@ -49,7 +49,9 @@
 #define IPA_IOCTL_V4_DEL_NAT     26
 #define IPA_IOCTL_PULL_MSG       27
 #define IPA_IOCTL_GET_NAT_OFFSET 28
-#define IPA_IOCTL_MAX            29
+#define IPA_IOCTL_RM_ADD_DEPENDENCY 29
+#define IPA_IOCTL_RM_DEL_DEPENDENCY 30
+#define IPA_IOCTL_MAX            31
 
 /**
  * max size of the header to be inserted
@@ -173,6 +175,35 @@
 	WLAN_STA_DISCONNECT,
 };
 
+/**
+ * enum ipa_rm_resource_name - IPA RM clients identification names
+ *
+ * Add new mapping to ipa_rm_dep_prod_index() / ipa_rm_dep_cons_index()
+ * when adding new entry to this enum.
+ */
+enum ipa_rm_resource_name {
+	IPA_RM_RESOURCE_PROD = 0,
+	IPA_RM_RESOURCE_BRIDGE_PROD = IPA_RM_RESOURCE_PROD,
+	IPA_RM_RESOURCE_A2_PROD,
+	IPA_RM_RESOURCE_USB_PROD,
+	IPA_RM_RESOURCE_HSIC_PROD,
+	IPA_RM_RESOURCE_STD_ECM_PROD,
+	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,
+	IPA_RM_RESOURCE_WLAN_PROD,
+	IPA_RM_RESOURCE_PROD_MAX,
+
+	IPA_RM_RESOURCE_A2_CONS = IPA_RM_RESOURCE_PROD_MAX,
+	IPA_RM_RESOURCE_USB_CONS,
+	IPA_RM_RESOURCE_HSIC_CONS,
+	IPA_RM_RESOURCE_MAX
+};
 
 /**
  * struct ipa_rule_attrib - attributes of a routing/filtering
@@ -682,6 +713,15 @@
 	uint8_t mac_addr[IPA_MAC_ADDR_SIZE];
 };
 
+/**
+ * struct ipa_ioc_rm_dependency - parameters for add/delete dependency
+ * @resource_name: name of dependent resource
+ * @depends_on_name: name of its dependency
+ */
+struct ipa_ioc_rm_dependency {
+	enum ipa_rm_resource_name resource_name;
+	enum ipa_rm_resource_name depends_on_name;
+};
 
 
 /**
@@ -768,6 +808,12 @@
 #define IPA_IOC_PULL_MSG _IOWR(IPA_IOC_MAGIC, \
 				IPA_IOCTL_PULL_MSG, \
 				struct ipa_msg_meta *)
+#define IPA_IOC_RM_ADD_DEPENDENCY _IOWR(IPA_IOC_MAGIC, \
+				IPA_IOCTL_RM_ADD_DEPENDENCY, \
+				struct ipa_ioc_rm_dependency *)
+#define IPA_IOC_RM_DEL_DEPENDENCY _IOWR(IPA_IOC_MAGIC, \
+				IPA_IOCTL_RM_DEL_DEPENDENCY, \
+				struct ipa_ioc_rm_dependency *)
 
 /*
  * unique magic number of the Tethering bridge ioctls
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 0683296..6e4b7a6 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -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 */
@@ -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/uhid.h b/include/linux/uhid.h
index 16b786a..9c6974f 100644
--- a/include/linux/uhid.h
+++ b/include/linux/uhid.h
@@ -23,11 +23,82 @@
 #include <linux/types.h>
 
 enum uhid_event_type {
-	UHID_DUMMY,
+	UHID_CREATE,
+	UHID_DESTROY,
+	UHID_START,
+	UHID_STOP,
+	UHID_OPEN,
+	UHID_CLOSE,
+	UHID_OUTPUT,
+	UHID_OUTPUT_EV,
+	UHID_INPUT,
+	UHID_FEATURE,
+	UHID_FEATURE_ANSWER,
+};
+
+struct uhid_create_req {
+	__u8 name[128];
+	__u8 phys[64];
+	__u8 uniq[64];
+	__u8 __user *rd_data;
+	__u16 rd_size;
+
+	__u16 bus;
+	__u32 vendor;
+	__u32 product;
+	__u32 version;
+	__u32 country;
+} __attribute__((__packed__));
+
+#define UHID_DATA_MAX 4096
+
+enum uhid_report_type {
+	UHID_FEATURE_REPORT,
+	UHID_OUTPUT_REPORT,
+	UHID_INPUT_REPORT,
+};
+
+struct uhid_input_req {
+	__u8 data[UHID_DATA_MAX];
+	__u16 size;
+} __attribute__((__packed__));
+
+struct uhid_output_req {
+	__u8 data[UHID_DATA_MAX];
+	__u16 size;
+	__u8 rtype;
+} __attribute__((__packed__));
+
+struct uhid_output_ev_req {
+	__u16 type;
+	__u16 code;
+	__s32 value;
+} __attribute__((__packed__));
+
+struct uhid_feature_req {
+	__u32 id;
+	__u8 rnum;
+	__u8 rtype;
+} __attribute__((__packed__));
+
+struct uhid_feature_answer_req {
+	__u32 id;
+	__u16 err;
+	__u16 size;
+	__u8 data[UHID_DATA_MAX];
 };
 
 struct uhid_event {
 	__u32 type;
+
+	union {
+		struct uhid_create_req create;
+		struct uhid_input_req input;
+		struct uhid_output_req output;
+		struct uhid_output_ev_req output_ev;
+		struct uhid_feature_req feature;
+		struct uhid_feature_answer_req feature_answer;
+	} u;
 } __attribute__((__packed__));
 
 #endif /* __UHID_H_ */
diff --git a/include/linux/usb/ehci_pdriver.h b/include/linux/usb/ehci_pdriver.h
index 4c1b7a0..1894f42 100644
--- a/include/linux/usb/ehci_pdriver.h
+++ b/include/linux/usb/ehci_pdriver.h
@@ -41,7 +41,6 @@
 	unsigned	big_endian_mmio:1;
 	unsigned	port_power_on:1;
 	unsigned	port_power_off:1;
-	unsigned	pool_64_bit_align:1;
 };
 
 #endif /* __USB_CORE_EHCI_PDRIVER_H */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index e249953..b65a6d2 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -407,6 +407,7 @@
 
 	/*standalone latency is required when HSCI is active*/
 	u32 standalone_latency;
+	bool pool_64_bit_align;
 };
 
 struct msm_usb_host_platform_data {
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 6666c69..3a7edf3 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1320,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
@@ -1714,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);
 };
 
 /*
@@ -3386,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/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 1ccc69e..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 */
@@ -6311,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
@@ -6919,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,
-	},
 
 };
 
@@ -8164,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/samples/uhid/Makefile b/samples/uhid/Makefile
new file mode 100644
index 0000000..c95a696
--- /dev/null
+++ b/samples/uhid/Makefile
@@ -0,0 +1,10 @@
+# kbuild trick to avoid linker error. Can be omitted if a module is built.
+obj- := dummy.o
+
+# List of programs to build
+hostprogs-y := uhid-example
+
+# Tell kbuild to always build the programs
+always := $(hostprogs-y)
+
+HOSTCFLAGS_uhid-example.o += -I$(objtree)/usr/include
diff --git a/samples/uhid/uhid-example.c b/samples/uhid/uhid-example.c
new file mode 100644
index 0000000..03ce3c0
--- /dev/null
+++ b/samples/uhid/uhid-example.c
@@ -0,0 +1,381 @@
+/*
+ * UHID Example
+ *
+ * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
+ *
+ * The code may be used by anyone for any purpose,
+ * and can serve as a starting point for developing
+ * applications using uhid.
+ */
+
+/* UHID Example
+ * This example emulates a basic 3 buttons mouse with wheel over UHID. Run this
+ * program as root and then use the following keys to control the mouse:
+ *   q: Quit the application
+ *   1: Toggle left button (down, up, ...)
+ *   2: Toggle right button
+ *   3: Toggle middle button
+ *   a: Move mouse left
+ *   d: Move mouse right
+ *   w: Move mouse up
+ *   s: Move mouse down
+ *   r: Move wheel up
+ *   f: Move wheel down
+ *
+ * If uhid is not available as /dev/uhid, then you can pass a different path as
+ * first argument.
+ * If <linux/uhid.h> is not installed in /usr, then compile this with:
+ *   gcc -o ./uhid_test -Wall -I./include ./samples/uhid/uhid-example.c
+ * And ignore the warning about kernel headers. However, it is recommended to
+ * use the installed uhid.h if available.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <linux/uhid.h>
+
+/* HID Report Desciptor
+ * We emulate a basic 3 button mouse with wheel. This is the report-descriptor
+ * as the kernel will parse it:
+ *
+ * INPUT[INPUT]
+ *   Field(0)
+ *     Physical(GenericDesktop.Pointer)
+ *     Application(GenericDesktop.Mouse)
+ *     Usage(3)
+ *       Button.0001
+ *       Button.0002
+ *       Button.0003
+ *     Logical Minimum(0)
+ *     Logical Maximum(1)
+ *     Report Size(1)
+ *     Report Count(3)
+ *     Report Offset(0)
+ *     Flags( Variable Absolute )
+ *   Field(1)
+ *     Physical(GenericDesktop.Pointer)
+ *     Application(GenericDesktop.Mouse)
+ *     Usage(3)
+ *       GenericDesktop.X
+ *       GenericDesktop.Y
+ *       GenericDesktop.Wheel
+ *     Logical Minimum(-128)
+ *     Logical Maximum(127)
+ *     Report Size(8)
+ *     Report Count(3)
+ *     Report Offset(8)
+ *     Flags( Variable Relative )
+ *
+ * This is the mapping that we expect:
+ *   Button.0001 ---> Key.LeftBtn
+ *   Button.0002 ---> Key.RightBtn
+ *   Button.0003 ---> Key.MiddleBtn
+ *   GenericDesktop.X ---> Relative.X
+ *   GenericDesktop.Y ---> Relative.Y
+ *   GenericDesktop.Wheel ---> Relative.Wheel
+ *
+ * This information can be verified by reading /sys/kernel/debug/hid/<dev>/rdesc
+ * This file should print the same information as showed above.
+ */
+
+static unsigned char rdesc[] = {
+	0x05, 0x01, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x01,
+	0xa1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
+	0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01,
+	0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01,
+	0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x38,
+	0x15, 0x80, 0x25, 0x7f, 0x75, 0x08, 0x95, 0x03,
+	0x81, 0x06, 0xc0, 0xc0,
+};
+
+static int uhid_write(int fd, const struct uhid_event *ev)
+{
+	ssize_t ret;
+
+	ret = write(fd, ev, sizeof(*ev));
+	if (ret < 0) {
+		fprintf(stderr, "Cannot write to uhid: %m\n");
+		return -errno;
+	} else if (ret != sizeof(*ev)) {
+		fprintf(stderr, "Wrong size written to uhid: %ld != %lu\n",
+			ret, sizeof(ev));
+		return -EFAULT;
+	} else {
+		return 0;
+	}
+}
+
+static int create(int fd)
+{
+	struct uhid_event ev;
+
+	memset(&ev, 0, sizeof(ev));
+	ev.type = UHID_CREATE;
+	strcpy((char*)ev.u.create.name, "test-uhid-device");
+	ev.u.create.rd_data = rdesc;
+	ev.u.create.rd_size = sizeof(rdesc);
+	ev.u.create.bus = BUS_USB;
+	ev.u.create.vendor = 0x15d9;
+	ev.u.create.product = 0x0a37;
+	ev.u.create.version = 0;
+	ev.u.create.country = 0;
+
+	return uhid_write(fd, &ev);
+}
+
+static void destroy(int fd)
+{
+	struct uhid_event ev;
+
+	memset(&ev, 0, sizeof(ev));
+	ev.type = UHID_DESTROY;
+
+	uhid_write(fd, &ev);
+}
+
+static int event(int fd)
+{
+	struct uhid_event ev;
+	ssize_t ret;
+
+	memset(&ev, 0, sizeof(ev));
+	ret = read(fd, &ev, sizeof(ev));
+	if (ret == 0) {
+		fprintf(stderr, "Read HUP on uhid-cdev\n");
+		return -EFAULT;
+	} else if (ret < 0) {
+		fprintf(stderr, "Cannot read uhid-cdev: %m\n");
+		return -errno;
+	} else if (ret != sizeof(ev)) {
+		fprintf(stderr, "Invalid size read from uhid-dev: %ld != %lu\n",
+			ret, sizeof(ev));
+		return -EFAULT;
+	}
+
+	switch (ev.type) {
+	case UHID_START:
+		fprintf(stderr, "UHID_START from uhid-dev\n");
+		break;
+	case UHID_STOP:
+		fprintf(stderr, "UHID_STOP from uhid-dev\n");
+		break;
+	case UHID_OPEN:
+		fprintf(stderr, "UHID_OPEN from uhid-dev\n");
+		break;
+	case UHID_CLOSE:
+		fprintf(stderr, "UHID_CLOSE from uhid-dev\n");
+		break;
+	case UHID_OUTPUT:
+		fprintf(stderr, "UHID_OUTPUT from uhid-dev\n");
+		break;
+	case UHID_OUTPUT_EV:
+		fprintf(stderr, "UHID_OUTPUT_EV from uhid-dev\n");
+		break;
+	default:
+		fprintf(stderr, "Invalid event from uhid-dev: %u\n", ev.type);
+	}
+
+	return 0;
+}
+
+static bool btn1_down;
+static bool btn2_down;
+static bool btn3_down;
+static signed char abs_hor;
+static signed char abs_ver;
+static signed char wheel;
+
+static int send_event(int fd)
+{
+	struct uhid_event ev;
+
+	memset(&ev, 0, sizeof(ev));
+	ev.type = UHID_INPUT;
+	ev.u.input.size = 4;
+
+	if (btn1_down)
+		ev.u.input.data[0] |= 0x1;
+	if (btn2_down)
+		ev.u.input.data[0] |= 0x2;
+	if (btn3_down)
+		ev.u.input.data[0] |= 0x4;
+
+	ev.u.input.data[1] = abs_hor;
+	ev.u.input.data[2] = abs_ver;
+	ev.u.input.data[3] = wheel;
+
+	return uhid_write(fd, &ev);
+}
+
+static int keyboard(int fd)
+{
+	char buf[128];
+	ssize_t ret, i;
+
+	ret = read(STDIN_FILENO, buf, sizeof(buf));
+	if (ret == 0) {
+		fprintf(stderr, "Read HUP on stdin\n");
+		return -EFAULT;
+	} else if (ret < 0) {
+		fprintf(stderr, "Cannot read stdin: %m\n");
+		return -errno;
+	}
+
+	for (i = 0; i < ret; ++i) {
+		switch (buf[i]) {
+		case '1':
+			btn1_down = !btn1_down;
+			ret = send_event(fd);
+			if (ret)
+				return ret;
+			break;
+		case '2':
+			btn2_down = !btn2_down;
+			ret = send_event(fd);
+			if (ret)
+				return ret;
+			break;
+		case '3':
+			btn3_down = !btn3_down;
+			ret = send_event(fd);
+			if (ret)
+				return ret;
+			break;
+		case 'a':
+			abs_hor = -20;
+			ret = send_event(fd);
+			abs_hor = 0;
+			if (ret)
+				return ret;
+			break;
+		case 'd':
+			abs_hor = 20;
+			ret = send_event(fd);
+			abs_hor = 0;
+			if (ret)
+				return ret;
+			break;
+		case 'w':
+			abs_ver = -20;
+			ret = send_event(fd);
+			abs_ver = 0;
+			if (ret)
+				return ret;
+			break;
+		case 's':
+			abs_ver = 20;
+			ret = send_event(fd);
+			abs_ver = 0;
+			if (ret)
+				return ret;
+			break;
+		case 'r':
+			wheel = 1;
+			ret = send_event(fd);
+			wheel = 0;
+			if (ret)
+				return ret;
+			break;
+		case 'f':
+			wheel = -1;
+			ret = send_event(fd);
+			wheel = 0;
+			if (ret)
+				return ret;
+			break;
+		case 'q':
+			return -ECANCELED;
+		default:
+			fprintf(stderr, "Invalid input: %c\n", buf[i]);
+		}
+	}
+
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	int fd;
+	const char *path = "/dev/uhid";
+	struct pollfd pfds[2];
+	int ret;
+	struct termios state;
+
+	ret = tcgetattr(STDIN_FILENO, &state);
+	if (ret) {
+		fprintf(stderr, "Cannot get tty state\n");
+	} else {
+		state.c_lflag &= ~ICANON;
+		state.c_cc[VMIN] = 1;
+		ret = tcsetattr(STDIN_FILENO, TCSANOW, &state);
+		if (ret)
+			fprintf(stderr, "Cannot set tty state\n");
+	}
+
+	if (argc >= 2) {
+		if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
+			fprintf(stderr, "Usage: %s [%s]\n", argv[0], path);
+			return EXIT_SUCCESS;
+		} else {
+			path = argv[1];
+		}
+	}
+
+	fprintf(stderr, "Open uhid-cdev %s\n", path);
+	fd = open(path, O_RDWR | O_CLOEXEC);
+	if (fd < 0) {
+		fprintf(stderr, "Cannot open uhid-cdev %s: %m\n", path);
+		return EXIT_FAILURE;
+	}
+
+	fprintf(stderr, "Create uhid device\n");
+	ret = create(fd);
+	if (ret) {
+		close(fd);
+		return EXIT_FAILURE;
+	}
+
+	pfds[0].fd = STDIN_FILENO;
+	pfds[0].events = POLLIN;
+	pfds[1].fd = fd;
+	pfds[1].events = POLLIN;
+
+	fprintf(stderr, "Press 'q' to quit...\n");
+	while (1) {
+		ret = poll(pfds, 2, -1);
+		if (ret < 0) {
+			fprintf(stderr, "Cannot poll for fds: %m\n");
+			break;
+		}
+		if (pfds[0].revents & POLLHUP) {
+			fprintf(stderr, "Received HUP on stdin\n");
+			break;
+		}
+		if (pfds[1].revents & POLLHUP) {
+			fprintf(stderr, "Received HUP on uhid-cdev\n");
+			break;
+		}
+
+		if (pfds[0].revents & POLLIN) {
+			ret = keyboard(fd);
+			if (ret)
+				break;
+		}
+		if (pfds[1].revents & POLLIN) {
+			ret = event(fd);
+			if (ret)
+				break;
+		}
+	}
+
+	fprintf(stderr, "Destroy uhid device\n");
+	destroy(fd);
+	return EXIT_SUCCESS;
+}
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index b3d4901..af268bd 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -1807,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) {
@@ -1838,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);
@@ -2151,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;
@@ -2184,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;
@@ -2201,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);
 
@@ -4299,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,
@@ -4414,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),
@@ -5067,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;
@@ -5113,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);
@@ -5179,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/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/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 1f2f307..b32daaa 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -1017,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);