Merge "board-8960: Update 8960AB and 8064AB SPM sequences."
diff --git a/Documentation/ABI/testing/sysfs-bus-pil b/Documentation/ABI/testing/sysfs-bus-pil
deleted file mode 100644
index 797b2ea..0000000
--- a/Documentation/ABI/testing/sysfs-bus-pil
+++ /dev/null
@@ -1,18 +0,0 @@
-What:		/sys/bus/pil/devices/.../name
-Date:		March 2012
-Contact:	Stephen Boyd <sboyd@codeaurora.org>
-Description:
-		Shows the name of the peripheral used in pil_get().
-
-What:		/sys/bus/pil/devices/.../state
-Date:		March 2012
-Contact:	Stephen Boyd <sboyd@codeaurora.org>
-Description:
-		Shows the state state of a peripheral. Current states
-		supported are:
-
-			OFFLINE - peripheral is offline
-			ONLINE - peripheral is online
-
-		This file supports poll() to detect when a peripheral changes
-		state.
diff --git a/Documentation/DMA-attributes.txt b/Documentation/DMA-attributes.txt
index 5c72eed..d62d0c6 100644
--- a/Documentation/DMA-attributes.txt
+++ b/Documentation/DMA-attributes.txt
@@ -49,3 +49,30 @@
 consistent or non-consistent memory as it sees fit.  By using this API,
 you are guaranteeing to the platform that you have all the correct and
 necessary sync points for this memory in the driver.
+
+DMA_ATTR_NO_KERNEL_MAPPING
+--------------------------
+
+DMA_ATTR_NO_KERNEL_MAPPING lets the platform to avoid creating a kernel
+virtual mapping for the allocated buffer. On some architectures creating
+such mapping is non-trivial task and consumes very limited resources
+(like kernel virtual address space or dma consistent address space).
+Buffers allocated with this attribute can be only passed to user space
+by calling dma_mmap_attrs(). By using this API, you are guaranteeing
+that you won't dereference the pointer returned by dma_alloc_attr(). You
+can threat it as a cookie that must be passed to dma_mmap_attrs() and
+dma_free_attrs(). Make sure that both of these also get this attribute
+set on each call.
+
+Since it is optional for platforms to implement
+DMA_ATTR_NO_KERNEL_MAPPING, those that do not will simply ignore the
+attribute and exhibit default behavior.
+
+DMA_ATTR_STRONGLY_ORDERED
+-------------------------
+
+DMA_ATTR_STRONGLY_ORDERED allocates memory with a very restrictive type
+of mapping (no unaligned accesses, no re-ordering, no write merging, no
+buffering, no pre-fetching). This has severe performance penalties and
+should not be used for general purpose DMA allocations. It should only
+be used if one of the restrictions on strongly ordered memory is required.
diff --git a/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt b/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt
index d82284d..53a67a4 100644
--- a/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt
+++ b/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt
@@ -5,10 +5,14 @@
 - reg : the location and size of the BAM hardware
 - interrupts : the BAM hardware to apps processor interrupt line
 
+Optional properties:
+-qcom,satellite-mode: the hardware needs to be configured in satellite mode
+
 Example:
 
 	qcom,bam_dmux@fc834000 {
 		compatible = "qcom,bam_dmux";
 		reg = <0xfc834000 0x7000>;
 		interrupts = <0 29 1>;
+		qcom,satellite-mode;
 	};
diff --git a/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt b/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt
index 068e256..c1b79ae 100644
--- a/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt
+++ b/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt
@@ -40,3 +40,32 @@
 EXPORT_COMPAT("qcom,a-driver") to the driver, similar to EXPORT_SYMBOL.
 The EXPORT_COMPAT is to ensure that memory is only carved out if the
 driver is actually enabled, otherwise the memory will not be used.
+
+If a reservation is needed that isn't associated directly with any one
+driver, the compatible string "qcom,msm-contig-mem" can be used. For
+example:
+
+	qcom,msm-contig-mem {
+		compatible = "qcom,msm-contig-mem";
+		qcom,memory-reservation-type = "EBI1";
+		qcom,memory-reservation-size = <0x280000>; /* 2.5M EBI1 buffer */
+	};
+
+
+In order to specify the size and address of the fixed memory which has
+previously been removed the memory-fixed binding can be used. This assumes
+that the region has been removed by a separate memblock-remove property
+present in the device tree.
+
+Required parameters:
+-qcom,memory-fixed: base and size of the fixed memory region
+
+	qcom,a-driver {
+		compatible = "qcom,a-driver";
+		/* Fixed Memory region of 4MB at 0x200000*/
+		qcom,memory-fixed = <0x200000 0x400000>;
+	};
+
+This region is assumed to be a part of a separate hole that has been removed
+and this binding specifies the fixed location and size of the region within
+that hole.
diff --git a/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt b/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
new file mode 100644
index 0000000..b429072
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
@@ -0,0 +1,28 @@
+* MSM PM-8x60
+
+PM-8x60 is the low power management device for MSM (Snapdragon class) chipsets.
+This device sets up different components to do low power modes and registers with
+the kernel to be notified of idle and suspend states and when called, follows
+through the set of instructions in putting the application cores to the lowest
+power mode possible.
+
+The required properties for PM-8x60 are:
+
+- compatible: "qcom,pm-8x60"
+
+The optional properties are:
+
+- qcom,use-sync-timer: Indicates whether the target uses the synchronized QTimer.
+- qcom,pc-mode: Indicates the type of power collapse used by the target. The
+           valid values for this are:
+	0  (Power collapse terminates in TZ; integrated L2 cache controller)
+	1, (Power collapse doesn't terminate in TZ; external L2 cache controller)
+	2  (Power collapse terminates in TZ; external L2 cache controller)
+
+Example:
+
+qcom,pm-8x60 {
+		compatible = "qcom,pm-8x60";
+		qcom,pc-mode = <0>;
+		qcom,use-sync-timer;
+	};
diff --git a/Documentation/devicetree/bindings/arm/msm/rpm-stats.txt b/Documentation/devicetree/bindings/arm/msm/rpm-stats.txt
new file mode 100644
index 0000000..3137e91
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/rpm-stats.txt
@@ -0,0 +1,22 @@
+* RPM Sleep Stats
+
+RPM maintains sleep data in the RPM RAM. A device tree node is added
+that will hold the address of the RPM RAM from where sleep stats are read.
+Additionally a version number is added to distinguish the type of data
+structure being read from the RAM.
+
+The required properties for rpm-stats are:
+
+- compatible: "qcom,rpm-stats"
+- reg: The address on the RPM RAM from where stats are read.
+- reg-names: Name given the register holding address.
+- qcom,sleep-stats-version: Version number.
+
+Example:
+
+qcom,rpm-stats@fc19dbd0 {
+		compatible = "qcom,rpm-stats";
+		reg = <0xfc19dbd0 0x1000>;
+		reg-names = "phys_addr_base";
+		qcom,sleep-stats-version = <2>;
+};
diff --git a/Documentation/devicetree/bindings/gpio/qpnp-pin.txt b/Documentation/devicetree/bindings/gpio/qpnp-pin.txt
index 31c3bc2..36ac336 100644
--- a/Documentation/devicetree/bindings/gpio/qpnp-pin.txt
+++ b/Documentation/devicetree/bindings/gpio/qpnp-pin.txt
@@ -94,7 +94,7 @@
 			QPNP_PIN_OUT_STRENGTH_MED  = 2, (GPIO)
 			QPNP_PIN_OUT_STRENGTH_HIGH = 3, (GPIO)
 
-  - qcom,src-select:	select a function for the pin. Certain pins
+  - qcom,src-sel:	select a function for the pin. Certain pins
 			can be paired (shorted) with each other. Some gpio pins
 			can act as alternate functions.
 			In the context of gpio, this acts as a source select.
diff --git a/Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt b/Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt
index 88fca69..bcea355 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt
@@ -29,6 +29,8 @@
 					needed
  - atmel,need-calibration	: specify to indicate whether calibration is
 					needed during wakeup.
+ - atmel,no-force-update	: flag that signifies whether force configuration
+					update is applicable or not
 
 Example:
 	i2c@f9966000 {
@@ -52,7 +54,8 @@
 			vcc_i2c-supply = <&pm8941_lvs1>;
 			atmel,panel-coords = <0 0 479 799>;
 			atmel,display-coords = <0 0 479 799>;
-			atmel,i2c-pull-up = <1>;
+			atmel,i2c-pull-up;
+			atmel,no-force-update;
 			atmel,dig-reg-support;
 			atmel,key-codes = <
 				102 139 0 0 0 0 0 0
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index eda7cba..d7290e0 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -4,9 +4,7 @@
 controlling LEDs that are part of PMIC on Qualcomm reference
 platforms. The PMIC is connected to Host processor via
 SPMI bus. This driver supports various LED modules such as
-WLED (white LED), RGB LED and flash LED. The first version of
-the driver supports WLED and other features are added in the
-next versions.
+WLED (white LED), RGB LED and flash LED.
 
 Required Properties:
 - compatible	: should be "qcom,leds-qpnp"
@@ -37,8 +35,93 @@
 - linux,default-trigger: trigger the led from external modules such as display
 - qcom,default-state:  default state of the led, should be "on" or "off"
 
+Flash is used primarily as a camera or video flash.
+
+Optional properties for flash:
+- qcom,headroom: headroom to use, mV
+- qcom,duration: duration of the flash, ms
+- qcom,clamp-curr: current to clamp at, mA
+- qcom,startup-dly: delay before flashing after flash executed, us
+- qcom,saftey-timer: include for safety timer use, otherwise watchdog timer will be used
+- linux,default-trigger: trigger the led from external modules such as display
+- qcom,default-state:  default state of the led, should be "on" or "off"
+
+RGB Led is a tri-colored led, Red, Blue & Green.
+
+Required properties for RGB led:
+- qcom,mode: mode the led should operate in, options 0 = PWM, 1 = LPG
+- qcom,pwm-channel: pwm channel the led will operate on
+- qcom,pwm-us: time the pwm device will modulate at (us)
+
+Required properties for LPG mode only:
+- qcom,duty-ms: duty cycle time the led will operate at (ms)
+- qcom,duty-pcts: array of values for duty cycle to go through
+- qcom,start-idx: starting point duty-pcts array
+
+Optional properties for RGB led:
+- linux,default-trigger: trigger the led from external modules such as display
+- qcom,default-state:  default state of the led, should be "on" or "off"
+
 Example:
 
+	qcom,leds@d000 {
+		status = "okay";
+		qcom,rgb_pwm {
+			label = "rgb";
+			linux,name = "led:rgb_red";
+			qcom,mode = <0>;
+			qcom,pwm-channel = <6>;
+			qcom,pwm-us = <1000>;
+			qcom,duty-ms = <20>;
+			qcom,start-idx = <1>;
+			qcom,idx-len = <10>;
+			qcom,duty-pcts = [00 19 32 4B 64
+					 64 4B 32 19 00];
+			qcom,max-current = <12>;
+			qcom,default-state = "off";
+			qcom,id = <3>;
+			linux,default-trigger =
+				"battery-charging";
+		};
+
+		qcom,rgb_lpg {
+			label = "rgb";
+			linux,name = "led:rgb_blue";
+			qcom,mode = <1>;
+			qcom,pwm-channel = <4>;
+			qcom,pwm-us = <1000>;
+			qcom,duty-ms = <20>;
+			qcom,start-idx = <1>;
+			qcom,idx-len = <10>;
+			qcom,duty-pcts = [00 19 32 4B 64
+					 64 4B 32 19 00];
+			qcom,max-current = <12>;
+			qcom,default-state = "off";
+			qcom,id = <5>;
+			linux,default-trigger = "none";
+		};
+	};
+
+	qcom,leds@d300 {
+			compatible = "qcom,leds-qpnp";
+			status = "okay";
+			qcom,flash_0 {
+				qcom,max-current = <1000>;
+				qcom,default-state = "off";
+				qcom,headroom = <0>;
+				qcom,duration = <200>;
+				qcom,clamp-curr = <200>;
+				qcom,startup-dly = <1>;
+				qcom,safety-timer;
+				label = "flash";
+				linux,default-trigger =
+					"flash0_trigger";
+				linux,name = "led:flash_0";
+				qcom,current = <625>;
+				qcom,id = <1>;
+			};
+	};
+
 	qcom,leds@d800 {
 			compatible = "qcom,leds-qpnp";
 			status = "okay";
@@ -59,4 +142,3 @@
 				linux,name = "led:wled_backlight";
 			};
 	};
-
diff --git a/Documentation/devicetree/bindings/mmc/msm_sdcc.txt b/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
index 5f7651a..46173a0 100644
--- a/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
+++ b/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
@@ -10,42 +10,56 @@
   "reg-names" examples are "core_mem", "dml_mem" and "bam_mem"
   - interrupts : should contain SDCC core interrupt.
   - interrupt-names : indicates interrupts passed to driver (via interrupts property) by name.
-  "interrupt-names" examples are "core_irq", "bam_irq" and "status_irq"
-  - qcom,sdcc-clk-rates : specifies supported SDCC clock frequencies, Units - Hz.
-  - qcom,sdcc-sup-voltages: specifies supported voltage ranges for card. Should always be
+  "core_irq" is mandatory, "bam_irq" is mandatory only when BAM DMA engine is used,
+  "status_irq" and "sdiowakeup_irq" are optional.
+  - qcom,clk-rates : specifies supported SDCC clock frequencies, Units - Hz.
+  - qcom,sup-voltages: specifies supported voltage ranges for card. Should always be
 			specified in pairs (min, max), Units - mV.
   - <supply-name>-supply: phandle to the regulator device tree node
   "supply-name" examples are "vdd", "vdd-io".
 
 Optional Properties:
 	- cell-index - defines slot ID.
-	- qcom,sdcc-bus-width - defines the bus I/O width that controller supports.
+	- qcom,bus-width - defines the bus I/O width that controller supports.
 	- wp-gpios - specify GPIO for write protect switch detection.
 	- cd-gpios - specify GPIO for card detection.
-	- qcom,sdcc-nonremovable - specifies whether the card in slot is
+	- qcom,nonremovable - specifies whether the card in slot is
 				hot pluggable or hard wired.
-	- qcom,sdcc-disable_cmd23 - disable sending CMD23 to card when controller can't support it.
-	- qcom,sdcc-bus-speed-mode - specifies supported bus speed modes by host.
-	- qcom,sdcc-current-limit - specifies max. current the host can drive.
-	- qcom,sdcc-xpc - specifies if the host can supply more than 150mA for SDXC cards.
+	- qcom,disable-cmd23 - disable sending CMD23 to card when controller can't support it.
+	- qcom,bus-speed-mode - specifies supported bus speed modes by host.
+	- qcom,current-limit - specifies max. current the host can drive.
+	- qcom,xpc - specifies if the host can supply more than 150mA for SDXC cards.
+	- qcom,dat1-mpm-int - specifies MPM interrupt number corresponding to DAT1 line of SDCC
+					(used only if slot has dedicated DAT1 MSM pin (not GPIO))
 
 In the following, <supply> can be vdd (flash core voltage) or vdd-io (I/O voltage).
-	- qcom,sdcc-<supply>-always_on - specifies whether supply should be kept "on" always.
-	- qcom,sdcc-<supply>-lpm_sup - specifies whether supply can be kept in low power mode (lpm).
-	- qcom,sdcc-<supply>-voltage_level - specifies voltage levels for supply. Should be
+	- qcom,<supply>-always-on - specifies whether supply should be kept "on" always.
+	- qcom,<supply>-lpm-sup - specifies whether supply can be kept in low power mode (lpm).
+	- qcom,<supply>-voltage-level - specifies voltage levels for supply. Should be
 	specified in pairs (min, max), units uV.
-	- qcom,sdcc-<supply>-current_level - specifies load levels for supply in lpm or
+	- qcom,<supply>-current-level - specifies load levels for supply in lpm or
 	high power mode (hpm). Should be specified in pairs (lpm, hpm), units uA.
 
 	- gpios - specifies gpios assigned for sdcc slot.
-	- qcom,sdcc-gpio-names -  a list of strings that map in order to the list of gpios
+	- 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,sdcc-pad-pull-on - Active pull configuration for sdc tlmm pins
-	- qcom,sdcc-pad-pull-off - Suspend pull configuration for sdc tlmm pins.
-	- qcom,sdcc-pad-drv-on - Active drive strength configuration for sdc tlmm pins.
-	- qcom,sdcc-pad-drv-off - Suspend drive strength configuration for sdc tlmm pins.
+	- 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>
 
+	- qcom,bus-bw-vectors-bps - specifies array of throughput values in Bytes/sec. The
+	values in the array are determined according to supported bus speed modes. For example,
+	if host supports SDR12 mode, value is 13631488 Bytes/sec.
+	- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
+	below optional properties:
+		- qcom,msm-bus,name
+		- qcom,msm-bus,num-cases
+		- qcom,msm-bus,active-only
+		- qcom,msm-bus,num-paths
+		- qcom,msm-bus,vectors-KBps
+
 Example:
 
 	qcom,sdcc@f9600000 {
@@ -57,8 +71,21 @@
 		0xf9602000 0x2000> // BAM register interface
 
 	interrupts = <123>;
-	qcom,sdcc-clk-rates = <400000 24000000 48000000>;
-	qcom,sdcc-sup-voltages = <2700 3300>;
-	qcom,sdcc-bus-width = <8>; //8-bit wide
-	qcom,sdcc-nonremovable;
+	qcom,clk-rates = <400000 24000000 48000000>;
+	qcom,sup-voltages = <2700 3300>;
+	qcom,bus-width = <8>; //8-bit wide
+	qcom,nonremovable;
+
+	qcom,msm-bus,name = "sdcc2";
+	qcom,msm-bus,num-cases = <7>;
+	qcom,msm-bus,active-only = <0>;
+	qcom,msm-bus,num-paths = <1>;
+	qcom,msm-bus,vectors-KBps = <81 512 0 0>, /* No vote */
+			<81 512 6656 13312>, /* 13 MB/s*/
+			<81 512 13312 26624>, /* 26 MB/s */
+			<81 512 26624 53248>, /* 52 MB/s */
+			<81 512 53248 106496>, /* 104 MB/s */
+			<81 512 106496 212992>, /* 208 MB/s */
+			<81 512 2147483647 4294967295>; /* Max. bandwidth */
+	qcom,bus-bw-vectors-bps = <0 13631488 27262976 54525952 109051904 218103808 4294967295>;
 };
diff --git a/Documentation/devicetree/bindings/pil/pil-mba.txt b/Documentation/devicetree/bindings/pil/pil-mba.txt
deleted file mode 100644
index ce6bb8f..0000000
--- a/Documentation/devicetree/bindings/pil/pil-mba.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-Qualcomm Modem Boot Authenticator Peripheral Image Loader
-
-pil-mba is a peripheral image loader (PIL) driver. It is used for loading
-modem images using the self-authenticating hardware and software features
-of the Modem Boot Authenticator.
-
-Required properties:
-- compatible:	      Must be "qcom,pil-mba"
-- reg:		      Two pairs of physical base addresses and sizes. The
-		      first corresponds to the Relay Message Buffer (RMB)
-		      register base. The second specifies the address at which
-		      the primary modem image metadata should be stored.
-- reg-names:	      Names for the above base addresses. "rmb_base" and
-	              "metadata_base" are expected.
-- interrupts:         The modem watchdog interrupt
-- qcom,firmware-name: Base name of the firmware image. Ex. "modem"
-
-Optional properties:
-- qcom,depends-on:    firmware-name of a prerequisite image that must already
-		      be running.
-
-Example:
-	qcom,mba@fc820000 {
-		compatible = "qcom,pil-mba";
-		reg = <0xfc820000 0x0020>,
-		      <0x0d1f0000 0x4000>;
-		reg-names = "rmb_base", "metadata_base";
-		interrupts = <0 56 1>;
-
-		qcom,firmware-name = "modem";
-		qcom,depends-on    = "mba";
-	};
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index 41ffd8a..556300d 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -10,13 +10,16 @@
 - reg:		      Pairs of physical base addresses and region sizes of
 		      memory mapped registers.
 - reg-names:	      Names of the bases for the above registers. "qdsp6_base",
-		      "halt_base", "rmb_base", "restart_reg" and "clamp_reg"
-		      are expected.
+		      "halt_base", "rmb_base", "restart_reg", and
+		      "metadata_base" are expected.
+- interrupts:         The modem watchdog interrupt
 - vdd_mss-supply:     Reference to the regulator that supplies the processor.
 - qcom,firmware-name: Base name of the firmware image. Ex. "mdsp"
 - qcom,pil-self-auth: <0> if the hardware does not require self-authenticating
 		      images and self-authentication is not desired;
 		      <1> if the hardware requires self-authenticating images.
+- qcom,is_loadable:   <0> if PIL should not load the modem image
+                      <1> if PIL is required to load the modem image
 
 Example:
 	qcom,mss@fc880000 {
@@ -25,11 +28,13 @@
 		      <0xfd485000 0x400>,
 		      <0xfc820000 0x020>,
 		      <0xfc401680 0x004>,
-		      <0xfc980008 0x004>;
+		      <0x0d1f0000 0x4000>;
 		reg-names = "qdsp6_base", "halt_base", "rmb_base",
-			    "restart_reg", "clamp_reg";
+			    "restart_reg", metadata_base";
+		interrupts = <0 24 1>;
 		vdd_mss-supply = <&pm8841_s3>;
 
+		qcom,is_loadable = <1>;
 		qcom,firmware-name = "mba";
 		qcom,pil-self-auth = <1>;
 	};
diff --git a/Documentation/devicetree/bindings/pil/pil-venus.txt b/Documentation/devicetree/bindings/pil/pil-venus.txt
index 4b87f17..232c2cd 100644
--- a/Documentation/devicetree/bindings/pil/pil-venus.txt
+++ b/Documentation/devicetree/bindings/pil/pil-venus.txt
@@ -12,8 +12,6 @@
              "vbif_base" are expected.
 - vdd-supply: regulator to supply venus.
 - qcom,firmware-name: Base name of the firmware image. Ex. "venus"
-- qcom,firmware-min-paddr: The lowest addr boundary for firmware image in DDR
-- qcom,firmware-max-paddr: The highest addr boundary for firmware image in DDR
 
 Example:
         qcom,venus@fdce0000 {
@@ -24,7 +22,4 @@
                 vdd-supply = <&gdsc_venus>;
 
                 qcom,firmware-name = "venus";
-                qcom,firmware-min-paddr = <0xF500000>;
-                qcom,firmware-max-paddr = <0xFA00000>;
-
         };
diff --git a/Documentation/devicetree/bindings/power/bq28400-battery.txt b/Documentation/devicetree/bindings/power/bq28400-battery.txt
index 3879b4d..1460d70 100644
--- a/Documentation/devicetree/bindings/power/bq28400-battery.txt
+++ b/Documentation/devicetree/bindings/power/bq28400-battery.txt
@@ -5,13 +5,13 @@
 The device is usually embedded inside the "smart battery" pack.
 
 node required properties:
-- compatible:	Must be "ti,bq28400-battery".
+- compatible:	Must be "ti,bq28400-battery" or "ti,bq30z55-battery"
 - reg:		I2C Address must be 0xb.
 
 Example:
 	i2c@f9967000 {
 		battery@b {
-			compatible = "ti,bq28400-battery";
+			compatible = "ti,bq28400-battery", "ti,bq30z55-battery";
 			reg = <0xb>;
 		};
 	};
diff --git a/Documentation/devicetree/bindings/power/smb137c-charger.txt b/Documentation/devicetree/bindings/power/smb137c-charger.txt
new file mode 100644
index 0000000..c0c4333
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/smb137c-charger.txt
@@ -0,0 +1,86 @@
+Summit SMB137C Battery Charger
+
+The SMB137C is controlled via an I2C bus.  Its 7-bit I2C slave address is
+programmed during manufacturing.
+
+Required properties:
+- compatible:		Must be "summit,smb137c".
+- reg:			The device's 7-bit I2C address.
+
+Optional properties:
+- summit,chg-current-ma		Maximum battery charging current in milliamps.
+				Supported values are: 500, 650, 750, 850, 950,
+				1100, 1300, and 1500.
+- summit,term-current-ma	Charging terminaton current in milliamps.
+				Supported values are: 0, 35, 50, 100, and 150.
+				A value of 0 means no termination current is
+				used.
+- summit,pre-chg-current-ma	Maximum battery pre-charging current in
+				milliamps.  This current limit is applied while
+				the battery voltage is below the pre-charge /
+				fast-charge threshold.  Supported values are:
+				50, 100, 150, and 200.
+- summit,float-voltage-mv	Battery voltage threshold in millivolts at which
+				point charging switches from constant current to
+				constant voltage.  Supported values are: 3460 up
+				through 4730 in 10 mV steps.
+- summit,thresh-voltage-mv	Threshold voltage in millivolts which is used to
+				switch between pre-charge and fast-charge
+				current limits.  Supported values are: 2400 up
+				to 3100 in 100 mV steps.
+- summit,recharge-thresh-mv	Specifies the minimum voltage drop in millivolts
+				below the float voltage that is required in
+				order to initiate a new charging cycle.
+				Supported values are: 75 and 120.
+- summit,system-voltage-mv	Regulated voltage output on the VOUTL pin in
+				millivolts.  Supported values are 4250 and 4460.
+- summit,charging-timeout	Maximum duration in minutes that a single charge
+				cycle may last.  Supported values are: 0, 382,
+				764, and 1527.  A value of 0 means that no
+				charge cycle timeout is used and charging can
+				continue indefinitely.
+- summit,pre-charge-timeout	Maximum time in minutes spent in the pre-charge
+				state in any given charge cycle.  Supports
+				values are: 0, 48, 95, and 191.  A value of 0
+				means that there is no limit to the amount of
+				time that may be spent in the pre-charge state.
+- summit,therm-current-ua	Thermistor current in microamps to be used for
+				battery temperature monitoring.  Supported
+				values are 10, 20, 40, and 100.  These values
+				correspond to 100, 50, 25, and 10 kohm NTC
+				thermistors respectively.
+- summit,temperature-min	Specifies the minimum temperature at which
+				charging is allowed.  Supported values are
+				0 to 7.  These values correspond to -20 C to
+				+15 C in 5 C increments for an NTC thermistor
+				with beta = 4400.
+- summit,temperature-max	Specifies the maximum temperature at which
+				charging is allowed.  Supported values are
+				0 to 7.  These values correspond to +30 C to
+				+65 C in 5 C increments for an NTC thermistor
+				with beta = 4400.
+
+Note: If an optional property is not specified, then the hardware default value
+will be used.
+
+Example:
+/ {
+	i2c@f9925000 {
+		charger@57 {
+			compatible = "summit,smb137c";
+			reg = <0x57>;
+			summit,chg-current-ma = <1500>;
+			summit,term-current-ma = <50>;
+			summit,pre-chg-current-ma = <100>;
+			summit,float-voltage-mv = <4200>;
+			summit,thresh-voltage-mv = <3000>;
+			summit,recharge-thresh-mv = <75>;
+			summit,system-voltage-mv = <4250>;
+			summit,charging-timeout = <382>;
+			summit,pre-charge-timeout = <48>;
+			summit,therm-current-ua = <10>;
+			summit,temperature-min = <4>; /*  0 C */
+			summit,temperature-max = <3>; /* 45 C */
+		};
+	};
+};
diff --git a/Documentation/devicetree/bindings/regulator/krait-regulator.txt b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
new file mode 100644
index 0000000..fddae80
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
@@ -0,0 +1,27 @@
+Krait Voltage regulators
+
+Required properties:
+- compatible:			Must be "qcom,krait-regulator"
+- reg:				Specifies the address and size for this regulator device
+- qcom,headroom-voltage:	The minimum required voltage drop between the input
+			 	voltage and the output voltage for the LDO to be
+			 	operational, in microvolts
+- qcom,retention-voltage:	The value for retention voltage in microvolts
+- qcom,ldo-default-voltage:	The default value for LDO voltage in microvolts
+- qcom,ldo-threshold-voltage:	The voltage value above which LDO is nonfunctional
+
+Any property defined as part of the core regulator
+binding, defined in regulator.txt, can also be used.
+
+Example:
+	krait0_vreg: regulator@f9088000 {
+		compatible = "qcom,krait-regulator";
+		regulator-name = "krait0";
+		reg = <0xf9088000 0x1000>;
+		regulator-min-microvolt = <500000>;
+		regulator-max-microvolt = <1100000>;
+		qcom,headroom-voltage = <150000>;
+		qcom,retention-voltage = <745000>;
+		qcom,ldo-default-voltage = <745000>;
+		qcom,ldo-threshold-voltage = <750000>;
+	};
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 9743d0d..bf605ec 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -212,6 +212,36 @@
 			qcom,msm-dai-q6-dev-id = <16385>;
 		};
 
+		qcom,msm-dai-q6-sb-1-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16386>;
+		};
+
+		qcom,msm-dai-q6-sb-1-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16387>;
+		};
+
+		qcom,msm-dai-q6-sb-3-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16390>;
+		};
+
+		qcom,msm-dai-q6-sb-3-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16391>;
+		};
+
+		qcom,msm-dai-q6-sb-4-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16392>;
+		};
+
+		qcom,msm-dai-q6-sb-4-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16393>;
+		};
+
 		qcom,msm-dai-q6-bt-sco-rx {
 			compatible = "qcom,msm-dai-q6-dev";
 			qcom,msm-dai-q6-dev-id = <12288>;
diff --git a/Documentation/devicetree/bindings/tty/serial/msm_serial.txt b/Documentation/devicetree/bindings/tty/serial/msm_serial.txt
index 3b0426b..e784bfa 100644
--- a/Documentation/devicetree/bindings/tty/serial/msm_serial.txt
+++ b/Documentation/devicetree/bindings/tty/serial/msm_serial.txt
@@ -34,10 +34,15 @@
 - reg : offset and length of the register set for the device.
 - interrupts : should contain the uart interrupt.
 
+Optional properties:
+- cell-index: An integer specifying the line number of the UART device that
+  represents this HSL hardware instance.
+
 Example:
 
 	serial@19c400000 {
 		compatible = "qcom,msm-lsuart-v14"
 		reg = <0x19c40000 0x1000">;
 		interrupts = <195>;
+		cell-index = <0>;	// this device will be named ttyHSL0
 	};
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 186a58d..7bff0f2 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -81,13 +81,16 @@
 - compatible: should be "qcom,android-usb"
 
 Optional properties :
-- reg  : offset and length of memory region that is used by driver to
+- reg  : offset and length of memory region that is used by device to
   update USB PID and serial numbers used by bootloader in DLOAD mode.
+- qcom,android-usb-swfi-latency : value to be used by device to vote
+  for DMA latency in microsecs.
 
 Example Android USB device node :
 	android_usb@fc42b0c8 {
 		compatible = "qcom,android-usb";
 		reg = <0xfc42b0c8 0xc8>;
+		qcom,android-usb-swfi-latency = <1>;
 	};
 
 
diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
index 99274d5..57d776f 100644
--- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
@@ -28,8 +28,10 @@
 - interrupt-names : Optional interrupt resource entries are:
     "hs_phy_irq" : Interrupt from HSPHY for asynchronous events in LPM.
 	This is not used if wakeup events are received externally (e.g. PMIC)
-- qcom,dwc-usb3-msm-otg-capability: If present then depends on PMIC
-  for VBUS notifications, otherwise depends on PHY.
+- qcom,otg-capability: If present then depend on PMIC for VBUS notifications,
+  otherwise depend on PHY.
+- qcom,charging-disabled: If present then battery charging using USB
+  is disabled.
 
 Example MSM USB3.0 controller device node :
 	usb@f9200000 {
diff --git a/Documentation/trace/events-msm-low-power.txt b/Documentation/trace/events-msm-low-power.txt
new file mode 100644
index 0000000..5414146
--- /dev/null
+++ b/Documentation/trace/events-msm-low-power.txt
@@ -0,0 +1,57 @@
+Subsystem Trace Points: msm_low_power
+
+The msm_low_power tracing system captures the events during the entry
+and exit of various low power modes like power collapse, standalone
+power collapse, retention and wfi. The tracing system adds the following
+events to capture the state of the low power mode.
+
+1) msm_pm_enter
+===================
+msm_pm_enter: cpu: %u latency: %uus sleep: %uus
+msm_pm_enter_pc: cpu: %u latency: %uus sleep: %uus wake_up: %u
+msm_pm_enter_ret: cpu: %u latency: %uus sleep: %uus wake_up: %u
+msm_pm_enter_spc: cpu: %u latency: %uus sleep: %uus wake_up: %u
+msm_pm_enter_wfi: cpu: %u latency: %uus sleep: %uus wake_up: %u
+
+The event captures various parameters during the entry into low power
+modes.
+
+The 'cpu' parameter represents the cpu on which the low power mode is
+chosen.
+
+The 'latency_us' parameter represents the system latency at the time of
+choosing the low power mode.
+
+The 'sleep_us' parameter tells the maximum amount of time the kernel can
+sleep in this low power mode.
+
+The 'wake_up' parameter tells if there was any immediate wakeup required
+before entering low power mode.
+
+2) msm_pm_exit
+=================
+msm_pm_exit: cpu:%u success:%d
+msm_pm_exit_pc: cpu:%u success:%d
+msm_pm_exit_ret: cpu:%u success:%d
+msm_pm_exit_spc: cpu:%u success:%d
+msm_pm_exit_wfi: cpu:%u success:%d
+
+The event captures parameters during the exit of the low power modes.
+
+The 'cpu' parameter represents the cpu on which the low power mode is chosen.
+
+The 'success' parameter shows the state of power collapse/standalone power
+collapse. It will be set if power collapse/standalone power collapse were
+successful. For the rest of the low power modes it is set to one.
+
+3) lpm_resources
+=================
+lpm_resources: name:%s sleep_value:%d
+
+This event captures parameters for each of the lpm resources.
+
+The 'name' parameter represents the name of the lpm resource and it can hold
+l2, pxo, vdd mem, vdd dig depending on the resource chosen during power
+collapse.
+
+The 'sleep_value' parameter corresponds to the sleep value set for the resource.
diff --git a/arch/arm/boot/dts/mpq8092-regulator.dtsi b/arch/arm/boot/dts/mpq8092-regulator.dtsi
index fbc9586..b724a3d 100644
--- a/arch/arm/boot/dts/mpq8092-regulator.dtsi
+++ b/arch/arm/boot/dts/mpq8092-regulator.dtsi
@@ -159,7 +159,7 @@
 		};
 
 		pm8644_l13: regulator@4c00 {
-			regulator-min-microvolt = <2950000>;
+			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <2950000>;
 			qcom,enable-time = <200>;
 			qcom,pull-down-enable = <1>;
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
index 470d540..7961b78 100644
--- a/arch/arm/boot/dts/mpq8092.dtsi
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -65,6 +65,7 @@
 		/* 190,ee0_krait_hlos_spmi_periph_irq */
 		/* 187,channel_0_krait_hlos_trans_done_irq */
 		interrupts = <0 190 0 0 187 0>;
+		qcom,not-wakeup;
 		qcom,pmic-arb-ee = <0>;
 		qcom,pmic-arb-channel = <0>;
 		qcom,pmic-arb-ppid-map = <0x00100000>, /* PM8644_0 */
@@ -237,16 +238,16 @@
 		interrupts = <0 123 0>;
 		interrupt-names = "core_irq";
 
-		qcom,sdcc-pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-		qcom,sdcc-pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-		qcom,sdcc-pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
-		qcom,sdcc-pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+		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,sdcc-clk-rates = <400000 25000000 50000000 100000000 200000000>;
-		qcom,sdcc-sup-voltages = <2950 2950>;
-		qcom,sdcc-bus-width = <8>;
-		qcom,sdcc-nonremovable;
-		qcom,sdcc-bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+		qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+		qcom,sup-voltages = <2950 2950>;
+		qcom,bus-width = <8>;
+		qcom,nonremovable;
+		qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
 	};
 
 	sdcc2: qcom,sdcc@f98a4000 {
@@ -257,17 +258,17 @@
 		interrupts = <0 125 0>;
 		interrupt-names = "core_irq";
 
-		qcom,sdcc-pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-		qcom,sdcc-pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-		qcom,sdcc-pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
-		qcom,sdcc-pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+		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,sdcc-clk-rates = <400000 25000000 50000000 100000000 200000000>;
-		qcom,sdcc-sup-voltages = <2950 2950>;
-		qcom,sdcc-bus-width = <4>;
-		qcom,sdcc-xpc;
-		qcom,sdcc-bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
-		qcom,sdcc-current-limit = <800>;
+		qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+		qcom,sup-voltages = <2950 2950>;
+		qcom,bus-width = <4>;
+		qcom,xpc;
+		qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+		qcom,current-limit = <800>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index de30884..4ec5684 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -136,14 +136,14 @@
 						<0x0 0x10 0x6>,
 						<0x0 0x10 0x7>;
 
-				interrupt-names =	"chg-done",
-							"chg-failed",
-							"fast-chg-on",
-							"trkl-chg-on",
-							"state-change",
-							"chgwdog",
+				interrupt-names =	"vbat-det-lo",
 							"vbat-det-hi",
-							"vbat-det-lo";
+							"chgwdog",
+							"state-change",
+							"trkl-chg-on",
+							"fast-chg-on",
+							"chg-failed",
+							"chg-done";
 			};
 
 			qcom,chg-buck@1100 {
@@ -157,13 +157,13 @@
 						<0x0 0x11 0x5>,
 						<0x0 0x11 0x6>;
 
-				interrupt-names =	"vdd-loop",
-							"ibat-loop",
-							"ichg-loop",
-							"vchg-loop",
+				interrupt-names =	"vbat-ov",
+							"vreg-ov",
 							"overtemp",
-							"vref-ov",
-							"vbat-ov";
+							"vchg-loop",
+							"ichg-loop",
+							"ibat-loop",
+							"vdd-loop";
 			};
 
 			qcom,chg-bat-if@1200 {
@@ -175,11 +175,12 @@
 						<0x0 0x12 0x3>,
 						<0x0 0x12 0x4>;
 
-				interrupt-names =	"psi",
-							"vcp-on",
-							"bat-fet-on",
+				interrupt-names =	"batt-pres",
 							"bat-temp-ok",
-							"batt-pres";
+							"bat-fet-on",
+							"vcp-on",
+							"psi";
+
 			};
 
 			qcom,chg-usb-chgpth@1300 {
@@ -200,8 +201,8 @@
 				interrupts =	<0x0 0x14 0x0>,
 						<0x0 0x14 0x1>;
 
-				interrupt-names =	"dcin-valid",
-							"coarse-det-dc";
+				interrupt-names =	"coarse-det-dc",
+							"dcin-valid";
 			};
 
 			qcom,chg-boost@1500 {
@@ -210,8 +211,8 @@
 				interrupts =	<0x0 0x15 0x0>,
 						<0x0 0x15 0x1>;
 
-				interrupt-names =	"limit-error",
-							"boost-pwr-ok";
+				interrupt-names =	"boost-pwr-ok",
+							"limit-error";
 			};
 
 			qcom,chg-misc@1600 {
@@ -993,6 +994,54 @@
 			status = "disabled";
 		};
 
+		qcom,leds@d000 {
+			compatible = "qcom,leds-qpnp";
+			reg = <0xd000 0x100>;
+			label = "rgb";
+		};
+
+		qcom,leds@d100 {
+			compatible = "qcom,leds-qpnp";
+			reg = <0xd100 0x100>;
+			label = "rgb";
+		};
+
+		qcom,leds@d200 {
+			compatible = "qcom,leds-qpnp";
+			reg = <0xd200 0x100>;
+			label = "rgb";
+		};
+
+		qcom,leds@d300 {
+			compatible = "qcom,leds-qpnp";
+			reg = <0xd300 0x100>;
+			label = "flash";
+		};
+
+		qcom,leds@d400 {
+			compatible = "qcom,leds-qpnp";
+			reg = <0xd400 0x100>;
+			label = "flash";
+		};
+
+		qcom,leds@d500 {
+			compatible = "qcom,leds-qpnp";
+			reg = <0xd500 0x100>;
+			label = "flash";
+		};
+
+		qcom,leds@d600 {
+			compatible = "qcom,leds-qpnp";
+			reg = <0xd600 0x100>;
+			label = "flash";
+		};
+
+		qcom,leds@d700 {
+			compatible = "qcom,leds-qpnp";
+			reg = <0xd700 0x100>;
+			label = "flash";
+		};
+
 		qcom,leds@d800 {
 			compatible = "qcom,leds-qpnp";
 			reg = <0xd800 0x100>;
diff --git a/arch/arm/boot/dts/msm8226-ion.dtsi b/arch/arm/boot/dts/msm8226-ion.dtsi
index beaffe5..b06ad42 100644
--- a/arch/arm/boot/dts/msm8226-ion.dtsi
+++ b/arch/arm/boot/dts/msm8226-ion.dtsi
@@ -19,5 +19,33 @@
 		qcom,ion-heap@30 { /* SYSTEM HEAP */
 			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>;
+		};
+
+		qcom,ion-heap@27 { /* QSECOM HEAP */
+			compatible = "qcom,msm-ion-reserve";
+			reg = <27>;
+			qcom,heap-align = <0x1000>;
+			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
+			qcom,memory-reservation-size = <0x780000>;
+		};
+
+		qcom,ion-heap@28 { /* AUDIO HEAP */
+			compatible = "qcom,msm-ion-reserve";
+			reg = <28>;
+			qcom,heap-align = <0x1000>;
+			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
+			qcom,memory-reservation-size = <0x314000>;
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
new file mode 100644
index 0000000..8fe94a5
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -0,0 +1,274 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ */
+
+ /* Stub Regulators */
+
+ / {
+	pm8026_s1: regulator-s1 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_s1";
+		qcom,hpm-min-load = <100000>;
+		regulator-min-microvolt = <1150000>;
+		regulator-max-microvolt = <1150000>;
+	};
+
+	pm8026_s2: regulator-s2 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_s2";
+		qcom,hpm-min-load = <100000>;
+		regulator-min-microvolt = <1050000>;
+		regulator-max-microvolt = <1050000>;
+	};
+
+	pm8026_s3: regulator-s3 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_s3";
+		qcom,hpm-min-load = <100000>;
+		regulator-min-microvolt = <1300000>;
+		regulator-max-microvolt = <1300000>;
+	};
+
+	pm8026_s4: regulator-s4 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_s4";
+		qcom,hpm-min-load = <100000>;
+		regulator-min-microvolt = <2100000>;
+		regulator-max-microvolt = <2100000>;
+	};
+
+	pm8026_s5: regulator-s5 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_s5";
+		qcom,hpm-min-load = <100000>;
+		regulator-min-microvolt = <1150000>;
+		regulator-max-microvolt = <1150000>;
+	};
+
+	pm8026_l1: regulator-l1 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_l1";
+		parent-supply = <&pm8026_s3>;
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1225000>;
+		regulator-max-microvolt = <1225000>;
+	};
+
+	pm8026_l2: regulator-l2 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_l2";
+		parent-supply = <&pm8026_s3>;
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1200000>;
+		regulator-max-microvolt = <1200000>;
+	};
+
+	pm8026_l3: regulator-l3 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_l3";
+		parent-supply = <&pm8026_s3>;
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1150000>;
+		regulator-max-microvolt = <1150000>;
+	};
+
+	pm8026_l4: regulator-l4 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_l4";
+		parent-supply = <&pm8026_s3>;
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1200000>;
+		regulator-max-microvolt = <1200000>;
+	};
+
+	pm8026_l5: regulator-l5 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_l5";
+		parent-supply = <&pm8026_s3>;
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1200000>;
+		regulator-max-microvolt = <1200000>;
+	};
+
+	pm8026_l6: regulator-l6 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_l6";
+		parent-supply = <&pm8026_s4>;
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	pm8026_l7: regulator-l7 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_l7";
+		parent-supply = <&pm8026_s4>;
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1850000>;
+		regulator-max-microvolt = <1850000>;
+	};
+
+	pm8026_l8: regulator-l8 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_l8";
+		parent-supply = <&pm8026_s4>;
+		qcom,hpm-min-load = <5000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	pm8026_l9: regulator-l9 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_l9";
+		parent-supply = <&pm8026_s4>;
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <2050000>;
+		regulator-max-microvolt = <2050000>;
+	};
+
+	pm8026_l10: regulator-l10 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_l10";
+		parent-supply = <&pm8026_s4>;
+		qcom,hpm-min-load = <5000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	pm8026_l12: regulator-l12 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_l12";
+		qcom,hpm-min-load = <5000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	pm8026_l14: regulator-l14 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_l14";
+		qcom,hpm-min-load = <5000>;
+		regulator-min-microvolt = <2750000>;
+		regulator-max-microvolt = <2750000>;
+	};
+
+	pm8026_l15: regulator-l15 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_l15";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <2800000>;
+		regulator-max-microvolt = <2800000>;
+	};
+
+	pm8026_l16: regulator-l16 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_l16";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <3000000>;
+		regulator-max-microvolt = <3000000>;
+	};
+
+	pm8026_l17: regulator-l17 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_l17";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <2950000>;
+		regulator-max-microvolt = <2950000>;
+	};
+
+	pm8026_l18: regulator-l18 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_l18";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <2950000>;
+		regulator-max-microvolt = <2950000>;
+	};
+
+	pm8026_l19: regulator-l19 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_l19";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <2850000>;
+		regulator-max-microvolt = <2850000>;
+	};
+
+	pm8026_l20: regulator-l20 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_l20";
+		qcom,hpm-min-load = <5000>;
+		regulator-min-microvolt = <3075000>;
+		regulator-max-microvolt = <3075000>;
+	};
+
+	pm8026_l21: regulator-l21 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_l21";
+		qcom,hpm-min-load = <5000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <2950000>;
+	};
+
+	pm8026_l22: regulator-l22 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_l22";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <2950000>;
+	};
+
+	pm8026_l23: regulator-l23 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_l23";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <2950000>;
+	};
+
+	pm8026_l24: regulator-l24 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_l24";
+		parent-supply = <&pm8026_s3>;
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1300000>;
+		regulator-max-microvolt = <1300000>;
+	};
+
+	pm8026_l26: regulator-l26 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_l26";
+		parent-supply = <&pm8026_s3>;
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1225000>;
+		regulator-max-microvolt = <1225000>;
+	};
+
+	pm8026_l27: regulator-l27 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_l27";
+		parent-supply = <&pm8026_s4>;
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <2050000>;
+		regulator-max-microvolt = <2050000>;
+	};
+
+	pm8026_l28: regulator-l28 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_l28";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <2950000>;
+	};
+
+	 pm8026_lvs1: regulator-lvs1 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8026_lvs1";
+		parent-supply = <&pm8026_l6>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8226-sim.dts b/arch/arm/boot/dts/msm8226-sim.dts
index 7c25680..41ac69d 100644
--- a/arch/arm/boot/dts/msm8226-sim.dts
+++ b/arch/arm/boot/dts/msm8226-sim.dts
@@ -12,7 +12,6 @@
 
 /dts-v1/;
 /include/ "msm8226.dtsi"
-/include/ "msm8226-ion.dtsi"
 /include/ "msm8226-camera.dtsi"
 
 / {
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 6d2ffec..f0e950a 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -11,6 +11,7 @@
  */
 
 /include/ "skeleton.dtsi"
+/include/ "msm8226-ion.dtsi"
 
 / {
 	model = "Qualcomm MSM 8226";
@@ -58,6 +59,9 @@
 		reg = <0xf9a55000 0x400>;
 		interrupts = <0 134 0>;
 		interrupt-names = "core_irq";
+                HSUSB_VDDCX-supply = <&pm8026_s1>;
+                HSUSB_1p8-supply = <&pm8026_l10>;
+                HSUSB_3p3-supply = <&pm8026_l20>;
 
 		qcom,hsusb-otg-phy-type = <2>;
 		qcom,hsusb-otg-mode = <1>;
@@ -70,3 +74,5 @@
 	};
 
 };
+
+/include/ "msm8226-regulator.dtsi"
diff --git a/arch/arm/boot/dts/msm8910-regulator.dtsi b/arch/arm/boot/dts/msm8910-regulator.dtsi
new file mode 100644
index 0000000..a32d4ab
--- /dev/null
+++ b/arch/arm/boot/dts/msm8910-regulator.dtsi
@@ -0,0 +1,218 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ */
+
+ /* Stub Regulators */
+
+ / {
+	pm8110_s1: regulator-s1 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8110_s1";
+		qcom,hpm-min-load = <100000>;
+		regulator-min-microvolt = <1150000>;
+		regulator-max-microvolt = <1150000>;
+	};
+
+	pm8110_s2: regulator-s2 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8110_s2";
+		qcom,hpm-min-load = <100000>;
+		regulator-min-microvolt = <1050000>;
+		regulator-max-microvolt = <1050000>;
+	};
+
+	pm8110_s3: regulator-s3 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8110_s3";
+		qcom,hpm-min-load = <100000>;
+		regulator-min-microvolt = <1350000>;
+		regulator-max-microvolt = <1350000>;
+	};
+
+	pm8110_s4: regulator-s4 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8110_s4";
+		qcom,hpm-min-load = <100000>;
+		regulator-min-microvolt = <2150000>;
+		regulator-max-microvolt = <2150000>;
+	};
+
+	pm8110_l1: regulator-l1 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8110_l1";
+		parent-supply = <&pm8110_s3>;
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1225000>;
+		regulator-max-microvolt = <1225000>;
+	};
+
+	pm8110_l2: regulator-l2 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8110_l2";
+		parent-supply = <&pm8110_s3>;
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1200000>;
+		regulator-max-microvolt = <1200000>;
+	};
+
+	pm8110_l3: regulator-l3 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8110_l3";
+		parent-supply = <&pm8110_s3>;
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1150000>;
+		regulator-max-microvolt = <1150000>;
+	};
+
+	pm8110_l4: regulator-l4 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8110_l4";
+		parent-supply = <&pm8110_s3>;
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1200000>;
+		regulator-max-microvolt = <1200000>;
+	};
+
+	pm8110_l5: regulator-l5 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8110_l5";
+		parent-supply = <&pm8110_s3>;
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1300000>;
+		regulator-max-microvolt = <1300000>;
+	};
+
+	pm8110_l6: regulator-l6 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8110_l6";
+		parent-supply = <&pm8110_s4>;
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	pm8110_l7: regulator-l7 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8110_l7";
+		parent-supply = <&pm8110_s4>;
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <2050000>;
+		regulator-max-microvolt = <2050000>;
+	};
+
+	pm8110_l8: regulator-l8 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8110_l8";
+		parent-supply = <&pm8110_s4>;
+		qcom,hpm-min-load = <5000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	pm8110_l9: regulator-l9 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8110_l9";
+		parent-supply = <&pm8110_s4>;
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <2050000>;
+		regulator-max-microvolt = <2050000>;
+	};
+
+	pm8110_l10: regulator-l10 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8110_l10";
+		parent-supply = <&pm8110_s4>;
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	pm8110_l12: regulator-l12 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8110_l12";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	pm8110_l14: regulator-l14 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8110_l14";
+		parent-supply = <&pm8110_s4>;
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	pm8110_l15: regulator-l15 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8110_l15";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	pm8110_l16: regulator-l16 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8110_l16";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <3000000>;
+		regulator-max-microvolt = <3000000>;
+	};
+
+	pm8110_l17: regulator-l17 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8110_l17";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <2900000>;
+		regulator-max-microvolt = <2900000>;
+	};
+
+	pm8110_l18: regulator-l18 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8110_l18";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <2950000>;
+	};
+
+	pm8110_l19: regulator-l19 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8110_l19";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <2850000>;
+		regulator-max-microvolt = <2850000>;
+	};
+
+	pm8110_l20: regulator-l20 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8110_l20";
+		qcom,hpm-min-load = <5000>;
+		regulator-min-microvolt = <3075000>;
+		regulator-max-microvolt = <3075000>;
+	};
+
+	pm8110_l21: regulator-l21 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8110_l21";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <2950000>;
+	};
+
+	pm8110_l22: regulator-l22 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8110_l22";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <3300000>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8910.dtsi b/arch/arm/boot/dts/msm8910.dtsi
index 83dabfb..1f3c1d8 100644
--- a/arch/arm/boot/dts/msm8910.dtsi
+++ b/arch/arm/boot/dts/msm8910.dtsi
@@ -51,6 +51,9 @@
 		reg = <0xf9a55000 0x400>;
 		interrupts = <0 134 0>;
 		interrupt-names = "core_irq";
+		HSUSB_VDDCX-supply = <&pm8110_s1>;
+		HSUSB_1p8-supply = <&pm8110_l10>;
+		HSUSB_3p3-supply = <&pm8110_l20>;
 
 		qcom,hsusb-otg-phy-type = <2>;
 		qcom,hsusb-otg-mode = <1>;
@@ -62,4 +65,47 @@
 		compatible = "qcom,android-usb";
 	};
 
+	sdcc1: qcom,sdcc@f9824000 {
+		cell-index = <1>; /* SDC1 eMMC slot */
+		compatible = "qcom,msm-sdcc";
+		reg = <0xf9824000 0x800>;
+		reg-names = "core_mem";
+		interrupts = <0 123 0>;
+		interrupt-names = "core_irq";
+
+		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,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+		qcom,sup-voltages = <2950 2950>;
+		qcom,bus-width = <8>;
+		qcom,nonremovable;
+		qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+	};
+
+	sdcc2: qcom,sdcc@f98a4000 {
+		cell-index = <2>; /* SDC2 SD card slot */
+		compatible = "qcom,msm-sdcc";
+		reg = <0xf98a4000 0x800>;
+		reg-names = "core_mem";
+		interrupts = <0 125 0>;
+		interrupt-names = "core_irq";
+
+		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,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+		qcom,sup-voltages = <2950 2950>;
+		qcom,bus-width = <4>;
+		qcom,xpc;
+		qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+		qcom,current-limit = <800>;
+	};
+
 };
+
+/include/ "msm8910-regulator.dtsi"
diff --git a/arch/arm/boot/dts/msm8974-cdp.dts b/arch/arm/boot/dts/msm8974-cdp.dts
index 0e0f6cf..b8b3141 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-cdp.dts
@@ -13,356 +13,10 @@
 /dts-v1/;
 
 /include/ "msm8974.dtsi"
-/include/ "dsi-panel-toshiba-720p-video.dtsi"
+/include/ "msm8974-cdp.dtsi"
 
 / {
 	model = "Qualcomm MSM 8974 CDP";
 	compatible = "qcom,msm8974-cdp", "qcom,msm8974";
 	qcom,msm-id = <126 1 0>;
-
-	serial@f991e000 {
-		status = "ok";
-	};
-
-	qcom,mdss_dsi@fd922800 {
-		qcom,mdss_dsi_toshiba_720p_video {
-			status = "ok";
-		};
-	};
-
-	qcom,hdmi_tx@fd922100 {
-		status = "ok";
-	};
-
-	i2c@f9924000 {
-		atmel_mxt_ts@4a {
-			compatible = "atmel,mxt-ts";
-			reg = <0x4a>;
-			interrupt-parent = <&msmgpio>;
-			interrupts = <61 0x2>;
-			vdd_ana-supply = <&pm8941_l18>;
-			vcc_i2c-supply = <&pm8941_lvs1>;
-			atmel,reset-gpio = <&msmgpio 60 0x00>;
-			atmel,irq-gpio = <&msmgpio 61 0x00>;
-			atmel,panel-coords = <0  0 760 1424>;
-			atmel,display-coords = <0 0 720 1280>;
-			atmel,i2c-pull-up = <1>;
-			atmel,cfg_1 {
-				atmel,family-id = <0x82>;
-				atmel,variant-id = <0x19>;
-				atmel,version = <0x10>;
-				atmel,build = <0xaa>;
-				atmel,config = [
-					/* Object 6, Instance = 0 */
-					00 00 00 00 00 00
-					/* Object 38, Instance = 0 */
-					15 00 02 10 08 0C 00 00
-					/* Object 7, Instance = 0 */
-					FF FF 32 03
-					/* Object 8, Instance = 0 */
-					0F 00 0A 0A 00 00 0A 00 00 00
-					/* Object 9, Instance = 0 */
-					83 00 00 18 0E 00 70 32 02 01
-					00 03 01 01 05 0A 0A 0A 90 05
-					F8 02 00 00 0F 0F 00 00 48 2D
-					07 0C 00 00 00 00
-					/* Object 15, Instance = 0 */
-					00 00 00 00 00 00 00 00 00 00
-					00
-					/* Object 18, Instance = 0 */
-					00 00
-					/* Object 19, Instance = 0 */
-					00 00 00 00 00 00
-					/* Object 23, Instance = 0 */
-					00 00 00 00 00 00 00 00 00 00
-					00 00 00 00 00
-					/* Object 25, Instance = 0 */
-					00 00 00 00 00 00 00 00 00 00
-					00 00 00 00 00
-					/* Object 40, Instance = 0 */
-					00 00 00 00 00
-					/* Object 42, Instance = 0 */
-					00 00 00 00 00 00 00 00 00 00
-					/* Object 46, Instance = 0 */
-					00 00 10 10 00 00 03 00 00 01
-					/* Object 47, Instance = 0 */
-					08 0A 28 0A 02 0A 00 8C 00 20
-					00 00 00
-					/* Object 55, Instance = 0 */
-					00 00 00 00 00 00
-					/* Object 56, Instance = 0 */
-					03 00 01 18 05 05 05 05 05 05
-					05 05 05 05 05 05 05 05 05 05
-					05 05 05 05 05 05 05 05 00 00
-					00 00 00 00 00 00 00 00 00 00
-					00 00
-					/* Object 57, Instance = 0 */
-					00 00 00
-					/* Object 61, Instance = 0 */
-					00 00 00 00 00
-					/* Object 61, Instance = 1 */
-					00 00 00 00 00
-					/* Object 62, Instance = 0 */
-					7F 03 00 16 00 00 00 00 00 00
-					04 08 10 18 05 00 0A 05 05 50
-					14 19 34 1A 64 00 00 04 40 00
-					00 00 00 00 30 32 02 00 01 00
-					05 00 00 00 00 00 00 00 00 00
-					00 00 0C 00
-					];
-			};
-		};
-	};
-
-	gpio_keys {
-		compatible = "gpio-keys";
-		input-name = "gpio-keys";
-
-		camera_snapshot {
-			label = "camera_snapshot";
-			gpios = <&pm8941_gpios 3 0x1>;
-			linux,input-type = <1>;
-			linux,code = <0x2fe>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-
-		camera_focus {
-			label = "camera_focus";
-			gpios = <&pm8941_gpios 4 0x1>;
-			linux,input-type = <1>;
-			linux,code = <0x210>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-
-		vol_up {
-			label = "volume_up";
-			gpios = <&pm8941_gpios 5 0x1>;
-			linux,input-type = <1>;
-			linux,code = <115>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-	};
-
-	spi@f9923000 {
-		ethernet-switch@2 {
-			compatible = "micrel,ks8851";
-			reg = <2>;
-			interrupt-parent = <&msmgpio>;
-			interrupts = <94 0>;
-			spi-max-frequency = <4800000>;
-			rst-gpio = <&pm8941_mpps 6 0>;
-			vdd-io-supply = <&spi_eth_vreg>;
-			vdd-phy-supply = <&spi_eth_vreg>;
-		};
-	};
-};
-
-&sdcc2 {
-	#address-cells = <0>;
-	interrupt-parent = <&sdcc2>;
-	interrupts = <0 1 2>;
-	#interrupt-cells = <1>;
-	interrupt-map-mask = <0xffffffff>;
-	interrupt-map = <0 &intc 0 125 0
-			1 &intc 0 220 0
-			2 &msmgpio 62 0x3>;
-	interrupt-names = "core_irq", "bam_irq", "status_irq";
-	cd-gpios = <&msmgpio 62 0x1>;
-	wp-gpios = <&pm8941_gpios 29 0x1>;
-};
-
-&pm8941_gpios {
-	gpio@c000 { /* GPIO 1 */
-	};
-
-	gpio@c100 { /* GPIO 2 */
-	};
-
-	gpio@c200 { /* GPIO 3 */
-		qcom,mode = <0>;
-		qcom,pull = <0>;
-		qcom,vin-sel = <2>;
-		qcom,select = <0>;
-	};
-
-	gpio@c300 { /* GPIO 4 */
-		qcom,mode = <0>;
-		qcom,pull = <0>;
-		qcom,vin-sel = <2>;
-		qcom,select = <0>;
-	};
-
-	gpio@c400 { /* GPIO 5 */
-		qcom,mode = <0>;
-		qcom,pull = <0>;
-		qcom,vin-sel = <2>;
-		qcom,select = <0>;
-	};
-
-	gpio@c500 { /* GPIO 6 */
-	};
-
-	gpio@c600 { /* GPIO 7 */
-	};
-
-	gpio@c700 { /* GPIO 8 */
-	};
-
-	gpio@c800 { /* GPIO 9 */
-	};
-
-	gpio@c900 { /* GPIO 10 */
-	};
-
-	gpio@ca00 { /* GPIO 11 */
-	};
-
-	gpio@cb00 { /* GPIO 12 */
-	};
-
-	gpio@cc00 { /* GPIO 13 */
-	};
-
-	gpio@cd00 { /* GPIO 14 */
-	};
-
-	gpio@ce00 { /* GPIO 15 */
-		qcom,mode = <1>;
-		qcom,output-type = <0>;
-		qcom,pull = <5>;
-		qcom,vin-sel = <2>;
-		qcom,out-strength = <3>;
-		qcom,src-select = <2>;
-		qcom,master-en = <1>;
-	};
-
-	gpio@cf00 { /* GPIO 16 */
-	};
-
-	gpio@d000 { /* GPIO 17 */
-	};
-
-	gpio@d100 { /* GPIO 18 */
-	};
-
-	gpio@d200 { /* GPIO 19 */
-		qcom,mode = <1>;		/* QPNP_PIN_MODE_DIG_OUT */
-		qcom,output-type = <0>;		/* QPNP_PIN_OUT_BUF_CMOS */
-		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO */
-		qcom,vin-sel = <2>;		/* QPNP_PIN_VIN2 */
-		qcom,out-strength = <2>;	/* QPNP_PIN_OUT_STRENGTH_MED */
-		qcom,src-select = <0>;		/* QPNP_PIN_SEL_FUNC_CONSTANT */
-		qcom,master-en = <1>;
-	};
-
-	gpio@d300 { /* GPIO 20 */
-	};
-
-	gpio@d400 { /* GPIO 21 */
-	};
-
-	gpio@d500 { /* GPIO 22 */
-	};
-
-	gpio@d600 { /* GPIO 23 */
-	};
-
-	gpio@d700 { /* GPIO 24 */
-	};
-
-	gpio@d800 { /* GPIO 25 */
-	};
-
-	gpio@d900 { /* GPIO 26 */
-	};
-
-	gpio@da00 { /* GPIO 27 */
-	};
-
-	gpio@db00 { /* GPIO 28 */
-	};
-
-	gpio@dc00 { /* GPIO 29 */
-		qcom,pull = <0>; /* set to default pull */
-		qcom,master-en = <1>;
-		qcom,vin-sel = <2>; /* select 1.8 V source */
-	};
-
-	gpio@dd00 { /* GPIO 30 */
-	};
-
-	gpio@de00 { /* GPIO 31 */
-	};
-
-	gpio@df00 { /* GPIO 32 */
-	};
-
-	gpio@e000 { /* GPIO 33 */
-	};
-
-	gpio@e100 { /* GPIO 34 */
-	};
-
-	gpio@e200 { /* GPIO 35 */
-	};
-
-	gpio@e300 { /* GPIO 36 */
-	};
-};
-
-&pm8941_mpps {
-
-	mpp@a000 { /* MPP 1 */
-	};
-
-	mpp@a100 { /* MPP 2 */
-	};
-
-	mpp@a200 { /* MPP 3 */
-	};
-
-	mpp@a300 { /* MPP 4 */
-	};
-
-	mpp@a400 { /* MPP 5 */
-		/* SPI_ETH config */
-		qcom,mode = <1>; /* DIG_OUT */
-		qcom,output-type = <0>; /* CMOS */
-		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
-		qcom,src-select = <0>; /* CONSTANT */
-		qcom,master-en = <1>; /* ENABLE MPP */
-	};
-
-	mpp@a500 { /* MPP 6 */
-		/* SPI_ETH_RST config */
-		qcom,mode = <1>; /* DIG_OUT */
-		qcom,output-type = <0>; /* CMOS */
-		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
-		qcom,src-select = <0>; /* CONSTANT */
-		qcom,master-en = <1>; /* ENABLE MPP */
-	};
-
-	mpp@a600 { /* MPP 7 */
-	};
-
-	mpp@a700 { /* MPP 8 */
-	};
-};
-
-&pm8841_mpps {
-
-	mpp@a000 { /* MPP 1 */
-	};
-
-	mpp@a100 { /* MPP 2 */
-	};
-
-	mpp@a200 { /* MPP 3 */
-	};
-
-	mpp@a300 { /* MPP 4 */
-	};
 };
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
new file mode 100644
index 0000000..6004d15
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -0,0 +1,362 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/ "dsi-panel-toshiba-720p-video.dtsi"
+
+/ {
+	serial@f991e000 {
+		status = "ok";
+	};
+
+	qcom,mdss_dsi@fd922800 {
+		qcom,mdss_dsi_toshiba_720p_video {
+			status = "ok";
+		};
+	};
+
+	qcom,hdmi_tx@fd922100 {
+		status = "ok";
+	};
+
+	i2c@f9924000 {
+		atmel_mxt_ts@4a {
+			compatible = "atmel,mxt-ts";
+			reg = <0x4a>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <61 0x2>;
+			vdd_ana-supply = <&pm8941_l18>;
+			vcc_i2c-supply = <&pm8941_lvs1>;
+			atmel,reset-gpio = <&msmgpio 60 0x00>;
+			atmel,irq-gpio = <&msmgpio 61 0x00>;
+			atmel,panel-coords = <0  0 760 1424>;
+			atmel,display-coords = <0 0 720 1280>;
+			atmel,i2c-pull-up;
+			atmel,no-force-update;
+			atmel,cfg_1 {
+				atmel,family-id = <0x82>;
+				atmel,variant-id = <0x19>;
+				atmel,version = <0x10>;
+				atmel,build = <0xaa>;
+				atmel,config = [
+					/* Object 6, Instance = 0 */
+					00 00 00 00 00 00
+					/* Object 38, Instance = 0 */
+					15 00 02 10 08 0C 00 00
+					/* Object 7, Instance = 0 */
+					FF FF 32 03
+					/* Object 8, Instance = 0 */
+					0F 00 0A 0A 00 00 0A 00 00 00
+					/* Object 9, Instance = 0 */
+					83 00 00 18 0E 00 70 32 02 01
+					00 03 01 01 05 0A 0A 0A 90 05
+					F8 02 00 00 0F 0F 00 00 48 2D
+					07 0C 00 00 00 00
+					/* Object 15, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					00
+					/* Object 18, Instance = 0 */
+					00 00
+					/* Object 19, Instance = 0 */
+					00 00 00 00 00 00
+					/* Object 23, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					00 00 00 00 00
+					/* Object 25, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					00 00 00 00 00
+					/* Object 40, Instance = 0 */
+					00 00 00 00 00
+					/* Object 42, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					/* Object 46, Instance = 0 */
+					00 00 10 10 00 00 03 00 00 01
+					/* Object 47, Instance = 0 */
+					08 0A 28 0A 02 0A 00 8C 00 20
+					00 00 00
+					/* Object 55, Instance = 0 */
+					00 00 00 00 00 00
+					/* Object 56, Instance = 0 */
+					03 00 01 18 05 05 05 05 05 05
+					05 05 05 05 05 05 05 05 05 05
+					05 05 05 05 05 05 05 05 00 00
+					00 00 00 00 00 00 00 00 00 00
+					00 00
+					/* Object 57, Instance = 0 */
+					00 00 00
+					/* Object 61, Instance = 0 */
+					00 00 00 00 00
+					/* Object 61, Instance = 1 */
+					00 00 00 00 00
+					/* Object 62, Instance = 0 */
+					7F 03 00 16 00 00 00 00 00 00
+					04 08 10 18 05 00 0A 05 05 50
+					14 19 34 1A 64 00 00 04 40 00
+					00 00 00 00 30 32 02 00 01 00
+					05 00 00 00 00 00 00 00 00 00
+					00 00 0C 00
+					];
+			};
+		};
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+
+		camera_snapshot {
+			label = "camera_snapshot";
+			gpios = <&pm8941_gpios 3 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x2fe>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		camera_focus {
+			label = "camera_focus";
+			gpios = <&pm8941_gpios 4 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x210>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&pm8941_gpios 5 0x1>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+	};
+
+	spi@f9923000 {
+		ethernet-switch@2 {
+			compatible = "micrel,ks8851";
+			reg = <2>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <94 0>;
+			spi-max-frequency = <4800000>;
+			rst-gpio = <&pm8941_mpps 6 0>;
+			vdd-io-supply = <&spi_eth_vreg>;
+			vdd-phy-supply = <&spi_eth_vreg>;
+		};
+	};
+};
+
+&sdcc2 {
+	#address-cells = <0>;
+	interrupt-parent = <&sdcc2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+			1 &intc 0 220 0
+			2 &msmgpio 62 0x3>;
+	interrupt-names = "core_irq", "bam_irq", "status_irq";
+	cd-gpios = <&msmgpio 62 0x1>;
+	wp-gpios = <&pm8941_gpios 29 0x1>;
+};
+
+&pm8941_gpios {
+	gpio@c000 { /* GPIO 1 */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+	};
+
+	gpio@c200 { /* GPIO 3 */
+		qcom,mode = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,src-sel = <0>;
+	};
+
+	gpio@c300 { /* GPIO 4 */
+		qcom,mode = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,src-sel = <0>;
+	};
+
+	gpio@c400 { /* GPIO 5 */
+		qcom,mode = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,src-sel = <0>;
+	};
+
+	gpio@c500 { /* GPIO 6 */
+	};
+
+	gpio@c600 { /* GPIO 7 */
+	};
+
+	gpio@c700 { /* GPIO 8 */
+	};
+
+	gpio@c800 { /* GPIO 9 */
+	};
+
+	gpio@c900 { /* GPIO 10 */
+	};
+
+	gpio@ca00 { /* GPIO 11 */
+	};
+
+	gpio@cb00 { /* GPIO 12 */
+	};
+
+	gpio@cc00 { /* GPIO 13 */
+	};
+
+	gpio@cd00 { /* GPIO 14 */
+	};
+
+	gpio@ce00 { /* GPIO 15 */
+		qcom,mode = <1>;
+		qcom,output-type = <0>;
+		qcom,pull = <5>;
+		qcom,vin-sel = <2>;
+		qcom,out-strength = <3>;
+		qcom,src-sel = <2>;
+		qcom,master-en = <1>;
+	};
+
+	gpio@cf00 { /* GPIO 16 */
+	};
+
+	gpio@d000 { /* GPIO 17 */
+	};
+
+	gpio@d100 { /* GPIO 18 */
+	};
+
+	gpio@d200 { /* GPIO 19 */
+		qcom,mode = <1>;		/* QPNP_PIN_MODE_DIG_OUT */
+		qcom,output-type = <0>;		/* QPNP_PIN_OUT_BUF_CMOS */
+		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO */
+		qcom,vin-sel = <2>;		/* QPNP_PIN_VIN2 */
+		qcom,out-strength = <2>;	/* QPNP_PIN_OUT_STRENGTH_MED */
+		qcom,src-sel = <0>;		/* QPNP_PIN_SEL_FUNC_CONSTANT */
+		qcom,master-en = <1>;
+	};
+
+	gpio@d300 { /* GPIO 20 */
+	};
+
+	gpio@d400 { /* GPIO 21 */
+	};
+
+	gpio@d500 { /* GPIO 22 */
+	};
+
+	gpio@d600 { /* GPIO 23 */
+	};
+
+	gpio@d700 { /* GPIO 24 */
+	};
+
+	gpio@d800 { /* GPIO 25 */
+	};
+
+	gpio@d900 { /* GPIO 26 */
+	};
+
+	gpio@da00 { /* GPIO 27 */
+	};
+
+	gpio@db00 { /* GPIO 28 */
+	};
+
+	gpio@dc00 { /* GPIO 29 */
+		qcom,pull = <0>; /* set to default pull */
+		qcom,master-en = <1>;
+		qcom,vin-sel = <2>; /* select 1.8 V source */
+	};
+
+	gpio@dd00 { /* GPIO 30 */
+	};
+
+	gpio@de00 { /* GPIO 31 */
+	};
+
+	gpio@df00 { /* GPIO 32 */
+	};
+
+	gpio@e000 { /* GPIO 33 */
+	};
+
+	gpio@e100 { /* GPIO 34 */
+	};
+
+	gpio@e200 { /* GPIO 35 */
+	};
+
+	gpio@e300 { /* GPIO 36 */
+	};
+};
+
+&pm8941_mpps {
+
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+
+	mpp@a400 { /* MPP 5 */
+		/* SPI_ETH config */
+		qcom,mode = <1>; /* DIG_OUT */
+		qcom,output-type = <0>; /* CMOS */
+		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+		qcom,src-sel = <0>; /* CONSTANT */
+		qcom,master-en = <1>; /* ENABLE MPP */
+	};
+
+	mpp@a500 { /* MPP 6 */
+		/* SPI_ETH_RST config */
+		qcom,mode = <1>; /* DIG_OUT */
+		qcom,output-type = <0>; /* CMOS */
+		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+		qcom,src-sel = <0>; /* CONSTANT */
+		qcom,master-en = <1>; /* ENABLE MPP */
+	};
+
+	mpp@a600 { /* MPP 7 */
+	};
+
+	mpp@a700 { /* MPP 8 */
+	};
+};
+
+&pm8841_mpps {
+
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974-fluid.dts b/arch/arm/boot/dts/msm8974-fluid.dts
index 891379f..b014e14 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dts
+++ b/arch/arm/boot/dts/msm8974-fluid.dts
@@ -13,359 +13,10 @@
 /dts-v1/;
 
 /include/ "msm8974.dtsi"
-/include/ "dsi-panel-toshiba-720p-video.dtsi"
+/include/ "msm8974-fluid.dtsi"
 
 / {
 	model = "Qualcomm MSM 8974 FLUID";
 	compatible = "qcom,msm8974-fluid", "qcom,msm8974";
 	qcom,msm-id = <126 3 0>;
-
-	serial@f991e000 {
-		status = "ok";
-	};
-
-	qcom,mdss_dsi@fd922800 {
-		qcom,mdss_dsi_toshiba_720p_video {
-			status = "ok";
-		};
-	};
-
-	qcom,hdmi_tx@fd922100 {
-		status = "ok";
-	};
-
-	i2c@f9924000 {
-		atmel_mxt_ts@4a {
-			compatible = "atmel,mxt-ts";
-			reg = <0x4a>;
-			interrupt-parent = <&msmgpio>;
-			interrupts = <61 0x2>;
-			vdd_ana-supply = <&pm8941_l18>;
-			vcc_i2c-supply = <&pm8941_lvs1>;
-			atmel,reset-gpio = <&msmgpio 60 0x00>;
-			atmel,irq-gpio = <&msmgpio 61 0x00>;
-			atmel,panel-coords = <0  0 760 1424>;
-			atmel,display-coords = <0 0 720 1280>;
-			atmel,i2c-pull-up = <1>;
-			atmel,cfg_1 {
-				atmel,family-id = <0x82>;
-				atmel,variant-id = <0x19>;
-				atmel,version = <0x10>;
-				atmel,build = <0xaa>;
-				atmel,config = [
-					/* Object 6, Instance = 0 */
-					00 00 00 00 00 00
-					/* Object 38, Instance = 0 */
-					15 00 02 10 08 0C 00 00
-					/* Object 7, Instance = 0 */
-					FF FF 32 03
-					/* Object 8, Instance = 0 */
-					0F 00 0A 0A 00 00 0A 00 00 00
-					/* Object 9, Instance = 0 */
-					83 00 00 18 0E 00 70 32 02 01
-					00 03 01 01 05 0A 0A 0A 90 05
-					F8 02 00 00 0F 0F 00 00 48 2D
-					07 0C 00 00 00 00
-					/* Object 15, Instance = 0 */
-					00 00 00 00 00 00 00 00 00 00
-					00
-					/* Object 18, Instance = 0 */
-					00 00
-					/* Object 19, Instance = 0 */
-					00 00 00 00 00 00
-					/* Object 23, Instance = 0 */
-					00 00 00 00 00 00 00 00 00 00
-					00 00 00 00 00
-					/* Object 25, Instance = 0 */
-					00 00 00 00 00 00 00 00 00 00
-					00 00 00 00 00
-					/* Object 40, Instance = 0 */
-					00 00 00 00 00
-					/* Object 42, Instance = 0 */
-					00 00 00 00 00 00 00 00 00 00
-					/* Object 46, Instance = 0 */
-					00 00 10 10 00 00 03 00 00 01
-					/* Object 47, Instance = 0 */
-					08 0A 28 0A 02 0A 00 8C 00 20
-					00 00 00
-					/* Object 55, Instance = 0 */
-					00 00 00 00 00 00
-					/* Object 56, Instance = 0 */
-					03 00 01 18 05 05 05 05 05 05
-					05 05 05 05 05 05 05 05 05 05
-					05 05 05 05 05 05 05 05 00 00
-					00 00 00 00 00 00 00 00 00 00
-					00 00
-					/* Object 57, Instance = 0 */
-					00 00 00
-					/* Object 61, Instance = 0 */
-					00 00 00 00 00
-					/* Object 61, Instance = 1 */
-					00 00 00 00 00
-					/* Object 62, Instance = 0 */
-					7F 03 00 16 00 00 00 00 00 00
-					04 08 10 18 05 00 0A 05 05 50
-					14 19 34 1A 64 00 00 04 40 00
-					00 00 00 00 30 32 02 00 01 00
-					05 00 00 00 00 00 00 00 00 00
-					00 00 0C 00
-					];
-			};
-		};
-	};
-
-	gpio_keys {
-		compatible = "gpio-keys";
-		input-name = "gpio-keys";
-
-		camera_snapshot {
-			label = "camera_snapshot";
-			gpios = <&pm8941_gpios 3 0x1>;
-			linux,input-type = <1>;
-			linux,code = <0x2fe>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-
-		camera_focus {
-			label = "camera_focus";
-			gpios = <&pm8941_gpios 4 0x1>;
-			linux,input-type = <1>;
-			linux,code = <0x210>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-
-		vol_up {
-			label = "volume_up";
-			gpios = <&pm8941_gpios 5 0x1>;
-			linux,input-type = <1>;
-			linux,code = <115>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-	};
-
-	spi@f9923000 {
-		ethernet-switch@2 {
-			compatible = "micrel,ks8851";
-			reg = <2>;
-			interrupt-parent = <&msmgpio>;
-			interrupts = <94 0>;
-			spi-max-frequency = <4800000>;
-			rst-gpio = <&pm8941_mpps 6 0>;
-			vdd-io-supply = <&spi_eth_vreg>;
-			vdd-phy-supply = <&spi_eth_vreg>;
-		};
-	};
-};
-
-&sdcc1 {
-	qcom,sdcc-bus-width = <4>;
-};
-
-&sdcc2 {
-	#address-cells = <0>;
-	interrupt-parent = <&sdcc2>;
-	interrupts = <0 1 2>;
-	#interrupt-cells = <1>;
-	interrupt-map-mask = <0xffffffff>;
-	interrupt-map = <0 &intc 0 125 0
-			1 &intc 0 220 0
-			2 &msmgpio 62 0x3>;
-	interrupt-names = "core_irq", "bam_irq", "status_irq";
-	cd-gpios = <&msmgpio 62 0x1>;
-};
-
-&pm8941_gpios {
-	gpio@c000 { /* GPIO 1 */
-	};
-
-	gpio@c100 { /* GPIO 2 */
-	};
-
-	gpio@c200 { /* GPIO 3 */
-		qcom,mode = <0>;
-		qcom,pull = <0>;
-		qcom,vin-sel = <2>;
-		qcom,select = <0>;
-	};
-
-	gpio@c300 { /* GPIO 4 */
-		qcom,mode = <0>;
-		qcom,pull = <0>;
-		qcom,vin-sel = <2>;
-		qcom,select = <0>;
-	};
-
-	gpio@c400 { /* GPIO 5 */
-		qcom,mode = <0>;
-		qcom,pull = <0>;
-		qcom,vin-sel = <2>;
-		qcom,select = <0>;
-	};
-
-	gpio@c500 { /* GPIO 6 */
-	};
-
-	gpio@c600 { /* GPIO 7 */
-	};
-
-	gpio@c700 { /* GPIO 8 */
-	};
-
-	gpio@c800 { /* GPIO 9 */
-	};
-
-	gpio@c900 { /* GPIO 10 */
-	};
-
-	gpio@ca00 { /* GPIO 11 */
-	};
-
-	gpio@cb00 { /* GPIO 12 */
-	};
-
-	gpio@cc00 { /* GPIO 13 */
-	};
-
-	gpio@cd00 { /* GPIO 14 */
-	};
-
-	gpio@ce00 { /* GPIO 15 */
-		qcom,mode = <1>;
-		qcom,output-type = <0>;
-		qcom,pull = <5>;
-		qcom,vin-sel = <2>;
-		qcom,out-strength = <3>;
-		qcom,src-select = <2>;
-		qcom,master-en = <1>;
-	};
-
-	gpio@cf00 { /* GPIO 16 */
-	};
-
-	gpio@d000 { /* GPIO 17 */
-	};
-
-	gpio@d100 { /* GPIO 18 */
-	};
-
-	gpio@d200 { /* GPIO 19 */
-		qcom,mode = <1>;		/* QPNP_PIN_MODE_DIG_OUT */
-		qcom,output-type = <0>;		/* QPNP_PIN_OUT_BUF_CMOS */
-		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO */
-		qcom,vin-sel = <2>;		/* QPNP_PIN_VIN2 */
-		qcom,out-strength = <2>;	/* QPNP_PIN_OUT_STRENGTH_MED */
-		qcom,src-select = <0>;		/* QPNP_PIN_SEL_FUNC_CONSTANT */
-		qcom,master-en = <1>;
-	};
-
-	gpio@d300 { /* GPIO 20 */
-	};
-
-	gpio@d400 { /* GPIO 21 */
-	};
-
-	gpio@d500 { /* GPIO 22 */
-	};
-
-	gpio@d600 { /* GPIO 23 */
-	};
-
-	gpio@d700 { /* GPIO 24 */
-	};
-
-	gpio@d800 { /* GPIO 25 */
-	};
-
-	gpio@d900 { /* GPIO 26 */
-	};
-
-	gpio@da00 { /* GPIO 27 */
-	};
-
-	gpio@db00 { /* GPIO 28 */
-	};
-
-	gpio@dc00 { /* GPIO 29 */
-		qcom,pull = <0>; /* set to default pull */
-		qcom,master-en = <1>;
-		qcom,vin-sel = <2>; /* select 1.8 V source */
-	};
-
-	gpio@dd00 { /* GPIO 30 */
-	};
-
-	gpio@de00 { /* GPIO 31 */
-	};
-
-	gpio@df00 { /* GPIO 32 */
-	};
-
-	gpio@e000 { /* GPIO 33 */
-	};
-
-	gpio@e100 { /* GPIO 34 */
-	};
-
-	gpio@e200 { /* GPIO 35 */
-	};
-
-	gpio@e300 { /* GPIO 36 */
-	};
-};
-
-&pm8941_mpps {
-
-	mpp@a000 { /* MPP 1 */
-	};
-
-	mpp@a100 { /* MPP 2 */
-	};
-
-	mpp@a200 { /* MPP 3 */
-	};
-
-	mpp@a300 { /* MPP 4 */
-	};
-
-	mpp@a400 { /* MPP 5 */
-		/* SPI_ETH config */
-		qcom,mode = <1>; /* DIG_OUT */
-		qcom,output-type = <0>; /* CMOS */
-		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
-		qcom,src-select = <0>; /* CONSTANT */
-		qcom,master-en = <1>; /* ENABLE MPP */
-	};
-
-	mpp@a500 { /* MPP 6 */
-		/* SPI_ETH_RST config */
-		qcom,mode = <1>; /* DIG_OUT */
-		qcom,output-type = <0>; /* CMOS */
-		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
-		qcom,src-select = <0>; /* CONSTANT */
-		qcom,master-en = <1>; /* ENABLE MPP */
-	};
-
-	mpp@a600 { /* MPP 7 */
-	};
-
-	mpp@a700 { /* MPP 8 */
-	};
-};
-
-&pm8841_mpps {
-
-	mpp@a000 { /* MPP 1 */
-	};
-
-	mpp@a100 { /* MPP 2 */
-	};
-
-	mpp@a200 { /* MPP 3 */
-	};
-
-	mpp@a300 { /* MPP 4 */
-	};
 };
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
new file mode 100644
index 0000000..938bc22
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -0,0 +1,365 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/ "dsi-panel-toshiba-720p-video.dtsi"
+
+/ {
+	serial@f991e000 {
+		status = "ok";
+	};
+
+	qcom,mdss_dsi@fd922800 {
+		qcom,mdss_dsi_toshiba_720p_video {
+			status = "ok";
+		};
+	};
+
+	qcom,hdmi_tx@fd922100 {
+		status = "ok";
+	};
+
+	i2c@f9924000 {
+		atmel_mxt_ts@4a {
+			compatible = "atmel,mxt-ts";
+			reg = <0x4a>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <61 0x2>;
+			vdd_ana-supply = <&pm8941_l18>;
+			vcc_i2c-supply = <&pm8941_lvs1>;
+			atmel,reset-gpio = <&msmgpio 60 0x00>;
+			atmel,irq-gpio = <&msmgpio 61 0x00>;
+			atmel,panel-coords = <0  0 760 1424>;
+			atmel,display-coords = <0 0 720 1280>;
+			atmel,i2c-pull-up;
+			atmel,no-force-update;
+			atmel,cfg_1 {
+				atmel,family-id = <0x82>;
+				atmel,variant-id = <0x19>;
+				atmel,version = <0x10>;
+				atmel,build = <0xaa>;
+				atmel,config = [
+					/* Object 6, Instance = 0 */
+					00 00 00 00 00 00
+					/* Object 38, Instance = 0 */
+					15 00 02 10 08 0C 00 00
+					/* Object 7, Instance = 0 */
+					FF FF 32 03
+					/* Object 8, Instance = 0 */
+					0F 00 0A 0A 00 00 0A 00 00 00
+					/* Object 9, Instance = 0 */
+					83 00 00 18 0E 00 70 32 02 01
+					00 03 01 01 05 0A 0A 0A 90 05
+					F8 02 00 00 0F 0F 00 00 48 2D
+					07 0C 00 00 00 00
+					/* Object 15, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					00
+					/* Object 18, Instance = 0 */
+					00 00
+					/* Object 19, Instance = 0 */
+					00 00 00 00 00 00
+					/* Object 23, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					00 00 00 00 00
+					/* Object 25, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					00 00 00 00 00
+					/* Object 40, Instance = 0 */
+					00 00 00 00 00
+					/* Object 42, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					/* Object 46, Instance = 0 */
+					00 00 10 10 00 00 03 00 00 01
+					/* Object 47, Instance = 0 */
+					08 0A 28 0A 02 0A 00 8C 00 20
+					00 00 00
+					/* Object 55, Instance = 0 */
+					00 00 00 00 00 00
+					/* Object 56, Instance = 0 */
+					03 00 01 18 05 05 05 05 05 05
+					05 05 05 05 05 05 05 05 05 05
+					05 05 05 05 05 05 05 05 00 00
+					00 00 00 00 00 00 00 00 00 00
+					00 00
+					/* Object 57, Instance = 0 */
+					00 00 00
+					/* Object 61, Instance = 0 */
+					00 00 00 00 00
+					/* Object 61, Instance = 1 */
+					00 00 00 00 00
+					/* Object 62, Instance = 0 */
+					7F 03 00 16 00 00 00 00 00 00
+					04 08 10 18 05 00 0A 05 05 50
+					14 19 34 1A 64 00 00 04 40 00
+					00 00 00 00 30 32 02 00 01 00
+					05 00 00 00 00 00 00 00 00 00
+					00 00 0C 00
+					];
+			};
+		};
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+
+		camera_snapshot {
+			label = "camera_snapshot";
+			gpios = <&pm8941_gpios 3 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x2fe>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		camera_focus {
+			label = "camera_focus";
+			gpios = <&pm8941_gpios 4 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x210>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&pm8941_gpios 5 0x1>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+	};
+
+	spi@f9923000 {
+		ethernet-switch@2 {
+			compatible = "micrel,ks8851";
+			reg = <2>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <94 0>;
+			spi-max-frequency = <4800000>;
+			rst-gpio = <&pm8941_mpps 6 0>;
+			vdd-io-supply = <&spi_eth_vreg>;
+			vdd-phy-supply = <&spi_eth_vreg>;
+		};
+	};
+};
+
+&sdcc1 {
+	qcom,bus-width = <4>;
+};
+
+&sdcc2 {
+	#address-cells = <0>;
+	interrupt-parent = <&sdcc2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+			1 &intc 0 220 0
+			2 &msmgpio 62 0x3>;
+	interrupt-names = "core_irq", "bam_irq", "status_irq";
+	cd-gpios = <&msmgpio 62 0x1>;
+};
+
+&pm8941_gpios {
+	gpio@c000 { /* GPIO 1 */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+	};
+
+	gpio@c200 { /* GPIO 3 */
+		qcom,mode = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,src-sel = <0>;
+	};
+
+	gpio@c300 { /* GPIO 4 */
+		qcom,mode = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,src-sel = <0>;
+	};
+
+	gpio@c400 { /* GPIO 5 */
+		qcom,mode = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,src-sel = <0>;
+	};
+
+	gpio@c500 { /* GPIO 6 */
+	};
+
+	gpio@c600 { /* GPIO 7 */
+	};
+
+	gpio@c700 { /* GPIO 8 */
+	};
+
+	gpio@c800 { /* GPIO 9 */
+	};
+
+	gpio@c900 { /* GPIO 10 */
+	};
+
+	gpio@ca00 { /* GPIO 11 */
+	};
+
+	gpio@cb00 { /* GPIO 12 */
+	};
+
+	gpio@cc00 { /* GPIO 13 */
+	};
+
+	gpio@cd00 { /* GPIO 14 */
+	};
+
+	gpio@ce00 { /* GPIO 15 */
+		qcom,mode = <1>;
+		qcom,output-type = <0>;
+		qcom,pull = <5>;
+		qcom,vin-sel = <2>;
+		qcom,out-strength = <3>;
+		qcom,src-sel = <2>;
+		qcom,master-en = <1>;
+	};
+
+	gpio@cf00 { /* GPIO 16 */
+	};
+
+	gpio@d000 { /* GPIO 17 */
+	};
+
+	gpio@d100 { /* GPIO 18 */
+	};
+
+	gpio@d200 { /* GPIO 19 */
+		qcom,mode = <1>;		/* QPNP_PIN_MODE_DIG_OUT */
+		qcom,output-type = <0>;		/* QPNP_PIN_OUT_BUF_CMOS */
+		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO */
+		qcom,vin-sel = <2>;		/* QPNP_PIN_VIN2 */
+		qcom,out-strength = <2>;	/* QPNP_PIN_OUT_STRENGTH_MED */
+		qcom,src-sel = <0>;		/* QPNP_PIN_SEL_FUNC_CONSTANT */
+		qcom,master-en = <1>;
+	};
+
+	gpio@d300 { /* GPIO 20 */
+	};
+
+	gpio@d400 { /* GPIO 21 */
+	};
+
+	gpio@d500 { /* GPIO 22 */
+	};
+
+	gpio@d600 { /* GPIO 23 */
+	};
+
+	gpio@d700 { /* GPIO 24 */
+	};
+
+	gpio@d800 { /* GPIO 25 */
+	};
+
+	gpio@d900 { /* GPIO 26 */
+	};
+
+	gpio@da00 { /* GPIO 27 */
+	};
+
+	gpio@db00 { /* GPIO 28 */
+	};
+
+	gpio@dc00 { /* GPIO 29 */
+		qcom,pull = <0>; /* set to default pull */
+		qcom,master-en = <1>;
+		qcom,vin-sel = <2>; /* select 1.8 V source */
+	};
+
+	gpio@dd00 { /* GPIO 30 */
+	};
+
+	gpio@de00 { /* GPIO 31 */
+	};
+
+	gpio@df00 { /* GPIO 32 */
+	};
+
+	gpio@e000 { /* GPIO 33 */
+	};
+
+	gpio@e100 { /* GPIO 34 */
+	};
+
+	gpio@e200 { /* GPIO 35 */
+	};
+
+	gpio@e300 { /* GPIO 36 */
+	};
+};
+
+&pm8941_mpps {
+
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+
+	mpp@a400 { /* MPP 5 */
+		/* SPI_ETH config */
+		qcom,mode = <1>; /* DIG_OUT */
+		qcom,output-type = <0>; /* CMOS */
+		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+		qcom,src-sel = <0>; /* CONSTANT */
+		qcom,master-en = <1>; /* ENABLE MPP */
+	};
+
+	mpp@a500 { /* MPP 6 */
+		/* SPI_ETH_RST config */
+		qcom,mode = <1>; /* DIG_OUT */
+		qcom,output-type = <0>; /* CMOS */
+		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+		qcom,src-sel = <0>; /* CONSTANT */
+		qcom,master-en = <1>; /* ENABLE MPP */
+	};
+
+	mpp@a600 { /* MPP 7 */
+	};
+
+	mpp@a700 { /* MPP 8 */
+	};
+};
+
+&pm8841_mpps {
+
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974-ion.dtsi b/arch/arm/boot/dts/msm8974-ion.dtsi
index 9b5aaac..01e200a 100644
--- a/arch/arm/boot/dts/msm8974-ion.dtsi
+++ b/arch/arm/boot/dts/msm8974-ion.dtsi
@@ -28,41 +28,30 @@
 			qcom,memory-reservation-size = <0x7800000>;
 		};
 
-		qcom,ion-heap@29 { /* FIRMWARE HEAP */
+		qcom,ion-heap@23 { /* PIL1 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>;
-		};
-
-		qcom,ion-heap@12 { /* MFC HEAP */
-			compatible = "qcom,msm-ion-reserve";
-			reg = <12>;
-			qcom,heap-align = <0x1000>;
-			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
-			qcom,memory-reservation-size = <0x2000>;
-		};
-
-		qcom,ion-heap@24 { /* SF HEAP */
-			compatible = "qcom,msm-ion-reserve";
-			reg = <24>;
-			qcom,heap-align = <0x1000>;
-			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
-			qcom,memory-reservation-size = <0x2800000>;
+			reg = <23>;
+			qcom,heap-align = <0x10000>;
+			qcom,memory-fixed = <0xd200000 0x2800000>;
 		};
 
 		qcom,ion-heap@25 { /* IOMMU HEAP */
 			reg = <25>;
 		};
 
+		qcom,ion-heap@26 { /* PIL2 HEAP */
+			compatible = "qcom,msm-ion-reserve";
+			reg = <26>;
+			qcom,heap-align = <0x10000>;
+			qcom,memory-fixed = <0x8400000 0x4e00000>;
+		};
+
 		qcom,ion-heap@27 { /* QSECOM HEAP */
 			compatible = "qcom,msm-ion-reserve";
 			reg = <27>;
 			qcom,heap-align = <0x1000>;
 			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
-			qcom,memory-reservation-size = <0x600000>;
+			qcom,memory-reservation-size = <0x780000>;
 		};
 
 		qcom,ion-heap@28 { /* AUDIO HEAP */
diff --git a/arch/arm/boot/dts/msm8974-liquid.dts b/arch/arm/boot/dts/msm8974-liquid.dts
index d1a6148..ef38036 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dts
+++ b/arch/arm/boot/dts/msm8974-liquid.dts
@@ -13,392 +13,10 @@
 /dts-v1/;
 
 /include/ "msm8974.dtsi"
+/include/ "msm8974-liquid.dtsi"
 
 / {
 	model = "Qualcomm MSM 8974 LIQUID";
 	compatible = "qcom,msm8974-liquid", "qcom,msm8974";
 	qcom,msm-id = <126 9 0>;
-
-	serial@f991e000 {
-		status = "ok";
-	};
-
-	qcom,mdss_edp@fd923400 {
-		status = "ok";
-	};
-
-	i2c@f9967000 {
-		battery@b {
-			compatible = "ti,bq28400-battery";
-			reg = <0xb>;
-		};
-	};
-
-	gpio_keys {
-		compatible = "gpio-keys";
-		input-name = "gpio-keys";
-
-		home {
-			label = "home";
-			gpios = <&pm8941_gpios 1 0x1>;
-			linux,input-type = <1>;
-			linux,code = <102>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-
-		vol_down {
-			label = "volume_down";
-			gpios = <&pm8941_gpios 2 0x1>;
-			linux,input-type = <1>;
-			linux,code = <114>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-
-		vol_up {
-			label = "volume_up";
-			gpios = <&pm8941_gpios 5 0x1>;
-			linux,input-type = <1>;
-			linux,code = <115>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-	};
-
-	qcom,mdss_mdp@fd900000 {
-		qcom,memory-reservation-size = <0x1000000>; /* size 16MB */
-	};
-
-	qcom,hdmi_tx@fd922100 {
-		status = "ok";
-	};
-
-	i2c@f9924000 {
-		atmel_mxt_ts@4a {
-			compatible = "atmel,mxt-ts";
-			reg = <0x4a>;
-			interrupt-parent = <&msmgpio>;
-			interrupts = <61 0x2>;
-			vdd_ana-supply = <&pm8941_l22>;
-			vcc_i2c-supply = <&pm8941_s3>;
-			atmel,reset-gpio = <&msmgpio 60 0x00>;
-			atmel,irq-gpio = <&msmgpio 61 0x00>;
-			atmel,panel-coords = <0 0 1080 1920>;
-			atmel,display-coords = <0 0 1080 1920>;
-			atmel,i2c-pull-up = <1>;
-			atmel,cfg_1 {
-				atmel,family-id = <0xa2>;
-				atmel,variant-id = <0x00>;
-				atmel,version = <0x11>;
-				atmel,build = <0xaa>;
-				atmel,config = [
-					/* Object 6, Instance = 0 */
-					00 00 00 00 00 00
-					/* Object 38, Instance = 0 */
-					16 00 00 14 09 0C 00 00 00 00
-					00 00 00 00 00 00 00 00 00 00
-					00 00 00 00 00 00 00 00 00 00
-					00 00 00 00 00 00 00 00 00 00
-					00 00 00 00 00 00 00 00 00 00
-					00 00 00 00 00 00 00 00 00 00
-					00 00 00 00
-					/* Object 7, Instance = 0 */
-					FF FF 0A 03
-					/* Object 8, Instance = 0 */
-					5F 00 14 14 00 00 00 01 00 00
-					/* Object 9, Instance = 0 */
-					8F 00 00 20 34 00 87 3C 08 03
-					00 05 03 80 0A 14 14 0A 80 07
-					38 04 00 00 00 00 00 00 00 00
-					0F 0F 2E 33 02 00
-					/* Object 15, Instance = 0 */
-					00 00 00 00 00 00 00 00 00 00
-					00
-					/* Object 18, Instance = 0 */
-					04 00
-					/* Object 24, Instance = 0 */
-					00 00 00 00 00 00 00 00 00 00
-					00 00 00 00 00 00 00 00 00
-					/* Object 25, Instance = 0 */
-					00 00 54 6F F0 55 00 00 00 00
-					00 00 00 00 00
-					/* Object 27, Instance = 0 */
-					00 00 00 00 00 00 00
-					/* Object 40, Instance = 0 */
-					00 14 14 14 14
-					/* Object 42, Instance = 0 */
-					20 14 00 00 00 14 11 00 03 00
-					/* Object 43, Instance = 0 */
-					09 00 01 01 91 00 80 00 00 00
-					00 00
-					/* Object 46, Instance = 0 */
-					00 00 10 10 00 00 01 00 00 0F
-					0A
-					/* Object 47, Instance = 0 */
-					00 14 23 02 05 1E 01 78 03 10
-					00 00 0C 00 00 00 00 00 00 00
-					00 00
-					/* Object 55, Instance = 0 */
-					00 00 00 00 00 00 00
-					/* Object 56, Instance = 0 */
-					02 00 01 30 13 14 14 14 15 15
-					15 15 15 15 15 16 16 16 16 16
-					16 16 16 16 16 15 14 14 14 14
-					15 14 14 14 14 13 00 00 01 02
-					05 05 00 00 00 00 00 00 00 00
-					00
-					/* Object 57, Instance = 0 */
-					00 00 00
-					/* Object 61, Instance = 0 */
-					00 00 00 00 00
-					/* Object 62, Instance = 0 */
-					00 01 03 01 00 00 00 00 00 0A
-					0F 14 19 23 05 00 0A 05 05 69
-					23 23 34 11 64 06 06 04 40 00
-					00 00 00 00 69 4B 02 00 00 80
-					0A 14 14 18 18 10 10 80 00 80
-					00 00 0F 02 00 00 00 00 00 00
-					00 00 00 00 00 00 00 00 00 00
-					00 00 00 00
-					/* Object 63, Instance = 0 */
-					00 00 00 00 00 00 00 00 00 00
-					00 00
-					];
-			};
-		};
-	};
-
-	ext_5v: regulator-smb210 {
-		compatible = "regulator-fixed";
-		regulator-name = "ext_5v";
-		gpio = <&pm8941_mpps 2 0>;
-		enable-active-high;
-	};
-};
-
-&pm8941_mvs1 {
-	parent-supply = <&ext_5v>;
-};
-
-&pm8941_mvs2 {
-	parent-supply = <&ext_5v>;
-};
-
-&pm8941_gpios {
-	gpio@c000 { /* GPIO 1 */
-		qcom,mode = <0>;
-		qcom,pull = <0>;
-		qcom,vin-sel = <2>;
-		qcom,select = <0>;
-	};
-
-	gpio@c100 { /* GPIO 2 */
-		qcom,mode = <0>;
-		qcom,pull = <0>;
-		qcom,vin-sel = <2>;
-		qcom,select = <0>;
-	};
-
-	gpio@c200 { /* GPIO 3 */
-	};
-
-	gpio@c300 { /* GPIO 4 */
-	};
-
-	gpio@c400 { /* GPIO 5 */
-		qcom,mode = <0>;
-		qcom,pull = <0>;
-		qcom,vin-sel = <2>;
-		qcom,select = <0>;
-	};
-
-	gpio@c500 { /* GPIO 6 */
-	};
-
-	gpio@c600 { /* GPIO 7 */
-	};
-
-	gpio@c700 { /* GPIO 8 */
-	};
-
-	gpio@c800 { /* GPIO 9 */
-	};
-
-	gpio@c900 { /* GPIO 10 */
-	};
-
-	gpio@ca00 { /* GPIO 11 */
-	};
-
-	gpio@cb00 { /* GPIO 12 */
-	};
-
-	gpio@cc00 { /* GPIO 13 */
-	};
-
-	gpio@cd00 { /* GPIO 14 */
-	};
-
-	gpio@ce00 { /* GPIO 15 */
-		qcom,mode = <1>;
-		qcom,output-type = <0>;
-		qcom,pull = <5>;
-		qcom,vin-sel = <2>;
-		qcom,out-strength = <3>;
-		qcom,src-select = <2>;
-		qcom,master-en = <1>;
-	};
-
-	gpio@cf00 { /* GPIO 16 */
-	};
-
-	gpio@d000 { /* GPIO 17 */
-	};
-
-	gpio@d100 { /* GPIO 18 */
-	};
-
-	gpio@d200 { /* GPIO 19 */
-		qcom,mode = <1>;		/* QPNP_PIN_MODE_DIG_OUT */
-		qcom,output-type = <0>;		/* QPNP_PIN_OUT_BUF_CMOS */
-		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO */
-		qcom,vin-sel = <2>;		/* QPNP_PIN_VIN2 */
-		qcom,out-strength = <2>;	/* QPNP_PIN_OUT_STRENGTH_MED */
-		qcom,src-select = <0>;		/* QPNP_PIN_SEL_FUNC_CONSTANT */
-		qcom,master-en = <1>;
-	};
-
-	gpio@d300 { /* GPIO 20 */
-	};
-
-	gpio@d400 { /* GPIO 21 */
-	};
-
-	gpio@d500 { /* GPIO 22 */
-	};
-
-	gpio@d600 { /* GPIO 23 */
-	};
-
-	gpio@d700 { /* GPIO 24 */
-	};
-
-	gpio@d800 { /* GPIO 25 */
-	};
-
-	gpio@d900 { /* GPIO 26 */
-	};
-
-	gpio@da00 { /* GPIO 27 */
-	};
-
-	gpio@db00 { /* GPIO 28 */
-	};
-
-	gpio@dc00 { /* GPIO 29 */
-		qcom,pull = <0>; /* set to default pull */
-		qcom,master-en = <1>;
-		qcom,vin-sel = <2>; /* select 1.8 V source */
-	};
-
-	gpio@dd00 { /* GPIO 30 */
-	};
-
-	gpio@de00 { /* GPIO 31 */
-	};
-
-	gpio@df00 { /* GPIO 32 */
-	};
-
-	gpio@e000 { /* GPIO 33 */
-	};
-
-	gpio@e100 { /* GPIO 34 */
-	};
-
-	gpio@e200 { /* GPIO 35 */
-	};
-
-	gpio@e300 { /* GPIO 36 */
-		qcom,mode = <1>;  /* QPNP_PIN_MODE_DIG_OUT */
-		qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
-		qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
-		qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
-		qcom,out-strength = <3>; /* QPNP_PIN_OUT_STRENGTH_HIGH */
-		qcom,src-select = <3>; /* QPNP_PIN_SEL_FUNC_2 */
-		qcom,master-en = <1>;
-	};
-};
-
-&pm8941_mpps {
-
-	mpp@a000 { /* MPP 1 */
-	};
-
-	mpp@a100 { /* MPP 2 */
-		/* ext_5v regulator enable */
-		qcom,mode = <1>; /* Digital output */
-		qcom,invert = <0>; /* Output low initially */
-		qcom,vin-sel = <2>; /* PM8941 S3 = 1.8 V */
-		qcom,src-select = <0>; /* Constant */
-		qcom,master-en = <1>; /* Enable MPP */
-	};
-
-	mpp@a200 { /* MPP 3 */
-	};
-
-	mpp@a300 { /* MPP 4 */
-	};
-
-	mpp@a400 { /* MPP 5 */
-		/* SPI_ETH config */
-		qcom,mode = <1>; /* DIG_OUT */
-		qcom,output-type = <0>; /* CMOS */
-		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
-		qcom,src-select = <0>; /* CONSTANT */
-		qcom,master-en = <1>; /* ENABLE MPP */
-	};
-
-	mpp@a500 { /* MPP 6 */
-		/* SPI_ETH_RST config */
-		qcom,mode = <1>; /* DIG_OUT */
-		qcom,output-type = <0>; /* CMOS */
-		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
-		qcom,src-select = <0>; /* CONSTANT */
-		qcom,master-en = <1>; /* ENABLE MPP */
-	};
-
-	mpp@a600 { /* MPP 7 */
-	};
-
-	mpp@a700 { /* MPP 8 */
-	};
-};
-
-&pm8841_mpps {
-
-	mpp@a000 { /* MPP 1 */
-	};
-
-	mpp@a100 { /* MPP 2 */
-	};
-
-	mpp@a200 { /* HDMI_MUX_SEL MPP 3*/
-		status = "ok";
-		qcom,mode = <1>; /* DIG_OUT */
-		qcom,output-type = <0>; /* CMOS */
-		qcom,vin-sel = <2>; /* PM8841_S3A 1.8V */
-		qcom,src-select = <0>; /* CONSTANT */
-		qcom,master-en = <1>; /* ENABLE MPP */
-	};
-
-	mpp@a300 { /* HDMI_MUX_EN MPP 4*/
-		status = "ok";
-		qcom,mode = <1>; /* DIG_OUT */
-		qcom,output-type = <0>; /* CMOS */
-		qcom,vin-sel = <0>; /* PM8841_VPH 3.4V */
-		qcom,src-select = <0>; /* CONSTANT */
-		qcom,master-en = <1>; /* ENABLE MPP */
-	};
 };
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
new file mode 100644
index 0000000..68207af
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -0,0 +1,433 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ */
+
+/ {
+	serial@f991e000 {
+		status = "ok";
+	};
+
+	qcom,mdss_edp@fd923400 {
+		status = "ok";
+	};
+
+	i2c@f9967000 {
+		battery@b {
+			compatible = "ti,bq28400-battery";
+			reg = <0xb>;
+		};
+
+		charger@2b {
+			compatible = "summit,smb350-charger";
+			reg = <0x2b>; /* 0x56/0x57 */
+			summit,stat-gpio = <&pm8941_gpios 30 0x00>;
+			summit,chg-en-n-gpio = <&pm8941_gpios 10 0x00>;
+			summit,chg-susp-n-gpio = <&pm8941_gpios 13 0x00>;
+			summit,chg-current-ma = <1600>;
+			summit,term-current-ma = <300>;
+		};
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+
+		home {
+			label = "home";
+			gpios = <&pm8941_gpios 1 0x1>;
+			linux,input-type = <1>;
+			linux,code = <102>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		vol_down {
+			label = "volume_down";
+			gpios = <&pm8941_gpios 2 0x1>;
+			linux,input-type = <1>;
+			linux,code = <114>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&pm8941_gpios 5 0x1>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+	};
+
+	qcom,mdss_mdp@fd900000 {
+		qcom,memory-reservation-size = <0x1000000>; /* size 16MB */
+	};
+
+	qcom,hdmi_tx@fd922100 {
+		status = "ok";
+	};
+
+	i2c@f9924000 {
+		atmel_mxt_ts@4a {
+			compatible = "atmel,mxt-ts";
+			reg = <0x4a>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <61 0x2>;
+			vdd_ana-supply = <&pm8941_l22>;
+			vcc_i2c-supply = <&pm8941_s3>;
+			atmel,reset-gpio = <&msmgpio 60 0x00>;
+			atmel,irq-gpio = <&msmgpio 61 0x00>;
+			atmel,panel-coords = <0 0 1080 1920>;
+			atmel,display-coords = <0 0 1080 1920>;
+			atmel,i2c-pull-up;
+			atmel,no-force-update;
+			atmel,cfg_1 {
+				atmel,family-id = <0xa2>;
+				atmel,variant-id = <0x00>;
+				atmel,version = <0x11>;
+				atmel,build = <0xaa>;
+				atmel,config = [
+					/* Object 6, Instance = 0 */
+					00 00 00 00 00 00
+					/* Object 38, Instance = 0 */
+					16 00 00 14 09 0C 00 00 00 00
+					00 00 00 00 00 00 00 00 00 00
+					00 00 00 00 00 00 00 00 00 00
+					00 00 00 00 00 00 00 00 00 00
+					00 00 00 00 00 00 00 00 00 00
+					00 00 00 00 00 00 00 00 00 00
+					00 00 00 00
+					/* Object 7, Instance = 0 */
+					FF FF 0A 03
+					/* Object 8, Instance = 0 */
+					5F 00 14 14 00 00 00 01 00 00
+					/* Object 9, Instance = 0 */
+					8F 00 00 20 34 00 87 3C 08 03
+					00 05 03 80 0A 14 14 0A 80 07
+					38 04 00 00 00 00 00 00 00 00
+					0F 0F 2E 33 02 00
+					/* Object 15, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					00
+					/* Object 18, Instance = 0 */
+					04 00
+					/* Object 24, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					00 00 00 00 00 00 00 00 00
+					/* Object 25, Instance = 0 */
+					00 00 54 6F F0 55 00 00 00 00
+					00 00 00 00 00
+					/* Object 27, Instance = 0 */
+					00 00 00 00 00 00 00
+					/* Object 40, Instance = 0 */
+					00 14 14 14 14
+					/* Object 42, Instance = 0 */
+					20 14 00 00 00 14 11 00 03 00
+					/* Object 43, Instance = 0 */
+					09 00 01 01 91 00 80 00 00 00
+					00 00
+					/* Object 46, Instance = 0 */
+					00 00 10 10 00 00 01 00 00 0F
+					0A
+					/* Object 47, Instance = 0 */
+					00 14 23 02 05 1E 01 78 03 10
+					00 00 0C 00 00 00 00 00 00 00
+					00 00
+					/* Object 55, Instance = 0 */
+					00 00 00 00 00 00 00
+					/* Object 56, Instance = 0 */
+					02 00 01 30 13 14 14 14 15 15
+					15 15 15 15 15 16 16 16 16 16
+					16 16 16 16 16 15 14 14 14 14
+					15 14 14 14 14 13 00 00 01 02
+					05 05 00 00 00 00 00 00 00 00
+					00
+					/* Object 57, Instance = 0 */
+					00 00 00
+					/* Object 61, Instance = 0 */
+					00 00 00 00 00
+					/* Object 62, Instance = 0 */
+					00 01 03 01 00 00 00 00 00 0A
+					0F 14 19 23 05 00 0A 05 05 69
+					23 23 34 11 64 06 06 04 40 00
+					00 00 00 00 69 4B 02 00 00 80
+					0A 14 14 18 18 10 10 80 00 80
+					00 00 0F 02 00 00 00 00 00 00
+					00 00 00 00 00 00 00 00 00 00
+					00 00 00 00
+					/* Object 63, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					00 00
+					];
+			};
+		};
+	};
+
+	ext_5v: regulator-smb210 {
+		compatible = "regulator-fixed";
+		regulator-name = "ext_5v";
+		gpio = <&pm8941_mpps 2 0>;
+		enable-active-high;
+	};
+};
+
+&usb3 {
+	qcom,charging-disabled;
+};
+
+&pm8941_mvs1 {
+	parent-supply = <&ext_5v>;
+};
+
+&pm8941_mvs2 {
+	parent-supply = <&ext_5v>;
+};
+
+&pm8941_gpios {
+	gpio@c000 { /* GPIO 1 */
+		qcom,mode = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,src-sel = <0>;
+	};
+
+	gpio@c100 { /* GPIO 2 */
+		qcom,mode = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,src-sel = <0>;
+	};
+
+	gpio@c200 { /* GPIO 3 */
+	};
+
+	gpio@c300 { /* GPIO 4 */
+	};
+
+	gpio@c400 { /* GPIO 5 */
+		qcom,mode = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,src-sel = <0>;
+	};
+
+	gpio@c500 { /* GPIO 6 */
+	};
+
+	gpio@c600 { /* GPIO 7 */
+	};
+
+	gpio@c700 { /* GPIO 8 */
+	};
+
+	gpio@c800 { /* GPIO 9 */
+	};
+
+	gpio@c900 { /* GPIO 10 */
+		/* SMB350-CHG-EN-N */
+		qcom,mode = <1>;		/* DIG_OUT */
+		qcom,output-type = <0>;		/* CMOS */
+		qcom,pull = <5>;		/* PULL_NO */
+		qcom,vin-sel = <0>;		/* VPH */
+		qcom,out-strength = <2>;	/* STRENGTH_MED */
+		qcom,src-sel = <0>;		/* CONSTANT */
+		qcom,master-en = <1>;
+	};
+
+	gpio@ca00 { /* GPIO 11 */
+	};
+
+	gpio@cb00 { /* GPIO 12 */
+	};
+
+	gpio@cc00 { /* GPIO 13 */
+		/* SMB350-CHG-SUSP-N */
+		qcom,mode = <1>;		/* DIG_OUT */
+		qcom,output-type = <0>;		/* CMOS */
+		qcom,pull = <5>;		/* PULL_NO */
+		qcom,vin-sel = <0>;		/* VPH */
+		qcom,out-strength = <2>;	/* STRENGTH_MED */
+		qcom,src-sel = <0>;		/* CONSTANT */
+		qcom,master-en = <1>;
+	};
+
+	gpio@cd00 { /* GPIO 14 */
+	};
+
+	gpio@ce00 { /* GPIO 15 */
+		qcom,mode = <1>;
+		qcom,output-type = <0>;
+		qcom,pull = <5>;
+		qcom,vin-sel = <2>;
+		qcom,out-strength = <3>;
+		qcom,src-sel = <2>;
+		qcom,master-en = <1>;
+	};
+
+	gpio@cf00 { /* GPIO 16 */
+	};
+
+	gpio@d000 { /* GPIO 17 */
+	};
+
+	gpio@d100 { /* GPIO 18 */
+	};
+
+	gpio@d200 { /* GPIO 19 */
+		qcom,mode = <1>;		/* QPNP_PIN_MODE_DIG_OUT */
+		qcom,output-type = <0>;		/* QPNP_PIN_OUT_BUF_CMOS */
+		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO */
+		qcom,vin-sel = <2>;		/* QPNP_PIN_VIN2 */
+		qcom,out-strength = <2>;	/* QPNP_PIN_OUT_STRENGTH_MED */
+		qcom,src-sel = <0>;		/* QPNP_PIN_SEL_FUNC_CONSTANT */
+		qcom,master-en = <1>;
+	};
+
+	gpio@d300 { /* GPIO 20 */
+	};
+
+	gpio@d400 { /* GPIO 21 */
+	};
+
+	gpio@d500 { /* GPIO 22 */
+	};
+
+	gpio@d600 { /* GPIO 23 */
+	};
+
+	gpio@d700 { /* GPIO 24 */
+	};
+
+	gpio@d800 { /* GPIO 25 */
+	};
+
+	gpio@d900 { /* GPIO 26 */
+	};
+
+	gpio@da00 { /* GPIO 27 */
+	};
+
+	gpio@db00 { /* GPIO 28 */
+	};
+
+	gpio@dc00 { /* GPIO 29 */
+		qcom,pull = <0>; /* set to default pull */
+		qcom,master-en = <1>;
+		qcom,vin-sel = <2>; /* select 1.8 V source */
+	};
+
+	gpio@dd00 { /* GPIO 30 */
+		/* SMB350-STAT */
+		qcom,mode = <0>;		/* DIG_IN */
+		qcom,pull = <5>;		/* PULL_NO */
+		qcom,vin-sel = <2>;		/* S3 1.8V */
+		qcom,src-sel = <0>;		/* CONSTANT */
+		qcom,master-en = <1>;
+	};
+
+	gpio@de00 { /* GPIO 31 */
+	};
+
+	gpio@df00 { /* GPIO 32 */
+	};
+
+	gpio@e000 { /* GPIO 33 */
+	};
+
+	gpio@e100 { /* GPIO 34 */
+	};
+
+	gpio@e200 { /* GPIO 35 */
+	};
+
+	gpio@e300 { /* GPIO 36 */
+		qcom,mode = <1>;  /* QPNP_PIN_MODE_DIG_OUT */
+		qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+		qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+		qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+		qcom,out-strength = <3>; /* QPNP_PIN_OUT_STRENGTH_HIGH */
+		qcom,src-sel = <3>; /* QPNP_PIN_SEL_FUNC_2 */
+		qcom,master-en = <1>;
+	};
+};
+
+&pm8941_mpps {
+
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+		/* ext_5v regulator enable */
+		qcom,mode = <1>; /* Digital output */
+		qcom,invert = <0>; /* Output low initially */
+		qcom,vin-sel = <2>; /* PM8941 S3 = 1.8 V */
+		qcom,src-sel = <0>; /* Constant */
+		qcom,master-en = <1>; /* Enable MPP */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+
+	mpp@a400 { /* MPP 5 */
+		/* SPI_ETH config */
+		qcom,mode = <1>; /* DIG_OUT */
+		qcom,output-type = <0>; /* CMOS */
+		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+		qcom,src-sel = <0>; /* CONSTANT */
+		qcom,master-en = <1>; /* ENABLE MPP */
+	};
+
+	mpp@a500 { /* MPP 6 */
+		/* SPI_ETH_RST config */
+		qcom,mode = <1>; /* DIG_OUT */
+		qcom,output-type = <0>; /* CMOS */
+		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+		qcom,src-sel = <0>; /* CONSTANT */
+		qcom,master-en = <1>; /* ENABLE MPP */
+	};
+
+	mpp@a600 { /* MPP 7 */
+	};
+
+	mpp@a700 { /* MPP 8 */
+	};
+};
+
+&pm8841_mpps {
+
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* HDMI_MUX_SEL MPP 3*/
+		status = "ok";
+		qcom,mode = <1>; /* DIG_OUT */
+		qcom,output-type = <0>; /* CMOS */
+		qcom,vin-sel = <2>; /* PM8841_S3A 1.8V */
+		qcom,src-sel = <0>; /* CONSTANT */
+		qcom,master-en = <1>; /* ENABLE MPP */
+	};
+
+	mpp@a300 { /* HDMI_MUX_EN MPP 4*/
+		status = "ok";
+		qcom,mode = <1>; /* DIG_OUT */
+		qcom,output-type = <0>; /* CMOS */
+		qcom,vin-sel = <0>; /* PM8841_VPH 3.4V */
+		qcom,src-sel = <0>; /* CONSTANT */
+		qcom,master-en = <1>; /* ENABLE MPP */
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974-mtp.dts b/arch/arm/boot/dts/msm8974-mtp.dts
index c5fabab..9946cf0 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-mtp.dts
@@ -13,403 +13,10 @@
 /dts-v1/;
 
 /include/ "msm8974.dtsi"
-/include/ "dsi-panel-toshiba-720p-video.dtsi"
+/include/ "msm8974-mtp.dtsi"
 
 / {
 	model = "Qualcomm MSM 8974 MTP";
 	compatible = "qcom,msm8974-mtp", "qcom,msm8974";
 	qcom,msm-id = <126 8 0>;
-
-	serial@f991e000 {
-		status = "ok";
-	};
-
-	qcom,mdss_dsi@fd922800 {
-		qcom,mdss_dsi_toshiba_720p_video {
-			status = "ok";
-		};
-	};
-
-	qcom,hdmi_tx@fd922100 {
-		status = "disabled";
-	};
-
-	i2c@f9924000 {
-		atmel_mxt_ts@4a {
-			compatible = "atmel,mxt-ts";
-			reg = <0x4a>;
-			interrupt-parent = <&msmgpio>;
-			interrupts = <61 0x2>;
-			vdd_ana-supply = <&pm8941_l18>;
-			vcc_i2c-supply = <&pm8941_lvs1>;
-			atmel,reset-gpio = <&msmgpio 60 0x00>;
-			atmel,irq-gpio = <&msmgpio 61 0x00>;
-			atmel,panel-coords = <0  0 760 1424>;
-			atmel,display-coords = <0 0 720 1280>;
-			atmel,i2c-pull-up = <1>;
-			atmel,cfg_1 {
-				atmel,family-id = <0x82>;
-				atmel,variant-id = <0x19>;
-				atmel,version = <0x10>;
-				atmel,build = <0xaa>;
-				atmel,config = [
-					/* Object 6, Instance = 0 */
-					00 00 00 00 00 00
-					/* Object 38, Instance = 0 */
-					15 00 02 10 08 0C 00 00
-					/* Object 7, Instance = 0 */
-					FF FF 32 03
-					/* Object 8, Instance = 0 */
-					0F 00 0A 0A 00 00 0A 00 00 00
-					/* Object 9, Instance = 0 */
-					83 00 00 18 0E 00 70 32 02 01
-					00 03 01 01 05 0A 0A 0A 90 05
-					F8 02 00 00 0F 0F 00 00 48 2D
-					07 0C 00 00 00 00
-					/* Object 15, Instance = 0 */
-					00 00 00 00 00 00 00 00 00 00
-					00
-					/* Object 18, Instance = 0 */
-					00 00
-					/* Object 19, Instance = 0 */
-					00 00 00 00 00 00
-					/* Object 23, Instance = 0 */
-					00 00 00 00 00 00 00 00 00 00
-					00 00 00 00 00
-					/* Object 25, Instance = 0 */
-					00 00 00 00 00 00 00 00 00 00
-					00 00 00 00 00
-					/* Object 40, Instance = 0 */
-					00 00 00 00 00
-					/* Object 42, Instance = 0 */
-					00 00 00 00 00 00 00 00 00 00
-					/* Object 46, Instance = 0 */
-					00 00 10 10 00 00 03 00 00 01
-					/* Object 47, Instance = 0 */
-					08 0A 28 0A 02 0A 00 8C 00 20
-					00 00 00
-					/* Object 55, Instance = 0 */
-					00 00 00 00 00 00
-					/* Object 56, Instance = 0 */
-					03 00 01 18 05 05 05 05 05 05
-					05 05 05 05 05 05 05 05 05 05
-					05 05 05 05 05 05 05 05 00 00
-					00 00 00 00 00 00 00 00 00 00
-					00 00
-					/* Object 57, Instance = 0 */
-					00 00 00
-					/* Object 61, Instance = 0 */
-					00 00 00 00 00
-					/* Object 61, Instance = 1 */
-					00 00 00 00 00
-					/* Object 62, Instance = 0 */
-					7F 03 00 16 00 00 00 00 00 00
-					04 08 10 18 05 00 0A 05 05 50
-					14 19 34 1A 64 00 00 04 40 00
-					00 00 00 00 30 32 02 00 01 00
-					05 00 00 00 00 00 00 00 00 00
-					00 00 0C 00
-					];
-			};
-		};
-	};
-
-	gpio_keys {
-		compatible = "gpio-keys";
-		input-name = "gpio-keys";
-
-		camera_snapshot {
-			label = "camera_snapshot";
-			gpios = <&pm8941_gpios 3 0x1>;
-			linux,input-type = <1>;
-			linux,code = <0x2fe>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-
-		camera_focus {
-			label = "camera_focus";
-			gpios = <&pm8941_gpios 4 0x1>;
-			linux,input-type = <1>;
-			linux,code = <0x210>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-
-		vol_up {
-			label = "volume_up";
-			gpios = <&pm8941_gpios 5 0x1>;
-			linux,input-type = <1>;
-			linux,code = <115>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-	};
-
-	spi@f9923000 {
-		ethernet-switch@2 {
-			compatible = "micrel,ks8851";
-			reg = <2>;
-			interrupt-parent = <&msmgpio>;
-			interrupts = <94 0>;
-			spi-max-frequency = <4800000>;
-			rst-gpio = <&pm8941_mpps 6 0>;
-			vdd-io-supply = <&spi_eth_vreg>;
-			vdd-phy-supply = <&spi_eth_vreg>;
-		};
-	};
-};
-
-&sdcc2 {
-	#address-cells = <0>;
-	interrupt-parent = <&sdcc2>;
-	interrupts = <0 1 2>;
-	#interrupt-cells = <1>;
-	interrupt-map-mask = <0xffffffff>;
-	interrupt-map = <0 &intc 0 125 0
-			1 &intc 0 220 0
-			2 &msmgpio 62 0x3>;
-	interrupt-names = "core_irq", "bam_irq", "status_irq";
-	cd-gpios = <&msmgpio 62 0x1>;
-};
-
-&usb_otg {
-	qcom,hsusb-otg-otg-control = <2>;
-};
-
-&usb3 {
-	qcom,dwc-usb3-msm-otg-capability;
-};
-
-&pm8941_chg {
-	status = "ok";
-
-	qcom,chg-charging-disabled;
-
-	qcom,chg-chgr@1000 {
-		status = "ok";
-	};
-
-	qcom,chg-buck@1100 {
-		status = "ok";
-	};
-
-	qcom,chg-bat-if@1200 {
-		status = "ok";
-	};
-
-	qcom,chg-usb-chgpth@1300 {
-		status = "ok";
-	};
-
-	qcom,chg-dc-chgpth@1400 {
-		status = "ok";
-	};
-
-	qcom,chg-boost@1500 {
-		status = "ok";
-	};
-
-	qcom,chg-misc@1600 {
-		status = "ok";
-	};
-};
-
-&pm8941_gpios {
-	gpio@c000 { /* GPIO 1 */
-	};
-
-	gpio@c100 { /* GPIO 2 */
-	};
-
-	gpio@c200 { /* GPIO 3 */
-		qcom,mode = <0>;
-		qcom,pull = <0>;
-		qcom,vin-sel = <2>;
-		qcom,select = <0>;
-	};
-
-	gpio@c300 { /* GPIO 4 */
-		qcom,mode = <0>;
-		qcom,pull = <0>;
-		qcom,vin-sel = <2>;
-		qcom,select = <0>;
-	};
-
-	gpio@c400 { /* GPIO 5 */
-		qcom,mode = <0>;
-		qcom,pull = <0>;
-		qcom,vin-sel = <2>;
-		qcom,select = <0>;
-	};
-
-	gpio@c500 { /* GPIO 6 */
-	};
-
-	gpio@c600 { /* GPIO 7 */
-	};
-
-	gpio@c700 { /* GPIO 8 */
-	};
-
-	gpio@c800 { /* GPIO 9 */
-	};
-
-	gpio@c900 { /* GPIO 10 */
-	};
-
-	gpio@ca00 { /* GPIO 11 */
-	};
-
-	gpio@cb00 { /* GPIO 12 */
-	};
-
-	gpio@cc00 { /* GPIO 13 */
-	};
-
-	gpio@cd00 { /* GPIO 14 */
-	};
-
-	gpio@ce00 { /* GPIO 15 */
-		qcom,mode = <1>;
-		qcom,output-type = <0>;
-		qcom,pull = <5>;
-		qcom,vin-sel = <2>;
-		qcom,out-strength = <3>;
-		qcom,src-select = <2>;
-		qcom,master-en = <1>;
-	};
-
-	gpio@cf00 { /* GPIO 16 */
-	};
-
-	gpio@d000 { /* GPIO 17 */
-	};
-
-	gpio@d100 { /* GPIO 18 */
-	};
-
-	gpio@d200 { /* GPIO 19 */
-		qcom,mode = <1>;		/* QPNP_PIN_MODE_DIG_OUT */
-		qcom,output-type = <0>;		/* QPNP_PIN_OUT_BUF_CMOS */
-		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO */
-		qcom,vin-sel = <2>;		/* QPNP_PIN_VIN2 */
-		qcom,out-strength = <2>;	/* QPNP_PIN_OUT_STRENGTH_MED */
-		qcom,src-select = <0>;		/* QPNP_PIN_SEL_FUNC_CONSTANT */
-		qcom,master-en = <1>;
-	};
-
-	gpio@d300 { /* GPIO 20 */
-	};
-
-	gpio@d400 { /* GPIO 21 */
-	};
-
-	gpio@d500 { /* GPIO 22 */
-	};
-
-	gpio@d600 { /* GPIO 23 */
-	};
-
-	gpio@d700 { /* GPIO 24 */
-	};
-
-	gpio@d800 { /* GPIO 25 */
-	};
-
-	gpio@d900 { /* GPIO 26 */
-	};
-
-	gpio@da00 { /* GPIO 27 */
-	};
-
-	gpio@db00 { /* GPIO 28 */
-	};
-
-	gpio@dc00 { /* GPIO 29 */
-		qcom,pull = <0>; /* set to default pull */
-		qcom,master-en = <1>;
-		qcom,vin-sel = <2>; /* select 1.8 V source */
-	};
-
-	gpio@dd00 { /* GPIO 30 */
-	};
-
-	gpio@de00 { /* GPIO 31 */
-	};
-
-	gpio@df00 { /* GPIO 32 */
-	};
-
-	gpio@e000 { /* GPIO 33 */
-	};
-
-	gpio@e100 { /* GPIO 34 */
-	};
-
-	gpio@e200 { /* GPIO 35 */
-	};
-
-	gpio@e300 { /* GPIO 36 */
-	};
-};
-
-&pm8941_mpps {
-
-	mpp@a000 { /* MPP 1 */
-	};
-
-	mpp@a100 { /* MPP 2 */
-	};
-
-	mpp@a200 { /* MPP 3 */
-	};
-
-	mpp@a300 { /* MPP 4 */
-	};
-
-	mpp@a400 { /* MPP 5 */
-		/* SPI_ETH config */
-		qcom,mode = <1>; /* DIG_OUT */
-		qcom,output-type = <0>; /* CMOS */
-		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
-		qcom,src-select = <0>; /* CONSTANT */
-		qcom,master-en = <1>; /* ENABLE MPP */
-	};
-
-	mpp@a500 { /* MPP 6 */
-		/* SPI_ETH_RST config */
-		qcom,mode = <1>; /* DIG_OUT */
-		qcom,output-type = <0>; /* CMOS */
-		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
-		qcom,src-select = <0>; /* CONSTANT */
-		qcom,master-en = <1>; /* ENABLE MPP */
-	};
-
-	mpp@a600 { /* MPP 7 */
-	};
-
-	mpp@a700 { /* MPP 8 */
-	};
-};
-
-&pm8841_mpps {
-
-	mpp@a000 { /* MPP 1 */
-	};
-
-	mpp@a100 { /* MPP 2 */
-	};
-
-	mpp@a200 { /* MPP 3 */
-	};
-
-	mpp@a300 { /* MPP 4 */
-	};
-};
-
-&slim_msm {
-	taiko_codec {
-		qcom,cdc-micbias2-ext-cap;
-	};
 };
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
new file mode 100644
index 0000000..6553fc0
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -0,0 +1,409 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/ "dsi-panel-toshiba-720p-video.dtsi"
+
+/ {
+	serial@f991e000 {
+		status = "ok";
+	};
+
+	qcom,mdss_dsi@fd922800 {
+		qcom,mdss_dsi_toshiba_720p_video {
+			status = "ok";
+		};
+	};
+
+	qcom,hdmi_tx@fd922100 {
+		status = "disabled";
+	};
+
+	i2c@f9924000 {
+		atmel_mxt_ts@4a {
+			compatible = "atmel,mxt-ts";
+			reg = <0x4a>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <61 0x2>;
+			vdd_ana-supply = <&pm8941_l18>;
+			vcc_i2c-supply = <&pm8941_lvs1>;
+			atmel,reset-gpio = <&msmgpio 60 0x00>;
+			atmel,irq-gpio = <&msmgpio 61 0x00>;
+			atmel,panel-coords = <0  0 760 1424>;
+			atmel,display-coords = <0 0 720 1280>;
+			atmel,i2c-pull-up;
+			atmel,no-force-update;
+			atmel,cfg_1 {
+				atmel,family-id = <0x82>;
+				atmel,variant-id = <0x19>;
+				atmel,version = <0x10>;
+				atmel,build = <0xaa>;
+				atmel,config = [
+					/* Object 6, Instance = 0 */
+					00 00 00 00 00 00
+					/* Object 38, Instance = 0 */
+					15 00 02 10 08 0C 00 00
+					/* Object 7, Instance = 0 */
+					FF FF 32 03
+					/* Object 8, Instance = 0 */
+					0F 00 0A 0A 00 00 0A 00 00 00
+					/* Object 9, Instance = 0 */
+					83 00 00 18 0E 00 70 32 02 01
+					00 03 01 01 05 0A 0A 0A 90 05
+					F8 02 00 00 0F 0F 00 00 48 2D
+					07 0C 00 00 00 00
+					/* Object 15, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					00
+					/* Object 18, Instance = 0 */
+					00 00
+					/* Object 19, Instance = 0 */
+					00 00 00 00 00 00
+					/* Object 23, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					00 00 00 00 00
+					/* Object 25, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					00 00 00 00 00
+					/* Object 40, Instance = 0 */
+					00 00 00 00 00
+					/* Object 42, Instance = 0 */
+					00 00 00 00 00 00 00 00 00 00
+					/* Object 46, Instance = 0 */
+					00 00 10 10 00 00 03 00 00 01
+					/* Object 47, Instance = 0 */
+					08 0A 28 0A 02 0A 00 8C 00 20
+					00 00 00
+					/* Object 55, Instance = 0 */
+					00 00 00 00 00 00
+					/* Object 56, Instance = 0 */
+					03 00 01 18 05 05 05 05 05 05
+					05 05 05 05 05 05 05 05 05 05
+					05 05 05 05 05 05 05 05 00 00
+					00 00 00 00 00 00 00 00 00 00
+					00 00
+					/* Object 57, Instance = 0 */
+					00 00 00
+					/* Object 61, Instance = 0 */
+					00 00 00 00 00
+					/* Object 61, Instance = 1 */
+					00 00 00 00 00
+					/* Object 62, Instance = 0 */
+					7F 03 00 16 00 00 00 00 00 00
+					04 08 10 18 05 00 0A 05 05 50
+					14 19 34 1A 64 00 00 04 40 00
+					00 00 00 00 30 32 02 00 01 00
+					05 00 00 00 00 00 00 00 00 00
+					00 00 0C 00
+					];
+			};
+		};
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+
+		camera_snapshot {
+			label = "camera_snapshot";
+			gpios = <&pm8941_gpios 3 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x2fe>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		camera_focus {
+			label = "camera_focus";
+			gpios = <&pm8941_gpios 4 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x210>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&pm8941_gpios 5 0x1>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+	};
+
+	spi@f9923000 {
+		ethernet-switch@2 {
+			compatible = "micrel,ks8851";
+			reg = <2>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <94 0>;
+			spi-max-frequency = <4800000>;
+			rst-gpio = <&pm8941_mpps 6 0>;
+			vdd-io-supply = <&spi_eth_vreg>;
+			vdd-phy-supply = <&spi_eth_vreg>;
+		};
+	};
+};
+
+&sdcc2 {
+	#address-cells = <0>;
+	interrupt-parent = <&sdcc2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+			1 &intc 0 220 0
+			2 &msmgpio 62 0x3>;
+	interrupt-names = "core_irq", "bam_irq", "status_irq";
+	cd-gpios = <&msmgpio 62 0x1>;
+};
+
+&usb_otg {
+	qcom,hsusb-otg-otg-control = <2>;
+};
+
+&usb3 {
+	qcom,otg-capability;
+};
+
+&pm8941_chg {
+	status = "ok";
+
+	qcom,chg-charging-disabled;
+
+	qcom,chg-chgr@1000 {
+		status = "ok";
+	};
+
+	qcom,chg-buck@1100 {
+		status = "ok";
+	};
+
+	qcom,chg-bat-if@1200 {
+		status = "ok";
+	};
+
+	qcom,chg-usb-chgpth@1300 {
+		status = "ok";
+	};
+
+	qcom,chg-dc-chgpth@1400 {
+		status = "ok";
+	};
+
+	qcom,chg-boost@1500 {
+		status = "ok";
+	};
+
+	qcom,chg-misc@1600 {
+		status = "ok";
+	};
+};
+
+&pm8941_gpios {
+	gpio@c000 { /* GPIO 1 */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+	};
+
+	gpio@c200 { /* GPIO 3 */
+		qcom,mode = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,src-sel = <0>;
+	};
+
+	gpio@c300 { /* GPIO 4 */
+		qcom,mode = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,src-sel = <0>;
+	};
+
+	gpio@c400 { /* GPIO 5 */
+		qcom,mode = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,src-sel = <0>;
+	};
+
+	gpio@c500 { /* GPIO 6 */
+	};
+
+	gpio@c600 { /* GPIO 7 */
+	};
+
+	gpio@c700 { /* GPIO 8 */
+	};
+
+	gpio@c800 { /* GPIO 9 */
+	};
+
+	gpio@c900 { /* GPIO 10 */
+	};
+
+	gpio@ca00 { /* GPIO 11 */
+	};
+
+	gpio@cb00 { /* GPIO 12 */
+	};
+
+	gpio@cc00 { /* GPIO 13 */
+	};
+
+	gpio@cd00 { /* GPIO 14 */
+	};
+
+	gpio@ce00 { /* GPIO 15 */
+		qcom,mode = <1>;
+		qcom,output-type = <0>;
+		qcom,pull = <5>;
+		qcom,vin-sel = <2>;
+		qcom,out-strength = <3>;
+		qcom,src-sel = <2>;
+		qcom,master-en = <1>;
+	};
+
+	gpio@cf00 { /* GPIO 16 */
+	};
+
+	gpio@d000 { /* GPIO 17 */
+	};
+
+	gpio@d100 { /* GPIO 18 */
+	};
+
+	gpio@d200 { /* GPIO 19 */
+		qcom,mode = <1>;		/* QPNP_PIN_MODE_DIG_OUT */
+		qcom,output-type = <0>;		/* QPNP_PIN_OUT_BUF_CMOS */
+		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO */
+		qcom,vin-sel = <2>;		/* QPNP_PIN_VIN2 */
+		qcom,out-strength = <2>;	/* QPNP_PIN_OUT_STRENGTH_MED */
+		qcom,src-sel = <0>;		/* QPNP_PIN_SEL_FUNC_CONSTANT */
+		qcom,master-en = <1>;
+	};
+
+	gpio@d300 { /* GPIO 20 */
+	};
+
+	gpio@d400 { /* GPIO 21 */
+	};
+
+	gpio@d500 { /* GPIO 22 */
+	};
+
+	gpio@d600 { /* GPIO 23 */
+	};
+
+	gpio@d700 { /* GPIO 24 */
+	};
+
+	gpio@d800 { /* GPIO 25 */
+	};
+
+	gpio@d900 { /* GPIO 26 */
+	};
+
+	gpio@da00 { /* GPIO 27 */
+	};
+
+	gpio@db00 { /* GPIO 28 */
+	};
+
+	gpio@dc00 { /* GPIO 29 */
+		qcom,pull = <0>; /* set to default pull */
+		qcom,master-en = <1>;
+		qcom,vin-sel = <2>; /* select 1.8 V source */
+	};
+
+	gpio@dd00 { /* GPIO 30 */
+	};
+
+	gpio@de00 { /* GPIO 31 */
+	};
+
+	gpio@df00 { /* GPIO 32 */
+	};
+
+	gpio@e000 { /* GPIO 33 */
+	};
+
+	gpio@e100 { /* GPIO 34 */
+	};
+
+	gpio@e200 { /* GPIO 35 */
+	};
+
+	gpio@e300 { /* GPIO 36 */
+	};
+};
+
+&pm8941_mpps {
+
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+
+	mpp@a400 { /* MPP 5 */
+		/* SPI_ETH config */
+		qcom,mode = <1>; /* DIG_OUT */
+		qcom,output-type = <0>; /* CMOS */
+		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+		qcom,src-sel = <0>; /* CONSTANT */
+		qcom,master-en = <1>; /* ENABLE MPP */
+	};
+
+	mpp@a500 { /* MPP 6 */
+		/* SPI_ETH_RST config */
+		qcom,mode = <1>; /* DIG_OUT */
+		qcom,output-type = <0>; /* CMOS */
+		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+		qcom,src-sel = <0>; /* CONSTANT */
+		qcom,master-en = <1>; /* ENABLE MPP */
+	};
+
+	mpp@a600 { /* MPP 7 */
+	};
+
+	mpp@a700 { /* MPP 8 */
+	};
+};
+
+&pm8841_mpps {
+
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+};
+
+&slim_msm {
+	taiko_codec {
+		qcom,cdc-micbias2-ext-cap;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974-pm.dtsi b/arch/arm/boot/dts/msm8974-pm.dtsi
index c6cbca3..52f2a41 100644
--- a/arch/arm/boot/dts/msm8974-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-pm.dtsi
@@ -125,7 +125,7 @@
 		qcom,vctl-port = <0x0>;
 		qcom,phase-port = <0x1>;
 		qcom,pfm-port = <0x2>;
-		qcom,saw2-spm-cmd-ret = [00 20 03 22 00 0f];
+		qcom,saw2-spm-cmd-ret = [1f 00 20 03 22 00 0f];
 		qcom,saw2-spm-cmd-gdhs = [00 20 32 42 07 44 22 50 02 32 50 0f];
 		qcom,saw2-spm-cmd-pc = [00 10 32 b0 11 42 07 01 b0 12 44
 				50 02 32 50 0f];
@@ -422,4 +422,17 @@
 		compatible = "qcom,pc-cntr";
 		reg = <0xfe805664 0x40>;
 	};
+
+	qcom,pm-8x60 {
+		compatible = "qcom,pm-8x60";
+		qcom,pc-mode = <0>; /*MSM_PC_TZ_L2_INT */
+		qcom,use-sync-timer;
+	};
+
+	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-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index de9e98c..495d3fb 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -456,6 +456,10 @@
 		reg = <0xf9088000 0x1000>;
 		regulator-min-microvolt = <500000>;
 		regulator-max-microvolt = <1100000>;
+		qcom,headroom-voltage = <150000>;
+		qcom,retention-voltage = <745000>;
+		qcom,ldo-default-voltage = <745000>;
+		qcom,ldo-threshold-voltage = <750000>;
 	};
 
 	krait1_vreg: regulator@f9098000 {
@@ -464,6 +468,10 @@
 		reg = <0xf9098000 0x1000>;
 		regulator-min-microvolt = <500000>;
 		regulator-max-microvolt = <1100000>;
+		qcom,headroom-voltage = <150000>;
+		qcom,retention-voltage = <745000>;
+		qcom,ldo-default-voltage = <745000>;
+		qcom,ldo-threshold-voltage = <750000>;
 	};
 
 	krait2_vreg: regulator@f90a8000 {
@@ -472,6 +480,10 @@
 		reg = <0xf90a8000 0x1000>;
 		regulator-min-microvolt = <500000>;
 		regulator-max-microvolt = <1100000>;
+		qcom,headroom-voltage = <150000>;
+		qcom,retention-voltage = <745000>;
+		qcom,ldo-default-voltage = <745000>;
+		qcom,ldo-threshold-voltage = <750000>;
 	};
 
 	krait3_vreg: regulator@f90b8000 {
@@ -480,6 +492,10 @@
 		reg = <0xf90b8000 0x1000>;
 		regulator-min-microvolt = <500000>;
 		regulator-max-microvolt = <1100000>;
+		qcom,headroom-voltage = <150000>;
+		qcom,retention-voltage = <745000>;
+		qcom,ldo-default-voltage = <745000>;
+		qcom,ldo-threshold-voltage = <750000>;
 	};
 
 	spi_eth_vreg: spi_eth_phy_vreg {
diff --git a/arch/arm/boot/dts/msm8974-rumi.dts b/arch/arm/boot/dts/msm8974-rumi.dts
index 3533151..738ff86 100644
--- a/arch/arm/boot/dts/msm8974-rumi.dts
+++ b/arch/arm/boot/dts/msm8974-rumi.dts
@@ -13,103 +13,10 @@
 /dts-v1/;
 
 /include/ "msm8974.dtsi"
+/include/ "msm8974-rumi.dtsi"
 
 / {
 	model = "Qualcomm MSM 8974 RUMI";
 	compatible = "qcom,msm8974-rumi", "qcom,msm8974";
 	qcom,msm-id = <126 15 0>;
-
-	timer {
-		clock-frequency = <5000000>;
-	};
-
-	serial@f995e000 {
-		status = "ok";
-	};
-
-	usb@f9a55000 {
-		status = "disable";
-	};
-
-	qcom,sdcc@f9824000 {
-                qcom,sdcc-clk-rates = <400000 19200000>;
-        };
-
-        qcom,sdcc@f98a4000 {
-                qcom,sdcc-clk-rates = <400000 19200000>;
-        };
-
-	qcom,sps@f998000 {
-		status = "disable";
-	};
-
-	spi@f9924000 {
-		status = "disable";
-	};
-
-	spi@f9923000 {
-		compatible = "qcom,spi-qup-v2";
-		reg = <0xf9923000 0x1000>;
-		interrupts = <0 95 0>;
-		spi-max-frequency = <24000000>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		gpios = <&msmgpio 3 0>, /* CLK  */
-			<&msmgpio 1 0>, /* MISO */
-			<&msmgpio 0 0>; /* MOSI */
-		cs-gpios = <&msmgpio 9 0>;
-
-		ethernet-switch@2 {
-			compatible = "simtec,ks8851";
-			reg = <2>;
-			interrupt-parent = <&msmgpio>;
-			interrupts = <90 0>;
-			spi-max-frequency = <5000000>;
-		};
-	};
-
-	i2c@f9966000 {
-		status = "disable";
-	};
-
-	i2c@f9967000 {
-		cell-index = <0>;
-		compatible = "qcom,i2c-qup";
-		reg = <0Xf9967000 0x1000>;
-		reg-names = "qup_phys_addr";
-		interrupts = <0 105 0>;
-		interrupt-names = "qup_err_intr";
-		qcom,i2c-bus-freq = <100000>;
-		qcom,i2c-src-freq = <24000000>;
-		gpios = <&msmgpio 83 0>, /* DAT  */
-			<&msmgpio 84 0>; /* CLK */
-	};
-
-	slim@fe12f000 {
-		status = "disable";
-	};
-
-	qcom,mdss_dsi@fd922800 {
-		status = "disable";
-	};
-
-	qcom,spmi@fc4c0000 {
-		status = "disable";
-	};
-
-	qcom,ssusb@F9200000 {
-		status = "disable";
-	};
-
-	qcom,lpass@fe200000 {
-		status = "disable";
-	};
-
-	qcom,pronto@fb21b000 {
-		status = "disable";
-	};
-
-	qcom,mss@fc880000 {
-		status = "disable";
-	};
 };
diff --git a/arch/arm/boot/dts/msm8974-rumi.dtsi b/arch/arm/boot/dts/msm8974-rumi.dtsi
new file mode 100644
index 0000000..5a16be7
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-rumi.dtsi
@@ -0,0 +1,107 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ */
+
+/ {
+	timer {
+		clock-frequency = <5000000>;
+	};
+
+	serial@f995e000 {
+		status = "ok";
+	};
+
+	usb@f9a55000 {
+		status = "disable";
+	};
+
+	qcom,sdcc@f9824000 {
+                qcom,clk-rates = <400000 19200000>;
+        };
+
+        qcom,sdcc@f98a4000 {
+                qcom,clk-rates = <400000 19200000>;
+        };
+
+	qcom,sps@f998000 {
+		status = "disable";
+	};
+
+	spi@f9924000 {
+		status = "disable";
+	};
+
+	spi@f9923000 {
+		compatible = "qcom,spi-qup-v2";
+		reg = <0xf9923000 0x1000>;
+		interrupts = <0 95 0>;
+		spi-max-frequency = <24000000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		gpios = <&msmgpio 3 0>, /* CLK  */
+			<&msmgpio 1 0>, /* MISO */
+			<&msmgpio 0 0>; /* MOSI */
+		cs-gpios = <&msmgpio 9 0>;
+
+		ethernet-switch@2 {
+			compatible = "simtec,ks8851";
+			reg = <2>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <90 0>;
+			spi-max-frequency = <5000000>;
+		};
+	};
+
+	i2c@f9966000 {
+		status = "disable";
+	};
+
+	i2c@f9967000 {
+		cell-index = <0>;
+		compatible = "qcom,i2c-qup";
+		reg = <0Xf9967000 0x1000>;
+		reg-names = "qup_phys_addr";
+		interrupts = <0 105 0>;
+		interrupt-names = "qup_err_intr";
+		qcom,i2c-bus-freq = <100000>;
+		qcom,i2c-src-freq = <24000000>;
+		gpios = <&msmgpio 83 0>, /* DAT  */
+			<&msmgpio 84 0>; /* CLK */
+	};
+
+	slim@fe12f000 {
+		status = "disable";
+	};
+
+	qcom,mdss_dsi@fd922800 {
+		status = "disable";
+	};
+
+	qcom,spmi@fc4c0000 {
+		status = "disable";
+	};
+
+	qcom,ssusb@F9200000 {
+		status = "disable";
+	};
+
+	qcom,lpass@fe200000 {
+		status = "disable";
+	};
+
+	qcom,pronto@fb21b000 {
+		status = "disable";
+	};
+
+	qcom,mss@fc880000 {
+		status = "disable";
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974-sim.dts b/arch/arm/boot/dts/msm8974-sim.dts
index d5368fa..09ea419 100644
--- a/arch/arm/boot/dts/msm8974-sim.dts
+++ b/arch/arm/boot/dts/msm8974-sim.dts
@@ -13,86 +13,10 @@
 /dts-v1/;
 
 /include/ "msm8974.dtsi"
-/include/ "dsi-panel-sim-video.dtsi"
+/include/ "msm8974-sim.dtsi"
 
 / {
 	model = "Qualcomm MSM 8974 Simulator";
 	compatible = "qcom,msm8974-sim", "qcom,msm8974";
 	qcom,msm-id = <126 16 0>;
-
-	qcom,mdss_dsi@fd922800 {
-		qcom,mdss_dsi_sim_video {
-			status = "ok";
-		};
-	};
-
-	serial@f991f000 {
-		status = "ok";
-	};
-
-	serial@f995e000 {
-		status = "ok";
-	};
-};
-
-&jpeg_iommu {
-		qcom,iommu-ctx@fda6c000 {
-			interrupts = <0 69 0>;
-		};
-
-		qcom,iommu-ctx@fda6d000 {
-			interrupts = <0 70 0>;
-		};
-
-		qcom,iommu-ctx@fda6e000 {
-			interrupts = <0 71 0>;
-		};
-};
-
-&mdp_iommu {
-		qcom,iommu-ctx@fd930000 {
-			interrupts = <0 46 0>;
-		};
-
-		qcom,iommu-ctx@fd931000 {
-			interrupts = <0 47 0>;
-		};
-};
-
-&venus_iommu {
-		qcom,iommu-ctx@fdc8c000 {
-			interrupts = <0 43 0>;
-		};
-
-		qcom,iommu-ctx@fdc8d000 {
-			interrupts = <0 42 0>;
-		};
-
-		qcom,iommu-ctx@fdc8e000 {
-			interrupts = <0 41 0>;
-		};
-};
-
-&kgsl_iommu {
-		qcom,iommu-ctx@fdb18000 {
-			interrupts = <0 240 0>;
-		};
-
-		qcom,iommu-ctx@fdb19000 {
-			interrupts = <0 241 0>;
-		};
-};
-
-&vfe_iommu {
-		qcom,iommu-ctx@fda4c000 {
-			interrupts = <0 64 0>;
-		};
-
-		qcom,iommu-ctx@fda4d000 {
-			interrupts = <0 65 0>;
-		};
-
-		qcom,iommu-ctx@fda4e000 {
-			interrupts = <0 66 0>;
-		};
 };
diff --git a/arch/arm/boot/dts/msm8974-sim.dtsi b/arch/arm/boot/dts/msm8974-sim.dtsi
new file mode 100644
index 0000000..41e37de
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-sim.dtsi
@@ -0,0 +1,91 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/ "dsi-panel-sim-video.dtsi"
+
+/ {
+	qcom,mdss_dsi@fd922800 {
+		qcom,mdss_dsi_sim_video {
+			status = "ok";
+		};
+	};
+
+	serial@f991f000 {
+		status = "ok";
+	};
+
+	serial@f995e000 {
+		status = "ok";
+	};
+};
+
+&jpeg_iommu {
+		qcom,iommu-ctx@fda6c000 {
+			interrupts = <0 69 0>;
+		};
+
+		qcom,iommu-ctx@fda6d000 {
+			interrupts = <0 70 0>;
+		};
+
+		qcom,iommu-ctx@fda6e000 {
+			interrupts = <0 71 0>;
+		};
+};
+
+&mdp_iommu {
+		qcom,iommu-ctx@fd930000 {
+			interrupts = <0 46 0>;
+		};
+
+		qcom,iommu-ctx@fd931000 {
+			interrupts = <0 47 0>;
+		};
+};
+
+&venus_iommu {
+		qcom,iommu-ctx@fdc8c000 {
+			interrupts = <0 43 0>;
+		};
+
+		qcom,iommu-ctx@fdc8d000 {
+			interrupts = <0 42 0>;
+		};
+
+		qcom,iommu-ctx@fdc8e000 {
+			interrupts = <0 41 0>;
+		};
+};
+
+&kgsl_iommu {
+		qcom,iommu-ctx@fdb18000 {
+			interrupts = <0 240 0>;
+		};
+
+		qcom,iommu-ctx@fdb19000 {
+			interrupts = <0 241 0>;
+		};
+};
+
+&vfe_iommu {
+		qcom,iommu-ctx@fda4c000 {
+			interrupts = <0 64 0>;
+		};
+
+		qcom,iommu-ctx@fda4d000 {
+			interrupts = <0 65 0>;
+		};
+
+		qcom,iommu-ctx@fda4e000 {
+			interrupts = <0 66 0>;
+		};
+};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 84ee006..0e30129 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -122,6 +122,7 @@
 	android_usb@fc42b0c8 {
 		compatible = "qcom,android-usb";
 		reg = <0xfc42b0c8 0xc8>;
+		qcom,android-usb-swfi-latency = <1>;
 	};
 
 	sdcc1: qcom,sdcc@f9824000 {
@@ -136,25 +137,26 @@
 		vdd-supply = <&pm8941_l20>;
 		vdd-io-supply = <&pm8941_s3>;
 
-		qcom,sdcc-vdd-always_on;
-		qcom,sdcc-vdd-lpm_sup;
-		qcom,sdcc-vdd-voltage_level = <2950000 2950000>;
-		qcom,sdcc-vdd-current_level = <800 500000>;
+		qcom,vdd-always-on;
+		qcom,vdd-lpm-sup;
+		qcom,vdd-voltage-level = <2950000 2950000>;
+		qcom,vdd-current-level = <800 500000>;
 
-		qcom,sdcc-vdd-io-always_on;
-		qcom,sdcc-vdd-io-voltage_level = <1800000 1800000>;
-		qcom,sdcc-vdd-io-current_level = <250 154000>;
+		qcom,vdd-io-always-on;
+		qcom,vdd-io-voltage-level = <1800000 1800000>;
+		qcom,vdd-io-current-level = <250 154000>;
 
-		qcom,sdcc-pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-		qcom,sdcc-pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-		qcom,sdcc-pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
-		qcom,sdcc-pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+		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,sdcc-clk-rates = <400000 25000000 50000000 100000000 200000000>;
-		qcom,sdcc-sup-voltages = <2950 2950>;
-		qcom,sdcc-bus-width = <8>;
-		qcom,sdcc-nonremovable;
-		qcom,sdcc-bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+		qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+		qcom,sup-voltages = <2950 2950>;
+		qcom,bus-width = <8>;
+		qcom,nonremovable;
+		qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+		qcom,dat1-mpm-int = <42>;
 	};
 
 	sdcc2: qcom,sdcc@f98a4000 {
@@ -169,25 +171,26 @@
 		vdd-supply = <&pm8941_l21>;
 		vdd-io-supply = <&pm8941_l13>;
 
-		qcom,sdcc-vdd-voltage_level = <2950000 2950000>;
-		qcom,sdcc-vdd-current_level = <9000 800000>;
+		qcom,vdd-voltage-level = <2950000 2950000>;
+		qcom,vdd-current-level = <9000 800000>;
 
-		qcom,sdcc-vdd-io-always_on;
-		qcom,sdcc-vdd-io-lpm_sup;
-		qcom,sdcc-vdd-io-voltage_level = <1800000 2950000>;
-		qcom,sdcc-vdd-io-current_level = <6 22000>;
+		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,sdcc-pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-		qcom,sdcc-pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-		qcom,sdcc-pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
-		qcom,sdcc-pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+		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,sdcc-clk-rates = <400000 25000000 50000000 100000000 200000000>;
-		qcom,sdcc-sup-voltages = <2950 2950>;
-		qcom,sdcc-bus-width = <4>;
-		qcom,sdcc-xpc;
-		qcom,sdcc-bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
-		qcom,sdcc-current-limit = <800>;
+		qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+		qcom,sup-voltages = <2950 2950>;
+		qcom,bus-width = <4>;
+		qcom,xpc;
+		qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+		qcom,current-limit = <800>;
+		qcom,dat1-mpm-int = <44>;
 	};
 
 	sdcc3: qcom,sdcc@f9864000 {
@@ -197,8 +200,15 @@
 			<0xf9864800 0x100>,
 			<0xf9844000 0x7000>;
 		reg-names = "core_mem", "dml_mem", "bam_mem";
-		interrupts = <0 127 0>, <0 223 0>;
-		interrupt-names = "core_irq", "bam_irq";
+		#address-cells = <0>;
+		interrupt-parent = <&sdcc3>;
+		interrupts = <0 1 2>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0xffffffff>;
+		interrupt-map = <0 &intc 0 127 0
+				1 &intc 0 223 0
+				2 &msmgpio 37 0x8>;
+		interrupt-names = "core_irq", "bam_irq", "sdiowakeup_irq";
 
 		gpios = <&msmgpio 40 0>, /* CLK */
 			<&msmgpio 39 0>, /* CMD */
@@ -206,12 +216,12 @@
 			<&msmgpio 37 0>, /* DATA1 */
 			<&msmgpio 36 0>, /* DATA2 */
 			<&msmgpio 35 0>; /* DATA3 */
-		qcom,sdcc-gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
+		qcom,gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
 
-		qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000>;
-		qcom,sdcc-sup-voltages = <1800 1800>;
-		qcom,sdcc-bus-width = <4>;
-		qcom,sdcc-bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50";
+		qcom,clk-rates = <400000 25000000 50000000 100000000>;
+		qcom,sup-voltages = <1800 1800>;
+		qcom,bus-width = <4>;
+		qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50";
 		status = "disable";
 	};
 
@@ -222,8 +232,15 @@
 			<0xf98e4800 0x100>,
 			<0xf98c4000 0x7000>;
 		reg-names = "core_mem", "dml_mem", "bam_mem";
-		interrupts = <0 129 0>, <0 226 0>;
-		interrupt-names = "core_irq", "bam_irq";
+		#address-cells = <0>;
+		interrupt-parent = <&sdcc4>;
+		interrupts = <0 1 2>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0xffffffff>;
+		interrupt-map = <0 &intc 0 129 0
+				1 &intc 0 226 0
+				2 &msmgpio 95 0x8>;
+		interrupt-names = "core_irq", "bam_irq", "sdiowakeup_irq";
 
 		gpios = <&msmgpio 93 0>, /* CLK */
 			<&msmgpio 91 0>, /* CMD */
@@ -231,12 +248,12 @@
 			<&msmgpio 95 0>, /* DATA1 */
 			<&msmgpio 94 0>, /* DATA2 */
 			<&msmgpio 92 0>; /* DATA3 */
-		qcom,sdcc-gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
+		qcom,gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
 
-		qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000>;
-		qcom,sdcc-sup-voltages = <1800 1800>;
-		qcom,sdcc-bus-width = <4>;
-		qcom,sdcc-bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50";
+		qcom,clk-rates = <400000 25000000 50000000 100000000>;
+		qcom,sup-voltages = <1800 1800>;
+		qcom,bus-width = <4>;
+		qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50";
 		status = "disable";
 	};
 
@@ -527,6 +544,57 @@
 					 <0x1e70008c>; /* LPG_CHAN12 */
 
 		qcom,pm8941@1 {
+			qcom,leds@d300 {
+				status = "okay";
+				qcom,flash_0 {
+					qcom,max-current = <1000>;
+					qcom,default-state = "off";
+					qcom,headroom = <0>;
+					qcom,duration = <1280>;
+					qcom,clamp-curr = <200>;
+					qcom,startup-dly = <1>;
+					qcom,safety-timer;
+					label = "flash";
+					linux,default-trigger =
+						"flash0_trigger";
+					qcom,id = <1>;
+					linux,name = "led:flash_0";
+					qcom,current = <625>;
+				};
+
+				qcom,flash_1 {
+					qcom,max-current = <1000>;
+					qcom,default-state = "off";
+					qcom,headroom = <0>;
+					qcom,duration = <1280>;
+					qcom,clamp-curr = <200>;
+					qcom,startup-dly = <1>;
+					qcom,safety-timer;
+					linux,default-trigger =
+						"flash1_trigger";
+					label = "flash";
+					qcom,id = <2>;
+					linux,name = "led:flash_1";
+					qcom,current = <625>;
+				};
+			};
+
+			qcom,leds@d400 {
+				status = "disabled";
+			};
+
+			qcom,leds@d500 {
+				status = "disabled";
+			};
+
+			qcom,leds@d600 {
+				status = "disabled";
+			};
+
+			qcom,leds@d700 {
+				status = "disabled";
+			};
+
 			qcom,leds@d800 {
 				status = "okay";
 				qcom,wled_0 {
@@ -535,7 +603,7 @@
 					linux,default-trigger = "bkl-trigger";
 					qcom,cs-out-en;
 					qcom,op-fdbck;
-					qcom,default-state = "on";
+					qcom,default-state = "off";
 					qcom,max-current = <25>;
 					qcom,ctrl-delay-us = <0>;
 					qcom,boost-curr-lim = <3>;
@@ -582,6 +650,7 @@
 			qcom,leds@e100 {
 				status = "disabled";
 			};
+
 		};
 	};
 
@@ -745,6 +814,36 @@
 			qcom,msm-dai-q6-dev-id = <16385>;
 		};
 
+		qcom,msm-dai-q6-sb-1-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16386>;
+		};
+
+		qcom,msm-dai-q6-sb-1-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16387>;
+		};
+
+		qcom,msm-dai-q6-sb-3-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16390>;
+		};
+
+		qcom,msm-dai-q6-sb-3-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16391>;
+		};
+
+		qcom,msm-dai-q6-sb-4-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16392>;
+		};
+
+		qcom,msm-dai-q6-sb-4-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16393>;
+		};
+
 		qcom,msm-dai-q6-bt-sco-rx {
 			compatible = "qcom,msm-dai-q6-dev";
 			qcom,msm-dai-q6-dev-id = <12288>;
@@ -829,27 +928,18 @@
 		      <0xfd485000 0x400>,
 		      <0xfc820000 0x020>,
 		      <0xfc401680 0x004>,
-		      <0xfc980008 0x004>;
+		      <0x0d1fc000 0x4000>;
 		reg-names = "qdsp6_base", "halt_base", "rmb_base",
-			    "restart_reg", "clamp_reg";
+			    "restart_reg", "metadata_base";
 
+		interrupts = <0 24 1>;
 		vdd_mss-supply = <&pm8841_s3>;
 
+		qcom,is_loadable = <1>;
 		qcom,firmware-name = "mba";
 		qcom,pil-self-auth = <1>;
 	};
 
-	qcom,mba@fc820000 {
-		compatible = "qcom,pil-mba";
-		reg = <0xfc820000 0x0020>,
-		      <0x0d1fc000 0x4000>;
-		reg-names = "rmb_base", "metadata_base";
-		interrupts = <0 24 1>;
-
-		qcom,firmware-name = "modem";
-		qcom,depends-on    = "mba";
-	};
-
 	qcom,pronto@fb21b000 {
 		compatible = "qcom,pil-pronto";
 		reg = <0xfb21b000 0x3000>,
@@ -974,8 +1064,6 @@
 		vdd-supply = <&gdsc_venus>;
 
 		qcom,firmware-name = "venus";
-		qcom,firmware-min-paddr = <0xF500000>;
-		qcom,firmware-max-paddr = <0xFA00000>;
 	};
 
 	qcom,cache_erp {
@@ -1010,6 +1098,12 @@
 		qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
 	};
 
+	qcom,msm-contig-mem {
+		compatible = "qcom,msm-contig-mem";
+		qcom,memory-reservation-type = "EBI1";
+		qcom,memory-reservation-size = <0x280000>; /* 2.5M EBI1 buffer */
+	};
+
         qcom,qcedev@fd440000 {
 		compatible = "qcom,qcedev";
 		reg = <0xfd440000 0x20000>,
@@ -1118,7 +1212,10 @@
                compatible = "qcom,msm-wdog-debug";
                reg = <0xfc401000 0x1000>;
         };
-
+        qcom,msm-mem-hole {
+                compatible = "qcom,msm-mem-hole";
+                qcom,memblock-remove = <0x8400000 0x7b00000>; /* Address and Size of Hole */
+        };
 };
 
 /include/ "msm-pm8x41-rpm-regulator.dtsi"
diff --git a/arch/arm/boot/dts/msm9625-cdp.dts b/arch/arm/boot/dts/msm9625-cdp.dts
index 89c269e..ba5bbcf 100644
--- a/arch/arm/boot/dts/msm9625-cdp.dts
+++ b/arch/arm/boot/dts/msm9625-cdp.dts
@@ -18,6 +18,25 @@
 	model = "Qualcomm MSM 9625 CDP";
 	compatible = "qcom,msm9625-cdp", "qcom,msm9625";
 	qcom,msm-id = <134 1 0>, <152 1 0>;
+
+	i2c@f9925000 {
+		charger@57 {
+			compatible = "summit,smb137c";
+			reg = <0x57>;
+			summit,chg-current-ma = <1500>;
+			summit,term-current-ma = <50>;
+			summit,pre-chg-current-ma = <100>;
+			summit,float-voltage-mv = <4200>;
+			summit,thresh-voltage-mv = <3000>;
+			summit,recharge-thresh-mv = <75>;
+			summit,system-voltage-mv = <4250>;
+			summit,charging-timeout = <382>;
+			summit,pre-charge-timeout = <48>;
+			summit,therm-current-ua = <10>;
+			summit,temperature-min = <4>; /*  0 C */
+			summit,temperature-max = <3>; /* 45 C */
+		};
+	};
 };
 
 /* PM8019 GPIO and MPP configuration */
@@ -38,7 +57,7 @@
 		qcom,invert = <0>; /* Output low */
 		qcom,out-strength = <1>; /* Low */
 		qcom,vin-sel = <2>; /* PM8019 L11 - 1.8V */
-		qcom,src-select = <0>; /* Constant */
+		qcom,src-sel = <0>; /* Constant */
 		qcom,master-en = <1>; /* Enable GPIO */
 	};
 
diff --git a/arch/arm/boot/dts/msm9625-coresight.dtsi b/arch/arm/boot/dts/msm9625-coresight.dtsi
new file mode 100644
index 0000000..f01fe63
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-coresight.dtsi
@@ -0,0 +1,118 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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>;
+
+		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>;
+
+		coresight-id = <1>;
+		coresight-name = "coresight-tpiu";
+		coresight-nr-inports = <1>;
+	};
+
+	replicator: replicator@fc31c000 {
+		compatible = "qcom,coresight-replicator";
+		reg = <0xfc31c000 0x1000>;
+
+		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>;
+
+		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>;
+
+		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>;
+
+		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>;
+
+		coresight-id = <6>;
+		coresight-name = "coresight-funnel-in1";
+		coresight-nr-inports = <8>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_merg>;
+		coresight-child-ports = <1>;
+	};
+
+	stm: stm@fc321000 {
+		compatible = "arm,coresight-stm";
+		reg = <0xfc321000 0x1000>,
+		      <0xfa280000 0x180000>;
+
+		coresight-id = <7>;
+		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>;
+
+		coresight-id = <8>;
+		coresight-name = "coresight-csr";
+		coresight-nr-inports = <0>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm9625-mtp.dts b/arch/arm/boot/dts/msm9625-mtp.dts
index a5673e5..7780686 100644
--- a/arch/arm/boot/dts/msm9625-mtp.dts
+++ b/arch/arm/boot/dts/msm9625-mtp.dts
@@ -18,6 +18,25 @@
 	model = "Qualcomm MSM 9625 MTP";
 	compatible = "qcom,msm9625-mtp", "qcom,msm9625";
 	qcom,msm-id = <134 7 0>, <152 7 0>;
+
+	i2c@f9925000 {
+		charger@57 {
+			compatible = "summit,smb137c";
+			reg = <0x57>;
+			summit,chg-current-ma = <1500>;
+			summit,term-current-ma = <50>;
+			summit,pre-chg-current-ma = <100>;
+			summit,float-voltage-mv = <4200>;
+			summit,thresh-voltage-mv = <3000>;
+			summit,recharge-thresh-mv = <75>;
+			summit,system-voltage-mv = <4250>;
+			summit,charging-timeout = <382>;
+			summit,pre-charge-timeout = <48>;
+			summit,therm-current-ua = <10>;
+			summit,temperature-min = <4>; /*  0 C */
+			summit,temperature-max = <3>; /* 45 C */
+		};
+	};
 };
 
 /* PM8019 GPIO and MPP configuration */
@@ -38,7 +57,7 @@
 		qcom,invert = <0>; /* Output low */
 		qcom,out-strength = <1>; /* Low */
 		qcom,vin-sel = <2>; /* PM8019 L11 - 1.8V */
-		qcom,src-select = <0>; /* Constant */
+		qcom,src-sel = <0>; /* Constant */
 		qcom,master-en = <1>; /* Enable GPIO */
 	};
 
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
new file mode 100644
index 0000000..d62f7e7
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -0,0 +1,214 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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@f9009000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf9009000 0x1000>;
+		qcom,core-id = <0>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x101>;
+		qcom,saw2-spm-dly= <0>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-cmd-wfi = [04 03 04 0f];
+		qcom,saw2-spm-cmd-spc = [34 04 44 14 24 54 03 54 44 14 04 24
+		3e 0f];
+		qcom,saw2-spm-cmd-pc = [34 04 44 14 24 54 07 54 44 14 04 24
+		3e 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 = <0x616F646C>;       /* "ldoa" */
+			qcom,id = <0x0A>;
+			qcom,key = <0x6e726f63>;	/* "corn" */
+		};
+
+		qcom,lpm-resources@1 {
+			reg = <0x1>;
+			qcom,name = "vdd-mem";
+			qcom,resource-type = <0>;
+			qcom,type = <0x616F646C>;       /* "ldoa" */
+			qcom,id = <0x0C>;
+			qcom,key =  <0x7675>;		/* "uv" */
+		};
+
+		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,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 = <3>;          /* ACTIVE */
+			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 = <100>;
+			qcom,ss-power = <8000>;
+			qcom,energy-overhead = <100000>;
+			qcom,time-overhead = <1>;
+		};
+
+		qcom,lpm-level@1 {
+			reg = <0x1>;
+			qcom,mode = <2>;        /* MSM_PM_SLEEP_MODE_STANDALONE_POWER_COLLAPSE */
+			qcom,xo = <1>;          /* ON */
+			qcom,l2 = <3>;          /* ACTIVE */
+			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 = <2000>;
+			qcom,ss-power = <5000>;
+			qcom,energy-overhead = <60100000>;
+			qcom,time-overhead = <3000>;
+		};
+
+		qcom,lpm-level@2 {
+			reg = <0x2>;
+			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,latency-us = <3500>;
+			qcom,ss-power = <5000>;
+			qcom,energy-overhead = <60350000>;
+			qcom,time-overhead = <6300>;
+		};
+
+		qcom,lpm-level@3 {
+			reg = <0x3>;
+			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>; /* NORMAL */
+			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+			qcom,vdd-dig-lower-bound = <4>;  /* NORMAL */
+			qcom,latency-us = <6800>;
+			qcom,ss-power = <2000>;
+			qcom,energy-overhead = <71850000>;
+			qcom,time-overhead = <13300>;
+		};
+
+		qcom,lpm-level@4 {
+			reg = <0x4>;
+			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 = <9800>;
+			qcom,ss-power = <0>;
+			qcom,energy-overhead = <76350000>;
+			qcom,time-overhead = <28300>;
+		};
+	};
+
+	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 = <41 172>, /* usb2_hsic_async_wakeup_irq */
+			<0xff 208>; /* summary_irq_kpss */
+
+		qcom,gpio-parent = <&msmgpio>;
+		qcom,gpio-map = <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>;
+	};
+
+	qcom,pm-8x60 {
+		compatible = "qcom,pm-8x60";
+		qcom,pc-mode = <2>; /*MSM_PC_TZ_L2_EXT */
+		qcom,use-sync-timer;
+	};
+
+	qcom,rpm-stats@fc19dbd0 {
+		compatible = "qcom,rpm-stats";
+		reg = <0xfc19dbd0 0x1000>;
+		reg-names = "phys_addr_base";
+		qcom,sleep-stats-version = <2>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm9625-regulator.dtsi b/arch/arm/boot/dts/msm9625-regulator.dtsi
index dccc723..b128648 100644
--- a/arch/arm/boot/dts/msm9625-regulator.dtsi
+++ b/arch/arm/boot/dts/msm9625-regulator.dtsi
@@ -215,7 +215,7 @@
 		status = "okay";
 		pm8019_l12: regulator-l12 {
 			parent-supply = <&pm8019_s3>;
-			regulator-min-microvolt = <750000>;
+			regulator-min-microvolt = <675000>;
 			regulator-max-microvolt = <1050000>;
 			status = "okay";
 		};
@@ -224,10 +224,20 @@
 			regulator-name = "8019_l12_ao";
 			qcom,set = <1>;
 			parent-supply = <&pm8019_s3_ao>;
-			regulator-min-microvolt = <750000>;
+			regulator-min-microvolt = <675000>;
 			regulator-max-microvolt = <1050000>;
 			status = "okay";
 		};
+		pm8019_l12_so: regulator-l12-so {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8019_l12_so";
+			qcom,set = <2>;
+			parent-supply = <&pm8019_s3>;
+			regulator-min-microvolt = <675000>;
+			regulator-max-microvolt = <1050000>;
+			qcom,init-voltage = <675000>;
+			status = "okay";
+		};
 	};
 
 	rpm-regulator-ldoa13 {
@@ -258,4 +268,9 @@
 		gpio = <&pm8019_gpios 4 0>;
 		enable-active-high;
 	};
+
+	usb_vbus: regulator-usb-vbus {
+		compatible = "regulator-fixed";
+		regulator-name = "usb_vbus";
+	};
 };
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 2f2518d..26f8ab7 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -12,6 +12,8 @@
 
 /include/ "skeleton.dtsi"
 /include/ "msm9625-ion.dtsi"
+/include/ "msm9625-pm.dtsi"
+/include/ "msm9625-coresight.dtsi"
 
 / {
 	model = "Qualcomm MSM 9625";
@@ -73,6 +75,7 @@
 		HSUSB_VDDCX-supply = <&pm8019_l12>;
 		HSUSB_1p8-supply = <&pm8019_l2>;
 		HSUSB_3p3-supply = <&pm8019_l4>;
+		vbus_otg-supply = <&usb_vbus>;
 
 		qcom,hsusb-otg-phy-type = <2>;
 		qcom,hsusb-otg-mode = <1>;
@@ -140,7 +143,6 @@
 		/* 190,ee0_krait_hlos_spmi_periph_irq */
 		/* 187,channel_0_krait_hlos_trans_done_irq */
 		interrupts = <0 190 0 0 187 0>;
-		qcom,not-wakeup;
 		qcom,pmic-arb-ee = <0>;
 		qcom,pmic-arb-channel = <0>;
 		qcom,pmic-arb-ppid-map = <0x02400000>, /* TEMP_ALARM */
@@ -183,22 +185,22 @@
 		vdd-supply = <&ext_2p95v>;
 
 		vdd-io-supply = <&pm8019_l13>;
-		qcom,sdcc-vdd-io-always_on;
-		qcom,sdcc-vdd-io-lpm_sup;
-		qcom,sdcc-vdd-io-voltage_level = <1800000 2950000>;
-		qcom,sdcc-vdd-io-current_level = <6 22000>;
+		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,sdcc-pad-pull-on = <0x0 0x3 0x3>;
-		qcom,sdcc-pad-pull-off = <0x0 0x3 0x3>;
-		qcom,sdcc-pad-drv-on = <0x7 0x4 0x4>;
-		qcom,sdcc-pad-drv-off = <0x0 0x0 0x0>;
+		qcom,pad-pull-on = <0x0 0x3 0x3>;
+		qcom,pad-pull-off = <0x0 0x3 0x3>;
+		qcom,pad-drv-on = <0x7 0x4 0x4>;
+		qcom,pad-drv-off = <0x0 0x0 0x0>;
 
-		qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000 200000000>;
-		qcom,sdcc-sup-voltages = <2950 2950>;
-		qcom,sdcc-bus-width = <4>;
-		qcom,sdcc-xpc;
-		qcom,sdcc-bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
-		qcom,sdcc-current-limit = <800>;
+		qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+		qcom,sup-voltages = <2950 2950>;
+		qcom,bus-width = <4>;
+		qcom,xpc;
+		qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+		qcom,current-limit = <800>;
 
 		interrupt-parent = <&sdcc2>;
 		#address-cells = <0>;
@@ -228,12 +230,12 @@
 			<&msmgpio 17 0>,
 			<&msmgpio 18 0>,
 			<&msmgpio 19 0>;
-		qcom,sdcc-gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
+		qcom,gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
 
-		qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000>;
-		qcom,sdcc-sup-voltages = <2950 2950>;
-		qcom,sdcc-bus-width = <4>;
-		qcom,sdcc-bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50";
+		qcom,clk-rates = <400000 25000000 50000000 100000000>;
+		qcom,sup-voltages = <2950 2950>;
+		qcom,bus-width = <4>;
+		qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50";
 	};
 
 	qcom,bam_dmux@fc834000 {
@@ -250,6 +252,22 @@
 		a5_cpu-supply = <&pm8019_l10_corner_ao>;
 		a5_mem-supply = <&pm8019_l12_ao>;
 	};
+
+	gdsc_usb_hsic: qcom,gdsc@fc400404 {
+		compatible = "qcom,gdsc";
+		reg = <0xfc400404 0x4>;
+		regulator-name = "gdsc_usb_hsic";
+	};
+
+	tsens@fc4a8000 {
+		compatible = "qcom,msm-tsens";
+		reg = <0xfc4a8000 0x2000>,
+		      <0xfc4b8000 0x1000>;
+		reg-names = "tsens_physical", "tsens_eeprom_physical";
+		interrupts = <0 184 0>;
+		qcom,sensors = <5>;
+		qcom,slope = <3200 3200 3200 3200 3200>;
+	};
 };
 
 /include/ "msm-pm8019-rpm-regulator.dtsi"
@@ -311,4 +329,10 @@
 		qcom,hw-settle-time = <0>;
 		qcom,fast-avg-setup = <0>;
 	};
+
+	qcom,msm-rng@f9bff000 {
+		compatible = "qcom,msm-rng";
+		reg = <0xf9bff000 0x200>;
+		qcom,msm-rng-iface-clk;
+	};
 };
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index 76650e0..8e948c2 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -42,6 +42,7 @@
 # CONFIG_MSM_SMD_NMEA is not set
 # CONFIG_MSM_SMD_QMI is not set
 CONFIG_MSM_ONCRPCROUTER=y
+CONFIG_MSM_IPC_ROUTER=y
 # CONFIG_MSM_RPCSERVER_TIME_REMOTE is not set
 CONFIG_MSM_RMT_STORAGE_CLIENT=y
 # CONFIG_MSM_HW3D is not set
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index 8ab57de..d403cec 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -42,6 +42,7 @@
 # CONFIG_MSM_SMD_NMEA is not set
 # CONFIG_MSM_SMD_QMI is not set
 CONFIG_MSM_ONCRPCROUTER=y
+CONFIG_MSM_IPC_ROUTER=y
 # CONFIG_MSM_RPCSERVER_TIME_REMOTE is not set
 CONFIG_MSM_RMT_STORAGE_CLIENT=y
 # CONFIG_MSM_HW3D is not set
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index 2ee3f3b..828484a 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -295,7 +295,6 @@
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_SX150X=y
 CONFIG_POWER_SUPPLY=y
-# CONFIG_BATTERY_MSM is not set
 CONFIG_BATTERY_MSM8X60=y
 CONFIG_PM8058_CHARGER=y
 CONFIG_ISL9519_CHARGER=y
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index 25c5207..28d7b12 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -295,7 +295,6 @@
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_SX150X=y
 CONFIG_POWER_SUPPLY=y
-# CONFIG_BATTERY_MSM is not set
 CONFIG_BATTERY_MSM8X60=y
 CONFIG_PM8058_CHARGER=y
 CONFIG_ISL9519_CHARGER=y
diff --git a/arch/arm/configs/msm8910_defconfig b/arch/arm/configs/msm8910_defconfig
index e4dd4fb..5876a0f 100644
--- a/arch/arm/configs/msm8910_defconfig
+++ b/arch/arm/configs/msm8910_defconfig
@@ -10,8 +10,6 @@
 CONFIG_CGROUP_CPUACCT=y
 CONFIG_RESOURCE_COUNTERS=y
 CONFIG_CGROUP_SCHED=y
-CONFIG_VFP=y
-# CONFIG_FAIR_GROUP_SCHED is not set
 CONFIG_RT_GROUP_SCHED=y
 CONFIG_NAMESPACES=y
 # CONFIG_UTS_NS is not set
@@ -22,24 +20,31 @@
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_RD_BZIP2=y
 CONFIG_RD_LZMA=y
+CONFIG_PANIC_TIMEOUT=5
 CONFIG_KALLSYMS_ALL=y
+CONFIG_ASHMEM=y
 CONFIG_EMBEDDED=y
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=m
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
 CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
 CONFIG_ARCH_MSM=y
 CONFIG_ARCH_MSM8910=y
+CONFIG_ARCH_MSM8226=y
 # CONFIG_MSM_STACKED_MEMORY is not set
 CONFIG_CPU_HAS_L2_PMU=y
 # CONFIG_MSM_FIQ_SUPPORT is not set
 # CONFIG_MSM_PROC_COMM is not set
 CONFIG_MSM_SMD=y
+# CONFIG_MSM_HW3D is not set
 CONFIG_MSM_DIRECT_SCLK_ACCESS=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
+# CONFIG_SMP_ON_UP is not set
 CONFIG_ARM_ARCH_TIMER=y
 CONFIG_HOTPLUG_CPU=y
 CONFIG_PREEMPT=y
@@ -47,21 +52,47 @@
 CONFIG_HIGHMEM=y
 CONFIG_VMALLOC_RESERVE=0x19000000
 CONFIG_USE_OF=y
+CONFIG_VFP=y
+CONFIG_NEON=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 # CONFIG_SUSPEND is not set
 CONFIG_NET=y
+CONFIG_PACKET=y
 CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
 CONFIG_NETFILTER=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
-# CONFIG_ANDROID_PMEM is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_INPUT_GPIO=m
-CONFIG_SERIO_LIBPS2=y
 CONFIG_SERIAL_MSM_HSL=y
 CONFIG_SERIAL_MSM_HSL_CONSOLE=y
 CONFIG_DIAG_CHAR=y
@@ -69,6 +100,12 @@
 CONFIG_DEBUG_GPIO=y
 CONFIG_GPIO_SYSFS=y
 # CONFIG_HWMON is not set
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_FB=y
+CONFIG_FB_VIRTUAL=y
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_SOC=y
@@ -86,10 +123,21 @@
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_TEST=m
 CONFIG_MMC_MSM=y
-CONFIG_MMC_MSM_SPS_SUPPORT=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
-# CONFIG_MISC_FILESYSTEMS is not set
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ASCII=y
 CONFIG_NLS_ISO8859_1=y
@@ -104,19 +152,11 @@
 CONFIG_DYNAMIC_DEBUG=y
 CONFIG_DEBUG_USER=y
 CONFIG_KEYS=y
-CONFIG_CRYPTO_AUTHENC=y
-CONFIG_CRYPTO_CBC=y
-CONFIG_CRYPTO_HMAC=y
 CONFIG_CRYPTO_MD4=y
-CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_SHA1=y
 CONFIG_CRYPTO_SHA256=y
 CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_ARC4=y
-CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_TWOFISH=y
-CONFIG_CRYPTO_DEFLATE=y
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC_CCITT=y
-CONFIG_CRC16=y
 CONFIG_LIBCRC32C=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index ec00b68..33c7718 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -315,7 +315,6 @@
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_SX150X=y
 CONFIG_POWER_SUPPLY=y
-# CONFIG_BATTERY_MSM is not set
 CONFIG_ISL9519_CHARGER=y
 CONFIG_SMB349_CHARGER=y
 CONFIG_PM8921_CHARGER=y
@@ -356,6 +355,7 @@
 CONFIG_MSM_CAMERA_FLASH_SC628A=y
 CONFIG_MSM_CAMERA_FLASH_TPS61310=y
 CONFIG_OV2720=y
+CONFIG_IMX135=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_ACTUATOR=y
 CONFIG_MSM_EEPROM=y
@@ -367,14 +367,12 @@
 CONFIG_S5K3L1YX=y
 CONFIG_IMX091=y
 CONFIG_MSM_WFD=y
-CONFIG_IMX135=y
 CONFIG_RADIO_IRIS=y
 CONFIG_RADIO_IRIS_TRANSPORT=m
 # CONFIG_DVB_FE_CUSTOMISE is not set
 CONFIG_DVB_MPQ=m
 CONFIG_DVB_MPQ_DEMUX=m
 CONFIG_DVB_MPQ_VIDEO=m
-CONFIG_DVB_MPQ_TSPP1=y
 CONFIG_ION=y
 CONFIG_ION_MSM=y
 CONFIG_MSM_KGSL=y
@@ -466,6 +464,7 @@
 CONFIG_ANDROID_RAM_CONSOLE=y
 CONFIG_ANDROID_TIMED_GPIO=y
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES=y
 CONFIG_MSM_SSBI=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_BAMDMA=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 33f7987..8c11368 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -320,7 +320,6 @@
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_SX150X=y
 CONFIG_POWER_SUPPLY=y
-# CONFIG_BATTERY_MSM is not set
 CONFIG_ISL9519_CHARGER=y
 CONFIG_SMB349_CHARGER=y
 CONFIG_PM8921_CHARGER=y
@@ -360,6 +359,7 @@
 CONFIG_IMX074_ACT=y
 CONFIG_MSM_CAMERA_FLASH_SC628A=y
 CONFIG_OV2720=y
+CONFIG_IMX135=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_ACTUATOR=y
 CONFIG_MSM_EEPROM=y
@@ -371,14 +371,12 @@
 CONFIG_S5K3L1YX=y
 CONFIG_IMX091=y
 CONFIG_MSM_WFD=y
-CONFIG_IMX135=y
 CONFIG_RADIO_IRIS=y
 CONFIG_RADIO_IRIS_TRANSPORT=m
 # CONFIG_DVB_FE_CUSTOMISE is not set
 CONFIG_DVB_MPQ=m
 CONFIG_DVB_MPQ_DEMUX=m
 CONFIG_DVB_MPQ_VIDEO=m
-CONFIG_DVB_MPQ_TSPP1=y
 CONFIG_ION=y
 CONFIG_ION_MSM=y
 CONFIG_MSM_KGSL=y
@@ -469,6 +467,7 @@
 CONFIG_ANDROID_RAM_CONSOLE=y
 CONFIG_ANDROID_TIMED_GPIO=y
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES=y
 CONFIG_MSM_SSBI=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_BAMDMA=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index b2ee503..5e1fa4a 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -48,11 +48,12 @@
 CONFIG_MSM_BAM_DMUX=y
 CONFIG_MSM_IPC_ROUTER=y
 CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_QMI_INTERFACE=y
 # CONFIG_MSM_HW3D is not set
 CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_SYSMON_COMM=y
 CONFIG_MSM_PIL_LPASS_QDSP6V5=y
 CONFIG_MSM_PIL_MSS_QDSP6V5=y
-CONFIG_MSM_PIL_MBA=y
 CONFIG_MSM_PIL_VENUS=y
 CONFIG_MSM_PIL_PRONTO=y
 CONFIG_MSM_TZ_LOG=y
@@ -74,7 +75,6 @@
 CONFIG_STRICT_MEMORY_RWX=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
-CONFIG_SMP=y
 # CONFIG_SMP_ON_UP is not set
 CONFIG_ARM_ARCH_TIMER=y
 CONFIG_PREEMPT=y
@@ -239,6 +239,7 @@
 CONFIG_SLIP=y
 CONFIG_SLIP_COMPRESSED=y
 CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_USB_USBNET=y
 CONFIG_WCNSS_CORE=y
 CONFIG_WCNSS_CORE_PRONTO=y
 CONFIG_INPUT_EVDEV=y
@@ -269,11 +270,16 @@
 CONFIG_GPIO_QPNP_PIN=y
 CONFIG_GPIO_QPNP_PIN_DEBUG=y
 CONFIG_POWER_SUPPLY=y
-# CONFIG_BATTERY_MSM is not set
+CONFIG_BATTERY_BQ28400=y
+CONFIG_QPNP_CHARGER=y
+CONFIG_BATTERY_BCL=y
+CONFIG_QPNP_BMS=y
+CONFIG_SENSORS_EPM_ADC=y
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_SENSORS_QPNP_ADC_CURRENT=y
 CONFIG_THERMAL=y
 CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_QPNP=y
 CONFIG_WCD9320_CODEC=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_STUB=y
@@ -283,6 +289,7 @@
 CONFIG_VIDEO_DEV=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_USB_VIDEO_CLASS=y
 CONFIG_V4L_PLATFORM_DRIVERS=y
 CONFIG_MSM_CAMERA_V4L2=y
 CONFIG_MT9M114=y
@@ -297,6 +304,7 @@
 CONFIG_MSM_CSI2_REGISTER=y
 CONFIG_MSM_ISPIF=y
 CONFIG_S5K3L1YX=y
+CONFIG_MSM_WFD=y
 CONFIG_RADIO_IRIS=y
 CONFIG_RADIO_IRIS_TRANSPORT=m
 CONFIG_ION=y
@@ -314,10 +322,12 @@
 # CONFIG_BACKLIGHT_GENERIC is not set
 CONFIG_SOUND=y
 CONFIG_SND=y
+CONFIG_SND_USB_AUDIO=y
 CONFIG_SND_SOC=y
 CONFIG_SND_SOC_MSM8974=y
 CONFIG_USB=y
 CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_ACM=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_STORAGE_DATAFAB=y
 CONFIG_USB_STORAGE_FREECOM=y
@@ -333,7 +343,7 @@
 CONFIG_USB_STORAGE_ENE_UB6250=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_DEBUG_FILES=y
-CONFIG_USB_CI13XXX_MSM=y
+CONFIG_USB_DWC3_MSM=y
 CONFIG_USB_G_ANDROID=y
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
@@ -365,6 +375,7 @@
 CONFIG_USB_BAM=y
 CONFIG_SPS_SUPPORT_BAMDMA=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_PWM=y
 CONFIG_QPNP_POWER_ON=y
 CONFIG_QPNP_CLKDIV=y
 CONFIG_MSM_IOMMU=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index c49ad93..4d68a72 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -36,7 +36,6 @@
 CONFIG_EFI_PARTITION=y
 CONFIG_ARCH_MSM=y
 CONFIG_ARCH_MSM8974=y
-CONFIG_ARCH_MSM8226=y
 CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
 # CONFIG_MSM_STACKED_MEMORY is not set
 CONFIG_CPU_HAS_L2_PMU=y
@@ -47,12 +46,12 @@
 CONFIG_MSM_BAM_DMUX=y
 CONFIG_MSM_IPC_ROUTER=y
 CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_QMI_INTERFACE=y
 # CONFIG_MSM_HW3D is not set
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_SYSMON_COMM=y
 CONFIG_MSM_PIL_LPASS_QDSP6V5=y
 CONFIG_MSM_PIL_MSS_QDSP6V5=y
-CONFIG_MSM_PIL_MBA=y
 CONFIG_MSM_PIL_VENUS=y
 CONFIG_MSM_PIL_PRONTO=y
 CONFIG_MSM_TZ_LOG=y
@@ -242,6 +241,7 @@
 CONFIG_SLIP=y
 CONFIG_SLIP_COMPRESSED=y
 CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_USB_USBNET=y
 CONFIG_WCNSS_CORE=y
 CONFIG_WCNSS_CORE_PRONTO=y
 CONFIG_INPUT_EVDEV=y
@@ -272,10 +272,12 @@
 CONFIG_GPIO_QPNP_PIN=y
 CONFIG_GPIO_QPNP_PIN_DEBUG=y
 CONFIG_POWER_SUPPLY=y
-# CONFIG_BATTERY_MSM is not set
-CONFIG_QPNP_CHARGER=y
-CONFIG_QPNP_BMS=y
+CONFIG_SMB350_CHARGER=y
 CONFIG_BATTERY_BQ28400=y
+CONFIG_QPNP_CHARGER=y
+CONFIG_BATTERY_BCL=y
+CONFIG_QPNP_BMS=y
+CONFIG_SENSORS_EPM_ADC=y
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_SENSORS_QPNP_ADC_CURRENT=y
 CONFIG_THERMAL=y
@@ -285,12 +287,12 @@
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_STUB=y
 CONFIG_REGULATOR_QPNP=y
-CONFIG_QPNP_PWM=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_USB_VIDEO_CLASS=y
 CONFIG_V4L_PLATFORM_DRIVERS=y
 CONFIG_MSM_CAMERA_V4L2=y
 CONFIG_MT9M114=y
@@ -323,10 +325,12 @@
 # CONFIG_BACKLIGHT_GENERIC is not set
 CONFIG_SOUND=y
 CONFIG_SND=y
+CONFIG_SND_USB_AUDIO=y
 CONFIG_SND_SOC=y
 CONFIG_SND_SOC_MSM8974=y
 CONFIG_USB=y
 CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_ACM=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_STORAGE_DATAFAB=y
 CONFIG_USB_STORAGE_FREECOM=y
@@ -342,7 +346,7 @@
 CONFIG_USB_STORAGE_ENE_UB6250=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_DEBUG_FILES=y
-CONFIG_USB_CI13XXX_MSM=y
+CONFIG_USB_DWC3_MSM=y
 CONFIG_USB_G_ANDROID=y
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
@@ -374,6 +378,7 @@
 CONFIG_USB_BAM=y
 CONFIG_SPS_SUPPORT_BAMDMA=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_PWM=y
 CONFIG_QPNP_POWER_ON=y
 CONFIG_QPNP_CLKDIV=y
 CONFIG_MSM_IOMMU=y
@@ -400,6 +405,7 @@
 CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
 # CONFIG_DEBUG_PREEMPT is not set
 CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
 CONFIG_DEBUG_ATOMIC_SLEEP=y
 CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index 81b853d..a052609 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -199,7 +199,6 @@
 CONFIG_DEBUG_GPIO=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_POWER_SUPPLY=y
-# CONFIG_BATTERY_MSM is not set
 CONFIG_SENSORS_PM8XXX_ADC=y
 CONFIG_THERMAL=y
 CONFIG_THERMAL_TSENS8960=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index e1d4ca0..2b73a3e 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -21,6 +21,7 @@
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_RD_BZIP2=y
 CONFIG_RD_LZMA=y
+CONFIG_PANIC_TIMEOUT=5
 CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
 CONFIG_PROFILING=y
@@ -43,6 +44,7 @@
 CONFIG_MSM_RPM_REGULATOR_SMD=y
 CONFIG_MSM_DIRECT_SCLK_ACCESS=y
 CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_DLOAD_MODE=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_ARM_ARCH_TIMER=y
@@ -51,12 +53,12 @@
 CONFIG_HIGHMEM=y
 CONFIG_VMALLOC_RESERVE=0x19000000
 CONFIG_USE_OF=y
-CONFIG_CPU_IDLE=y
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
 CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
 CONFIG_VFP=y
 CONFIG_NEON=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
@@ -66,11 +68,23 @@
 CONFIG_UNIX=y
 CONFIG_INET=y
 CONFIG_IPV6=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_DEBUG=y
+CONFIG_NETFILTER_NETLINK_QUEUE=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CONNTRACK_TIMESTAMP=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
 CONFIG_NET_SCHED=y
 CONFIG_NET_SCH_HTB=y
 CONFIG_NET_SCH_PRIO=y
 CONFIG_NET_CLS_FW=y
-# CONFIG_WIRELESS is not set
+CONFIG_CFG80211=m
+CONFIG_NL80211_TESTMODE=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_OF_PARTS=y
@@ -85,13 +99,6 @@
 # CONFIG_NET_VENDOR_CIRRUS is not set
 # CONFIG_NET_VENDOR_FARADAY is not set
 # CONFIG_NET_VENDOR_INTEL is not set
-CONFIG_WIRELESS=y
-CONFIG_CFG80211=m
-CONFIG_NL80211_TESTMODE=y
-CONFIG_ATH_COMMON=m
-CONFIG_ATH6KL=m
-CONFIG_ATH6KL_SDIO=m
-CONFIG_ATH6KL_DEBUG=y
 CONFIG_KS8851=y
 # CONFIG_NET_VENDOR_MICROCHIP is not set
 # CONFIG_MSM_RMNET is not set
@@ -104,6 +111,7 @@
 # CONFIG_INPUT_MOUSEDEV is not set
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_INPUT_GPIO=m
@@ -122,15 +130,17 @@
 CONFIG_SPMI=y
 CONFIG_SPMI_MSM_PMIC_ARB=y
 CONFIG_MSM_QPNP_INT=y
-CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_DEBUG_GPIO=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_QPNP_PIN=y
 CONFIG_GPIO_QPNP_PIN_DEBUG=y
 CONFIG_POWER_SUPPLY=y
-CONFIG_HWMON=y
+CONFIG_SMB137C_CHARGER=y
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_TSENS8974=y
 CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_QPNP=y
 CONFIG_ION=y
 CONFIG_ION_MSM=y
@@ -191,5 +201,5 @@
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC_CCITT=y
 CONFIG_LIBCRC32C=y
-CONFIG_PANIC_TIMEOUT=5
-CONFIG_MSM_DLOAD_MODE=y
+CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_MSM_QDSS=y
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index 5f28327..abb222f 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -261,6 +261,58 @@
 	return dma_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, &attrs);
 }
 
+static inline void *dma_alloc_stronglyordered(struct device *dev, size_t size,
+				       dma_addr_t *dma_handle, gfp_t flag)
+{
+	DEFINE_DMA_ATTRS(attrs);
+	dma_set_attr(DMA_ATTR_STRONGLY_ORDERED, &attrs);
+	return dma_alloc_attrs(dev, size, dma_handle, flag, &attrs);
+}
+
+static inline void dma_free_stronglyordered(struct device *dev, size_t size,
+				     void *cpu_addr, dma_addr_t dma_handle)
+{
+	DEFINE_DMA_ATTRS(attrs);
+	dma_set_attr(DMA_ATTR_STRONGLY_ORDERED, &attrs);
+	return dma_free_attrs(dev, size, cpu_addr, dma_handle, &attrs);
+}
+
+static inline int dma_mmap_stronglyordered(struct device *dev,
+		struct vm_area_struct *vma, void *cpu_addr,
+		dma_addr_t dma_addr, size_t size)
+{
+	DEFINE_DMA_ATTRS(attrs);
+	dma_set_attr(DMA_ATTR_STRONGLY_ORDERED, &attrs);
+	return dma_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, &attrs);
+}
+
+static inline void *dma_alloc_nonconsistent(struct device *dev, size_t size,
+				       dma_addr_t *dma_handle, gfp_t flag)
+{
+	DEFINE_DMA_ATTRS(attrs);
+	dma_set_attr(DMA_ATTR_NON_CONSISTENT, &attrs);
+	return dma_alloc_attrs(dev, size, dma_handle, flag, &attrs);
+}
+
+static inline void dma_free_nonconsistent(struct device *dev, size_t size,
+				     void *cpu_addr, dma_addr_t dma_handle)
+{
+	DEFINE_DMA_ATTRS(attrs);
+	dma_set_attr(DMA_ATTR_NON_CONSISTENT, &attrs);
+	return dma_free_attrs(dev, size, cpu_addr, dma_handle, &attrs);
+}
+
+static inline int dma_mmap_nonconsistent(struct device *dev,
+		struct vm_area_struct *vma, void *cpu_addr,
+		dma_addr_t dma_addr, size_t size)
+{
+	DEFINE_DMA_ATTRS(attrs);
+	dma_set_attr(DMA_ATTR_NON_CONSISTENT, &attrs);
+	return dma_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, &attrs);
+}
+
+
+
 /*
  * This can be called during boot to increase the size of the consistent
  * DMA region above it's default value of 2MB. It must be called before the
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 42fef7c..938be62 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -268,12 +268,17 @@
 					__raw_readw(c)); __r; })
 #define readl_relaxed(c) ({ u32 __r = le32_to_cpu((__force __le32) \
 					__raw_readl(c)); __r; })
+#define readl_relaxed_no_log(c) ({ u32 __r = le32_to_cpu((__force __le32) \
+					__raw_readl_no_log(c)); __r; })
+
 
 #define writeb_relaxed(v,c)	((void)__raw_writeb(v,c))
 #define writew_relaxed(v,c)	((void)__raw_writew((__force u16) \
 					cpu_to_le16(v),c))
 #define writel_relaxed(v,c)	((void)__raw_writel((__force u32) \
 					cpu_to_le32(v),c))
+#define writel_relaxed_no_log(v, c)  ((void)__raw_writel_no_log((__force u32) \
+					cpu_to_le32(v), c))
 
 #define readb(c)		({ u8  __v = readb_relaxed(c); __iormb(); __v; })
 #define readw(c)		({ u16 __v = readw_relaxed(c); __iormb(); __v; })
diff --git a/arch/arm/include/asm/mach/mmc.h b/arch/arm/include/asm/mach/mmc.h
index d341ea9..e7de62e 100644
--- a/arch/arm/include/asm/mach/mmc.h
+++ b/arch/arm/include/asm/mach/mmc.h
@@ -149,7 +149,7 @@
 	int status_gpio;
 	/* Indicates the polarity of the GPIO line when card is inserted */
 	bool is_status_gpio_active_low;
-        unsigned int sdiowakeup_irq;
+	int sdiowakeup_irq;
         unsigned long irq_flags;
         unsigned long mmc_bus_width;
         int (*wpswitch) (struct device *);
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index 88d0872..5188dbf 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -32,6 +32,10 @@
  *	interrupt and passed the address of the low level handler,
  *	and can be used to implement any platform specific handling
  *	before or after calling it.
+ * @request_pmu_irq: an optional handler in case the platform wants
+ *	to use a percpu IRQ API call. e.g. request_percpu_irq
+ * @free_pmu_irq: an optional handler in case the platform wants
+ *	to use a percpu IRQ API call. e.g. free_percpu_irq
  * @enable_irq: an optional handler which will be called after
  *	request_irq and be used to handle some platform specific
  *	irq enablement
@@ -42,6 +46,8 @@
 struct arm_pmu_platdata {
 	irqreturn_t (*handle_irq)(int irq, void *dev,
 				  irq_handler_t pmu_handler);
+	int	(*request_pmu_irq)(int irq, irq_handler_t *irq_h);
+	void	(*free_pmu_irq)(int irq);
 	void (*enable_irq)(int irq);
 	void (*disable_irq)(int irq);
 };
@@ -114,8 +120,8 @@
 	u64		max_period;
 	struct platform_device	*plat_device;
 	irqreturn_t	(*handle_irq)(int irq_num, void *dev);
-	int     	(*request_pmu_irq)(int irq, irq_handler_t *irq_h);
-	void    	(*free_pmu_irq)(int irq);
+	int		(*request_pmu_irq)(int irq, irq_handler_t *irq_h);
+	void		(*free_pmu_irq)(int irq);
 	void		(*enable)(struct hw_perf_event *evt, int idx, int cpu);
 	void		(*disable)(struct hw_perf_event *evt, int idx);
 	int		(*get_event_idx)(struct pmu_hw_events *hw_events,
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 3f6a6d3..2464140 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -437,6 +437,16 @@
 	else
 		handle_irq = armpmu->handle_irq;
 
+	if (plat && plat->request_pmu_irq)
+		armpmu->request_pmu_irq = plat->request_pmu_irq;
+	else
+		armpmu->request_pmu_irq = armpmu_generic_request_irq;
+
+	if (plat && plat->free_pmu_irq)
+		armpmu->free_pmu_irq = plat->free_pmu_irq;
+	else
+		armpmu->free_pmu_irq = armpmu_generic_free_irq;
+
 	irqs = min(pmu_device->num_resources, num_possible_cpus());
 	if (irqs < 1) {
 		pr_err("no irqs for PMUs defined\n");
diff --git a/arch/arm/kernel/perf_event_msm.c b/arch/arm/kernel/perf_event_msm.c
index 8f58adf..92dc7c7 100644
--- a/arch/arm/kernel/perf_event_msm.c
+++ b/arch/arm/kernel/perf_event_msm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -729,9 +729,6 @@
 	scorpion_pmu.name	= "ARMv7 Scorpion";
 	scorpion_pmu.num_events	= armv7_read_num_pmnc_events();
 	scorpion_pmu.pmu.attr_groups	= msm_l1_pmu_attr_grps;
-	/* Unicore can't use the percpu IRQ API. */
-	scorpion_pmu.request_pmu_irq	= armpmu_generic_request_irq;
-	scorpion_pmu.free_pmu_irq	= armpmu_generic_free_irq;
 	scorpion_clear_pmuregs();
 	return &scorpion_pmu;
 }
@@ -742,8 +739,6 @@
 	scorpion_pmu.name	= "ARMv7 Scorpion-MP";
 	scorpion_pmu.num_events	= armv7_read_num_pmnc_events();
 	scorpion_pmu.pmu.attr_groups	= msm_l1_pmu_attr_grps;
-	scorpion_pmu.request_pmu_irq	= msm_request_irq;
-	scorpion_pmu.free_pmu_irq	= msm_free_irq;
 	scorpion_clear_pmuregs();
 	return &scorpion_pmu;
 }
diff --git a/arch/arm/kernel/perf_event_msm_krait.c b/arch/arm/kernel/perf_event_msm_krait.c
index eec614b..5708d74 100644
--- a/arch/arm/kernel/perf_event_msm_krait.c
+++ b/arch/arm/kernel/perf_event_msm_krait.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -520,53 +520,6 @@
 	armv7_pmnc_write(ARMV7_PMNC_P | ARMV7_PMNC_C);
 }
 
-static void enable_irq_callback(void *info)
-{
-        int irq = *(unsigned int *)info;
-
-        enable_percpu_irq(irq, IRQ_TYPE_EDGE_RISING);
-}
-
-static void disable_irq_callback(void *info)
-{
-        int irq = *(unsigned int *)info;
-
-        disable_percpu_irq(irq);
-}
-
-static int
-msm_request_irq(int irq, irq_handler_t *handle_irq)
-{
-        int err = 0;
-        int cpu;
-
-	err = request_percpu_irq(irq, *handle_irq, "l1-armpmu",
-			&cpu_hw_events);
-
-        if (!err) {
-                for_each_cpu(cpu, cpu_online_mask) {
-                        smp_call_function_single(cpu,
-                                        enable_irq_callback, &irq, 1);
-                }
-        }
-
-        return err;
-}
-
-static void
-msm_free_irq(int irq)
-{
-        int cpu;
-
-        if (irq >= 0) {
-                for_each_cpu(cpu, cpu_online_mask) {
-                        smp_call_function_single(cpu,
-                                        disable_irq_callback, &irq, 1);
-                }
-                free_percpu_irq(irq, &cpu_hw_events);
-        }
-}
-
 /*
  * We check for column exclusion constraints here.
  * Two events cant have same reg and same group.
@@ -621,8 +574,6 @@
 
 static struct arm_pmu krait_pmu = {
 	.handle_irq		= armv7pmu_handle_irq,
-	.request_pmu_irq	= msm_request_irq,
-	.free_pmu_irq		= msm_free_irq,
 	.enable			= krait_pmu_enable_event,
 	.disable		= krait_pmu_disable_event,
 	.read_counter		= armv7pmu_read_counter,
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index 3163b2a..678c55d 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -1235,8 +1235,6 @@
 }
 
 static struct arm_pmu armv7pmu = {
-	.request_pmu_irq	= armpmu_generic_request_irq,
-	.free_pmu_irq		= armpmu_generic_free_irq,
 	.handle_irq		= armv7pmu_handle_irq,
 	.enable			= armv7pmu_enable_event,
 	.disable		= armv7pmu_disable_event,
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index b258707..dbb4328 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -264,6 +264,9 @@
 	select MSM_RPM_REGULATOR_SMD
 	select ARM_HAS_SG_CHAIN
 	select MSM_RUN_QUEUE_STATS
+	select MEMORY_HOLE_CARVEOUT
+	select MSM_RPM_STATS_LOG
+	select QMI_ENCDEC
 
 config ARCH_MPQ8092
 	bool "MPQ8092"
@@ -277,30 +280,6 @@
 	select SPARSE_IRQ
 	select MSM_NOPM
 
-config ARCH_MSM8226
-	bool "MSM8226"
-	select ARCH_MSM_KRAITMP
-	select GPIO_MSM_V3
-	select ARM_GIC
-	select CPU_V7
-	select MSM_SCM if SMP
-	select MSM_GPIOMUX
-	select MULTI_IRQ_HANDLER
-	select MSM_MULTIMEDIA_USE_ION
-	select MSM_PIL
-	select MSM_SPM_V2
-	select MSM_L2_SPM
-	select MSM_PM8X60 if PM
-	select MAY_HAVE_SPARSE_IRQ
-	select SPARSE_IRQ
-	select MSM_RPM_SMD
-	select REGULATOR
-	select MSM_QDSP6_APRV2
-	select MSM_QDSP6V2_CODECS
-	select MSM_AUDIO_QDSP6V2 if SND_SOC
-	select MSM_RPM_REGULATOR_SMD
-	select ARM_HAS_SG_CHAIN
-
 config ARCH_FSM9XXX
 	bool "FSM9XXX"
 	select ARCH_MSM_SCORPION
@@ -369,6 +348,7 @@
 	select MAY_HAVE_SPARSE_IRQ
 	select SPARSE_IRQ
 	select MSM_MULTIMEDIA_USE_ION
+	select MSM_RPM_STATS_LOG
 
 config ARCH_MSM8910
 	bool "MSM8910"
@@ -383,6 +363,22 @@
 	select MULTI_IRQ_HANDLER
 	select GPIO_MSM_V3
 	select MSM_GPIOMUX
+	select MSM_NATIVE_RESTART
+	select MSM_RESTART_V2
+
+config ARCH_MSM8226
+	bool "MSM8226"
+	select ARM_GIC
+	select GIC_SECURE
+	select SMP
+	select ARCH_MSM_CORTEXMP
+	select CPU_V7
+	select MSM_SCM if SMP
+	select MAY_HAVE_SPARSE_IRQ
+	select SPARSE_IRQ
+	select MULTI_IRQ_HANDLER
+	select GPIO_MSM_V3
+	select MSM_GPIOMUX
 endmenu
 
 choice
@@ -962,7 +958,7 @@
 	default "0x00000000" if ARCH_MSM8974
 	default "0x00000000" if ARCH_MPQ8092
 	default "0x00000000" if ARCH_MSM8226
-	default "0x80200000" if ARCH_MSM8910
+	default "0x00000000" if ARCH_MSM8910
 	default "0x10000000" if ARCH_FSM9XXX
 	default "0x00200000" if ARCH_MSM9625
 	default "0x00200000" if !MSM_STACKED_MEMORY
@@ -1522,6 +1518,17 @@
 	help
 	  SMD Transport Layer for IPC Router
 
+config MSM_QMI_INTERFACE
+	depends on MSM_IPC_ROUTER
+	depends on QMI_ENCDEC
+	default n
+	bool "MSM QMI Interface Library"
+	help
+	  Library to send and receive QMI messages over IPC Router.
+	  This library provides interface functions to the kernel drivers
+	  to perform QMI message marshaling and transport them over IPC
+	  Router.
+
 config MSM_ONCRPCROUTER_DEBUG
 	depends on MSM_ONCRPCROUTER
 	default y
@@ -1981,18 +1988,14 @@
 	  ADSP if the processor encounters a fatal error.
 
 config MSM_PIL_MSS_QDSP6V5
-       tristate "MSS QDSP6v5 (Hexagon) Boot Support"
-       depends on MSM_PIL
-       help
-         Support for booting and shutting down QDSP6v5 (Hexagon) processors
-	 in modem subsystems.
-
-config MSM_PIL_MBA
-	tristate "Support for modem self-authentication"
-	depends on MSM_PIL_MSS_QDSP6V5 && MSM_SUBSYSTEM_RESTART
+	tristate "MSS QDSP6v5 (Hexagon) Boot Support"
+	depends on MSM_PIL && MSM_SUBSYSTEM_RESTART
 	help
-	  Support for booting self-authenticating modems using the Modem Boot
-	  Authenticator.
+	  Support for booting and shutting down QDSP6v5 (Hexagon) processors
+	  in modem subsystems. If you would like to make or receive phone
+	  calls then say Y here.
+
+	  If unsure, say N.
 
 config MSM_PIL_RIVA
 	tristate "RIVA (WCNSS) Boot Support"
@@ -2098,7 +2101,7 @@
 config MSM_RPM_STATS_LOG
 	tristate "MSM Resource Power Manager Stat Driver"
 	depends on DEBUG_FS
-	depends on MSM_RPM
+	depends on MSM_RPM || MSM_RPM_SMD
 	default n
 	  help
 	  This option enables a driver which reads RPM messages from a shared
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 508c7f3..88ed433 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -84,7 +84,6 @@
 obj-$(CONFIG_MSM_PIL_MODEM_QDSP6V4) += pil-q6v4.o pil-q6v4-mss.o
 obj-$(CONFIG_MSM_PIL_LPASS_QDSP6V5) += pil-q6v5.o pil-q6v5-lpass.o
 obj-$(CONFIG_MSM_PIL_MSS_QDSP6V5) += pil-q6v5.o pil-q6v5-mss.o
-obj-$(CONFIG_MSM_PIL_MBA) += pil-mba.o
 obj-$(CONFIG_MSM_PIL_RIVA) += pil-riva.o
 obj-$(CONFIG_MSM_PIL_TZAPPS) += pil-tzapps.o
 obj-$(CONFIG_MSM_PIL_VIDC) += pil-vidc.o
@@ -139,6 +138,7 @@
 obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o
 obj-$(CONFIG_MSM_IPC_ROUTER) += ipc_router.o
 obj-$(CONFIG_MSM_IPC_ROUTER)+= ipc_socket.o
+obj-$(CONFIG_MSM_QMI_INTERFACE) += msm_qmi_interface.o
 obj-$(CONFIG_DEBUG_FS) += smd_rpc_sym.o
 obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_servers.o
 obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_clients.o
@@ -293,13 +293,14 @@
 obj-$(CONFIG_ARCH_MSM8974) += acpuclock-8974.o
 obj-$(CONFIG_ARCH_MSM8974) += clock-local2.o clock-pll.o clock-8974.o clock-rpm.o clock-voter.o clock-mdss-8974.o
 obj-$(CONFIG_ARCH_MSM8974) += gdsc.o
+obj-$(CONFIG_ARCH_MSM9625) += gdsc.o
 obj-$(CONFIG_ARCH_MSM8974) += krait-regulator.o
 obj-$(CONFIG_ARCH_MSM9625) += board-9625.o board-9625-gpiomux.o
 obj-$(CONFIG_ARCH_MSM9625) += clock-local2.o clock-pll.o clock-9625.o clock-rpm.o clock-voter.o acpuclock-9625.o
 obj-$(CONFIG_ARCH_MSM8930) += acpuclock-8930.o acpuclock-8627.o acpuclock-8930aa.o
 obj-$(CONFIG_ARCH_MPQ8092) += board-8092.o board-8092-gpiomux.o
 obj-$(CONFIG_ARCH_MSM8226) += board-8226.o board-8226-gpiomux.o
-obj-$(CONFIG_ARCH_MSM8910) += board-8910.o
+obj-$(CONFIG_ARCH_MSM8910) += board-8910.o board-8910-gpiomux.o
 
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
@@ -401,3 +402,5 @@
 endif
 obj-$(CONFIG_MSM_FIQ) += msm7k_fiq.o
 obj-$(CONFIG_MSM_FIQ) += msm7k_fiq_handler.o
+
+obj-$(CONFIG_MEMORY_HOLE_CARVEOUT) +=  msm_mem_hole.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index fa9ee54..cf1f401 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -66,4 +66,4 @@
    zreladdr-$(CONFIG_ARCH_MPQ8092)	:= 0x00008000
 
 # MSM8910
-   zreladdr-$(CONFIG_ARCH_MSM8910)	:= 0x80208000
+   zreladdr-$(CONFIG_ARCH_MSM8910)	:= 0x00008000
diff --git a/arch/arm/mach-msm/acpuclock-8064.c b/arch/arm/mach-msm/acpuclock-8064.c
index cda952f..88237af 100644
--- a/arch/arm/mach-msm/acpuclock-8064.c
+++ b/arch/arm/mach-msm/acpuclock-8064.c
@@ -233,40 +233,40 @@
 };
 
 static struct acpu_level tbl_PVS0_2000MHz[] __initdata = {
-	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   900000 },
-	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   900000 },
-	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),   900000 },
-	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),   900000 },
-	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),   912500 },
-	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),   962500 },
-	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),   987500 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1012500 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1025000 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1075000 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1112500 },
-	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1150000 },
-	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1200000 },
-	{ 1, {  1782000, HFPLL, 1, 0x42 }, L2(15), 1262500 },
-	{ 1, {  1890000, HFPLL, 1, 0x46 }, L2(15), 1300000 },
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   950000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   950000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),   950000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),   950000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),   962500 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),   975000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),  1000000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1025000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1037500 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1062500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1100000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1125000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1175000 },
+	{ 1, {  1782000, HFPLL, 1, 0x42 }, L2(15), 1225000 },
+	{ 1, {  1890000, HFPLL, 1, 0x46 }, L2(15), 1287500 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level tbl_PVS1_2000MHz[] __initdata = {
-	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   900000 },
-	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   900000 },
-	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),   900000 },
-	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),   900000 },
-	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),   900000 },
-	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),   962500 },
-	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),   987500 },
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   925000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   925000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),   925000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),   925000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),   937500 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),   950000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),   975000 },
 	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1000000 },
 	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1012500 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1062500 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1087500 },
-	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1125000 },
-	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1187500 },
-	{ 1, {  1782000, HFPLL, 1, 0x42 }, L2(15), 1237500 },
-	{ 1, {  1890000, HFPLL, 1, 0x46 }, L2(15), 1275000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1037500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1075000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1100000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1137500 },
+	{ 1, {  1782000, HFPLL, 1, 0x42 }, L2(15), 1187500 },
+	{ 1, {  1890000, HFPLL, 1, 0x46 }, L2(15), 1250000 },
 	{ 0, { 0 } }
 };
 
@@ -275,17 +275,17 @@
 	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   900000 },
 	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),   900000 },
 	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),   900000 },
-	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),   900000 },
-	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),   950000 },
-	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),   975000 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15),  987500 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1000000 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1050000 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1075000 },
-	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1112500 },
-	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1162500 },
-	{ 1, {  1782000, HFPLL, 1, 0x42 }, L2(15), 1212500 },
-	{ 1, {  1890000, HFPLL, 1, 0x46 }, L2(15), 1250000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),   912500 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),   925000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),   950000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15),  975000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15),  987500 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1012500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1050000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1075000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1112500 },
+	{ 1, {  1782000, HFPLL, 1, 0x42 }, L2(15), 1162500 },
+	{ 1, {  1890000, HFPLL, 1, 0x46 }, L2(15), 1212500 },
 	{ 0, { 0 } }
 };
 
@@ -295,44 +295,44 @@
 	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),   900000 },
 	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),   900000 },
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),   900000 },
-	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),   925000 },
-	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),   950000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),   912500 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),   937500 },
 	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15),  962500 },
 	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15),  975000 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1012500 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1037500 },
-	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1075000 },
-	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1112500 },
-	{ 1, {  1782000, HFPLL, 1, 0x42 }, L2(15), 1162500 },
-	{ 1, {  1890000, HFPLL, 1, 0x46 }, L2(15), 1200000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1000000 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1025000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1050000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1087500 },
+	{ 1, {  1782000, HFPLL, 1, 0x42 }, L2(15), 1137500 },
+	{ 1, {  1890000, HFPLL, 1, 0x46 }, L2(15), 1175000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level tbl_PVS4_2000MHz[] __initdata = {
-	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   900000 },
-	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   900000 },
-	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),   900000 },
-	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),   900000 },
-	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),   900000 },
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   875000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   875000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),   875000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),   875000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),   887500 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),   900000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),   925000 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15),  937500 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15),  950000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15),  950000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15),  962500 },
 	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15),  975000 },
 	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1000000 },
 	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1037500 },
-	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1062500 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1075000 },
 	{ 1, {  1782000, HFPLL, 1, 0x42 }, L2(15), 1112500 },
 	{ 1, {  1890000, HFPLL, 1, 0x46 }, L2(15), 1150000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level tbl_PVS5_2000MHz[] __initdata = {
-	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   900000 },
-	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   900000 },
-	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),   900000 },
-	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),   900000 },
-	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),   900000 },
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   875000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   875000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),   875000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),   875000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),   887500 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),   900000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),   925000 },
 	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15),  937500 },
@@ -340,18 +340,18 @@
 	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15),  962500 },
 	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15),  987500 },
 	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1012500 },
-	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1037500 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1050000 },
 	{ 1, {  1782000, HFPLL, 1, 0x42 }, L2(15), 1087500 },
 	{ 1, {  1890000, HFPLL, 1, 0x46 }, L2(15), 1125000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level tbl_PVS6_2000MHz[] __initdata = {
-	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   900000 },
-	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   900000 },
-	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),   900000 },
-	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),   900000 },
-	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),   900000 },
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   875000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   875000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),   875000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),   875000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),   887500 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),   900000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),   925000 },
 	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15),  937500 },
diff --git a/arch/arm/mach-msm/acpuclock-8960ab.c b/arch/arm/mach-msm/acpuclock-8960ab.c
index ae1cd7b..03a2004 100644
--- a/arch/arm/mach-msm/acpuclock-8960ab.c
+++ b/arch/arm/mach-msm/acpuclock-8960ab.c
@@ -105,40 +105,140 @@
 	{ }
 };
 
-static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
+static struct acpu_level freq_tbl_PVS0[] __initdata = {
 	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   950000 },
-	{ 0, {   432000, HFPLL, 2, 0x20 }, L2(3),   975000 },
-	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(3),   975000 },
-	{ 0, {   540000, HFPLL, 2, 0x28 }, L2(3),  1000000 },
-	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(3),  1000000 },
-	{ 0, {   648000, HFPLL, 1, 0x18 }, L2(3),  1025000 },
-	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(3),  1025000 },
-	{ 0, {   756000, HFPLL, 1, 0x1C }, L2(3),  1075000 },
-	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(3),  1075000 },
-	{ 0, {   864000, HFPLL, 1, 0x20 }, L2(3),  1100000 },
-	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(3),  1100000 },
-	{ 0, {   972000, HFPLL, 1, 0x24 }, L2(3),  1125000 },
-	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(3),  1125000 },
-	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(9),  1175000 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(9),  1175000 },
-	{ 0, {  1188000, HFPLL, 1, 0x2C }, L2(9),  1200000 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(9),  1200000 },
-	{ 0, {  1296000, HFPLL, 1, 0x30 }, L2(9),  1225000 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(9),  1225000 },
-	{ 0, {  1404000, HFPLL, 1, 0x34 }, L2(9),  1237500 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(9),  1237500 },
-	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(9),  1250000 },
-	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(9),  1250000 },
-	{ 1, {  1620000, HFPLL, 1, 0x3C }, L2(9),  1250000 },
-	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(9),  1250000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(3),   950000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(3),   975000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(3),  1000000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(3),  1025000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(3),  1050000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(3),  1075000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(9),  1100000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(9),  1125000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(9),  1150000 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(9),  1175000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(9),  1200000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(9),  1225000 },
 	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(9),  1250000 },
 	{ 0, { 0 } }
 };
 
+static struct acpu_level freq_tbl_PVS1[] __initdata = {
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   925000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(3),   925000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(3),   950000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(3),   975000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(3),  1000000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(3),  1025000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(3),  1050000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(9),  1075000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(9),  1100000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(9),  1125000 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(9),  1150000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(9),  1175000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(9),  1200000 },
+	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(9),  1225000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level freq_tbl_PVS2[] __initdata = {
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   900000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(3),   900000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(3),   925000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(3),   950000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(3),   975000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(3),  1000000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(3),  1025000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(9),  1050000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(9),  1075000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(9),  1100000 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(9),  1125000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(9),  1150000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(9),  1175000 },
+	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(9),  1200000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level freq_tbl_PVS3[] __initdata = {
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   900000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(3),   900000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(3),   900000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(3),   925000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(3),   950000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(3),   975000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(3),  1000000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(9),  1025000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(9),  1050000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(9),  1075000 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(9),  1100000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(9),  1125000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(9),  1150000 },
+	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(9),  1175000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level freq_tbl_PVS4[] __initdata = {
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   875000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(3),   875000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(3),   875000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(3),   900000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(3),   925000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(3),   950000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(3),   975000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(9),  1000000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(9),  1025000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(9),  1050000 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(9),  1075000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(9),  1100000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(9),  1125000 },
+	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(9),  1150000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level freq_tbl_PVS5[] __initdata = {
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   875000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(3),   875000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(3),   875000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(3),   875000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(3),   900000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(3),   925000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(3),   950000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(9),   975000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(9),  1000000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(9),  1025000 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(9),  1050000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(9),  1075000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(9),  1100000 },
+	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(9),  1125000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level freq_tbl_PVS6[] __initdata = {
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   850000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(3),   850000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(3),   850000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(3),   850000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(3),   875000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(3),   900000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(3),   925000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(9),   950000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(9),   975000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(9),  1000000 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(9),  1025000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(9),  1050000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(9),  1075000 },
+	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(9),  1100000 },
+	{ 0, { 0 } }
+};
+
 static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
-[0][PVS_SLOW]    = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow),  0 },
-[0][PVS_NOMINAL] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow),  0 },
-[0][PVS_FAST]    = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow),  0 },
+[0][0] = { freq_tbl_PVS0, sizeof(freq_tbl_PVS0),  0 },
+[0][1] = { freq_tbl_PVS1, sizeof(freq_tbl_PVS1),  0 },
+[0][2] = { freq_tbl_PVS2, sizeof(freq_tbl_PVS2),  0 },
+[0][3] = { freq_tbl_PVS3, sizeof(freq_tbl_PVS3),  0 },
+[0][4] = { freq_tbl_PVS4, sizeof(freq_tbl_PVS4),  0 },
+[0][5] = { freq_tbl_PVS5, sizeof(freq_tbl_PVS5),  0 },
+[0][6] = { freq_tbl_PVS6, sizeof(freq_tbl_PVS6),  0 },
 };
 
 static struct acpuclk_krait_params acpuclk_8960ab_params __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-9625.c b/arch/arm/mach-msm/acpuclock-9625.c
index 7fd00e6..b0556c3 100644
--- a/arch/arm/mach-msm/acpuclock-9625.c
+++ b/arch/arm/mach-msm/acpuclock-9625.c
@@ -386,7 +386,7 @@
 {
 	unsigned long max_cpu_khz = 0;
 	struct resource *res;
-	int i;
+	int i, rc;
 	u32 regval;
 
 	mutex_init(&drv_data.lock);
@@ -447,12 +447,43 @@
 				acpu_freq_tbl[i].use_for_scaling; i++)
 		max_cpu_khz = acpu_freq_tbl[i].khz;
 
+	/* Initialize regulators */
+	rc = increase_vdd(acpu_freq_tbl[i].vdd_cpu, acpu_freq_tbl[i].vdd_mem);
+	if (rc)
+		goto err_vdd;
+
+	rc = regulator_enable(drv_data.vdd_mem);
+	if (rc) {
+		dev_err(&pdev->dev, "regulator_enable for a5_mem failed\n");
+		goto err_vdd;
+	}
+
+	rc = regulator_enable(drv_data.vdd_cpu);
+	if (rc) {
+		dev_err(&pdev->dev, "regulator_enable for a5_cpu failed\n");
+		goto err_vdd_cpu;
+	}
+
 	acpuclk_9625_set_rate(smp_processor_id(), max_cpu_khz, SETRATE_INIT);
 
 	acpuclk_register(&acpuclk_9625_data);
 	cpufreq_table_init();
 
 	return 0;
+
+err_vdd_cpu:
+	regulator_disable(drv_data.vdd_mem);
+err_vdd:
+	regulator_put(drv_data.vdd_mem);
+	regulator_put(drv_data.vdd_cpu);
+
+	for (i = 0; i < NUM_SRC; i++) {
+		if (!src_clocks[i].name)
+			continue;
+		clk_unprepare(src_clocks[i].clk);
+		clk_put(src_clocks[i].clk);
+	}
+	return rc;
 }
 
 static struct of_device_id acpuclk_9625_match_table[] = {
diff --git a/arch/arm/mach-msm/avs.h b/arch/arm/mach-msm/avs.h
index a549e9d..e87bded 100644
--- a/arch/arm/mach-msm/avs.h
+++ b/arch/arm/mach-msm/avs.h
@@ -37,7 +37,8 @@
 u32 avs_get_avsdscr(void);
 u32 avs_get_tscsr(void);
 void avs_set_tscsr(u32 to_tscsr);
-void avs_disable(void);
+u32 avs_disable(void);
+void avs_enable(u32 avscsr);
 #else
 static inline u32 avs_reset_delays(u32 avsdscr)
 { return 0; }
@@ -48,7 +49,9 @@
 static inline u32 avs_get_tscsr(void)
 { return 0; }
 static inline void avs_set_tscsr(u32 to_tscsr) {}
-static inline void avs_disable(void) {}
+static inline u32 avs_disable(void)
+{return 0; }
+static inline void avs_enable(u32 avscsr) {}
 #endif
 
 /*#define AVSDEBUG(x...) pr_info("AVS: " x);*/
@@ -60,9 +63,13 @@
 		put_cpu();			\
 	} while (0);
 
+/* AVSCSR(0x61) to enable CPU, V and L2 AVS module */
+
 #define AVS_ENABLE(cpu, x) do {			\
-		if (get_cpu() == (cpu))		\
+		if (get_cpu() == (cpu)) {       \
 			avs_reset_delays((x));	\
+			avs_enable(0x61);	\
+		}				\
 		put_cpu();			\
 	} while (0);
 
diff --git a/arch/arm/mach-msm/avs_hw.S b/arch/arm/mach-msm/avs_hw.S
index 1cc3ce0..efb9c47 100644
--- a/arch/arm/mach-msm/avs_hw.S
+++ b/arch/arm/mach-msm/avs_hw.S
@@ -102,23 +102,23 @@
 
 /*      Read r0=AVSDSCR */
 		mrc p15, 7, r0, c15, c0, 6
-
-/*      AVSCSR(0x61) to enable CPU, V and L2 AVS module  */
-		mov r3, #0x61
-		mcr p15, 7, r3, c15, c1, 7
-
 		bx lr
 
-
+	.global avs_enable
+avs_enable:
+/*	Restore the avs_scr register */
+		mcr p15, 7, r0, c15, c1, 7
+		bx lr
 
         .global avs_disable
 avs_disable:
 
+/*	Get the AVSCSR value */
+		mrc p15, 7, r0, c15, c1, 7
 /*      Clear AVSCSR */
-		mov r0, #0
-
+		mov r1, #0
 /*      Write AVSCSR */
-		mcr p15, 7, r0, c15, c1, 7
+		mcr p15, 7, r1, c15, c1, 7
 
 		bx lr
 
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 7ba22f4..c475e2d 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -193,6 +193,7 @@
 static struct sps_mem_buffer rx_desc_mem_buf;
 static struct sps_register_event tx_register_event;
 static struct sps_register_event rx_register_event;
+static bool satellite_mode;
 
 static struct bam_ch_info bam_ch[BAM_DMUX_NUM_CHANNELS];
 static int bam_mux_initialized;
@@ -2074,7 +2075,7 @@
 	a2_props.options = SPS_BAM_OPT_IRQ_WAKEUP;
 	a2_props.num_pipes = A2_NUM_PIPES;
 	a2_props.summing_threshold = A2_SUMMING_THRESHOLD;
-	if (cpu_is_msm9615())
+	if (cpu_is_msm9615() || satellite_mode)
 		a2_props.manage = SPS_BAM_MGR_DEVICE_REMOTE;
 	/* need to free on tear down */
 	ret = sps_register_bam_device(&a2_props, &h);
@@ -2246,7 +2247,7 @@
 	a2_props.options = SPS_BAM_OPT_IRQ_WAKEUP;
 	a2_props.num_pipes = A2_NUM_PIPES;
 	a2_props.summing_threshold = A2_SUMMING_THRESHOLD;
-	if (cpu_is_msm9615())
+	if (cpu_is_msm9615() || satellite_mode)
 		a2_props.manage = SPS_BAM_MGR_DEVICE_REMOTE;
 	ret = sps_register_bam_device(&a2_props, &h);
 	if (ret < 0) {
@@ -2374,10 +2375,14 @@
 			pr_err("%s: irq field missing\n", __func__);
 			return -ENODEV;
 		}
-		DBG("%s: base:%p size:%x irq:%d\n", __func__,
+		satellite_mode = of_property_read_bool(pdev->dev.of_node,
+						"qcom,satellite-mode");
+
+		DBG("%s: base:%p size:%x irq:%d satellite:%d\n", __func__,
 							a2_phys_base,
 							a2_phys_size,
-							a2_bam_irq);
+							a2_bam_irq,
+							satellite_mode);
 	} else { /* fallback to default init data */
 		a2_phys_base = (void *)(A2_PHYS_BASE);
 		a2_phys_size = A2_PHYS_SIZE;
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index 0a95e51..76d2844 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -187,8 +187,22 @@
 #define VFE_CAMIF_TIMER1_GPIO 3
 #define VFE_CAMIF_TIMER2_GPIO 1
 
+static struct gpio flash_init_gpio[] = {
+	{VFE_CAMIF_TIMER1_GPIO, GPIOF_OUT_INIT_LOW, "CAMIF_TIMER1"},
+	{VFE_CAMIF_TIMER2_GPIO, GPIOF_OUT_INIT_LOW, "CAMIF_TIMER2"},
+};
+
+static struct msm_gpio_set_tbl flash_set_gpio[] = {
+	{VFE_CAMIF_TIMER1_GPIO, GPIOF_OUT_INIT_HIGH, 2000},
+	{VFE_CAMIF_TIMER2_GPIO, GPIOF_OUT_INIT_HIGH, 2000},
+};
+
 static struct msm_camera_sensor_flash_src msm_flash_src = {
 	.flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
+	.init_gpio_tbl = flash_init_gpio,
+	.init_gpio_tbl_size = ARRAY_SIZE(flash_init_gpio),
+	.set_gpio_tbl = flash_set_gpio,
+	.set_gpio_tbl_size = ARRAY_SIZE(flash_set_gpio),
 	._fsrc.ext_driver_src.led_en = VFE_CAMIF_TIMER1_GPIO,
 	._fsrc.ext_driver_src.led_flash_en = VFE_CAMIF_TIMER2_GPIO,
 	._fsrc.ext_driver_src.flash_id = MAM_CAMERA_EXT_LED_FLASH_SC628A,
@@ -531,9 +545,15 @@
 	.sensor_type = BAYER_SENSOR,
 };
 
+static struct i2c_board_info sc628a_flash_i2c_info = {
+	I2C_BOARD_INFO("sc628a", 0x6E),
+};
+
 static struct msm_camera_sensor_flash_data flash_imx074 = {
 	.flash_type	= MSM_CAMERA_FLASH_LED,
-	.flash_src	= &msm_flash_src
+	.flash_src	= &msm_flash_src,
+	.board_info     = &sc628a_flash_i2c_info,
+	.bus_id         = APQ_8064_GSBI4_QUP_I2C_BUS_ID,
 };
 
 static struct msm_camera_csi_lane_params imx074_csi_lane_params = {
@@ -740,9 +760,6 @@
 	.platform_data = &msm_camera_sensor_ov2720_data,
 	},
 	{
-	I2C_BOARD_INFO("sc628a", 0x6E),
-	},
-	{
 	I2C_BOARD_INFO("imx091", 0x34),
 	.platform_data = &msm_camera_sensor_imx091_data,
 	},
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
index f35ae6b..5ebb010 100644
--- a/arch/arm/mach-msm/board-8064-gpu.c
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -226,7 +226,7 @@
 			.io_fraction = 0,
 		},
 		{
-			.gpu_freq = 325000000,
+			.gpu_freq = 320000000,
 			.bus_freq = 3,
 			.io_fraction = 33,
 		},
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index c973bd5..a358bba 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -395,7 +395,6 @@
 #define CHG_TERM_MA		100
 static struct pm8921_charger_platform_data
 apq8064_pm8921_chg_pdata __devinitdata = {
-	.safety_time		= 180,
 	.update_time		= 60000,
 	.max_voltage		= MAX_VOLTAGE_MV,
 	.min_voltage		= 3200,
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 61411d1..314bfd0 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -1257,29 +1257,20 @@
  * clock is running at 100KHz and voltage levels are at 3.3
  * and 5 volts
  */
-static int enable_100KHz_ls(int enable)
+static int enable_100KHz_ls(int enable, int gpio)
 {
-	int ret = 0;
-	if (enable) {
-		ret = gpio_request(SX150X_GPIO(1, 10),
-					"cs8427_100KHZ_ENABLE");
-		if (ret) {
-			pr_err("%s: Failed to request gpio %d\n", __func__,
-				SX150X_GPIO(1, 10));
-			return ret;
-		}
-		gpio_direction_output(SX150X_GPIO(1, 10), 1);
-	} else {
-		gpio_direction_output(SX150X_GPIO(1, 10), 0);
-		gpio_free(SX150X_GPIO(1, 10));
-	}
-	return ret;
+	if (enable)
+		gpio_direction_output(gpio, 1);
+	else
+		gpio_direction_output(gpio, 0);
+	return 0;
 }
 
 static struct cs8427_platform_data cs8427_i2c_platform_data = {
 	.irq = SX150X_GPIO(1, 4),
 	.reset_gpio = SX150X_GPIO(1, 6),
 	.enable = enable_100KHz_ls,
+	.ls_gpio = SX150X_GPIO(1, 10),
 };
 
 static struct i2c_board_info cs8427_device_info[] __initdata = {
@@ -1397,7 +1388,7 @@
 	/* T6 Object */
 	0, 0, 0, 0, 0, 0,
 	/* T38 Object */
-	14, 3, 0, 5, 7, 12, 0, 0, 0, 0,
+	14, 4, 0, 5, 11, 12, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -1405,7 +1396,7 @@
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0,
 	/* T7 Object */
-	32, 10, 50,
+	32, 8, 50,
 	/* T8 Object */
 	25, 0, 20, 20, 0, 0, 0, 0, 0, 0,
 	/* T9 Object */
@@ -2739,7 +2730,7 @@
 };
 
 static struct msm_spi_platform_data mpq8064_qup_spi_gsbi6_pdata = {
-	.max_clock_speed = 1100000,
+	.max_clock_speed = 10800000,
 };
 
 static struct ci_bridge_platform_data mpq8064_ci_bridge_pdata = {
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index 33f18a2..e5263c7 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -43,6 +43,21 @@
 #include "board-dt.h"
 #include "clock.h"
 
+static struct memtype_reserve msm8226_reserve_table[] __initdata = {
+	[MEMTYPE_SMI] = {
+	},
+	[MEMTYPE_EBI0] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+	[MEMTYPE_EBI1] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+};
+
+static int msm8226_paddr_to_memtype(unsigned int paddr)
+{
+	return MEMTYPE_EBI1;
+}
 static struct clk_lookup msm_clocks_dummy[] = {
 	CLK_DUMMY("core_clk",   BLSP1_UART_CLK, "f991f000.serial", OFF),
 	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "f991f000.serial", OFF),
@@ -50,11 +65,28 @@
 	CLK_DUMMY("core_clk",	HSUSB_CORE_CLK, "f9a55000.usb", OFF),
 };
 
-struct clock_init_data msm_dummy_clock_init_data __initdata = {
+static struct clock_init_data msm_dummy_clock_init_data __initdata = {
 	.table = msm_clocks_dummy,
 	.size = ARRAY_SIZE(msm_clocks_dummy),
 };
 
+static struct reserve_info msm8226_reserve_info __initdata = {
+	.memtype_reserve_table = msm8226_reserve_table,
+	.paddr_to_memtype = msm8226_paddr_to_memtype,
+};
+
+static void __init msm8226_early_memory(void)
+{
+	reserve_info = &msm8226_reserve_info;
+	of_scan_flat_dt(dt_scan_for_memory_reserve, msm8226_reserve_table);
+}
+
+static void __init msm8226_reserve(void)
+{
+	msm_reserve();
+}
+
+
 void __init msm8226_init(void)
 {
 	msm8226_init_gpiomux();
@@ -66,7 +98,6 @@
 	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 }
 
-
 static const char *msm8226_dt_match[] __initconst = {
 	"qcom,msm8226",
 	NULL
@@ -79,4 +110,6 @@
 	.handle_irq = gic_handle_irq,
 	.timer = &msm_dt_timer,
 	.dt_compat = msm8226_dt_match,
+	.reserve = msm8226_reserve,
+	.init_very_early = msm8226_early_memory
 MACHINE_END
diff --git a/arch/arm/mach-msm/board-8910-gpiomux.c b/arch/arm/mach-msm/board-8910-gpiomux.c
new file mode 100644
index 0000000..a67f916
--- /dev/null
+++ b/arch/arm/mach-msm/board-8910-gpiomux.c
@@ -0,0 +1,29 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+
+void __init msm8910_init_gpiomux(void)
+{
+	int rc;
+
+	rc = msm_gpiomux_init(NR_GPIO_IRQS);
+	if (rc) {
+		pr_err(KERN_ERR "msm_8910_init_gpiomux failed %d\n", rc);
+		return;
+	}
+}
diff --git a/arch/arm/mach-msm/board-8910.c b/arch/arm/mach-msm/board-8910.c
index 7039879..b031dac 100644
--- a/arch/arm/mach-msm/board-8910.c
+++ b/arch/arm/mach-msm/board-8910.c
@@ -31,6 +31,7 @@
 #include <mach/board.h>
 #include <mach/gpiomux.h>
 #include <mach/msm_iomap.h>
+#include <mach/restart.h>
 #ifdef CONFIG_ION_MSM
 #include <mach/ion.h>
 #endif
@@ -45,24 +46,38 @@
 	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "f991f000.serial", OFF),
 	CLK_DUMMY("iface_clk",  HSUSB_IFACE_CLK, "f9a55000.usb", OFF),
 	CLK_DUMMY("core_clk",	HSUSB_CORE_CLK, "f9a55000.usb", OFF),
-	CLK_DUMMY("iface_clk", NULL, "f9824000.qcom,sdcc", OFF),
-	CLK_DUMMY("core_clk", NULL, "f9824000.qcom,sdcc", OFF),
-	CLK_DUMMY("bus_clk",  NULL, "f9824000.qcom,sdcc", OFF),
+	CLK_DUMMY("iface_clk",	NULL,		"msm_sdcc.1", OFF),
+	CLK_DUMMY("core_clk",	NULL,		"msm_sdcc.1", OFF),
+	CLK_DUMMY("bus_clk",	NULL,		"msm_sdcc.1", OFF),
+	CLK_DUMMY("iface_clk",	NULL,		"msm_sdcc.2", OFF),
+	CLK_DUMMY("core_clk",	NULL,		"msm_sdcc.2", OFF),
+	CLK_DUMMY("bus_clk",	NULL,		"msm_sdcc.2", OFF),
 };
 
-struct clock_init_data msm_dummy_clock_init_data __initdata = {
+static struct clock_init_data msm_dummy_clock_init_data __initdata = {
 	.table = msm_clocks_dummy,
 	.size = ARRAY_SIZE(msm_clocks_dummy),
 };
 
+static struct of_dev_auxdata msm8910_auxdata_lookup[] __initdata = {
+	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9824000, \
+			"msm_sdcc.1", NULL),
+	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98A4000, \
+			"msm_sdcc.2", NULL),
+	{}
+};
+
 void __init msm8910_init(void)
 {
+	struct of_dev_auxdata *adata = msm8910_auxdata_lookup;
+
+	msm8910_init_gpiomux();
 	msm_clock_init(&msm_dummy_clock_init_data);
 
 	if (socinfo_init() < 0)
 		pr_err("%s: socinfo_init() failed\n", __func__);
 
-	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+	of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
 }
 
 static const char *msm8910_dt_match[] __initconst = {
@@ -77,4 +92,5 @@
 	.handle_irq = gic_handle_irq,
 	.timer = &msm_dt_timer,
 	.dt_compat = msm8910_dt_match,
+	.restart = msm_restart,
 MACHINE_END
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
index eb00f34..083d5ab 100644
--- a/arch/arm/mach-msm/board-8930-camera.c
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -188,6 +188,17 @@
 #define VFE_CAMIF_TIMER1_GPIO 2
 #define VFE_CAMIF_TIMER2_GPIO 3
 #define VFE_CAMIF_TIMER3_GPIO_INT 4
+
+static struct gpio flash_init_gpio[] = {
+	{VFE_CAMIF_TIMER1_GPIO, GPIOF_OUT_INIT_LOW, "CAMIF_TIMER1"},
+	{VFE_CAMIF_TIMER2_GPIO, GPIOF_OUT_INIT_LOW, "CAMIF_TIMER2"},
+};
+
+static struct msm_gpio_set_tbl flash_set_gpio[] = {
+	{VFE_CAMIF_TIMER1_GPIO, GPIOF_OUT_INIT_HIGH, 2000},
+	{VFE_CAMIF_TIMER2_GPIO, GPIOF_OUT_INIT_HIGH, 2000},
+};
+
 static struct msm_camera_sensor_strobe_flash_data strobe_flash_xenon = {
 	.flash_trigger = VFE_CAMIF_TIMER2_GPIO,
 	.flash_charge = VFE_CAMIF_TIMER1_GPIO,
@@ -196,14 +207,16 @@
 	.irq = MSM_GPIO_TO_INT(VFE_CAMIF_TIMER3_GPIO_INT),
 };
 
-#ifdef CONFIG_MSM_CAMERA_FLASH
 static struct msm_camera_sensor_flash_src msm_flash_src = {
 	.flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
+	.init_gpio_tbl = flash_init_gpio,
+	.init_gpio_tbl_size = ARRAY_SIZE(flash_init_gpio),
+	.set_gpio_tbl = flash_set_gpio,
+	.set_gpio_tbl_size = ARRAY_SIZE(flash_set_gpio),
 	._fsrc.ext_driver_src.led_en = VFE_CAMIF_TIMER1_GPIO,
 	._fsrc.ext_driver_src.led_flash_en = VFE_CAMIF_TIMER2_GPIO,
 	._fsrc.ext_driver_src.flash_id = MAM_CAMERA_EXT_LED_FLASH_TPS61310,
 };
-#endif
 
 static struct msm_bus_vectors cam_init_vectors[] = {
 	{
@@ -476,9 +489,7 @@
 
 static struct msm_camera_sensor_flash_data flash_imx074 = {
 	.flash_type	= MSM_CAMERA_FLASH_LED,
-#ifdef CONFIG_MSM_CAMERA_FLASH
 	.flash_src	= &msm_flash_src
-#endif
 };
 
 static struct msm_camera_csi_lane_params imx074_csi_lane_params = {
@@ -560,9 +571,15 @@
 	.sensor_type = BAYER_SENSOR,
 };
 
+static struct i2c_board_info tps61310_flash_i2c_info = {
+	I2C_BOARD_INFO("tps61310", 0x66),
+};
+
 static struct msm_camera_sensor_flash_data flash_s5k3l1yx = {
 	.flash_type = MSM_CAMERA_FLASH_LED,
-	.flash_src = &msm_flash_src
+	.flash_src = &msm_flash_src,
+	.board_info = &tps61310_flash_i2c_info,
+	.bus_id = MSM_8930_GSBI4_QUP_I2C_BUS_ID,
 };
 
 static struct msm_camera_csi_lane_params s5k3l1yx_csi_lane_params = {
@@ -650,9 +667,6 @@
 	I2C_BOARD_INFO("s5k3l1yx", 0x20),
 	.platform_data = &msm_camera_sensor_s5k3l1yx_data,
 	},
-	{
-	I2C_BOARD_INFO("tps61310", 0x66),
-	},
 };
 
 struct msm_camera_board_info msm8930_camera_board_info = {
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index 0c7666b..d35a907 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -315,7 +315,6 @@
 #define MAX_VOLTAGE_MV		4200
 #define CHG_TERM_MA		100
 static struct pm8921_charger_platform_data pm8921_chg_pdata __devinitdata = {
-	.safety_time		= 180,
 	.update_time		= 60000,
 	.max_voltage		= MAX_VOLTAGE_MV,
 	.min_voltage		= 3200,
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 05d2fe1..1b487fa 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -133,7 +133,7 @@
 #endif
 
 #define MSM_PMEM_ADSP_SIZE         0x7800000
-#define MSM_PMEM_AUDIO_SIZE        0x4CF000
+#define MSM_PMEM_AUDIO_SIZE        0x314000
 #ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
 #define MSM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
 #else
@@ -762,7 +762,7 @@
 	.regulator = {
 	{
 		.name = "CDC_VDD_CP",
-		.min_uV = 1800000,
+		.min_uV = 2200000,
 		.max_uV = 2200000,
 		.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
 	},
@@ -828,7 +828,7 @@
 	.regulator = {
 	{
 		.name = "CDC_VDD_CP",
-		.min_uV = 1800000,
+		.min_uV = 2200000,
 		.max_uV = 2200000,
 		.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
 	},
@@ -2295,7 +2295,6 @@
 
 static struct platform_device *common_devices[] __initdata = {
 	&msm_8960_q6_lpass,
-	&msm_8960_q6_mss,
 	&msm_8960_riva,
 	&msm_pil_tzapps,
 	&msm_pil_vidc,
@@ -2714,11 +2713,34 @@
 #endif
 }
 
+/*Modify the WCD9xxx platform data to support supplies from PM8917 */
+static void __init msm8930_pm8917_wcd9xxx_pdata_fixup(
+		struct wcd9xxx_pdata *cdc_pdata)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(cdc_pdata->regulator); i++) {
+
+		if (cdc_pdata->regulator[i].name != NULL
+			&& strncmp(cdc_pdata->regulator[i].name,
+				"CDC_VDD_CP", 10) == 0) {
+			cdc_pdata->regulator[i].min_uV =
+				cdc_pdata->regulator[i].max_uV = 1800000;
+			pr_info("%s: CDC_VDD_CP forced to 1.8 volts for PM8917\n",
+				__func__);
+			return;
+		}
+	}
+}
+
 /* Modify platform data values to match requirements for PM8917. */
 static void __init msm8930_pm8917_pdata_fixup(void)
 {
 	struct acpuclk_platform_data *pdata;
 
+	msm8930_pm8917_wcd9xxx_pdata_fixup(&sitar_platform_data);
+	msm8930_pm8917_wcd9xxx_pdata_fixup(&sitar1p1_platform_data);
+
 	mhl_platform_data.gpio_mhl_power = MHL_POWER_GPIO_PM8917;
 
 	gpio_keys_8930_pdata.buttons = keys_8930_pm8917;
@@ -2790,12 +2812,17 @@
 	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
 	msm_spm_l2_init(msm_spm_l2_data);
 	msm8930_init_buses();
-	if (cpu_is_msm8627())
+	if (cpu_is_msm8627()) {
 		platform_add_devices(msm8627_footswitch,
 				msm8627_num_footswitch);
-	else
-		platform_add_devices(msm8930_footswitch,
-				msm8930_num_footswitch);
+	} else {
+		if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+			platform_add_devices(msm8930_pm8917_footswitch,
+					msm8930_pm8917_num_footswitch);
+		else
+			platform_add_devices(msm8930_footswitch,
+					msm8930_num_footswitch);
+	}
 	if (cpu_is_msm8627())
 		platform_device_register(&msm8627_device_acpuclk);
 	else if (cpu_is_msm8930())
@@ -2825,6 +2852,10 @@
 	else
 		msm8930_pm8917_gpio_mpp_init();
 #endif
+	/* Don't add modem devices on APQ targets */
+	if (socinfo_get_id() != 119 && socinfo_get_id() != 157
+	    && socinfo_get_id() != 160)
+		platform_device_register(&msm_8960_q6_mss);
 	platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
 #ifdef CONFIG_MSM_CAMERA
 	msm8930_init_cam();
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index 88fd527..7a2e9e1 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -185,6 +185,17 @@
 #define VFE_CAMIF_TIMER1_GPIO 2
 #define VFE_CAMIF_TIMER2_GPIO 3
 #define VFE_CAMIF_TIMER3_GPIO_INT 4
+
+static struct gpio flash_init_gpio[] = {
+	{VFE_CAMIF_TIMER1_GPIO, GPIOF_OUT_INIT_LOW, "CAMIF_TIMER1"},
+	{VFE_CAMIF_TIMER2_GPIO, GPIOF_OUT_INIT_LOW, "CAMIF_TIMER2"},
+};
+
+static struct msm_gpio_set_tbl flash_set_gpio[] = {
+	{VFE_CAMIF_TIMER1_GPIO, GPIOF_OUT_INIT_HIGH, 2000},
+	{VFE_CAMIF_TIMER2_GPIO, GPIOF_OUT_INIT_HIGH, 2000},
+};
+
 static struct msm_camera_sensor_strobe_flash_data strobe_flash_xenon = {
 	.flash_trigger = VFE_CAMIF_TIMER2_GPIO,
 	.flash_charge = VFE_CAMIF_TIMER1_GPIO,
@@ -193,14 +204,16 @@
 	.irq = MSM_GPIO_TO_INT(VFE_CAMIF_TIMER3_GPIO_INT),
 };
 
-#ifdef CONFIG_MSM_CAMERA_FLASH
 static struct msm_camera_sensor_flash_src msm_flash_src = {
 	.flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
+	.init_gpio_tbl = flash_init_gpio,
+	.init_gpio_tbl_size = ARRAY_SIZE(flash_init_gpio),
+	.set_gpio_tbl = flash_set_gpio,
+	.set_gpio_tbl_size = ARRAY_SIZE(flash_set_gpio),
 	._fsrc.ext_driver_src.led_en = VFE_CAMIF_TIMER1_GPIO,
 	._fsrc.ext_driver_src.led_flash_en = VFE_CAMIF_TIMER2_GPIO,
 	._fsrc.ext_driver_src.flash_id = MAM_CAMERA_EXT_LED_FLASH_SC628A,
 };
-#endif
 
 static struct msm_bus_vectors cam_init_vectors[] = {
 	{
@@ -570,11 +583,15 @@
 	.vcm_enable     = 0,
 };
 
+static struct i2c_board_info sc628a_flash_i2c_info = {
+	I2C_BOARD_INFO("sc628a", 0x6E),
+};
+
 static struct msm_camera_sensor_flash_data flash_imx074 = {
 	.flash_type	= MSM_CAMERA_FLASH_LED,
-#ifdef CONFIG_MSM_CAMERA_FLASH
-	.flash_src	= &msm_flash_src
-#endif
+	.flash_src	= &msm_flash_src,
+	.board_info     = &sc628a_flash_i2c_info,
+	.bus_id         = MSM_8960_GSBI4_QUP_I2C_BUS_ID,
 };
 
 static struct msm_camera_csi_lane_params imx074_csi_lane_params = {
@@ -715,9 +732,9 @@
 
 static struct msm_camera_sensor_flash_data flash_imx091 = {
 	.flash_type	= MSM_CAMERA_FLASH_LED,
-#ifdef CONFIG_MSM_CAMERA_FLASH
-	.flash_src	= &msm_flash_src
-#endif
+	.flash_src	= &msm_flash_src,
+	.board_info     = &sc628a_flash_i2c_info,
+	.bus_id         = MSM_8960_GSBI4_QUP_I2C_BUS_ID,
 };
 
 static struct msm_camera_sensor_platform_info sensor_board_info_imx091 = {
@@ -876,11 +893,6 @@
 	I2C_BOARD_INFO("s5k3l1yx", 0x20),
 	.platform_data = &msm_camera_sensor_s5k3l1yx_data,
 	},
-#ifdef CONFIG_MSM_CAMERA_FLASH_SC628A
-	{
-	I2C_BOARD_INFO("sc628a", 0x6E),
-	},
-#endif
 	{
 	I2C_BOARD_INFO("imx091", 0x34),
 	.platform_data = &msm_camera_sensor_imx091_data,
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 9efedb1..1a3d90d 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -396,7 +396,6 @@
 #define MAX_VOLTAGE_MV		4200
 #define CHG_TERM_MA		100
 static struct pm8921_charger_platform_data pm8921_chg_pdata __devinitdata = {
-	.safety_time		= 180,
 	.update_time		= 60000,
 	.max_voltage		= MAX_VOLTAGE_MV,
 	.min_voltage		= 3200,
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 42b9816..9efc60a 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -2888,8 +2888,8 @@
 	/* Fixup data that needs to change based on GPU ID */
 	if (cpu_is_msm8960ab()) {
 		kgsl_3d0_pdata->chipid = ADRENO_CHIPID(3, 2, 1, 0);
-		/* 8960PRO nominal clock rate is 325Mhz instead of 320Mhz */
-		kgsl_3d0_pdata->pwrlevel[1].gpu_freq = 325000000;
+		/* 8960PRO nominal clock rate is 320Mhz */
+		kgsl_3d0_pdata->pwrlevel[1].gpu_freq = 320000000;
 	} else {
 		kgsl_3d0_pdata->iommu_count = 1;
 		if (SOCINFO_VERSION_MAJOR(soc_platform_version) == 1) {
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 19fb222..98a82b1 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -49,17 +49,6 @@
 #include "modem_notifier.h"
 #include "lpm_resources.h"
 
-#define MSM_KERNEL_EBI1_MEM_SIZE	0x280000
-
-#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
-static unsigned kernel_ebi1_mem_size = MSM_KERNEL_EBI1_MEM_SIZE;
-static int __init kernel_ebi1_mem_size_setup(char *p)
-{
-	kernel_ebi1_mem_size = memparse(p, NULL);
-	return 0;
-}
-early_param("kernel_ebi1_mem_size", kernel_ebi1_mem_size_setup);
-#endif
 
 static struct memtype_reserve msm8974_reserve_table[] __initdata = {
 	[MEMTYPE_SMI] = {
@@ -77,13 +66,6 @@
 	return MEMTYPE_EBI1;
 }
 
-static void __init reserve_ebi_memory(void)
-{
-#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
-	msm8974_reserve_table[MEMTYPE_EBI1].size += kernel_ebi1_mem_size;
-#endif
-}
-
 static struct resource smd_resource[] = {
 	{
 		.name	= "modem_smd_in",
@@ -246,14 +228,8 @@
 	}
 };
 
-static void __init msm8974_calculate_reserve_sizes(void)
-{
-	reserve_ebi_memory();
-}
-
 static struct reserve_info msm8974_reserve_info __initdata = {
 	.memtype_reserve_table = msm8974_reserve_table,
-	.calculate_reserve_sizes = msm8974_calculate_reserve_sizes,
 	.paddr_to_memtype = msm8974_paddr_to_memtype,
 };
 
@@ -501,7 +477,6 @@
 	OF_DEV_AUXDATA("qcom,pil-q6v5-lpass",   0xFE200000, \
 			"pil-q6v5-lpass", NULL),
 	OF_DEV_AUXDATA("qcom,pil-q6v5-mss", 0xFC880000, "pil-q6v5-mss", NULL),
-	OF_DEV_AUXDATA("qcom,pil-mba",     0xFC820000, "pil-mba", NULL),
 	OF_DEV_AUXDATA("qcom,pil-pronto", 0xFB21B000, \
 			"pil_pronto", NULL),
 	OF_DEV_AUXDATA("arm,coresight-tmc", 0xFC322000, \
diff --git a/arch/arm/mach-msm/board-9615-gpiomux.c b/arch/arm/mach-msm/board-9615-gpiomux.c
index 9339638..e5b7678 100644
--- a/arch/arm/mach-msm/board-9615-gpiomux.c
+++ b/arch/arm/mach-msm/board-9615-gpiomux.c
@@ -37,7 +37,7 @@
 
 static struct gpiomux_setting gsbi5 = {
 	.func = GPIOMUX_FUNC_1,
-	.drv = GPIOMUX_DRV_8MA,
+	.drv = GPIOMUX_DRV_2MA,
 	.pull = GPIOMUX_PULL_NONE,
 };
 
@@ -201,6 +201,23 @@
 	},
 };
 
+static struct gpiomux_setting sd_card_det = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_IN,
+};
+
+struct msm_gpiomux_config sd_card_det_config[] __initdata = {
+	{
+		.gpio = 80,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sd_card_det,
+			[GPIOMUX_SUSPENDED] = &sd_card_det,
+		},
+	},
+};
+
 #ifdef CONFIG_LTC4088_CHARGER
 static struct msm_gpiomux_config
 	msm9615_ltc4088_charger_config[] __initdata = {
@@ -362,6 +379,8 @@
 
 	msm_gpiomux_install(msm9615_ps_hold_config,
 			ARRAY_SIZE(msm9615_ps_hold_config));
+	msm_gpiomux_install(sd_card_det_config,
+			ARRAY_SIZE(sd_card_det_config));
 	msm_gpiomux_install(msm9615_sdcc2_configs,
 			ARRAY_SIZE(msm9615_sdcc2_configs));
 #ifdef CONFIG_LTC4088_CHARGER
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index b9da615..e0a6b4d 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -762,6 +762,7 @@
 	.disable_reset_on_disconnect	= true,
 	.enable_lpm_on_dev_suspend	= true,
 	.core_clk_always_on_workaround = true,
+	.delay_lpm_on_disconnect = true,
 };
 
 
@@ -907,6 +908,7 @@
 	&msm_cpu_fe,
 	&msm_stub_codec,
 	&msm_voice,
+	&msm_dtmf,
 	&msm_voip,
 	&msm_i2s_cpudai0,
 	&msm_i2s_cpudai1,
@@ -939,6 +941,7 @@
 	&msm9615_rpm_stat_device,
 	&msm9615_rpm_master_stat_device,
 	&msm_tsens_device,
+	&msm9615_pm_8x60,
 };
 
 static void __init msm9615_i2c_init(void)
diff --git a/arch/arm/mach-msm/board-9625-gpiomux.c b/arch/arm/mach-msm/board-9625-gpiomux.c
index c4e174b..6f36ef2 100644
--- a/arch/arm/mach-msm/board-9625-gpiomux.c
+++ b/arch/arm/mach-msm/board-9625-gpiomux.c
@@ -36,6 +36,12 @@
 	.pull = GPIOMUX_PULL_NONE,
 };
 
+static struct gpiomux_setting gpio_i2c_config = {
+	.func = GPIOMUX_FUNC_3,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
 static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
 	{
 		.gpio      = 8,	       /* BLSP1 UART TX */
@@ -50,6 +56,18 @@
 		},
 	},
 	{
+		.gpio      = 10,		/* BLSP1 QUP3 I2C_DAT */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+		},
+	},
+	{
+		.gpio      = 11,		/* BLSP1 QUP3 I2C_CLK */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+		},
+	},
+	{
 		.gpio      = 69,		/* BLSP6 QUP SPI_CS_N */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
@@ -152,6 +170,30 @@
 	},
 };
 
+static struct gpiomux_setting wlan_ath6kl_active_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_LOW,
+};
+
+static struct gpiomux_setting wlan_ath6kl_suspend_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_IN,
+};
+
+static struct msm_gpiomux_config wlan_ath6kl_configs[] __initdata = {
+	{
+		.gpio      = 62,/* CHIP_PWD_L */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &wlan_ath6kl_active_config,
+			[GPIOMUX_SUSPENDED] = &wlan_ath6kl_suspend_config,
+		},
+	},
+};
+
 void __init msm9625_init_gpiomux(void)
 {
 	int rc;
@@ -164,4 +206,6 @@
 
 	msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
 	msm_gpiomux_install(sdc3_configs, ARRAY_SIZE(sdc3_configs));
+	msm_gpiomux_install(wlan_ath6kl_configs,
+		ARRAY_SIZE(wlan_ath6kl_configs));
 }
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 5c7eebe..3e5fc9d 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -35,6 +35,7 @@
 #include <mach/rpm-smd.h>
 #include <mach/rpm-regulator-smd.h>
 #include "board-dt.h"
+#include <mach/msm_bus_board.h>
 #include "clock.h"
 #include "modem_notifier.h"
 #include "lpm_resources.h"
@@ -108,6 +109,8 @@
 			"msm_sdcc.2", NULL),
 	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9864000, \
 			"msm_sdcc.3", NULL),
+	OF_DEV_AUXDATA("qcom,msm-tsens", 0xFC4A8000, \
+			"msm-tsens", NULL),
 	{}
 };
 
@@ -251,6 +254,97 @@
 	}
 };
 
+#define BIMC_BASE	0xfc380000
+#define BIMC_SIZE	0x0006A000
+#define SYS_NOC_BASE	0xfc460000
+#define PERIPH_NOC_BASE 0xFC468000
+#define CONFIG_NOC_BASE	0xfc480000
+#define NOC_SIZE	0x00004000
+
+static struct resource bimc_res[] = {
+	{
+		.start = BIMC_BASE,
+		.end = BIMC_BASE + BIMC_SIZE,
+		.flags = IORESOURCE_MEM,
+		.name = "bimc_mem",
+	},
+};
+
+static struct resource sys_noc_res[] = {
+	{
+		.start = SYS_NOC_BASE,
+		.end = SYS_NOC_BASE + NOC_SIZE,
+		.flags = IORESOURCE_MEM,
+		.name = "sys_noc_mem",
+	},
+};
+
+static struct resource config_noc_res[] = {
+	{
+		.start = CONFIG_NOC_BASE,
+		.end = CONFIG_NOC_BASE + NOC_SIZE,
+		.flags = IORESOURCE_MEM,
+		.name = "config_noc_mem",
+	},
+};
+
+static struct resource periph_noc_res[] = {
+	{
+		.start = PERIPH_NOC_BASE,
+		.end = PERIPH_NOC_BASE + NOC_SIZE,
+		.flags = IORESOURCE_MEM,
+		.name = "periph_noc_mem",
+	},
+};
+
+static struct platform_device msm_bus_sys_noc = {
+	.name  = "msm_bus_fabric",
+	.id    =  MSM_BUS_FAB_SYS_NOC,
+	.num_resources = ARRAY_SIZE(sys_noc_res),
+	.resource = sys_noc_res,
+};
+
+static struct platform_device msm_bus_bimc = {
+	.name  = "msm_bus_fabric",
+	.id    = MSM_BUS_FAB_BIMC,
+	.num_resources = ARRAY_SIZE(bimc_res),
+	.resource = bimc_res,
+};
+
+static struct platform_device msm_bus_periph_noc = {
+	.name  = "msm_bus_fabric",
+	.id    = MSM_BUS_FAB_PERIPH_NOC,
+	.num_resources = ARRAY_SIZE(periph_noc_res),
+	.resource = periph_noc_res,
+};
+
+static struct platform_device msm_bus_config_noc = {
+	.name  = "msm_bus_fabric",
+	.id    = MSM_BUS_FAB_CONFIG_NOC,
+	.num_resources = ARRAY_SIZE(config_noc_res),
+	.resource = config_noc_res,
+};
+
+static struct platform_device *msm_bus_9625_devices[] = {
+	&msm_bus_sys_noc,
+	&msm_bus_bimc,
+	&msm_bus_periph_noc,
+	&msm_bus_config_noc,
+};
+
+static void __init msm9625_init_buses(void)
+{
+#ifdef CONFIG_MSM_BUS_SCALING
+	msm_bus_sys_noc.dev.platform_data =
+		&msm_bus_9625_sys_noc_pdata;
+	msm_bus_bimc.dev.platform_data = &msm_bus_9625_bimc_pdata;
+	msm_bus_periph_noc.dev.platform_data = &msm_bus_9625_periph_noc_pdata;
+	msm_bus_config_noc.dev.platform_data = &msm_bus_9625_config_noc_pdata;
+#endif
+	platform_add_devices(msm_bus_9625_devices,
+				ARRAY_SIZE(msm_bus_9625_devices));
+}
+
 void __init msm9625_add_devices(void)
 {
 	platform_device_register(&msm_device_smd_9625);
@@ -271,6 +365,7 @@
 	rpm_regulator_smd_driver_init();
 	msm_spm_device_init();
 	msm_clock_init(&msm9625_clock_init_data);
+	msm9625_init_buses();
 }
 
 void __init msm9625_init(void)
diff --git a/arch/arm/mach-msm/board-msm7627a-bt.c b/arch/arm/mach-msm/board-msm7627a-bt.c
index bcc9645..1c2d8a2 100644
--- a/arch/arm/mach-msm/board-msm7627a-bt.c
+++ b/arch/arm/mach-msm/board-msm7627a-bt.c
@@ -103,11 +103,12 @@
 	if (machine_is_msm7627a_qrd1())
 		gpio_bt_sys_rest_en = 114;
 	if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
-				|| machine_is_msm8625_evt()
-				|| machine_is_qrd_skud_prime())
+				|| machine_is_msm8625_evt())
 		gpio_bt_sys_rest_en = 16;
 	if (machine_is_msm8625_qrd7())
 		gpio_bt_sys_rest_en = 88;
+	if (machine_is_qrd_skud_prime())
+		gpio_bt_sys_rest_en = 35;
 	if (machine_is_msm7627a_qrd3()) {
 		if (socinfo == 0x70002)
 			gpio_bt_sys_rest_en = 88;
@@ -976,9 +977,6 @@
 	int i, rc = 0;
 	struct device *dev;
 
-	if (machine_is_qrd_skud_prime())
-		return;
-
 	gpio_bt_config();
 
 	rc = i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 13c4be2..4e14ff3 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -375,7 +375,8 @@
 };
 
 /* 8625 PM platform data */
-static struct msm_pm_platform_data msm8625_pm_data[MSM_PM_SLEEP_MODE_NR * 2] = {
+static struct msm_pm_platform_data
+		msm8625_pm_data[MSM_PM_SLEEP_MODE_NR * CONFIG_NR_CPUS] = {
 	/* CORE0 entries */
 	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
 					.idle_supported = 1,
@@ -433,6 +434,44 @@
 					.residency = 10,
 	},
 
+	/* picked latency & redisdency values from 7x30 */
+	[MSM_PM_MODE(2, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 0,
+					.suspend_enabled = 0,
+					.latency = 500,
+					.residency = 6000,
+	},
+
+	[MSM_PM_MODE(2, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 1,
+					.suspend_enabled = 1,
+					.latency = 2,
+					.residency = 10,
+	},
+
+	/* picked latency & redisdency values from 7x30 */
+	[MSM_PM_MODE(3, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 0,
+					.suspend_enabled = 0,
+					.latency = 500,
+					.residency = 6000,
+	},
+
+	[MSM_PM_MODE(3, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 1,
+					.suspend_enabled = 1,
+					.latency = 2,
+					.residency = 10,
+	},
+
 };
 
 static struct msm_pm_boot_platform_data msm_pm_8625_boot_pdata __initdata = {
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index fd322e9..023ce86 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -349,7 +349,8 @@
 };
 
 /* 8625 PM platform data */
-static struct msm_pm_platform_data msm8625_pm_data[MSM_PM_SLEEP_MODE_NR * 2] = {
+static struct msm_pm_platform_data
+		msm8625_pm_data[MSM_PM_SLEEP_MODE_NR * CONFIG_NR_CPUS] = {
 	/* CORE0 entries */
 	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
 					.idle_supported = 1,
@@ -407,6 +408,44 @@
 					.residency = 10,
 	},
 
+	/* picked latency & redisdency values from 7x30 */
+	[MSM_PM_MODE(2, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 0,
+					.suspend_enabled = 0,
+					.latency = 500,
+					.residency = 6000,
+	},
+
+	[MSM_PM_MODE(2, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 1,
+					.suspend_enabled = 1,
+					.latency = 2,
+					.residency = 10,
+	},
+
+	/* picked latency & redisdency values from 7x30 */
+	[MSM_PM_MODE(3, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 0,
+					.suspend_enabled = 0,
+					.latency = 500,
+					.residency = 6000,
+	},
+
+	[MSM_PM_MODE(3, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 1,
+					.suspend_enabled = 1,
+					.latency = 2,
+					.residency = 10,
+	},
+
 };
 
 static struct msm_pm_boot_platform_data msm_pm_8625_boot_pdata __initdata = {
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 3c417c3..5e5e274 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -3510,24 +3510,26 @@
 		.ctl_val = CC_BANKED(9, 6, n), \
 	}
 
-static struct clk_freq_tbl clk_tbl_gfx3d_8960ab[] = {
-	F_GFX3D(        0, gnd,  0,  0),
-	F_GFX3D( 27000000, pxo,  0,  0),
-	F_GFX3D( 48000000, pll8, 1,  8),
-	F_GFX3D( 54857000, pll8, 1,  7),
-	F_GFX3D( 64000000, pll8, 1,  6),
-	F_GFX3D( 76800000, pll8, 1,  5),
-	F_GFX3D( 96000000, pll8, 1,  4),
-	F_GFX3D(128000000, pll8, 1,  3),
-	F_GFX3D(145455000, pll2, 2, 11),
-	F_GFX3D(160000000, pll2, 1,  5),
-	F_GFX3D(177778000, pll2, 2,  9),
-	F_GFX3D(200000000, pll2, 1,  4),
-	F_GFX3D(228571000, pll2, 2,  7),
-	F_GFX3D(266667000, pll2, 1,  3),
-	F_GFX3D(320000000, pll2, 2,  5),
-	F_GFX3D(325000000, pll3, 1,  2),
-	F_GFX3D(400000000, pll2, 1,  2),
+/*Shared by 8064, 8930, and 8960ab*/
+static struct clk_freq_tbl clk_tbl_gfx3d[] = {
+	F_GFX3D(        0, gnd,   0,  0),
+	F_GFX3D( 27000000, pxo,   0,  0),
+	F_GFX3D( 48000000, pll8,  1,  8),
+	F_GFX3D( 54857000, pll8,  1,  7),
+	F_GFX3D( 64000000, pll8,  1,  6),
+	F_GFX3D( 76800000, pll8,  1,  5),
+	F_GFX3D( 96000000, pll8,  1,  4),
+	F_GFX3D(128000000, pll8,  1,  3),
+	F_GFX3D(145455000, pll2,  2, 11),
+	F_GFX3D(160000000, pll2,  1,  5),
+	F_GFX3D(177778000, pll2,  2,  9),
+	F_GFX3D(192000000, pll8,  1,  2),
+	F_GFX3D(200000000, pll2,  1,  4),
+	F_GFX3D(228571000, pll2,  2,  7),
+	F_GFX3D(266667000, pll2,  1,  3),
+	F_GFX3D(320000000, pll2,  2,  5),
+	F_GFX3D(400000000, pll2,  1,  2),
+	F_GFX3D(450000000, pll15, 1,  2),
 	F_END
 };
 
@@ -3552,28 +3554,7 @@
 	F_END
 };
 
-static struct clk_freq_tbl clk_tbl_gfx3d_8064[] = {
-	F_GFX3D(        0, gnd,   0,  0),
-	F_GFX3D( 27000000, pxo,   0,  0),
-	F_GFX3D( 48000000, pll8,  1,  8),
-	F_GFX3D( 54857000, pll8,  1,  7),
-	F_GFX3D( 64000000, pll8,  1,  6),
-	F_GFX3D( 76800000, pll8,  1,  5),
-	F_GFX3D( 96000000, pll8,  1,  4),
-	F_GFX3D(128000000, pll8,  1,  3),
-	F_GFX3D(145455000, pll2,  2, 11),
-	F_GFX3D(160000000, pll2,  1,  5),
-	F_GFX3D(177778000, pll2,  2,  9),
-	F_GFX3D(192000000, pll8,  1,  2),
-	F_GFX3D(200000000, pll2,  1,  4),
-	F_GFX3D(228571000, pll2,  2,  7),
-	F_GFX3D(266667000, pll2,  1,  3),
-	F_GFX3D(400000000, pll2,  1,  2),
-	F_GFX3D(450000000, pll15, 1,  2),
-	F_END
-};
-
-static struct clk_freq_tbl clk_tbl_gfx3d_8930[] = {
+static struct clk_freq_tbl clk_tbl_gfx3d_8930ab[] = {
 	F_GFX3D(        0, gnd,   0,  0),
 	F_GFX3D( 27000000, pxo,   0,  0),
 	F_GFX3D( 48000000, pll8,  1,  8),
@@ -3591,7 +3572,7 @@
 	F_GFX3D(266667000, pll2,  1,  3),
 	F_GFX3D(320000000, pll2,  2,  5),
 	F_GFX3D(400000000, pll2,  1,  2),
-	F_GFX3D(450000000, pll15, 1,  2),
+	F_GFX3D(500000000, pll15, 1,  2),
 	F_END
 };
 
@@ -3619,6 +3600,12 @@
 	[VDD_DIG_HIGH]    = 450000000
 };
 
+static unsigned long fmax_gfx3d_8930ab[VDD_DIG_NUM] = {
+	[VDD_DIG_LOW]     = 192000000,
+	[VDD_DIG_NOMINAL] = 320000000,
+	[VDD_DIG_HIGH]    = 500000000
+};
+
 static struct bank_masks bmnd_info_gfx3d = {
 	.bank_sel_mask =		BIT(11),
 	.bank0_mask = {
@@ -3651,7 +3638,7 @@
 	.ns_reg = GFX3D_NS_REG,
 	.root_en_mask = BIT(2),
 	.set_rate = set_rate_mnd_banked,
-	.freq_tbl = clk_tbl_gfx3d_8960,
+	.freq_tbl = clk_tbl_gfx3d,
 	.bank_info = &bmnd_info_gfx3d,
 	.current_freq = &rcg_dummy_freq,
 	.c = {
@@ -4366,6 +4353,12 @@
 	[VDD_DIG_HIGH]    = 266670000,
 };
 
+static unsigned long fmax_vcodec_8930ab[VDD_DIG_NUM] = {
+	[VDD_DIG_LOW]     = 100000000,
+	[VDD_DIG_NOMINAL] = 200000000,
+	[VDD_DIG_HIGH]    = 266670000
+};
+
 #define F_VPE(f, s, d) \
 	{ \
 		.freq_hz = f, \
@@ -6519,8 +6512,7 @@
 	}
 
 	/*
-	 * Program PLL15 to 900MHz with ref clk = 27MHz and
-	 * only enable PLL main output.
+	 * Change PLL15 configuration based on the SoC we're running on.
 	 */
 	if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
 		pll15_config.l = 0x21 | BVAL(31, 7, 0x600);
@@ -6529,6 +6521,13 @@
 		configure_sr_pll(&pll15_config, &pll15_regs, 0);
 		/* Disable AUX and BIST outputs */
 		writel_relaxed(0, MM_PLL3_TEST_CTL_REG);
+	} else if (cpu_is_msm8930ab()) {
+		pll15_config.l = 0x25 | BVAL(31, 7, 0x600);
+		pll15_config.m = 0x25;
+		pll15_config.n = 0x3E7;
+		configure_sr_pll(&pll15_config, &pll15_regs, 0);
+		/* Disable AUX and BIST outputs */
+		writel_relaxed(0, MM_PLL3_TEST_CTL_REG);
 	}
 }
 
@@ -6558,7 +6557,6 @@
 			sizeof(msm_clocks_8960_common));
 	if (cpu_is_msm8960ab()) {
 		pll3_clk.c.rate = 650000000;
-		gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8960ab;
 		gfx3d_clk.c.fmax[VDD_DIG_LOW] = 192000000;
 		gfx3d_clk.c.fmax[VDD_DIG_NOMINAL] = 325000000;
 		gfx3d_clk.c.fmax[VDD_DIG_HIGH] = 400000000;
@@ -6573,6 +6571,7 @@
 
 		gmem_axi_clk.c.depends = &gfx3d_axi_clk.c;
 	} else if (cpu_is_msm8960()) {
+		gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8960;
 		memcpy(msm_clocks_8960 + ARRAY_SIZE(msm_clocks_8960_common),
 			 msm_clocks_8960_only, sizeof(msm_clocks_8960_only));
 		msm8960_clock_init_data.size -=
@@ -6583,11 +6582,9 @@
 	 * clocks which differ between chips.
 	 */
 	if (cpu_is_apq8064()) {
-		gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8064;
 		gfx3d_clk.c.fmax = fmax_gfx3d_8064;
 	}
 	if (cpu_is_apq8064ab()) {
-		gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8064;
 		gfx3d_clk.c.fmax = fmax_gfx3d_8064ab;
 	}
 	if ((cpu_is_apq8064() &&
@@ -6610,15 +6607,19 @@
 	 * Change the freq tables and voltage requirements for
 	 * clocks which differ between 8960 and 8930.
 	 */
-	if (cpu_is_msm8930() || cpu_is_msm8627()) {
+	if (cpu_is_msm8930() || cpu_is_msm8627())
 		gfx3d_clk.c.fmax = fmax_gfx3d_8930;
-	} else if (cpu_is_msm8930aa()) {
+	else if (cpu_is_msm8930aa())
 		gfx3d_clk.c.fmax = fmax_gfx3d_8930aa;
-	}
 	if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
-		gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8930;
 		pll15_clk.c.rate = 900000000;
 		gmem_axi_clk.c.depends = &gfx3d_axi_clk_8930.c;
+	} else if (cpu_is_msm8930ab()) {
+		gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8930ab;
+		pll15_clk.c.rate = 1000000000;
+		gfx3d_clk.c.fmax = fmax_gfx3d_8930ab;
+		gmem_axi_clk.c.depends = &gfx3d_axi_clk_8930.c;
+		vcodec_clk.c.fmax = fmax_vcodec_8930ab;
 	}
 	if ((readl_relaxed(PRNG_CLK_NS_REG) & 0x7F) == 0x2B)
 		prng_clk.freq_tbl = clk_tbl_prng_64;
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 76b8abf..777e0bf 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -2829,8 +2829,8 @@
 	.div_src_val = BVAL(10, 8, dsipll0_byte_mm_source_val),
 };
 static struct clk_freq_tbl pixel_freq = {
-	.src_clk = &dsipll0_byte_clk_src,
-	.div_src_val = BVAL(10, 8, dsipll0_byte_mm_source_val),
+	.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;
@@ -5022,7 +5022,6 @@
 	CLK_LOOKUP("xo",	cxo_clk_src.c,	"msm_otg"),
 	CLK_LOOKUP("xo",	cxo_clk_src.c,	"pil-q6v5-lpass"),
 	CLK_LOOKUP("xo",	cxo_clk_src.c,	"pil-q6v5-mss"),
-	CLK_LOOKUP("xo",	cxo_clk_src.c,	"pil-mba"),
 	CLK_LOOKUP("xo",	cxo_clk_src.c,	"fb000000.qcom,wcnss-wlan"),
 	CLK_LOOKUP("xo",	cxo_clk_src.c,	"pil_pronto"),
 	CLK_LOOKUP("measure",	measure_clk.c,	"debug"),
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index 3816b54..5a9799a 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -607,7 +607,7 @@
 	},
 	.c = {
 		.dbg_name = "smi_2x_axi_clk",
-		.ops = &clk_ops_branch,
+		.ops = &clk_ops_smi_2x,
 		CLK_INIT(smi_2x_axi_clk.c),
 	},
 };
@@ -3101,7 +3101,7 @@
 	.c = {
 		.dbg_name = "pcm_clk",
 		.ops = &clk_ops_rcg,
-		VDD_DIG_FMAX_MAP1(LOW, 24580000),
+		VDD_DIG_FMAX_MAP1(LOW, 27000000),
 		CLK_INIT(pcm_clk.c),
 		.rate = ULONG_MAX,
 	},
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index b9362cf..0b8919b 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -2124,6 +2124,26 @@
 	CLK_LOOKUP("dfab_clk", pnoc_sps_clk.c, "msm_sps"),
 
 	CLK_LOOKUP("a5_m_clk", a5_m_clk, ""),
+
+	/* Coresight QDSS clocks */
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc322000.tmc"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc318000.tpiu"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc31c000.replicator"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc307000.tmc"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc31b000.funnel"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc319000.funnel"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc31a000.funnel"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc321000.stm"),
+
+	CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc322000.tmc"),
+	CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc318000.tpiu"),
+	CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc31c000.replicator"),
+	CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc307000.tmc"),
+	CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc31b000.funnel"),
+	CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc319000.funnel"),
+	CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc31a000.funnel"),
+	CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc321000.stm"),
+
 };
 
 static struct pll_config_regs gpll0_regs __initdata = {
diff --git a/arch/arm/mach-msm/clock-local.c b/arch/arm/mach-msm/clock-local.c
index d2260cb..c43ca46 100644
--- a/arch/arm/mach-msm/clock-local.c
+++ b/arch/arm/mach-msm/clock-local.c
@@ -839,6 +839,14 @@
 	.set_flags = branch_clk_set_flags,
 };
 
+struct clk_ops clk_ops_smi_2x = {
+	.prepare = branch_clk_enable,
+	.unprepare = branch_clk_disable,
+	.is_enabled = branch_clk_is_enabled,
+	.get_parent = branch_clk_get_parent,
+	.handoff = branch_clk_handoff,
+};
+
 struct clk_ops clk_ops_reset = {
 	.reset = branch_clk_reset,
 };
diff --git a/arch/arm/mach-msm/clock-local.h b/arch/arm/mach-msm/clock-local.h
index 1873343..fca6486 100644
--- a/arch/arm/mach-msm/clock-local.h
+++ b/arch/arm/mach-msm/clock-local.h
@@ -153,6 +153,7 @@
 };
 
 extern struct clk_ops clk_ops_branch;
+extern struct clk_ops clk_ops_smi_2x;
 extern struct clk_ops clk_ops_reset;
 
 int branch_reset(struct branch *b, enum clk_reset_action action);
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index 1603c93..e7a596d 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -67,7 +67,6 @@
 static int pll_byte_clk_rate;
 static int pll_pclk_rate;
 static int pll_initialized;
-static int pll_enabled;
 static struct clk *mdss_dsi_ahb_clk;
 static unsigned long dsi_pll_rate;
 
@@ -208,15 +207,12 @@
 	return 0;
 }
 
-static int mdss_dsi_pll_enable(struct clk *c)
+static int __mdss_dsi_pll_enable(struct clk *c)
 {
 	u32 status;
 	u32 max_reads, timeout_us;
 	int i;
 
-	if (pll_enabled)
-		return 0;
-
 	if (!pll_initialized) {
 		if (dsi_pll_rate)
 			mdss_dsi_pll_byte_set_rate(c, dsi_pll_rate);
@@ -266,12 +262,11 @@
 
 	pr_debug("%s: **** PLL Lock success\n", __func__);
 	clk_disable(mdss_dsi_ahb_clk);
-	pll_enabled = 1;
 
 	return 0;
 }
 
-static void mdss_dsi_pll_disable(struct clk *c)
+static void __mdss_dsi_pll_disable(void)
 {
 	if (!mdss_dsi_ahb_clk)
 		pr_err("%s: mdss_dsi_ahb_clk not initialized\n",
@@ -282,7 +277,40 @@
 	clk_disable(mdss_dsi_ahb_clk);
 	pr_debug("%s: **** disable pll Initialize\n", __func__);
 	pll_initialized = 0;
-	pll_enabled = 0;
+}
+
+static DEFINE_SPINLOCK(dsipll_lock);
+static int dsipll_refcount;
+
+static void mdss_dsi_pll_disable(struct clk *c)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dsipll_lock, flags);
+	if (WARN(dsipll_refcount == 0, "DSI PLL clock is unbalanced"))
+		goto out;
+	if (dsipll_refcount == 1)
+		__mdss_dsi_pll_disable();
+	dsipll_refcount--;
+out:
+	spin_unlock_irqrestore(&dsipll_lock, flags);
+}
+
+static int mdss_dsi_pll_enable(struct clk *c)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&dsipll_lock, flags);
+	if (dsipll_refcount == 0) {
+		ret = __mdss_dsi_pll_enable(c);
+		if (ret < 0)
+			goto out;
+	}
+	dsipll_refcount++;
+out:
+	spin_unlock_irqrestore(&dsipll_lock, flags);
+	return ret;
 }
 
 void hdmi_pll_disable(void)
diff --git a/arch/arm/mach-msm/clock-rpm.c b/arch/arm/mach-msm/clock-rpm.c
index daf83e2..63e67b3 100644
--- a/arch/arm/mach-msm/clock-rpm.c
+++ b/arch/arm/mach-msm/clock-rpm.c
@@ -12,37 +12,29 @@
  */
 
 #include <linux/err.h>
+#include <linux/mutex.h>
 #include <mach/clk-provider.h>
 
 #include "rpm_resources.h"
 #include "clock-rpm.h"
 
-#define __clk_rpmrs_set_rate(r, value, ctx, noirq) \
-	((r)->rpmrs_data->set_rate_fn((r), (value), (ctx), (noirq)))
+#define __clk_rpmrs_set_rate(r, value, ctx) \
+	((r)->rpmrs_data->set_rate_fn((r), (value), (ctx)))
 
 #define clk_rpmrs_set_rate_sleep(r, value) \
-	    __clk_rpmrs_set_rate((r), (value), (r)->rpmrs_data->ctx_sleep_id, 0)
-
-#define clk_rpmrs_set_rate_sleep_noirq(r, value) \
-	    __clk_rpmrs_set_rate((r), (value), (r)->rpmrs_data->ctx_sleep_id, 1)
+	    __clk_rpmrs_set_rate((r), (value), (r)->rpmrs_data->ctx_sleep_id)
 
 #define clk_rpmrs_set_rate_active(r, value) \
-	   __clk_rpmrs_set_rate((r), (value), (r)->rpmrs_data->ctx_active_id, 0)
-
-#define clk_rpmrs_set_rate_active_noirq(r, value) \
-	   __clk_rpmrs_set_rate((r), (value), (r)->rpmrs_data->ctx_active_id, 1)
+	   __clk_rpmrs_set_rate((r), (value), (r)->rpmrs_data->ctx_active_id)
 
 static int clk_rpmrs_set_rate(struct rpm_clk *r, uint32_t value,
-			   uint32_t context, int noirq)
+			   uint32_t context)
 {
 	struct msm_rpm_iv_pair iv = {
 		.id = r->rpm_clk_id,
 		.value = value,
 	};
-	if (noirq)
-		return msm_rpmrs_set_noirq(context, &iv, 1);
-	else
-		return msm_rpmrs_set(context, &iv, 1);
+	return msm_rpmrs_set(context, &iv, 1);
 }
 
 static int clk_rpmrs_get_rate(struct rpm_clk *r)
@@ -72,7 +64,7 @@
 }
 
 static int clk_rpmrs_set_rate_smd(struct rpm_clk *r, uint32_t value,
-				uint32_t context, int noirq)
+				uint32_t context)
 {
 	struct msm_rpm_kvp kvp = {
 		.key = r->rpm_key,
@@ -80,12 +72,8 @@
 		.length = sizeof(value),
 	};
 
-	if (noirq)
-		return msm_rpm_send_message_noirq(context,
-				r->rpm_res_type, r->rpm_clk_id, &kvp, 1);
-	else
-		return msm_rpm_send_message(context, r->rpm_res_type,
-						r->rpm_clk_id, &kvp, 1);
+	return msm_rpm_send_message(context, r->rpm_res_type, r->rpm_clk_id,
+			&kvp, 1);
 }
 
 static int clk_rpmrs_handoff_smd(struct rpm_clk *r)
@@ -94,8 +82,7 @@
 }
 
 struct clk_rpmrs_data {
-	int (*set_rate_fn)(struct rpm_clk *r, uint32_t value,
-				uint32_t context, int noirq);
+	int (*set_rate_fn)(struct rpm_clk *r, uint32_t value, uint32_t context);
 	int (*get_rate_fn)(struct rpm_clk *r);
 	int (*handoff_fn)(struct rpm_clk *r);
 	int ctx_active_id;
@@ -117,11 +104,10 @@
 	.ctx_sleep_id = MSM_RPM_CTX_SLEEP_SET,
 };
 
-static DEFINE_SPINLOCK(rpm_clock_lock);
+static DEFINE_MUTEX(rpm_clock_lock);
 
-static int rpm_clk_enable(struct clk *clk)
+static int rpm_clk_prepare(struct clk *clk)
 {
-	unsigned long flags;
 	struct rpm_clk *r = to_rpm_clk(clk);
 	uint32_t value;
 	int rc = 0;
@@ -129,7 +115,7 @@
 	unsigned long peer_khz = 0, peer_sleep_khz = 0;
 	struct rpm_clk *peer = r->peer;
 
-	spin_lock_irqsave(&rpm_clock_lock, flags);
+	mutex_lock(&rpm_clock_lock);
 
 	this_khz = r->last_set_khz;
 	/* Don't send requests to the RPM if the rate has not been set. */
@@ -148,7 +134,7 @@
 	if (r->branch)
 		value = !!value;
 
-	rc = clk_rpmrs_set_rate_active_noirq(r, value);
+	rc = clk_rpmrs_set_rate_active(r, value);
 	if (rc)
 		goto out;
 
@@ -156,28 +142,27 @@
 	if (r->branch)
 		value = !!value;
 
-	rc = clk_rpmrs_set_rate_sleep_noirq(r, value);
+	rc = clk_rpmrs_set_rate_sleep(r, value);
 	if (rc) {
 		/* Undo the active set vote and restore it to peer_khz */
 		value = peer_khz;
-		rc = clk_rpmrs_set_rate_active_noirq(r, value);
+		rc = clk_rpmrs_set_rate_active(r, value);
 	}
 
 out:
 	if (!rc)
 		r->enabled = true;
 
-	spin_unlock_irqrestore(&rpm_clock_lock, flags);
+	mutex_unlock(&rpm_clock_lock);
 
 	return rc;
 }
 
-static void rpm_clk_disable(struct clk *clk)
+static void rpm_clk_unprepare(struct clk *clk)
 {
-	unsigned long flags;
 	struct rpm_clk *r = to_rpm_clk(clk);
 
-	spin_lock_irqsave(&rpm_clock_lock, flags);
+	mutex_lock(&rpm_clock_lock);
 
 	if (r->last_set_khz) {
 		uint32_t value;
@@ -192,30 +177,29 @@
 		}
 
 		value = r->branch ? !!peer_khz : peer_khz;
-		rc = clk_rpmrs_set_rate_active_noirq(r, value);
+		rc = clk_rpmrs_set_rate_active(r, value);
 		if (rc)
 			goto out;
 
 		value = r->branch ? !!peer_sleep_khz : peer_sleep_khz;
-		rc = clk_rpmrs_set_rate_sleep_noirq(r, value);
+		rc = clk_rpmrs_set_rate_sleep(r, value);
 	}
 	r->enabled = false;
 out:
-	spin_unlock_irqrestore(&rpm_clock_lock, flags);
+	mutex_unlock(&rpm_clock_lock);
 
 	return;
 }
 
 static int rpm_clk_set_rate(struct clk *clk, unsigned long rate)
 {
-	unsigned long flags;
 	struct rpm_clk *r = to_rpm_clk(clk);
 	unsigned long this_khz, this_sleep_khz;
 	int rc = 0;
 
 	this_khz = DIV_ROUND_UP(rate, r->factor);
 
-	spin_lock_irqsave(&rpm_clock_lock, flags);
+	mutex_lock(&rpm_clock_lock);
 
 	/* Active-only clocks don't care what the rate is during sleep. So,
 	 * they vote for zero. */
@@ -236,12 +220,12 @@
 		}
 
 		value = max(this_khz, peer_khz);
-		rc = clk_rpmrs_set_rate_active_noirq(r, value);
+		rc = clk_rpmrs_set_rate_active(r, value);
 		if (rc)
 			goto out;
 
 		value = max(this_sleep_khz, peer_sleep_khz);
-		rc = clk_rpmrs_set_rate_sleep_noirq(r, value);
+		rc = clk_rpmrs_set_rate_sleep(r, value);
 	}
 	if (!rc) {
 		r->last_set_khz = this_khz;
@@ -249,7 +233,7 @@
 	}
 
 out:
-	spin_unlock_irqrestore(&rpm_clock_lock, flags);
+	mutex_unlock(&rpm_clock_lock);
 
 	return rc;
 }
@@ -319,8 +303,8 @@
 }
 
 struct clk_ops clk_ops_rpm = {
-	.enable = rpm_clk_enable,
-	.disable = rpm_clk_disable,
+	.prepare = rpm_clk_prepare,
+	.unprepare = rpm_clk_unprepare,
 	.set_rate = rpm_clk_set_rate,
 	.get_rate = rpm_clk_get_rate,
 	.is_enabled = rpm_clk_is_enabled,
@@ -330,8 +314,8 @@
 };
 
 struct clk_ops clk_ops_rpm_branch = {
-	.enable = rpm_clk_enable,
-	.disable = rpm_clk_disable,
+	.prepare = rpm_clk_prepare,
+	.unprepare = rpm_clk_unprepare,
 	.is_local = rpm_clk_is_local,
 	.handoff = rpm_clk_handoff,
 };
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index 6c9b413..e0d98b7 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -52,8 +52,11 @@
 static int set_cpu_freq(struct cpufreq_policy *policy, unsigned int new_freq)
 {
 	int ret = 0;
+	int saved_sched_policy = -EINVAL;
+	int saved_sched_rt_prio = -EINVAL;
 	struct cpufreq_freqs freqs;
 	struct cpu_freq *limit = &per_cpu(cpu_freq_info, policy->cpu);
+	struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
 
 	if (limit->limits_init) {
 		if (new_freq > limit->allowed_max) {
@@ -70,11 +73,29 @@
 	freqs.old = policy->cur;
 	freqs.new = new_freq;
 	freqs.cpu = policy->cpu;
+
+	/*
+	 * Put the caller into SCHED_FIFO priority to avoid cpu starvation
+	 * in the acpuclk_set_rate path while increasing frequencies
+	 */
+
+	if (freqs.new > freqs.old && current->policy != SCHED_FIFO) {
+		saved_sched_policy = current->policy;
+		saved_sched_rt_prio = current->rt_priority;
+		sched_setscheduler_nocheck(current, SCHED_FIFO, &param);
+	}
+
 	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
 	ret = acpuclk_set_rate(policy->cpu, new_freq, SETRATE_CPUFREQ);
 	if (!ret)
 		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 
+	/* Restore priority after clock ramp-up */
+	if (freqs.new > freqs.old && saved_sched_policy >= 0) {
+		param.sched_priority = saved_sched_rt_prio;
+		sched_setscheduler_nocheck(current, saved_sched_policy, &param);
+	}
 	return ret;
 }
 
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index fbfa036..abc0e6a 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -1103,10 +1103,10 @@
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.start	= 47,
-		.end	= 47,
+		.start	= MSM_GPIO_TO_INT(47),
+		.end	= MSM_GPIO_TO_INT(47),
 		.name	= "wakeup",
-		.flags	= IORESOURCE_IO,
+		.flags	= IORESOURCE_IRQ,
 	},
 };
 
@@ -1874,7 +1874,7 @@
 	},
 	{
 		.irq_config_id = SMD_Q6,
-		.subsys_name = "q6",
+		.subsys_name = "adsp",
 		.edge = SMD_APPS_QDSP,
 
 		.smd_int.irq_name = "adsp_a11",
@@ -2020,6 +2020,11 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	{
+		.start  = 0x00900000,
+		.end    = 0x00900000 + SZ_16K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
 		.start	= GSS_A5_WDOG_EXPIRED,
 		.end	= GSS_A5_WDOG_EXPIRED,
 		.flags	= IORESOURCE_IRQ,
@@ -2396,16 +2401,28 @@
 };
 
 static struct msm_rpmstats_platform_data msm_rpm_stat_pdata = {
-	.phys_addr_base = 0x0010DD04,
-	.phys_size = SZ_256,
+	.version = 1,
 };
 
+
+static struct resource msm_rpm_stat_resource[] = {
+	{
+		.start	= 0x0010D204,
+		.end	= 0x0010D204 + SZ_8K,
+		.flags	= IORESOURCE_MEM,
+		.name	= "phys_addr_base"
+	},
+};
+
+
 struct platform_device apq8064_rpm_stat_device = {
 	.name = "msm_rpm_stat",
 	.id = -1,
-	.dev = {
+	.resource = msm_rpm_stat_resource,
+	.num_resources	= ARRAY_SIZE(msm_rpm_stat_resource),
+	.dev	= {
 		.platform_data = &msm_rpm_stat_pdata,
-	},
+	}
 };
 
 static struct resource resources_rpm_master_stats[] = {
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index 322347b..c3be6ce 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -547,16 +547,28 @@
 };
 
 static struct msm_rpmstats_platform_data msm_rpm_stat_pdata = {
-	.phys_addr_base = 0x0010DD04,
-	.phys_size = SZ_256,
+	.version = 1,
 };
 
+static struct resource msm_rpm_stat_resource[] = {
+	{
+		.start	= 0x0010D204,
+		.end	= 0x0010D204 + SZ_8K,
+		.flags	= IORESOURCE_MEM,
+		.name	= "phys_addr_base"
+
+	},
+};
+
+
 struct platform_device msm8930_rpm_stat_device = {
 	.name = "msm_rpm_stat",
 	.id = -1,
-	.dev = {
+	.resource = msm_rpm_stat_resource,
+	.num_resources	= ARRAY_SIZE(msm_rpm_stat_resource),
+	.dev	= {
 		.platform_data = &msm_rpm_stat_pdata,
-	},
+	}
 };
 
 static struct resource resources_rpm_master_stats[] = {
@@ -693,6 +705,20 @@
 	.bus_port1 = MSM_BUS_MASTER_MDP_PORT1,
 };
 
+static struct fs_driver_data mdp_fs_data_8930_pm8917 = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ .name = "vsync_clk" },
+		{ .name = "lut_clk" },
+		{ .name = "reset1_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_MDP_PORT0,
+	.bus_port1 = MSM_BUS_MASTER_MDP_PORT1,
+};
+
 static struct fs_driver_data mdp_fs_data_8627 = {
 	.clks = (struct fs_clk_data[]){
 		{ .name = "core_clk" },
@@ -759,6 +785,18 @@
 };
 unsigned msm8930_num_footswitch __initdata = ARRAY_SIZE(msm8930_footswitch);
 
+struct platform_device *msm8930_pm8917_footswitch[] __initdata = {
+	FS_8X60(FS_MDP,    "vdd",	"mdp.0",      &mdp_fs_data_8930_pm8917),
+	FS_8X60(FS_ROT,    "vdd",	"msm_rotator.0", &rot_fs_data),
+	FS_8X60(FS_IJPEG,  "vdd",	"msm_gemini.0", &ijpeg_fs_data),
+	FS_8X60(FS_VFE,    "vdd",	"msm_vfe.0",	&vfe_fs_data),
+	FS_8X60(FS_VPE,    "vdd",	"msm_vpe.0",	&vpe_fs_data),
+	FS_8X60(FS_GFX3D,  "vdd",	"kgsl-3d0.0",	&gfx3d_fs_data),
+	FS_8X60(FS_VED,    "vdd",	"msm_vidc.0",	&ved_fs_data),
+};
+unsigned msm8930_pm8917_num_footswitch __initdata =
+		ARRAY_SIZE(msm8930_pm8917_footswitch);
+
 struct platform_device *msm8627_footswitch[] __initdata = {
 	FS_8X60(FS_MDP,    "vdd",	"mdp.0",	&mdp_fs_data_8627),
 	FS_8X60(FS_ROT,    "vdd",	"msm_rotator.0", &rot_fs_data),
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index f8132b4..a839fcf 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -1373,6 +1373,11 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	{
+		.start  = 0x00900000,
+		.end    = 0x00900000 + SZ_16K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
 		.start  = 0x08B00000,
 		.end    = 0x08B00000 + SZ_256 - 1,
 		.flags  = IORESOURCE_MEM,
@@ -1412,7 +1417,6 @@
 		.aclk_reg = MSM_CLK_CTL_BASE + 0x2C6C,
 		.jtag_clk_reg = MSM_CLK_CTL_BASE + 0x2044,
 		.name = "modem_fw",
-		.depends = "q6",
 		.pas_id = PAS_MODEM_FW,
 		.bus_port = MSM_BUS_MASTER_MSS_FW_PROC,
 	},
@@ -1423,7 +1427,6 @@
 		.aclk_reg = MSM_CLK_CTL_BASE + 0x2040,
 		.jtag_clk_reg = MSM_CLK_CTL_BASE + 0x2C68,
 		.name = "modem",
-		.depends = "modem_fw",
 		.pas_id = PAS_MODEM_SW,
 		.bus_port = MSM_BUS_MASTER_MSS_SW_PROC,
 	}
@@ -1444,6 +1447,11 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	{
+		.start  = 0x00900000,
+		.end    = 0x00900000 + SZ_16K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
 		.start  = RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ,
 		.end    = RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ,
 		.flags  = IORESOURCE_IRQ,
@@ -1464,6 +1472,11 @@
 
 static struct resource msm_pil_dsps_resources[] = {
 	{
+		.start  = 0x00900000,
+		.end    = 0x00900000 + SZ_16K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
 		.start = PPSS_WDOG_TIMER_IRQ,
 		.end   = PPSS_WDOG_TIMER_IRQ,
 		.flags = IORESOURCE_IRQ,
@@ -1557,7 +1570,7 @@
 	},
 	{
 		.irq_config_id = SMD_Q6,
-		.subsys_name = "q6",
+		.subsys_name = "adsp",
 		.edge = SMD_APPS_QDSP,
 
 		.smd_int.irq_name = "adsp_a11",
@@ -2520,6 +2533,17 @@
 	.bus_port1 = MSM_BUS_MASTER_HD_CODEC_PORT1,
 };
 
+static struct fs_driver_data ved_fs_data_8960ab = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_VIDEO_DEC,
+	.bus_port1 = MSM_BUS_MASTER_VIDEO_ENC,
+};
+
 static struct fs_driver_data vfe_fs_data = {
 	.clks = (struct fs_clk_data[]){
 		{ .name = "core_clk" },
@@ -2560,7 +2584,7 @@
 	FS_8X60(FS_VFE,    "vdd",	"msm_vfe.0",	&vfe_fs_data),
 	FS_8X60(FS_VPE,    "vdd",	"msm_vpe.0",	&vpe_fs_data),
 	FS_8X60(FS_GFX3D,  "vdd",	"kgsl-3d0.0",	&gfx3d_fs_data),
-	FS_8X60(FS_VED,    "vdd",	"msm_vidc.0",	&ved_fs_data),
+	FS_8X60(FS_VED,    "vdd",	"msm_vidc.0",	&ved_fs_data_8960ab),
 };
 unsigned msm8960ab_num_footswitch __initdata = ARRAY_SIZE(msm8960ab_footswitch);
 
@@ -3760,16 +3784,28 @@
 };
 
 static struct msm_rpmstats_platform_data msm_rpm_stat_pdata = {
-	.phys_addr_base = 0x0010DD04,
-	.phys_size = SZ_256,
+	.version = 1,
 };
 
+static struct resource msm_rpm_stat_resource[] = {
+	{
+		.start	= 0x0010D204,
+		.end	= 0x0010D204 + SZ_8K,
+		.flags	= IORESOURCE_MEM,
+		.name	= "phys_addr_base"
+	},
+};
+
+
+
 struct platform_device msm8960_rpm_stat_device = {
 	.name = "msm_rpm_stat",
 	.id = -1,
-	.dev = {
+	.resource = msm_rpm_stat_resource,
+	.num_resources	= ARRAY_SIZE(msm_rpm_stat_resource),
+	.dev	= {
 		.platform_data = &msm_rpm_stat_pdata,
-	},
+	}
 };
 
 static struct resource resources_rpm_master_stats[] = {
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index fe3a4d5..1ba408f 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -584,6 +584,10 @@
 	.name	= "msm-voip-dsp",
 	.id	= -1,
 };
+struct platform_device msm_dtmf = {
+	.name	= "msm-pcm-dtmf",
+	.id	= -1,
+};
 
 struct platform_device msm_compr_dsp = {
 	.name	= "msm-compr-dsp",
@@ -1361,16 +1365,29 @@
 };
 
 static struct msm_rpmstats_platform_data msm_rpm_stat_pdata = {
-	.phys_addr_base = 0x0010DD04,
-	.phys_size = SZ_256,
+	.version = 1,
 };
 
+
+static struct resource msm_rpm_stat_resource[] = {
+	{
+		.start	= 0x0010D204,
+		.end	= 0x0010D204 + SZ_8K,
+		.flags	= IORESOURCE_MEM,
+		.name	= "phys_addr_base"
+	},
+};
+
+
+
 struct platform_device msm9615_rpm_stat_device = {
 	.name = "msm_rpm_stat",
 	.id = -1,
-	.dev = {
+	.resource = msm_rpm_stat_resource,
+	.num_resources	= ARRAY_SIZE(msm_rpm_stat_resource),
+	.dev	= {
 		.platform_data = &msm_rpm_stat_pdata,
-	},
+	}
 };
 
 static struct resource resources_rpm_master_stats[] = {
@@ -1421,6 +1438,19 @@
 	},
 };
 
+static struct msm_pm_init_data_type msm_pm_data = {
+	.use_sync_timer = false,
+	.pc_mode = MSM_PM_PC_NOTZ_L2_EXT,
+};
+
+struct platform_device msm9615_pm_8x60 = {
+	.name	= "pm-8x60",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &msm_pm_data,
+	},
+};
+
 uint32_t __init msm9615_rpm_get_swfi_latency(void)
 {
 	int i;
diff --git a/arch/arm/mach-msm/devices-fsm9xxx.c b/arch/arm/mach-msm/devices-fsm9xxx.c
index 639eeae..9043223 100644
--- a/arch/arm/mach-msm/devices-fsm9xxx.c
+++ b/arch/arm/mach-msm/devices-fsm9xxx.c
@@ -228,6 +228,7 @@
 	.parts		= NULL,
 	.nr_parts	= 0,
 	.interleave     = 0,
+	.version	= VERSION_2,
 };
 
 struct platform_device msm_device_nand = {
diff --git a/arch/arm/mach-msm/devices-iommu.c b/arch/arm/mach-msm/devices-iommu.c
index 63c1dbd..091a8e8 100644
--- a/arch/arm/mach-msm/devices-iommu.c
+++ b/arch/arm/mach-msm/devices-iommu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -312,11 +312,6 @@
 	},
 };
 
-static struct platform_device msm_root_iommu_dev = {
-	.name = "msm_iommu",
-	.id = -1,
-};
-
 static struct msm_iommu_dev jpegd_iommu = {
 	.name = "jpegd",
 	.ncb = 2,
@@ -395,7 +390,6 @@
 	.name = "msm_iommu",
 	.id = 0,
 	.dev = {
-		.parent = &msm_root_iommu_dev.dev,
 		.platform_data = &jpegd_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_jpegd_resources),
@@ -406,7 +400,6 @@
 	.name = "msm_iommu",
 	.id = 1,
 	.dev = {
-		.parent = &msm_root_iommu_dev.dev,
 		.platform_data = &vpe_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_vpe_resources),
@@ -417,7 +410,6 @@
 	.name = "msm_iommu",
 	.id = 2,
 	.dev = {
-		.parent = &msm_root_iommu_dev.dev,
 		.platform_data = &mdp0_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_mdp0_resources),
@@ -428,7 +420,6 @@
 	.name = "msm_iommu",
 	.id = 3,
 	.dev = {
-		.parent = &msm_root_iommu_dev.dev,
 		.platform_data = &mdp1_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_mdp1_resources),
@@ -439,7 +430,6 @@
 	.name = "msm_iommu",
 	.id = 4,
 	.dev = {
-		.parent = &msm_root_iommu_dev.dev,
 		.platform_data = &rot_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_rot_resources),
@@ -450,7 +440,6 @@
 	.name = "msm_iommu",
 	.id = 5,
 	.dev = {
-		.parent = &msm_root_iommu_dev.dev,
 		.platform_data = &ijpeg_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_ijpeg_resources),
@@ -461,7 +450,6 @@
 	.name = "msm_iommu",
 	.id = 6,
 	.dev = {
-		.parent = &msm_root_iommu_dev.dev,
 		.platform_data = &vfe_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_vfe_resources),
@@ -472,7 +460,6 @@
 	.name = "msm_iommu",
 	.id = 7,
 	.dev = {
-		.parent = &msm_root_iommu_dev.dev,
 		.platform_data = &vcodec_a_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_vcodec_a_resources),
@@ -483,7 +470,6 @@
 	.name = "msm_iommu",
 	.id = 8,
 	.dev = {
-		.parent = &msm_root_iommu_dev.dev,
 		.platform_data = &vcodec_b_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_vcodec_b_resources),
@@ -494,7 +480,6 @@
 	.name = "msm_iommu",
 	.id = 9,
 	.dev = {
-		.parent = &msm_root_iommu_dev.dev,
 		.platform_data = &gfx3d_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_gfx3d_resources),
@@ -505,7 +490,6 @@
 	.name = "msm_iommu",
 	.id = 10,
 	.dev = {
-		.parent = &msm_root_iommu_dev.dev,
 		.platform_data = &gfx3d1_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_gfx3d1_resources),
@@ -516,7 +500,6 @@
 	.name = "msm_iommu",
 	.id = 10,
 	.dev = {
-		.parent = &msm_root_iommu_dev.dev,
 		.platform_data = &gfx2d0_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_gfx2d0_resources),
@@ -527,7 +510,6 @@
 	.name = "msm_iommu",
 	.id = 11,
 	.dev = {
-		.parent = &msm_root_iommu_dev.dev,
 		.platform_data = &gfx2d1_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_gfx2d1_resources),
@@ -538,7 +520,6 @@
 	.name = "msm_iommu",
 	.id = 11,
 	.dev = {
-		.parent = &msm_root_iommu_dev.dev,
 		.platform_data = &vcap_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_vcap_resources),
@@ -999,12 +980,6 @@
 		return -ENODEV;
 	}
 
-	ret = platform_device_register(&msm_root_iommu_dev);
-	if (ret != 0) {
-		pr_err("Failed to register root IOMMU device!\n");
-		goto failure;
-	}
-
 	/* Initialize common devs */
 	platform_add_devices(msm_iommu_common_devs,
 				ARRAY_SIZE(msm_iommu_common_devs));
@@ -1051,9 +1026,6 @@
 			ARRAY_SIZE(msm_iommu_vcap_ctx_devs));
 
 	return 0;
-
-failure:
-	return ret;
 }
 
 static void __exit iommu_exit(void)
@@ -1112,8 +1084,6 @@
 		for (i = 0; i < ARRAY_SIZE(msm_iommu_jpegd_devs); i++)
 			platform_device_unregister(msm_iommu_jpegd_devs[i]);
 	}
-
-	platform_device_unregister(&msm_root_iommu_dev);
 }
 
 subsys_initcall(iommu_init);
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 2c49b21..5296048 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -780,6 +780,16 @@
 		.notify_rpm = false,
 		.cmd = spm_pc_without_modem,
 	},
+	[2] = {
+		.mode = MSM_SPM_MODE_POWER_COLLAPSE,
+		.notify_rpm = false,
+		.cmd = spm_pc_without_modem,
+	},
+	[3] = {
+		.mode = MSM_SPM_MODE_POWER_COLLAPSE,
+		.notify_rpm = false,
+		.cmd = spm_pc_without_modem,
+	},
 };
 
 static struct msm_spm_platform_data msm_spm_data[] __initdata = {
@@ -797,6 +807,20 @@
 		.num_modes = ARRAY_SIZE(msm_spm_seq_list),
 		.modes = msm_spm_seq_list,
 	},
+	[2] = {
+		.reg_base_addr = MSM_SAW2_BASE,
+		.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x0,
+		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
+		.num_modes = ARRAY_SIZE(msm_spm_seq_list),
+		.modes = msm_spm_seq_list,
+	},
+	[3] = {
+		.reg_base_addr = MSM_SAW3_BASE,
+		.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x0,
+		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
+		.num_modes = ARRAY_SIZE(msm_spm_seq_list),
+		.modes = msm_spm_seq_list,
+	},
 };
 
 void __init msm8x25_spm_device_init(void)
@@ -1643,6 +1667,7 @@
 	case 0x771:
 	case 0x77C:
 	case 0x780:
+	case 0x785: /* Edge-only MSM8125-0 */
 	case 0x8D0:
 		cpu = MSM8625;
 		break;
@@ -1770,7 +1795,7 @@
 
 static struct msm_cpr_config msm_cpr_pdata = {
 	.ref_clk_khz = 19200,
-	.delay_us = 1000,
+	.delay_us = 25000,
 	.irq_line = 0,
 	.cpr_mode_data = msm_cpr_mode_data,
 	.tgt_count_div_N = 1,
@@ -1778,12 +1803,13 @@
 	.ceiling = 40,
 	.sw_vlevel = 20,
 	.up_threshold = 1,
-	.dn_threshold = 4,
+	.dn_threshold = 3,
 	.up_margin = 0,
 	.dn_margin = 0,
 	.max_nom_freq = 700800,
 	.max_freq = 1401600,
 	.max_quot = 0,
+	.disable_cpr = false,
 	.vp_data = &vp_data,
 	.get_quot = msm_cpr_get_quot,
 	.clk_enable = msm_cpr_clk_enable,
@@ -1816,6 +1842,7 @@
 	}
 
 	msm_smem_get_cpr_info(cpr_info);
+	msm_cpr_pdata.disable_cpr = cpr_info->disable_cpr;
 
 	/**
 	 * Set the ring_osc based on efuse BIT(0)
@@ -1848,11 +1875,11 @@
 	 * Ditto for a 1.0GHz part.
 	 */
 	if (msm8625_cpu_id() == MSM8625A) {
-		msm_cpr_pdata.max_quot += 100;
+		msm_cpr_pdata.max_quot += 30;
 		if (msm_cpr_pdata.max_quot > 1400)
 			msm_cpr_pdata.max_quot = 1400;
 	} else if (msm8625_cpu_id() == MSM8625) {
-		msm_cpr_pdata.max_quot += 120;
+		msm_cpr_pdata.max_quot += 50;
 		if (msm_cpr_pdata.max_quot > 1350)
 			msm_cpr_pdata.max_quot = 1350;
 	}
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 5554eb8..c6513d9 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -213,6 +213,11 @@
 		.flags  = IORESOURCE_MEM,
 	},
 	{
+		.start  = 0x00900000,
+		.end    = 0x00900000 + SZ_16K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
 		.start	= LPASS_Q6SS_WDOG_EXPIRED,
 		.end	= LPASS_Q6SS_WDOG_EXPIRED,
 		.flags	= IORESOURCE_IRQ,
@@ -241,6 +246,11 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.start  = 0x00900000,
+		.end    = 0x00900000 + SZ_16K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
 		.start	= MARM_WDOG_EXPIRED,
 		.end	= MARM_WDOG_EXPIRED,
 		.flags	= IORESOURCE_IRQ,
@@ -259,9 +269,19 @@
 	.id = -1,
 };
 
+static struct resource msm_pil_dsps_resources[] = {
+	{
+		.start  = 0x00900000,
+		.end    = 0x00900000 + SZ_16K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
 struct platform_device msm_pil_dsps = {
 	.name          = "pil_dsps",
 	.id            = -1,
+	.resource	= msm_pil_dsps_resources,
+	.num_resources	= ARRAY_SIZE(msm_pil_dsps_resources),
 	.dev.platform_data = "dsps",
 };
 
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 97adb35..cd99628 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -109,6 +109,8 @@
 extern struct platform_device msm_device_sdc3;
 extern struct platform_device msm_device_sdc4;
 
+extern struct platform_device msm9615_pm_8x60;
+
 extern struct platform_device msm8960_pc_cntr;
 extern struct platform_device msm8064_pc_cntr;
 extern struct platform_device msm8930_pc_cntr;
@@ -232,6 +234,7 @@
 extern struct platform_device msm_stub_codec;
 extern struct platform_device msm_voice;
 extern struct platform_device msm_voip;
+extern struct platform_device msm_dtmf;
 extern struct platform_device msm_lpa_pcm;
 extern struct platform_device msm_pcm_hostless;
 extern struct platform_device msm_cpudai_afe_01_rx;
@@ -307,6 +310,8 @@
 extern unsigned apq8064_num_footswitch;
 extern struct platform_device *msm8930_footswitch[];
 extern unsigned msm8930_num_footswitch;
+extern struct platform_device *msm8930_pm8917_footswitch[];
+extern unsigned msm8930_pm8917_num_footswitch;
 extern struct platform_device *msm8627_footswitch[];
 extern unsigned msm8627_num_footswitch;
 
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
index 1d8f313..ccd0bf7 100644
--- a/arch/arm/mach-msm/idle-v7.S
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -22,7 +22,7 @@
 #include "idle.h"
 #include "idle-macros.S"
 
-#ifdef CONFIG_ARCH_MSM_KRAIT
+#ifdef CONFIG_MSM_SCM
 #define SCM_SVC_BOOT 0x1
 #define SCM_CMD_TERMINATE_PC 0x2
 #endif
@@ -127,7 +127,18 @@
 	cmp	r1, #1
 	bne	skip
 	bl	v7_flush_dcache_all
+	ldr	r1, =msm_pm_flush_l2_fn
+	ldr	r1, [r1]
+	cmp	r1, #0
+	blxne	r1
+
 skip:
+	ldr	r1, =msm_pm_disable_l2_fn
+	ldr	r1, [r1]
+	cmp	r1, #0
+	blxne	r1
+	dmb
+
 	mrc	p15, 0, r0, c0, c0, 5	/* MPIDR */
 	and	r0, r0, #15		/* what CPU am I */
 
@@ -141,7 +152,7 @@
 	str	r2, [r1]
 skip_pc_debug1:
 
-#ifdef CONFIG_ARCH_MSM_KRAIT
+#ifdef CONFIG_MSM_SCM
 	ldr	r0, =SCM_SVC_BOOT
 	ldr	r1, =SCM_CMD_TERMINATE_PC
 	ldr	r2, =msm_pm_flush_l2_flag
@@ -182,6 +193,11 @@
 	str	r2, [r1]
 
 skip_pc_debug2:
+	ldr	r1, =msm_pm_enable_l2_fn
+	ldr	r1, [r1]
+	cmp	r1, #0
+	blxne	r1
+	dmb
 
 #ifdef CONFIG_MSM_JTAG
 	bl	msm_jtag_restore_state
@@ -286,11 +302,16 @@
 	SET_SMP_COHERENCY ON
 #endif
 
-#ifdef CONFIG_MSM_JTAG
+	ldr	r1, =msm_pm_enable_l2_fn
+	ldr	r1, [r1]
+	cmp	r1, #0
 	stmfd   sp!, {lr}
+	blxne	r1
+	dmb
+#ifdef CONFIG_MSM_JTAG
 	bl      msm_jtag_restore_state
-	ldmfd   sp!, {lr}
 #endif
+	ldmfd   sp!, {lr}
 	mov     r0, #1
 	bx      lr
 	nop
@@ -377,6 +398,18 @@
 msm_pc_debug_counters:
 	.long 0x0
 
+	.globl msm_pm_enable_l2_fn
+msm_pm_enable_l2_fn:
+	.long 0x0
+
+	.globl msm_pm_disable_l2_fn
+msm_pm_disable_l2_fn:
+	.long 0x0
+
+	.globl msm_pm_flush_l2_fn
+msm_pm_flush_l2_fn:
+	.long 0x0
+
 /*
  * Default the l2 flush flag to 1 so that caches are flushed during power
  * collapse unless the  L2 driver decides to flush them only during L2
diff --git a/arch/arm/mach-msm/idle.h b/arch/arm/mach-msm/idle.h
index 7a939ab..ee3209c 100644
--- a/arch/arm/mach-msm/idle.h
+++ b/arch/arm/mach-msm/idle.h
@@ -33,6 +33,9 @@
 int msm_pm_collapse(void);
 void msm_pm_collapse_exit(void);
 extern void *msm_saved_state;
+extern void (*msm_pm_disable_l2_fn)(void);
+extern void (*msm_pm_enable_l2_fn)(void);
+extern void (*msm_pm_flush_l2_fn)(void);
 extern unsigned long msm_saved_state_phys;
 
 #ifdef CONFIG_CPU_V7
diff --git a/arch/arm/mach-msm/include/mach/bam_dmux.h b/arch/arm/mach-msm/include/mach/bam_dmux.h
index f02a882..f11b72c 100644
--- a/arch/arm/mach-msm/include/mach/bam_dmux.h
+++ b/arch/arm/mach-msm/include/mach/bam_dmux.h
@@ -28,6 +28,18 @@
 	BAM_DMUX_DATA_RMNET_6,
 	BAM_DMUX_DATA_RMNET_7,
 	BAM_DMUX_USB_RMNET_0,
+	BAM_DMUX_RESERVED_0, /* 9..11 are reserved*/
+	BAM_DMUX_RESERVED_1,
+	BAM_DMUX_RESERVED_2,
+	BAM_DMUX_DATA_REV_RMNET_0,
+	BAM_DMUX_DATA_REV_RMNET_1,
+	BAM_DMUX_DATA_REV_RMNET_2,
+	BAM_DMUX_DATA_REV_RMNET_3,
+	BAM_DMUX_DATA_REV_RMNET_4,
+	BAM_DMUX_DATA_REV_RMNET_5,
+	BAM_DMUX_DATA_REV_RMNET_6,
+	BAM_DMUX_DATA_REV_RMNET_7,
+	BAM_DMUX_DATA_REV_RMNET_8,
 	BAM_DMUX_NUM_CHANNELS
 };
 
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index ff4776a..9c5e52c 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -129,6 +129,10 @@
 
 struct msm_camera_sensor_flash_src {
 	int flash_sr_type;
+	struct gpio *init_gpio_tbl;
+	uint8_t init_gpio_tbl_size;
+	struct msm_gpio_set_tbl *set_gpio_tbl;
+	uint8_t set_gpio_tbl_size;
 
 	union {
 		struct msm_camera_sensor_flash_pmic pmic_src;
@@ -144,6 +148,9 @@
 struct msm_camera_sensor_flash_data {
 	int flash_type;
 	struct msm_camera_sensor_flash_src *flash_src;
+	struct i2c_board_info const *board_info;
+	int bus_id;
+	uint8_t flash_src_index;
 };
 
 struct msm_camera_sensor_strobe_flash_data {
@@ -587,6 +594,7 @@
 void msm_map_msm8226_io(void);
 void msm8226_init_irq(void);
 void msm8226_init_gpiomux(void);
+void msm8910_init_gpiomux(void);
 void msm_map_msm8910_io(void);
 void msm8910_init_irq(void);
 
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index f5a158f..14fd092 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -508,35 +508,6 @@
 	struct msm_pmem_region *region;
 };
 
-#ifdef CONFIG_MSM_CAMERA_FLASH
-int msm_camera_flash_set_led_state(
-	struct msm_camera_sensor_flash_data *fdata,
-	unsigned led_state);
-int msm_strobe_flash_init(struct msm_sync *sync, uint32_t sftype);
-int msm_flash_ctrl(struct msm_camera_sensor_info *sdata,
-			struct flash_ctrl_data *flash_info);
-#else
-static inline int msm_camera_flash_set_led_state(
-	struct msm_camera_sensor_flash_data *fdata,
-	unsigned led_state)
-{
-	return -ENOTSUPP;
-}
-static inline int msm_strobe_flash_init(
-	struct msm_sync *sync, uint32_t sftype)
-{
-	return -ENOTSUPP;
-}
-static inline int msm_flash_ctrl(
-		struct msm_camera_sensor_info *sdata,
-		struct flash_ctrl_data *flash_info)
-{
-	return -ENOTSUPP;
-}
-#endif
-
-
-
 void msm_camvfe_init(void);
 int msm_camvfe_check(void *);
 void msm_camvfe_fn_init(struct msm_camvfe_fn *, void *);
@@ -704,4 +675,10 @@
 	(struct msm_camera_sensor_info *sinfo, int gpio_en);
 void msm_camera_bus_scale_cfg(uint32_t bus_perf_client,
 		enum msm_bus_perf_setting perf_setting);
+
+int msm_camera_init_gpio_table(struct gpio *gpio_tbl, uint8_t gpio_tbl_size,
+	int gpio_en);
+
+int msm_camera_set_gpio_table(struct msm_gpio_set_tbl *gpio_tbl,
+	uint8_t gpio_tbl_size, int gpio_en);
 #endif
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index 69ddeb9..054e70c 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -15,11 +15,11 @@
 
 #include <linux/interrupt.h>
 #include <linux/clk.h>
+#include <linux/list.h>
 #include <linux/regulator/consumer.h>
 #include <mach/socinfo.h>
 
 extern pgprot_t     pgprot_kernel;
-extern struct platform_device *msm_iommu_root_dev;
 extern struct bus_type msm_iommu_sec_bus_type;
 
 /* Domain attributes */
@@ -91,6 +91,8 @@
  * @name:	Human-readable name of this IOMMU device
  * @gdsc:	Regulator needed to power this HW block (v2 only)
  * @bfb_settings: Optional BFB performance tuning parameters
+ * @dev:	Struct device this hardware instance is tied to
+ * @list:	List head to link all iommus together
  *
  * A msm_iommu_drvdata holds the global driver data about a single piece
  * of an IOMMU hardware instance.
@@ -106,8 +108,13 @@
 	struct regulator *gdsc;
 	struct msm_iommu_bfb_settings *bfb_settings;
 	int sec_id;
+	struct device *dev;
+	struct list_head list;
 };
 
+void msm_iommu_add_drv(struct msm_iommu_drvdata *drv);
+void msm_iommu_remove_drv(struct msm_iommu_drvdata *drv);
+
 /**
  * struct msm_iommu_ctx_drvdata - an IOMMU context bank instance
  * @num:		Hardware context number of this context
@@ -154,7 +161,6 @@
 }
 #endif
 
-#endif
 
 static inline int msm_soc_version_supports_iommu_v1(void)
 {
@@ -178,3 +184,4 @@
 	}
 	return 1;
 }
+#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-8226.h b/arch/arm/mach-msm/include/mach/irqs-8226.h
index fad7b90..7e174b9 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8226.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8226.h
@@ -24,15 +24,12 @@
 #define GIC_PPI_START 16
 #define GIC_SPI_START 32
 
-#define AVS_SVICINT				(GIC_PPI_START + 6)
-#define AVS_SVICINTSWDONE			(GIC_PPI_START + 7)
 #define INT_ARMQC_PERFMON			(GIC_PPI_START + 10)
 /* PPI 15 is unused */
 
 #define APCC_QGICL2PERFMONIRPTREQ	(GIC_SPI_START + 1)
 #define SC_SICL2PERFMONIRPTREQ		APCC_QGICL2PERFMONIRPTREQ
 #define TLMM_MSM_SUMMARY_IRQ		(GIC_SPI_START + 208)
-#define SPS_BAM_DMA_IRQ			(GIC_SPI_START + 105)
 
 #define NR_MSM_IRQS 256
 #define NR_GPIO_IRQS 146
diff --git a/arch/arm/mach-msm/include/mach/irqs-8625.h b/arch/arm/mach-msm/include/mach/irqs-8625.h
index 2a61118..f591a9e 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8625.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8625.h
@@ -21,7 +21,7 @@
 #endif
 
 /* As per QGIC2 PPI 16 aka 0 is reserved */
-#define MSM8625_INT_A5_PMU_IRQ		(GIC_PPI_START + 1)
+#define MSM8625_INT_ARMQC_PERFMON	(GIC_PPI_START + 1)
 #define MSM8625_INT_DEBUG_TIMER_EXP	(GIC_PPI_START + 2)
 #define MSM8625_INT_GP_TIMER_EXP	(GIC_PPI_START + 3)
 #define MSM8625_INT_COMMRX		(GIC_PPI_START + 4)
diff --git a/arch/arm/mach-msm/include/mach/msm_bus_board.h b/arch/arm/mach-msm/include/mach/msm_bus_board.h
index 0a53b46..84a7dc0 100644
--- a/arch/arm/mach-msm/include/mach/msm_bus_board.h
+++ b/arch/arm/mach-msm/include/mach/msm_bus_board.h
@@ -92,6 +92,11 @@
 extern struct msm_bus_fabric_registration msm_bus_8974_config_noc_pdata;
 extern struct msm_bus_fabric_registration msm_bus_8974_ocmem_vnoc_pdata;
 
+extern struct msm_bus_fabric_registration msm_bus_9625_sys_noc_pdata;
+extern struct msm_bus_fabric_registration msm_bus_9625_bimc_pdata;
+extern struct msm_bus_fabric_registration msm_bus_9625_periph_noc_pdata;
+extern struct msm_bus_fabric_registration msm_bus_9625_config_noc_pdata;
+
 void msm_bus_rpm_set_mt_mask(void);
 int msm_bus_board_rpm_get_il_ids(uint16_t *id);
 int msm_bus_board_get_iid(int id);
@@ -291,8 +296,10 @@
 	MSM_BUS_MASTER_USB_HS,
 	MSM_BUS_MASTER_PNOC_CFG,
 	MSM_BUS_MASTER_V_OCMEM_GFX3D,
+	MSM_BUS_MASTER_IPA,
+	MSM_BUS_MASTER_QPIC,
 
-	MSM_BUS_MASTER_LAST = MSM_BUS_MASTER_V_OCMEM_GFX3D,
+	MSM_BUS_MASTER_LAST = MSM_BUS_MASTER_QPIC,
 
 	MSM_BUS_SYSTEM_FPB_MASTER_SYSTEM =
 		MSM_BUS_SYSTEM_MASTER_SYSTEM_FPB,
@@ -446,8 +453,10 @@
 	MSM_BUS_SLAVE_PHY_APU_CFG,
 	MSM_BUS_SLAVE_EBI1_PHY_CFG,
 	MSM_BUS_SLAVE_SERVICE_CNOC,
+	MSM_BUS_SLAVE_IPS_CFG,
+	MSM_BUS_SLAVE_QPIC,
 
-	MSM_BUS_SLAVE_LAST = MSM_BUS_SLAVE_SERVICE_CNOC,
+	MSM_BUS_SLAVE_LAST = MSM_BUS_SLAVE_QPIC,
 
 	MSM_BUS_SYSTEM_FPB_SLAVE_SYSTEM =
 		MSM_BUS_SYSTEM_SLAVE_SYSTEM_FPB,
diff --git a/arch/arm/mach-msm/include/mach/msm_hdmi_audio.h b/arch/arm/mach-msm/include/mach/msm_hdmi_audio.h
index 2455e93..9b04141 100644
--- a/arch/arm/mach-msm/include/mach/msm_hdmi_audio.h
+++ b/arch/arm/mach-msm/include/mach/msm_hdmi_audio.h
@@ -29,7 +29,8 @@
 	HDMI_SAMPLE_RATE_88_2KHZ,
 	HDMI_SAMPLE_RATE_96KHZ,
 	HDMI_SAMPLE_RATE_176_4KHZ,
-	HDMI_SAMPLE_RATE_192KHZ
+	HDMI_SAMPLE_RATE_192KHZ,
+	HDMI_SAMPLE_RATE_MAX
 };
 
 int hdmi_audio_enable(bool on , u32 fifo_water_mark);
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8226.h b/arch/arm/mach-msm/include/mach/msm_iomap-8226.h
index 08bc981..c03b513 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8226.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8226.h
@@ -45,7 +45,4 @@
 #define MSM_DEBUG_UART_PHYS	0xF991E000
 #endif
 
-#define MSM8226_DBG_IMEM_PHYS	0xFE805000
-#define MSM8226_DBG_IMEM_SIZE	SZ_4K
-
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8625.h b/arch/arm/mach-msm/include/mach/msm_iomap-8625.h
index 43250f5..9b6de20 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8625.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8625.h
@@ -54,6 +54,12 @@
 #define MSM8625_SAW1_PHYS		0xC0700000
 #define MSM8625_SAW1_SIZE		SZ_4K
 
+#define MSM8625_SAW2_PHYS		0xC0A00000
+#define MSM8625_SAW2_SIZE		SZ_4K
+
+#define MSM8625_SAW3_PHYS		0xC0B00000
+#define MSM8625_SAW3_SIZE		SZ_4K
+
 #define MSM8625_CFG_CTL_PHYS		0xA9800000
 #define MSM8625_CFG_CTL_SIZE		SZ_4K
 
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8910.h b/arch/arm/mach-msm/include/mach/msm_iomap-8910.h
index e4cd312..08f21b6 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8910.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8910.h
@@ -30,9 +30,12 @@
 #define MSM8910_TLMM_PHYS	0xFD510000
 #define MSM8910_TLMM_SIZE	SZ_16K
 
-#define MSM8910_IMEM_PHYS	0xFC42B000
+#define MSM8910_IMEM_PHYS	0xFE805000
 #define MSM8910_IMEM_SIZE	SZ_4K
 
+#define MSM8910_MPM2_PSHOLD_PHYS	0xFC4AB000
+#define MSM8910_MPM2_PSHOLD_SIZE	SZ_4K
+
 #ifdef CONFIG_DEBUG_MSM8910_UART
 #define MSM_DEBUG_UART_BASE	IOMEM(0xFA71E000)
 #define MSM_DEBUG_UART_PHYS	0xF991E000
diff --git a/arch/arm/mach-msm/include/mach/msm_ipc_router.h b/arch/arm/mach-msm/include/mach/msm_ipc_router.h
new file mode 100644
index 0000000..45a7e19
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_ipc_router.h
@@ -0,0 +1,181 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MSM_IPC_ROUTER_H
+#define _MSM_IPC_ROUTER_H
+
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/list.h>
+#include <linux/wakelock.h>
+#include <linux/msm_ipc.h>
+
+#define MAX_WAKELOCK_NAME_SZ 32
+
+/**
+ * enum msm_ipc_router_event - Events that will be generated by IPC Router
+ */
+enum msm_ipc_router_event {
+	MSM_IPC_ROUTER_READ_CB = 0,
+	MSM_IPC_ROUTER_WRITE_DONE,
+};
+
+struct msm_ipc_port {
+	struct list_head list;
+
+	struct msm_ipc_port_addr this_port;
+	struct msm_ipc_port_name port_name;
+	uint32_t type;
+	unsigned flags;
+	spinlock_t port_lock;
+
+	struct list_head incomplete;
+	struct mutex incomplete_lock;
+
+	struct list_head port_rx_q;
+	struct mutex port_rx_q_lock;
+	char rx_wakelock_name[MAX_WAKELOCK_NAME_SZ];
+	struct wake_lock port_rx_wake_lock;
+	wait_queue_head_t port_rx_wait_q;
+
+	int restart_state;
+	spinlock_t restart_lock;
+	wait_queue_head_t restart_wait;
+
+	void *endpoint;
+	void (*notify)(unsigned event, void *priv);
+
+	uint32_t num_tx;
+	uint32_t num_rx;
+	unsigned long num_tx_bytes;
+	unsigned long num_rx_bytes;
+	void *priv;
+};
+
+#ifdef CONFIG_MSM_IPC_ROUTER
+/**
+ * msm_ipc_router_create_port() - Create a IPC Router port/endpoint
+ * @notify: Callback function to notify any event on the port.
+ * @priv: Private info to be passed while the notification is generated.
+ *
+ * @return: Pointer to the port on success, NULL on error.
+ */
+struct msm_ipc_port *msm_ipc_router_create_port(
+	void (*notify)(unsigned event, void *priv),
+	void *priv);
+
+/**
+ * msm_ipc_router_lookup_server_name() - Resolve server address
+ * @srv_name: Name<service:instance> of the server to be resolved.
+ * @srv_info: Buffer to hold the resolved address.
+ * @num_entries_in_array: Number of server info the buffer can hold.
+ * @lookup_mask: Mask to specify the range of instances to be resolved.
+ *
+ * @return: Number of server addresses resolved on success, < 0 on error.
+ */
+int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
+				      struct msm_ipc_server_info *srv_info,
+				      int num_entries_in_array,
+				      uint32_t lookup_mask);
+
+/**
+ * msm_ipc_router_send_msg() - Send a message/packet
+ * @src: Sender's address/port.
+ * @dest: Destination address.
+ * @data: Pointer to the data to be sent.
+ * @data_len: Length of the data to be sent.
+ *
+ * @return: 0 on success, < 0 on error.
+ */
+int msm_ipc_router_send_msg(struct msm_ipc_port *src,
+			    struct msm_ipc_addr *dest,
+			    void *data, unsigned int data_len);
+
+/**
+ * msm_ipc_router_get_curr_pkt_size() - Get the packet size of the first
+ *                                      packet in the rx queue
+ * @port_ptr: Port which owns the rx queue.
+ *
+ * @return: Returns the size of the first packet, if available.
+ *          0 if no packets available, < 0 on error.
+ */
+int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr);
+
+/**
+ * msm_ipc_router_read_msg() - Read a message/packet
+ * @port_ptr: Receiver's port/address.
+ * @data: Pointer containing the address of the received data.
+ * @src: Address of the sender/source.
+ * @len: Length of the data being read.
+ *
+ * @return: 0 on success, < 0 on error.
+ */
+int msm_ipc_router_read_msg(struct msm_ipc_port *port_ptr,
+			    struct msm_ipc_addr *src,
+			    unsigned char **data,
+			    unsigned int *len);
+
+/**
+ * msm_ipc_router_close_port() - Close the port
+ * @port_ptr: Pointer to the port to be closed.
+ *
+ * @return: 0 on success, < 0 on error.
+ */
+int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr);
+
+#else
+
+struct msm_ipc_port *msm_ipc_router_create_port(
+	void (*notify)(unsigned event, void *priv),
+	void *priv)
+{
+	return NULL;
+}
+
+int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
+				      struct msm_ipc_server_info *srv_info,
+				      int num_entries_in_array,
+				      uint32_t lookup_mask)
+{
+	return -ENODEV;
+}
+
+int msm_ipc_router_send_msg(struct msm_ipc_port *src,
+			    struct msm_ipc_addr *dest,
+			    void *data, unsigned int data_len)
+{
+	return -ENODEV;
+}
+
+int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr)
+{
+	return -ENODEV;
+}
+
+int msm_ipc_router_read_msg(struct msm_ipc_port *port_ptr,
+			    struct msm_ipc_addr *src,
+			    unsigned char **data,
+			    unsigned int *len)
+{
+	return -ENODEV;
+}
+
+int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr)
+{
+	return -ENODEV;
+}
+
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_qmi_interface.h b/arch/arm/mach-msm/include/mach/msm_qmi_interface.h
new file mode 100644
index 0000000..11867f3
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_qmi_interface.h
@@ -0,0 +1,280 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MSM_QMI_INTERFACE_H_
+#define _MSM_QMI_INTERFACE_H_
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/list.h>
+#include <linux/socket.h>
+#include <linux/gfp.h>
+#include <linux/qmi_encdec.h>
+
+#define QMI_COMMON_TLV_TYPE 0
+
+enum qmi_event_type {
+	QMI_RECV_MSG = 1,
+	QMI_SERVER_ARRIVE,
+	QMI_SERVER_EXIT,
+};
+
+struct qmi_handle {
+	void *src_port;
+	void *dest_info;
+	uint16_t next_txn_id;
+	struct list_head txn_list;
+	struct mutex handle_lock;
+	spinlock_t notify_lock;
+	void (*notify)(struct qmi_handle *handle, enum qmi_event_type event,
+			void *notify_priv);
+	void *notify_priv;
+	void (*ind_cb)(struct qmi_handle *handle,
+			unsigned int msg_id, void *msg,
+			unsigned int msg_len, void *ind_cb_priv);
+	void *ind_cb_priv;
+	int handle_reset;
+	wait_queue_head_t reset_waitq;
+};
+
+enum qmi_result_type_v01 {
+	/* To force a 32 bit signed enum. Do not change or use*/
+	QMI_RESULT_TYPE_MIN_ENUM_VAL_V01 = INT_MIN,
+	QMI_RESULT_SUCCESS_V01 = 0,
+	QMI_RESULT_FAILURE_V01 = 1,
+	QMI_RESULT_TYPE_MAX_ENUM_VAL_V01 = INT_MAX,
+};
+
+enum qmi_error_type_v01 {
+	/* To force a 32 bit signed enum. Do not change or use*/
+	QMI_ERROR_TYPE_MIN_ENUM_VAL_V01 = INT_MIN,
+	QMI_ERR_NONE_V01 = 0x0000,
+	QMI_ERROR_MALFORMED_MSG_V01 = 0x0001,
+	QMI_ERR_NO_MEMORY_V01 = 0x0002,
+	QMI_ERR_INTERNAL_V01 = 0x0003,
+	QMI_ERR_INVALID_ID_V01 = 0x0029,
+	QMI_ERR_INCOMPATIBLE_STATE_V01 = 0x005A,
+	QMI_ERROR_TYPE_MAX_ENUM_VAL_V01 = INT_MAX,
+};
+
+struct qmi_response_type_v01 {
+	enum qmi_result_type_v01 result;
+	enum qmi_error_type_v01 error;
+};
+
+#ifdef CONFIG_MSM_QMI_INTERFACE
+
+/* Element info array describing common qmi response structure */
+extern struct elem_info qmi_response_type_v01_ei[];
+#define get_qmi_response_type_v01_ei() qmi_response_type_v01_ei
+
+/**
+ * qmi_handle_create() - Create a QMI handle
+ * @notify: Callback to notify events on the handle created.
+ * @notify_priv: Private information to be passed along with the notification.
+ *
+ * @return: Valid QMI handle on success, NULL on error.
+ */
+struct qmi_handle *qmi_handle_create(
+	void (*notify)(struct qmi_handle *handle,
+		       enum qmi_event_type event, void *notify_priv),
+	void *notify_priv);
+
+/**
+ * qmi_handle_destroy() - Destroy the QMI handle
+ * @handle: QMI handle to be destroyed.
+ *
+ * @return: 0 on success, < 0 on error.
+ */
+int qmi_handle_destroy(struct qmi_handle *handle);
+
+/**
+ * qmi_register_ind_cb() - Register the indication callback function
+ * @handle: QMI handle with which the function is registered.
+ * @ind_cb: Callback function to be registered.
+ * @ind_cb_priv: Private data to be passed with the indication callback.
+ *
+ * @return: 0 on success, < 0 on error.
+ */
+int qmi_register_ind_cb(struct qmi_handle *handle,
+	void (*ind_cb)(struct qmi_handle *handle,
+		       unsigned int msg_id, void *msg,
+		       unsigned int msg_len, void *ind_cb_priv),
+	void *ind_cb_priv);
+
+/**
+ * qmi_send_req_wait() - Send a synchronous QMI request
+ * @handle: QMI handle through which the QMI request is sent.
+ * @request_desc: Structure describing the request data structure.
+ * @req: Buffer containing the request data structure.
+ * @req_len: Length of the request data structure.
+ * @resp_desc: Structure describing the response data structure.
+ * @resp: Buffer to hold the response data structure.
+ * @resp_len: Length of the response data structure.
+ * @timeout_ms: Timeout before a response is received.
+ *
+ * @return: 0 on success, < 0 on error.
+ */
+int qmi_send_req_wait(struct qmi_handle *handle,
+		      struct msg_desc *req_desc,
+		      void *req, unsigned int req_len,
+		      struct msg_desc *resp_desc,
+		      void *resp, unsigned int resp_len,
+		      unsigned long timeout_ms);
+
+/**
+ * qmi_send_req_nowait() - Send an asynchronous QMI request
+ * @handle: QMI handle through which the QMI request is sent.
+ * @request_desc: Structure describing the request data structure.
+ * @req: Buffer containing the request data structure.
+ * @req_len: Length of the request data structure.
+ * @resp_desc: Structure describing the response data structure.
+ * @resp: Buffer to hold the response data structure.
+ * @resp_len: Length of the response data structure.
+ * @resp_cb: Callback function to be invoked when the response arrives.
+ * @resp_cb_data: Private information to be passed along with the callback.
+ *
+ * @return: 0 on success, < 0 on error.
+ */
+int qmi_send_req_nowait(struct qmi_handle *handle,
+			struct msg_desc *req_desc,
+			void *req, unsigned int req_len,
+			struct msg_desc *resp_desc,
+			void *resp, unsigned int resp_len,
+			void (*resp_cb)(struct qmi_handle *handle,
+					unsigned int msg_id, void *msg,
+					void *resp_cb_data),
+			void *resp_cb_data);
+
+/**
+ * qmi_recv_msg() - Receive the QMI message
+ * @handle: Handle for which the QMI message has to be received.
+ *
+ * @return: 0 on success, < 0 on error.
+ */
+int qmi_recv_msg(struct qmi_handle *handle);
+
+/**
+ * qmi_connect_to_service() - Connect the QMI handle with a QMI service
+ * @handle: QMI handle to be connected with the QMI service.
+ * @service_id: Service id to identify the QMI service.
+ * @instance_id: Instance id to identify the instance of the QMI service.
+ *
+ * @return: 0 on success, < 0 on error.
+ */
+int qmi_connect_to_service(struct qmi_handle *handle,
+			   uint32_t service_id, uint32_t instance_id);
+
+/**
+ * qmi_svc_event_notifier_register() - Register a notifier block to receive
+ *                                     events regarding a QMI service
+ * @service_id: Service ID to identify the QMI service.
+ * @instance_id: Instance ID to identify the instance of the QMI service.
+ * @nb: Notifier block used to receive the event.
+ *
+ * @return: 0 if successfully registered, < 0 on error.
+ */
+int qmi_svc_event_notifier_register(uint32_t service_id,
+				    uint32_t instance_id,
+				    struct notifier_block *nb);
+
+/**
+ * qmi_svc_event_notifier_unregister() - Unregister service event
+ *                                       notifier block
+ * @service_id: Service ID to identify the QMI service.
+ * @instance_id: Instance ID to identify the instance of the QMI service.
+ * @nb: Notifier block registered to receive the events.
+ *
+ * @return: 0 if successfully registered, < 0 on error.
+ */
+int qmi_svc_event_notifier_unregister(uint32_t service_id,
+				      uint32_t instance_id,
+				      struct notifier_block *nb);
+#else
+
+#define get_qmi_response_type_v01_ei() NULL
+
+static inline struct qmi_handle *qmi_handle_create(
+	void (*notify)(struct qmi_handle *handle,
+		       enum qmi_event_type event, void *notify_priv),
+	void *notify_priv)
+{
+	return NULL;
+}
+
+static inline int qmi_handle_destroy(struct qmi_handle *handle)
+{
+	return -ENODEV;
+}
+
+static inline int qmi_register_ind_cb(struct qmi_handle *handle,
+	void (*ind_cb)(struct qmi_handle *handle,
+		       unsigned int msg_id, void *msg,
+		       unsigned int msg_len, void *ind_cb_priv),
+	void *ind_cb_priv)
+{
+	return -ENODEV;
+}
+
+static inline int qmi_send_req_wait(struct qmi_handle *handle,
+				    struct msg_desc *req_desc,
+				    void *req, unsigned int req_len,
+				    struct msg_desc *resp_desc,
+				    void *resp, unsigned int resp_len,
+				    unsigned long timeout_ms)
+{
+	return -ENODEV;
+}
+
+static inline int qmi_send_req_nowait(struct qmi_handle *handle,
+				struct msg_desc *req_desc,
+				void *req, unsigned int req_len,
+				struct msg_desc *resp_desc,
+				void *resp, unsigned int resp_len,
+				void (*resp_cb)(struct qmi_handle *handle,
+						unsigned int msg_id, void *msg,
+						void *resp_cb_data),
+				void *resp_cb_data)
+{
+	return -ENODEV;
+}
+
+static inline int qmi_recv_msg(struct qmi_handle *handle)
+{
+	return -ENODEV;
+}
+
+static inline int qmi_connect_to_service(struct qmi_handle *handle,
+					 uint32_t service_id,
+					 uint32_t instance_id)
+{
+	return -ENODEV;
+}
+
+static inline int qmi_svc_event_notifier_register(uint32_t service_id,
+						  uint32_t instance_id,
+						  struct notifier_block *nb)
+{
+	return -ENODEV;
+}
+
+static inline int qmi_svc_event_notifier_unregister(uint32_t service_id,
+						    uint32_t instance_id,
+						    struct notifier_block *nb)
+{
+	return -ENODEV;
+}
+
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
index 44b52b6..c77c181 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -83,7 +83,7 @@
 #define SMSM_WKUP_REASON_TIMER	0x00000008
 #define SMSM_WKUP_REASON_ALARM	0x00000010
 #define SMSM_WKUP_REASON_RESET	0x00000020
-#define SMSM_A2_FORCE_SHUTDOWN 0x00002000
+#define SMSM_USB_PLUG_UNPLUG    0x00002000
 #define SMSM_A2_RESET_BAM      0x00004000
 
 #define SMSM_VENDOR             0x00020000
diff --git a/arch/arm/mach-msm/include/mach/msm_tspp.h b/arch/arm/mach-msm/include/mach/msm_tspp.h
index 5395b88..a024a99 100644
--- a/arch/arm/mach-msm/include/mach/msm_tspp.h
+++ b/arch/arm/mach-msm/include/mach/msm_tspp.h
@@ -25,31 +25,34 @@
 struct tspp_data_descriptor {
 	void *virt_base;   /* logical address of the actual data */
 	u32 phys_base;     /* physical address of the actual data */
-	int size;			 /* size of buffer in bytes */
+	u32 size;          /* size of buffer in bytes */
 	int id;            /* unique identifier */
 	void *user;        /* user-defined data */
 };
 
-typedef void (tspp_notifier)(int channel, void *user);
-typedef void* (tspp_allocator)(int channel, int size,
+typedef void (tspp_notifier)(int channel_id, void *user);
+typedef void* (tspp_allocator)(int channel_id, u32 size,
 	u32 *phys_base, void *user);
+typedef void (tspp_memfree)(int channel_id, u32 size,
+	void *virt_base, u32 phys_base, void *user);
 
 /* Kernel API functions */
 int tspp_open_stream(u32 dev, u32 channel_id,
-	struct tspp_select_source *source);
+			struct tspp_select_source *source);
 int tspp_close_stream(u32 dev, u32 channel_id);
 int tspp_open_channel(u32 dev, u32 channel_id);
 int tspp_close_channel(u32 dev, u32 channel_id);
-int tspp_add_filter(u32 dev, u32 channel_id,	struct tspp_filter *filter);
+int tspp_add_filter(u32 dev, u32 channel_id, struct tspp_filter *filter);
 int tspp_remove_filter(u32 dev, u32 channel_id,	struct tspp_filter *filter);
 int tspp_set_key(u32 dev, u32 channel_id, struct tspp_key *key);
-int tspp_register_notification(u32 dev, u32 channel, tspp_notifier *notify,
+int tspp_register_notification(u32 dev, u32 channel_id, tspp_notifier *notify,
 	void *data, u32 timer_ms);
-int tspp_unregister_notification(u32 dev, u32 channel);
-const struct tspp_data_descriptor *tspp_get_buffer(u32 dev, u32 channel);
-int tspp_release_buffer(u32 dev, u32 channel, u32 descriptor_id);
+int tspp_unregister_notification(u32 dev, u32 channel_id);
+const struct tspp_data_descriptor *tspp_get_buffer(u32 dev, u32 channel_id);
+int tspp_release_buffer(u32 dev, u32 channel_id, u32 descriptor_id);
 int tspp_allocate_buffers(u32 dev, u32 channel_id, u32 count,
-	u32 size, u32 int_freq, tspp_allocator *alloc, void *user);
+	u32 size, u32 int_freq, tspp_allocator *alloc,
+	tspp_memfree *memfree, void *user);
 
 #endif /* _MSM_TSPP_H_ */
 
diff --git a/arch/arm/mach-msm/include/mach/peripheral-loader.h b/arch/arm/mach-msm/include/mach/peripheral-loader.h
deleted file mode 100644
index 327c82f..0000000
--- a/arch/arm/mach-msm/include/mach/peripheral-loader.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* Copyright (c) 2010-2011, 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
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-#ifndef __MACH_PERIPHERAL_LOADER_H
-#define __MACH_PERIPHERAL_LOADER_H
-
-#ifdef CONFIG_MSM_PIL
-extern void *pil_get(const char *name);
-extern void pil_put(void *peripheral_handle);
-extern void pil_force_shutdown(const char *name);
-extern int pil_force_boot(const char *name);
-#else
-static inline void *pil_get(const char *name) { return NULL; }
-static inline void pil_put(void *peripheral_handle) { }
-static inline void pil_force_shutdown(const char *name) { }
-static inline int pil_force_boot(const char *name) { return -ENOSYS; }
-#endif
-
-#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
index 296f222..4c06af4 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -165,4 +165,5 @@
 enum apr_subsys_state apr_get_q6_state(void);
 int apr_set_q6_state(enum apr_subsys_state state);
 void apr_set_subsys_state(void);
+const char *apr_get_lpass_subsys_name(void);
 #endif
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator.h b/arch/arm/mach-msm/include/mach/rpm-regulator.h
index 075d20f..b063b97 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator.h
@@ -101,8 +101,7 @@
  * @init_data:		regulator constraints
  * @id:			regulator id; from enum rpm_vreg_id
  * @sleep_selectable:	flag which indicates that regulator should be accessable
- *			by external private API and that spinlocks should be
- *			used instead of mutex locks
+ *			by external private API
  * @system_uA:		current drawn from regulator not accounted for by any
  *			regulator framework consumer
  * @enable_time:	time in us taken to enable a regulator to the maximum
@@ -184,10 +183,8 @@
  * Returns 0 on success or errno.
  *
  * This function is used to vote for the voltage of a regulator without
- * using the regulator framework.  It is needed by consumers which hold spin
- * locks or have interrupts disabled because the regulator framework can sleep.
- * It is also needed by consumers which wish to only vote for active set
- * regulator voltage.
+ * using the regulator framework.  It is needed for consumers which wish to only
+ * vote for active set regulator voltage.
  *
  * If sleep_also == 0, then a sleep-set value of 0V will be voted for.
  *
diff --git a/arch/arm/mach-msm/include/mach/subsystem_restart.h b/arch/arm/mach-msm/include/mach/subsystem_restart.h
index a95e943..64190d2 100644
--- a/arch/arm/mach-msm/include/mach/subsystem_restart.h
+++ b/arch/arm/mach-msm/include/mach/subsystem_restart.h
@@ -70,6 +70,8 @@
 extern struct subsys_device *subsys_register(struct subsys_desc *desc);
 extern void subsys_unregister(struct subsys_device *dev);
 
+extern void subsys_default_online(struct subsys_device *dev);
+
 #else
 
 static inline int get_restart_level(void)
@@ -102,6 +104,8 @@
 
 static inline void subsys_unregister(struct subsys_device *dev) { }
 
+static inline void subsys_default_online(struct subsys_device *dev) { }
+
 #endif /* CONFIG_MSM_SUBSYSTEM_RESTART */
 
 #endif
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index c2c9233..52bb8ef 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -430,6 +430,8 @@
 	MSM_CHIP_DEVICE(CLK_CTL, MSM8625),
 	MSM_CHIP_DEVICE(SAW0, MSM8625),
 	MSM_CHIP_DEVICE(SAW1, MSM8625),
+	MSM_CHIP_DEVICE(SAW2, MSM8625),
+	MSM_CHIP_DEVICE(SAW3, MSM8625),
 	MSM_CHIP_DEVICE(AD5, MSM7XXX),
 	MSM_CHIP_DEVICE(MDC, MSM7XXX),
 #if defined(CONFIG_DEBUG_MSM_UART1) || defined(CONFIG_DEBUG_MSM_UART2) || \
@@ -517,7 +519,6 @@
 	MSM_CHIP_DEVICE(APCS_GCC, MSM8226),
 	MSM_CHIP_DEVICE(TLMM, MSM8226),
 	MSM_CHIP_DEVICE(IMEM, MSM8226),
-	MSM_CHIP_DEVICE(DBG_IMEM, MSM8226),
 	{
 		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
 		.length =   MSM_SHARED_RAM_SIZE,
@@ -540,6 +541,7 @@
 static struct map_desc msm8910_io_desc[] __initdata = {
 	MSM_CHIP_DEVICE(APCS_GCC, MSM8910),
 	MSM_CHIP_DEVICE(TLMM, MSM8910),
+	MSM_CHIP_DEVICE(MPM2_PSHOLD, MSM8910),
 	MSM_CHIP_DEVICE(IMEM, MSM8910),
 	{
 		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 3a632e5..8f1d197 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -33,6 +33,7 @@
 
 #include <mach/smem_log.h>
 #include <mach/subsystem_notif.h>
+#include <mach/msm_ipc_router.h>
 
 #include "ipc_router.h"
 #include "modem_notifier.h"
@@ -111,11 +112,14 @@
 struct msm_ipc_server {
 	struct list_head list;
 	struct msm_ipc_port_name name;
+	char pdev_name[32];
+	int next_pdev_id;
 	struct list_head server_port_list;
 };
 
 struct msm_ipc_server_port {
 	struct list_head list;
+	struct platform_device pdev;
 	struct msm_ipc_port_addr server_addr;
 	struct msm_ipc_router_xprt_info *xprt_info;
 };
@@ -366,6 +370,102 @@
 	return;
 }
 
+static struct sk_buff_head *msm_ipc_router_buf_to_skb(void *buf,
+						unsigned int buf_len)
+{
+	struct sk_buff_head *skb_head;
+	struct sk_buff *skb;
+	int first = 1, offset = 0;
+	int skb_size, data_size;
+	void *data;
+
+	skb_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
+	if (!skb_head) {
+		pr_err("%s: Couldnot allocate skb_head\n", __func__);
+		return NULL;
+	}
+	skb_queue_head_init(skb_head);
+
+	data_size = buf_len;
+	while (offset != buf_len) {
+		skb_size = data_size;
+		if (first)
+			skb_size += IPC_ROUTER_HDR_SIZE;
+
+		skb = alloc_skb(skb_size, GFP_KERNEL);
+		if (!skb) {
+			if (skb_size <= (PAGE_SIZE/2)) {
+				pr_err("%s: cannot allocate skb\n", __func__);
+				goto buf_to_skb_error;
+			}
+			data_size = data_size / 2;
+			continue;
+		}
+
+		if (first) {
+			skb_reserve(skb, IPC_ROUTER_HDR_SIZE);
+			first = 0;
+		}
+
+		data = skb_put(skb, data_size);
+		memcpy(skb->data, buf + offset, data_size);
+		skb_queue_tail(skb_head, skb);
+		offset += data_size;
+		data_size = buf_len - offset;
+	}
+	return skb_head;
+
+buf_to_skb_error:
+	while (!skb_queue_empty(skb_head)) {
+		skb = skb_dequeue(skb_head);
+		kfree_skb(skb);
+	}
+	kfree(skb_head);
+	return NULL;
+}
+
+static void *msm_ipc_router_skb_to_buf(struct sk_buff_head *skb_head,
+				       unsigned int len)
+{
+	struct sk_buff *temp;
+	int offset = 0, buf_len = 0, copy_len;
+	void *buf;
+
+	if (!skb_head) {
+		pr_err("%s: NULL skb_head\n", __func__);
+		return NULL;
+	}
+
+	temp = skb_peek(skb_head);
+	buf_len = len;
+	buf = kmalloc(buf_len, GFP_KERNEL);
+	if (!buf) {
+		pr_err("%s: cannot allocate buf\n", __func__);
+		return NULL;
+	}
+	skb_queue_walk(skb_head, temp) {
+		copy_len = buf_len < temp->len ? buf_len : temp->len;
+		memcpy(buf + offset, temp->data, copy_len);
+		offset += copy_len;
+		buf_len -= copy_len;
+	}
+	return buf;
+}
+
+static void msm_ipc_router_free_skb(struct sk_buff_head *skb_head)
+{
+	struct sk_buff *temp_skb;
+
+	if (!skb_head)
+		return;
+
+	while (!skb_queue_empty(skb_head)) {
+		temp_skb = skb_dequeue(skb_head);
+		kfree_skb(temp_skb);
+	}
+	kfree(skb_head);
+}
+
 static int post_control_ports(struct rr_packet *pkt)
 {
 	struct msm_ipc_port *port_ptr;
@@ -437,8 +537,7 @@
 }
 
 struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
-		void (*notify)(unsigned event, void *data,
-			       void *addr, void *priv),
+		void (*notify)(unsigned event, void *priv),
 		void *priv)
 {
 	struct msm_ipc_port *port_ptr;
@@ -628,6 +727,10 @@
 	return NULL;
 }
 
+static void dummy_release(struct device *dev)
+{
+}
+
 /**
  * msm_ipc_router_create_server() - Add server info to hash table
  * @service: Service ID of the server info to be created.
@@ -660,7 +763,7 @@
 			goto create_srv_port;
 	}
 
-	server = kmalloc(sizeof(struct msm_ipc_server), GFP_KERNEL);
+	server = kzalloc(sizeof(struct msm_ipc_server), GFP_KERNEL);
 	if (!server) {
 		pr_err("%s: Server allocation failed\n", __func__);
 		return NULL;
@@ -669,9 +772,12 @@
 	server->name.instance = instance;
 	INIT_LIST_HEAD(&server->server_port_list);
 	list_add_tail(&server->list, &server_list[key]);
+	scnprintf(server->pdev_name, sizeof(server->pdev_name),
+		  "QMI%08x:%08x", service, instance);
+	server->next_pdev_id = 1;
 
 create_srv_port:
-	server_port = kmalloc(sizeof(struct msm_ipc_server_port), GFP_KERNEL);
+	server_port = kzalloc(sizeof(struct msm_ipc_server_port), GFP_KERNEL);
 	if (!server_port) {
 		if (list_empty(&server->server_port_list)) {
 			list_del(&server->list);
@@ -685,6 +791,11 @@
 	server_port->xprt_info = xprt_info;
 	list_add_tail(&server_port->list, &server->server_port_list);
 
+	server_port->pdev.name = server->pdev_name;
+	server_port->pdev.id = server->next_pdev_id++;
+	server_port->pdev.dev.release = dummy_release;
+	platform_device_register(&server_port->pdev);
+
 	return server;
 }
 
@@ -714,6 +825,7 @@
 			break;
 	}
 	if (server_port) {
+		platform_device_unregister(&server_port->pdev);
 		list_del(&server_port->list);
 		kfree(server_port);
 	}
@@ -815,7 +927,6 @@
 
 	ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
 
-	mutex_lock(&server_list_lock);
 	for (i = 0; i < SRV_HASH_SIZE; i++) {
 		list_for_each_entry(server, &server_list[i], list) {
 			ctl.srv.service = server->name.service;
@@ -835,7 +946,6 @@
 			}
 		}
 	}
-	mutex_unlock(&server_list_lock);
 
 	return 0;
 }
@@ -1081,6 +1191,7 @@
 				ctl.srv.port_id = svr_port->server_addr.port_id;
 				relay_ctl_msg(xprt_info, &ctl);
 				broadcast_ctl_msg_locally(&ctl);
+				platform_device_unregister(&svr_port->pdev);
 				list_del(&svr_port->list);
 				kfree(svr_port);
 			}
@@ -1255,6 +1366,7 @@
 	 * Send list of servers from the local node and from nodes
 	 * outside the mesh network in which this XPRT is part of.
 	 */
+	mutex_lock(&server_list_lock);
 	mutex_lock(&routing_table_lock);
 	for (i = 0; i < RT_HASH_SIZE; i++) {
 		list_for_each_entry(rt_entry, &routing_table[i], list) {
@@ -1266,11 +1378,13 @@
 							     xprt_info);
 			if (rc < 0) {
 				mutex_unlock(&routing_table_lock);
+				mutex_unlock(&server_list_lock);
 				return rc;
 			}
 		}
 	}
 	mutex_unlock(&routing_table_lock);
+	mutex_unlock(&server_list_lock);
 	RR("HELLO message processed\n");
 	return rc;
 }
@@ -1431,7 +1545,6 @@
 	struct rr_packet *pkt = NULL;
 	struct msm_ipc_port *port_ptr;
 	struct sk_buff *head_skb;
-	struct msm_ipc_port_addr *src_addr;
 	struct msm_ipc_router_remote_port *rport_ptr;
 	uint32_t resume_tx, resume_tx_node_id, resume_tx_port_id;
 
@@ -1526,30 +1639,15 @@
 			}
 		}
 
-		if (!port_ptr->notify) {
-			mutex_lock(&port_ptr->port_rx_q_lock);
-			wake_lock(&port_ptr->port_rx_wake_lock);
-			list_add_tail(&pkt->list, &port_ptr->port_rx_q);
-			wake_up(&port_ptr->port_rx_wait_q);
-			mutex_unlock(&port_ptr->port_rx_q_lock);
-			mutex_unlock(&local_ports_lock);
-		} else {
-			mutex_lock(&port_ptr->port_rx_q_lock);
-			src_addr = kmalloc(sizeof(struct msm_ipc_port_addr),
-					   GFP_KERNEL);
-			if (src_addr) {
-				src_addr->node_id = hdr->src_node_id;
-				src_addr->port_id = hdr->src_port_id;
-			}
-			skb_pull(head_skb, IPC_ROUTER_HDR_SIZE);
-			mutex_unlock(&local_ports_lock);
+		mutex_lock(&port_ptr->port_rx_q_lock);
+		wake_lock(&port_ptr->port_rx_wake_lock);
+		list_add_tail(&pkt->list, &port_ptr->port_rx_q);
+		wake_up(&port_ptr->port_rx_wait_q);
+		if (port_ptr->notify)
 			port_ptr->notify(MSM_IPC_ROUTER_READ_CB,
-				pkt->pkt_fragment_q, src_addr, port_ptr->priv);
-			mutex_unlock(&port_ptr->port_rx_q_lock);
-			pkt->pkt_fragment_q = NULL;
-			src_addr = NULL;
-			release_pkt(pkt);
-		}
+					 port_ptr->priv);
+		mutex_unlock(&port_ptr->port_rx_q_lock);
+		mutex_unlock(&local_ports_lock);
 
 process_done:
 		if (resume_tx) {
@@ -1903,6 +2001,28 @@
 	return ret;
 }
 
+int msm_ipc_router_send_msg(struct msm_ipc_port *src,
+			    struct msm_ipc_addr *dest,
+			    void *data, unsigned int data_len)
+{
+	struct sk_buff_head *out_skb_head;
+	int ret;
+
+	out_skb_head = msm_ipc_router_buf_to_skb(data, data_len);
+	if (!out_skb_head) {
+		pr_err("%s: SKB conversion failed\n", __func__);
+		return -EFAULT;
+	}
+
+	ret = msm_ipc_router_send_to(src, out_skb_head, dest);
+	if (ret < 0) {
+		pr_err("%s: msm_ipc_router_send_to failed - ret: %d\n",
+			__func__, ret);
+		msm_ipc_router_free_skb(out_skb_head);
+	}
+	return 0;
+}
+
 int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
 			struct sk_buff_head **data,
 			size_t buf_len)
@@ -1938,7 +2058,7 @@
 int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
 			     struct sk_buff_head **data,
 			     struct msm_ipc_addr *src,
-			     unsigned long timeout)
+			     long timeout)
 {
 	int ret, data_len, align_size;
 	struct sk_buff *temp_skb;
@@ -1995,11 +2115,42 @@
 	return data_len;
 }
 
+int msm_ipc_router_read_msg(struct msm_ipc_port *port_ptr,
+			    struct msm_ipc_addr *src,
+			    unsigned char **data,
+			    unsigned int *len)
+{
+	struct sk_buff_head *in_skb_head;
+	int ret;
+
+	ret = msm_ipc_router_recv_from(port_ptr, &in_skb_head, src, -1);
+	if (ret < 0) {
+		pr_err("%s: msm_ipc_router_recv_from failed - ret: %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	*data = msm_ipc_router_skb_to_buf(in_skb_head, ret);
+	if (!(*data))
+		pr_err("%s: Buf conversion failed\n", __func__);
+
+	*len = ret;
+	msm_ipc_router_free_skb(in_skb_head);
+	return 0;
+}
+
 struct msm_ipc_port *msm_ipc_router_create_port(
-	void (*notify)(unsigned event, void *data, void *addr, void *priv),
+	void (*notify)(unsigned event, void *priv),
 	void *priv)
 {
 	struct msm_ipc_port *port_ptr;
+	int ret;
+
+	ret = wait_for_completion_interruptible(&msm_ipc_local_router_up);
+	if (ret < 0) {
+		pr_err("%s: Error waiting for local router\n", __func__);
+		return NULL;
+	}
 
 	port_ptr = msm_ipc_router_create_raw_port(NULL, notify, priv);
 	if (!port_ptr)
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index 07bc5e0..39038f2 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.h
@@ -18,22 +18,18 @@
 #include <linux/errno.h>
 #include <linux/mm.h>
 #include <linux/list.h>
-#include <linux/cdev.h>
 #include <linux/platform_device.h>
-#include <linux/wakelock.h>
 #include <linux/msm_ipc.h>
 
 #include <net/sock.h>
 
 /* definitions for the R2R wire protcol */
 #define IPC_ROUTER_VERSION			1
-#define IPC_ROUTER_PROCESSORS_MAX		4
 
 #define IPC_ROUTER_CLIENT_BCAST_ID		0xffffffff
 #define IPC_ROUTER_ADDRESS			0xfffffffe
 
 #define IPC_ROUTER_NID_LOCAL			1
-#define IPC_ROUTER_NID_REMOTE			0
 
 #define IPC_ROUTER_CTRL_CMD_DATA		1
 #define IPC_ROUTER_CTRL_CMD_HELLO		2
@@ -51,18 +47,11 @@
 #define IPC_ROUTER_XPRT_EVENT_OPEN  2
 #define IPC_ROUTER_XPRT_EVENT_CLOSE 3
 
-#define NUM_NODES 2
-
 #define IPC_ROUTER_INFINITY -1
 #define DEFAULT_RCV_TIMEO IPC_ROUTER_INFINITY
 
 #define ALIGN_SIZE(x) ((4 - ((x) & 3)) & 3)
 
-enum {
-	MSM_IPC_ROUTER_READ_CB = 0,
-	MSM_IPC_ROUTER_WRITE_DONE,
-};
-
 union rr_control_msg {
 	uint32_t cmd;
 	struct {
@@ -92,10 +81,6 @@
 
 #define IPC_ROUTER_HDR_SIZE sizeof(struct rr_header)
 #define MAX_IPC_PKT_SIZE 66000
-/* internals */
-
-#define IPC_ROUTER_MAX_REMOTE_SERVERS		100
-#define MAX_WAKELOCK_NAME_SZ 32
 
 struct rr_packet {
 	struct list_head list;
@@ -103,50 +88,12 @@
 	uint32_t length;
 };
 
-struct msm_ipc_port {
-	struct list_head list;
-
-	struct msm_ipc_port_addr this_port;
-	struct msm_ipc_port_name port_name;
-	uint32_t type;
-	unsigned flags;
-	spinlock_t port_lock;
-
-	struct list_head incomplete;
-	struct mutex incomplete_lock;
-
-	struct list_head port_rx_q;
-	struct mutex port_rx_q_lock;
-	char rx_wakelock_name[MAX_WAKELOCK_NAME_SZ];
-	struct wake_lock port_rx_wake_lock;
-	wait_queue_head_t port_rx_wait_q;
-
-	int restart_state;
-	spinlock_t restart_lock;
-	wait_queue_head_t restart_wait;
-
-	void *endpoint;
-	void (*notify)(unsigned event, void *data, void *addr, void *priv);
-
-	uint32_t num_tx;
-	uint32_t num_rx;
-	unsigned long num_tx_bytes;
-	unsigned long num_rx_bytes;
-	void *priv;
-};
-
 struct msm_ipc_sock {
 	struct sock sk;
 	struct msm_ipc_port *port;
 	void *default_pil;
 };
 
-enum write_data_type {
-	HEADER = 1,
-	PACKMARK,
-	PAYLOAD,
-};
-
 struct msm_ipc_router_xprt {
 	char *name;
 	uint32_t link_id;
@@ -161,8 +108,6 @@
 	int (*close)(struct msm_ipc_router_xprt *xprt);
 };
 
-extern struct completion msm_ipc_remote_router_up;
-
 void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
 				unsigned event,
 				void *data);
@@ -173,8 +118,7 @@
 
 
 struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
-		void (*notify)(unsigned event, void *data,
-			       void *addr, void *priv),
+		void (*notify)(unsigned event, void *priv),
 		void *priv);
 int msm_ipc_router_send_to(struct msm_ipc_port *src,
 			   struct sk_buff_head *data,
@@ -182,27 +126,16 @@
 int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
 			struct sk_buff_head **data,
 			size_t buf_len);
-int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr);
 int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr);
-int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
-				      struct msm_ipc_server_info *srv_info,
-				      int num_entries_in_array,
-				      uint32_t lookup_mask);
-int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr);
 
-struct msm_ipc_port *msm_ipc_router_create_port(
-	void (*notify)(unsigned event, void *data,
-		       void *addr, void *priv),
-	void *priv);
 int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
 		      struct sk_buff_head **data,
 		      struct msm_ipc_addr *src_addr,
-		      unsigned long timeout);
+		      long timeout);
 int msm_ipc_router_register_server(struct msm_ipc_port *server_port,
 			    struct msm_ipc_addr *name);
 int msm_ipc_router_unregister_server(struct msm_ipc_port *server_port);
 
-
 int msm_ipc_router_init_sockets(void);
 void msm_ipc_router_exit_sockets(void);
 
diff --git a/arch/arm/mach-msm/ipc_router_smd_xprt.c b/arch/arm/mach-msm/ipc_router_smd_xprt.c
index b2e6490..8c0bf4b 100644
--- a/arch/arm/mach-msm/ipc_router_smd_xprt.c
+++ b/arch/arm/mach-msm/ipc_router_smd_xprt.c
@@ -20,7 +20,7 @@
 #include <linux/types.h>
 
 #include <mach/msm_smd.h>
-#include <mach/peripheral-loader.h>
+#include <mach/subsystem_restart.h>
 
 #include "ipc_router.h"
 #include "smd_private.h"
@@ -210,7 +210,7 @@
 
 	rc = smd_close(smd_xprtp->channel);
 	if (smd_xprtp->pil) {
-		pil_put(smd_xprtp->pil);
+		subsystem_put(smd_xprtp->pil);
 		smd_xprtp->pil = NULL;
 	}
 	return rc;
@@ -402,7 +402,7 @@
 
 	peripheral = smd_edge_to_subsystem(edge);
 	if (peripheral) {
-		pil = pil_get(peripheral);
+		pil = subsystem_get(peripheral);
 		if (IS_ERR(pil)) {
 			pr_err("%s: Failed to load %s\n",
 				__func__, peripheral);
@@ -460,7 +460,7 @@
 		pr_err("%s: Channel open failed for %s\n",
 			__func__, smd_xprt_cfg[id].ch_name);
 		if (smd_remote_xprt[id].pil) {
-			pil_put(smd_remote_xprt[id].pil);
+			subsystem_put(smd_remote_xprt[id].pil);
 			smd_remote_xprt[id].pil = NULL;
 		}
 		destroy_workqueue(smd_remote_xprt[id].smd_xprt_wq);
@@ -481,7 +481,7 @@
 
 	peripheral = smd_edge_to_subsystem(SMD_APPS_MODEM);
 	if (peripheral && !strncmp(peripheral, "modem", 6)) {
-		pil = pil_get(peripheral);
+		pil = subsystem_get(peripheral);
 		if (IS_ERR(pil)) {
 			pr_err("%s: Failed to load %s\n",
 				__func__, peripheral);
@@ -495,7 +495,7 @@
 void msm_ipc_unload_default_node(void *pil)
 {
 	if (pil)
-		pil_put(pil);
+		subsystem_put(pil);
 }
 EXPORT_SYMBOL(msm_ipc_unload_default_node);
 
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index d3917f1..3a6abbd 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -30,6 +30,8 @@
 
 #include <net/sock.h>
 
+#include <mach/msm_ipc_router.h>
+
 #include "ipc_router.h"
 
 #define msm_ipc_sk(sk) ((struct msm_ipc_sock *)(sk))
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index aa9b344..63ae4e6 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -56,16 +56,10 @@
  *           |_________________|
  */
 
-#define V_RETENTION			600000
-#define V_LDO_HEADROOM			150000
-
 #define PMIC_VOLTAGE_MIN		350000
 #define PMIC_VOLTAGE_MAX		1355000
 #define LV_RANGE_STEP			5000
 
-/* use LDO for core voltage below LDO_THRESH */
-#define CORE_VOLTAGE_LDO_THRESH		750000
-
 #define LOAD_PER_PHASE			3200000
 
 #define CORE_VOLTAGE_MIN		900000
@@ -161,6 +155,10 @@
 	int				load_uA;
 	enum krait_supply_mode		mode;
 	void __iomem			*reg_base;
+	int				ldo_default_uV;
+	int				retention_uV;
+	int				headroom_uV;
+	int				ldo_threshold_uV;
 };
 
 static u32 version;
@@ -200,11 +198,22 @@
 	return uV;
 }
 
-static int set_krait_ldo_uv(struct krait_power_vreg *kvreg)
+static int set_krait_retention_uv(struct krait_power_vreg *kvreg, int uV)
 {
 	uint32_t reg_val;
 
-	reg_val = kvreg->uV - KRAIT_LDO_VOLTAGE_OFFSET / KRAIT_LDO_STEP;
+	reg_val = DIV_ROUND_UP(uV - KRAIT_LDO_VOLTAGE_OFFSET, KRAIT_LDO_STEP);
+	krait_masked_write(kvreg, APC_LDO_VREF_SET, VREF_RET_MASK,
+						reg_val << VREF_RET_POS);
+
+	return 0;
+}
+
+static int set_krait_ldo_uv(struct krait_power_vreg *kvreg, int uV)
+{
+	uint32_t reg_val;
+
+	reg_val = DIV_ROUND_UP(uV - KRAIT_LDO_VOLTAGE_OFFSET, KRAIT_LDO_STEP);
 	krait_masked_write(kvreg, APC_LDO_VREF_SET, VREF_LDO_MASK,
 						reg_val << VREF_LDO_BIT_POS);
 
@@ -252,7 +261,7 @@
 	if (kvreg->mode == LDO_MODE)
 		switch_to_using_hs(kvreg);
 
-	set_krait_ldo_uv(kvreg);
+	set_krait_ldo_uv(kvreg, kvreg->uV);
 
 	/*
 	 * enable ldo - note that both LDO and BHS are are supplying voltage to
@@ -310,8 +319,8 @@
 	int rc = 0;
 
 	list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
-		if (kvreg->uV > CORE_VOLTAGE_LDO_THRESH
-			 || kvreg->uV > vmax - V_LDO_HEADROOM) {
+		if (kvreg->uV > kvreg->ldo_threshold_uV
+			 || kvreg->uV > vmax - kvreg->headroom_uV) {
 			rc = switch_to_using_hs(kvreg);
 			if (rc < 0) {
 				pr_err("could not switch %s to hs rc = %d\n",
@@ -434,7 +443,7 @@
 	return rc;
 }
 
-static int __init pvreg_init(struct platform_device *pdev)
+static int __devinit pvreg_init(struct platform_device *pdev)
 {
 	struct pmic_gang_vreg *pvreg;
 
@@ -510,7 +519,7 @@
 	 * switch to LDO mode. Hence round the voltage as per the LDO
 	 * resolution
 	 */
-	if (min_uV < CORE_VOLTAGE_LDO_THRESH) {
+	if (min_uV < kvreg->ldo_threshold_uV) {
 		if (min_uV < KRAIT_LDO_VOLTAGE_MIN)
 			min_uV = KRAIT_LDO_VOLTAGE_MIN;
 		min_uV = ROUND_UP_VOLTAGE(min_uV, KRAIT_LDO_STEP);
@@ -638,6 +647,9 @@
 	/* BHS has six different segments, turn them all on */
 	krait_masked_write(kvreg, APC_PWR_GATE_CTL,
 		BHS_SEG_EN_MASK, BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS);
+
+	set_krait_retention_uv(kvreg, kvreg->retention_uV);
+	set_krait_ldo_uv(kvreg, kvreg->ldo_default_uV);
 }
 
 static void glb_init(struct platform_device *pdev)
@@ -649,12 +661,31 @@
 	pr_debug("version= 0x%x\n", version);
 }
 
+static int is_between(int left, int right, int value)
+{
+	if (left >= right && left >= value && value >= right)
+		return 1;
+	if (left <= right && left <= value && value <= right)
+		return 1;
+	return 0;
+}
+
+#define LDO_HDROOM_MIN		50000
+#define LDO_HDROOM_MAX		250000
+
+#define LDO_UV_MIN		465000
+#define LDO_UV_MAX		750000
+
+#define LDO_TH_MIN		600000
+#define LDO_TH_MAX		800000
+
 static int __devinit krait_power_probe(struct platform_device *pdev)
 {
 	struct krait_power_vreg *kvreg;
 	struct resource *res;
 	struct regulator_init_data *init_data = pdev->dev.platform_data;
 	int rc = 0;
+	int headroom_uV, retention_uV, ldo_default_uV, ldo_threshold_uV;
 
 	/* Initialize the pmic gang if it hasn't been initialized already */
 	if (the_gang == NULL) {
@@ -679,6 +710,57 @@
 			|= REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE
 			| REGULATOR_MODE_FAST;
 		init_data->constraints.input_uV = init_data->constraints.max_uV;
+		rc = of_property_read_u32(pdev->dev.of_node,
+					"qcom,headroom-voltage",
+					&headroom_uV);
+		if (rc < 0) {
+			pr_err("headroom-voltage missing rc=%d\n", rc);
+			return rc;
+		}
+		if (!is_between(LDO_HDROOM_MIN, LDO_HDROOM_MAX, headroom_uV)) {
+			pr_err("bad headroom-voltage = %d specified\n",
+					headroom_uV);
+			return -EINVAL;
+		}
+
+		rc = of_property_read_u32(pdev->dev.of_node,
+					"qcom,retention-voltage",
+					&retention_uV);
+		if (rc < 0) {
+			pr_err("retention-voltage missing rc=%d\n", rc);
+			return rc;
+		}
+		if (!is_between(LDO_UV_MIN, LDO_UV_MAX, retention_uV)) {
+			pr_err("bad retention-voltage = %d specified\n",
+					retention_uV);
+			return -EINVAL;
+		}
+
+		rc = of_property_read_u32(pdev->dev.of_node,
+					"qcom,ldo-default-voltage",
+					&ldo_default_uV);
+		if (rc < 0) {
+			pr_err("ldo-default-voltage missing rc=%d\n", rc);
+			return rc;
+		}
+		if (!is_between(LDO_UV_MIN, LDO_UV_MAX, ldo_default_uV)) {
+			pr_err("bad ldo-default-voltage = %d specified\n",
+					ldo_default_uV);
+			return -EINVAL;
+		}
+
+		rc = of_property_read_u32(pdev->dev.of_node,
+					"qcom,ldo-threshold-voltage",
+					&ldo_threshold_uV);
+		if (rc < 0) {
+			pr_err("ldo-threshold-voltage missing rc=%d\n", rc);
+			return rc;
+		}
+		if (!is_between(LDO_TH_MIN, LDO_TH_MAX, ldo_threshold_uV)) {
+			pr_err("bad ldo-threshold-voltage = %d specified\n",
+					ldo_threshold_uV);
+			return -EINVAL;
+		}
 	}
 
 	if (!init_data) {
@@ -708,15 +790,19 @@
 	kvreg->reg_base = devm_ioremap(&pdev->dev,
 				res->start, resource_size(res));
 
-	kvreg->pvreg	  = the_gang;
-	kvreg->name	  = init_data->constraints.name;
-	kvreg->desc.name  = kvreg->name;
-	kvreg->desc.ops   = &krait_power_ops;
-	kvreg->desc.type  = REGULATOR_VOLTAGE;
-	kvreg->desc.owner = THIS_MODULE;
-	kvreg->uV	  = CORE_VOLTAGE_MIN;
-	kvreg->mode	  = HS_MODE;
-	kvreg->desc.ops   = &krait_power_ops;
+	kvreg->pvreg		= the_gang;
+	kvreg->name		= init_data->constraints.name;
+	kvreg->desc.name	= kvreg->name;
+	kvreg->desc.ops		= &krait_power_ops;
+	kvreg->desc.type	= REGULATOR_VOLTAGE;
+	kvreg->desc.owner	= THIS_MODULE;
+	kvreg->uV		= CORE_VOLTAGE_MIN;
+	kvreg->mode		= HS_MODE;
+	kvreg->desc.ops		= &krait_power_ops;
+	kvreg->headroom_uV	= headroom_uV;
+	kvreg->retention_uV	= retention_uV;
+	kvreg->ldo_default_uV	= ldo_default_uV;
+	kvreg->ldo_threshold_uV = ldo_threshold_uV;
 
 	platform_set_drvdata(pdev, kvreg);
 
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index 4854fc48..61c2aa8 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -145,6 +145,11 @@
 		if (time_param->latency_us < level->latency_us)
 			continue;
 
+		if ((MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE == sleep_mode)
+			|| (MSM_PM_SLEEP_MODE_POWER_COLLAPSE == sleep_mode))
+			if (!cpu && msm_rpm_waiting_for_ack())
+					break;
+
 		if (time_param->sleep_us <= 1) {
 			pwr = level->energy_overhead;
 		} else if (time_param->sleep_us <= level->time_overhead_us) {
diff --git a/arch/arm/mach-msm/lpm_resources.c b/arch/arm/mach-msm/lpm_resources.c
index 255cd46..c21ea33 100644
--- a/arch/arm/mach-msm/lpm_resources.c
+++ b/arch/arm/mach-msm/lpm_resources.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -27,6 +27,7 @@
 #include "lpm_resources.h"
 #include "rpm-notifier.h"
 #include "idle.h"
+#include "trace_msm_low_power.h"
 
 /*Debug Definitions*/
 enum {
@@ -417,6 +418,7 @@
 
 	if (rs->valid)
 		rs->sleep_value = limits->l2_cache;
+	trace_lpm_resources(rs->sleep_value, rs->name);
 }
 
 static void msm_lpm_flush_l2(int notify_rpm)
@@ -497,6 +499,7 @@
 		else
 			rs->sleep_value = vdd_buf;
 	}
+	trace_lpm_resources(rs->sleep_value, rs->name);
 }
 
 static void msm_lpm_flush_vdd_dig(int notify_rpm)
@@ -551,6 +554,7 @@
 		else
 			rs->sleep_value = vdd_buf;
 	}
+	trace_lpm_resources(rs->sleep_value, rs->name);
 }
 
 static void msm_lpm_flush_vdd_mem(int notify_rpm)
@@ -608,6 +612,7 @@
 			pr_info("%s: pxo buf %d sleep value %d\n",
 					__func__, pxo_buf, rs->sleep_value);
 	}
+	trace_lpm_resources(rs->sleep_value, rs->name);
 }
 
 static void msm_lpm_flush_pxo(int notify_rpm)
diff --git a/arch/arm/mach-msm/mdm.c b/arch/arm/mach-msm/mdm.c
index 02978cf..8dd4bac 100644
--- a/arch/arm/mach-msm/mdm.c
+++ b/arch/arm/mach-msm/mdm.c
@@ -354,6 +354,7 @@
 		ret = PTR_ERR(charm_subsys);
 		goto fatal_err;
 	}
+	subsys_default_online(charm_subsys);
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index 58b26f2..b81832e 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -681,6 +681,7 @@
 		ret = PTR_ERR(mdm_subsys_dev);
 		goto fatal_err;
 	}
+	subsys_default_online(mdm_subsys_dev);
 
 	/* ERR_FATAL irq. */
 	irq = MSM_GPIO_TO_INT(mdm_drv->mdm2ap_errfatal_gpio);
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index 7d7380b..3fe65b8 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -464,3 +464,8 @@
 
 	return ret;
 }
+
+/* Provide a string that anonymous device tree allocations (those not
+ * directly associated with any driver) can use for their "compatible"
+ * field */
+EXPORT_COMPAT("qcom,msm-contig-mem");
diff --git a/arch/arm/mach-msm/msm_bus/Makefile b/arch/arm/mach-msm/msm_bus/Makefile
index bdc6fac..dde25ab 100644
--- a/arch/arm/mach-msm/msm_bus/Makefile
+++ b/arch/arm/mach-msm/msm_bus/Makefile
@@ -11,4 +11,5 @@
 obj-$(CONFIG_ARCH_APQ8064) += msm_bus_board_8064.o
 obj-$(CONFIG_ARCH_MSM8930) += msm_bus_board_8930.o
 obj-$(CONFIG_ARCH_MSM8974) += msm_bus_board_8974.o
+obj-$(CONFIG_ARCH_MSM9625) += msm_bus_board_9625.o
 obj-$(CONFIG_DEBUG_FS) += msm_bus_dbg.o
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_9625.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_9625.c
new file mode 100644
index 0000000..92cd255
--- /dev/null
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_9625.c
@@ -0,0 +1,1303 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/rpm.h>
+#include "msm_bus_core.h"
+#include "msm_bus_noc.h"
+#include "msm_bus_bimc.h"
+
+#define NMASTERS 120
+#define NSLAVES 150
+#define NFAB_9625 4
+
+enum msm_bus_9625_master_ports_type {
+	/* System NOC Masters */
+	MASTER_PORT_LPASS_AHB = 0,
+	MASTER_PORT_QDSS_BAM,
+	MASTER_PORT_SNOC_CFG,
+	MASTER_PORT_GW_BIMC_SNOC,
+	MASTER_PORT_GW_CNOC_SNOC,
+	MASTER_PORT_CRYPTO_CORE0,
+	MASTER_PORT_LPASS_PROC,
+	MASTER_PORT_MSS,
+	MASTER_PORT_MSS_NAV,
+	MASTER_PORT_IPA,
+	MASTER_PORT_GW_PNOC_SNOC,
+	MASTER_PORT_QDSS_ETR,
+
+	/* BIMC Masters */
+	MASTER_PORT_KMPSS_M0 = 0,
+	MASTER_PORT_MSS_PROC,
+	MASTER_PORT_GW_SNOC_BIMC_0,
+
+	/* Peripheral NOC Masters */
+	MASTER_PORT_QPIC = 0,
+	MASTER_PORT_SDCC_1,
+	MASTER_PORT_SDCC_3,
+	MASTER_PORT_SDCC_2,
+	MASTER_PORT_SDCC_4,
+	MASTER_PORT_TSIF,
+	MASTER_PORT_BAM_DMA,
+	MASTER_PORT_BLSP_2,
+	MASTER_PORT_USB_HSIC,
+	MASTER_PORT_BLSP_1,
+	MASTER_PORT_USB_HS1,
+	MASTER_PORT_USB_HS2,
+	MASTER_PORT_PNOC_CFG,
+	MASTER_PORT_GW_SNOC_PNOC,
+
+	/* Config NOC Masters */
+	MASTER_PORT_RPM_INST = 0,
+	MASTER_PORT_RPM_DATA,
+	MASTER_PORT_RPM_SYS,
+	MASTER_PORT_DEHR,
+	MASTER_PORT_QDSS_DAP,
+	MASTER_PORT_SPDM,
+	MASTER_PORT_TIC,
+	MASTER_PORT_GW_SNOC_CNOC,
+};
+
+enum msm_bus_9625_slave_ports_type {
+	/* System NOC Slaves */
+	SLAVE_PORT_KMPSS = 1,
+	SLAVE_PORT_LPASS,
+	SLAVE_PORT_GW_SNOC_BIMC_P0,
+	SLAVE_PORT_GW_SNOC_CNOC,
+	SLAVE_PORT_OCIMEM,
+	SLAVE_PORT_GW_SNOC_PNOC,
+	SLAVE_PORT_SERVICE_SNOC,
+	SLAVE_PORT_QDSS_STM,
+
+	/* BIMC Slaves */
+	SLAVE_PORT_EBI1_CH0 = 0,
+	SLAVE_PORT_GW_BIMC_SNOC,
+
+	/*Peripheral NOC Slaves */
+	SLAVE_PORT_QPIC = 0,
+	SLAVE_PORT_SDCC_1,
+	SLAVE_PORT_SDCC_3,
+	SLAVE_PORT_SDCC_2,
+	SLAVE_PORT_SDCC_4,
+	SLAVE_PORT_TSIF,
+	SLAVE_PORT_BAM_DMA,
+	SLAVE_PORT_BLSP_2,
+	SLAVE_PORT_USB_HSIC,
+	SLAVE_PORT_BLSP_1,
+	SLAVE_PORT_USB_HS1,
+	SLAVE_PORT_USB_HS2,
+	SLAVE_PORT_PDM,
+	SLAVE_PORT_PERIPH_APU_CFG,
+	SLAVE_PORT_PNOC_MPU_CFG,
+	SLAVE_PORT_PRNG,
+	SLAVE_PORT_GW_PNOC_SNOC,
+	SLAVE_PORT_SERVICE_PNOC,
+
+	/* Config NOC slaves */
+	SLAVE_PORT_CLK_CTL = 0,
+	SLAVE_PORT_CNOC_MSS,
+	SLAVE_PORT_SECURITY,
+	SLAVE_PORT_TCSR,
+	SLAVE_PORT_TLMM,
+	SLAVE_PORT_CRYPTO_0_CFG,
+	SLAVE_PORT_IMEM_CFG,
+	SLAVE_PORT_IPS_CFG,
+	SLAVE_PORT_MESSAGE_RAM,
+	SLAVE_PORT_BIMC_CFG,
+	SLAVE_PORT_BOOT_ROM,
+	SLAVE_PORT_PMIC_ARB,
+	SLAVE_PORT_SPDM_WRAPPER,
+	SLAVE_PORT_DEHR_CFG,
+	SLAVE_PORT_MPM,
+	SLAVE_PORT_QDSS_CFG,
+	SLAVE_PORT_RBCPR_CFG,
+	SLAVE_PORT_RBCPR_QDSS_APU_CFG,
+	SLAVE_PORT_SNOC_MPU_CFG,
+	SLAVE_PORT_PNOC_CFG,
+	SLAVE_PORT_SNOC_CFG,
+	SLAVE_PORT_PHY_APU_CFG,
+	SLAVE_PORT_EBI1_PHY_CFG,
+	SLAVE_PORT_RPM,
+	SLAVE_PORT_GW_CNOC_SNOC,
+	SLAVE_PORT_SERVICE_CNOC,
+};
+
+/* Hardware IDs for RPM */
+enum msm_bus_9625_mas_hw_id {
+	MAS_APPSS_PROC = 0,
+	MAS_AMSS_PROC,
+	MAS_MNOC_BIMC,
+	MAS_SNOC_BIMC,
+	MAS_CNOC_MNOC_MMSS_CFG,
+	MAS_CNOC_MNOC_CFG,
+	MAS_GFX3D,
+	MAS_JPEG,
+	MAS_MDP,
+	MAS_VIDEO_P0,
+	MAS_VIDEO_P1,
+	MAS_VFE,
+	MAS_CNOC_ONOC_CFG,
+	MAS_JPEG_OCMEM,
+	MAS_MDP_OCMEM,
+	MAS_VIDEO_P0_OCMEM,
+	MAS_VIDEO_P1_OCMEM,
+	MAS_VFE_OCMEM,
+	MAS_LPASS_AHB,
+	MAS_QDSS_BAM,
+	MAS_SNOC_CFG,
+	MAS_BIMC_SNOC,
+	MAS_CNOC_SNOC,
+	MAS_CRYPTO_CORE0,
+	MAS_CRYPTO_CORE1,
+	MAS_LPASS_PROC,
+	MAS_MSS,
+	MAS_MSS_NAV,
+	MAS_OCMEM_DMA,
+	MAS_PNOC_SNOC,
+	MAS_WCSS,
+	MAS_QDSS_ETR,
+	MAS_USB3,
+	MAS_SDCC_1,
+	MAS_SDCC_3,
+	MAS_SDCC_2,
+	MAS_SDCC_4,
+	MAS_TSIF,
+	MAS_BAM_DMA,
+	MAS_BLSP_2,
+	MAS_USB_HSIC,
+	MAS_BLSP_1,
+	MAS_USB_HS,
+	MAS_PNOC_CFG,
+	MAS_SNOC_PNOC,
+	MAS_RPM_INST,
+	MAS_RPM_DATA,
+	MAS_RPM_SYS,
+	MAS_DEHR,
+	MAS_QDSS_DAP,
+	MAS_SPDM,
+	MAS_TIC,
+	MAS_SNOC_CNOC,
+	MAS_OVNOC_SNOC,
+	MAS_OVNOC_ONOC,
+	MAS_V_OCMEM_GFX3D,
+	MAS_ONOC_OVNOC,
+	MAS_SNOC_OVNOC,
+	MAS_QPIC,
+	MAS_IPA,
+};
+
+enum msm_bus_9625_slv_hw_id {
+	SLV_EBI = 0,
+	SLV_APSS_L2,
+	SLV_BIMC_SNOC,
+	SLV_CAMERA_CFG,
+	SLV_DISPLAY_CFG,
+	SLV_OCMEM_CFG,
+	SLV_CPR_CFG,
+	SLV_CPR_XPU_CFG,
+	SLV_MISC_CFG,
+	SLV_MISC_XPU_CFG,
+	SLV_VENUS_CFG,
+	SLV_GFX3D_CFG,
+	SLV_MMSS_CLK_CFG,
+	SLV_MMSS_CLK_XPU_CFG,
+	SLV_MNOC_MPU_CFG,
+	SLV_ONOC_MPU_CFG,
+	SLV_MMSS_BIMC,
+	SLV_SERVICE_MNOC,
+	SLV_OCMEM,
+	SLV_SERVICE_ONOC,
+	SLV_APPSS,
+	SLV_LPASS,
+	SLV_USB3,
+	SLV_WCSS,
+	SLV_SNOC_BIMC,
+	SLV_SNOC_CNOC,
+	SLV_OCIMEM,
+	SLV_SNOC_OCMEM,
+	SLV_SNOC_PNOC,
+	SLV_SERVICE_SNOC,
+	SLV_QDSS_STM,
+	SLV_SDCC_1,
+	SLV_SDCC_3,
+	SLV_SDCC_2,
+	SLV_SDCC_4,
+	SLV_TSIF,
+	SLV_BAM_DMA,
+	SLV_BLSP_2,
+	SLV_USB_HSIC,
+	SLV_BLSP_1,
+	SLV_USB_HS,
+	SLV_PDM,
+	SLV_PERIPH_APU_CFG,
+	SLV_MPU_CFG,
+	SLV_PRNG,
+	SLV_PNOC_SNOC,
+	SLV_SERVICE_PNOC,
+	SLV_CLK_CTL,
+	SLV_CNOC_MSS,
+	SLV_SECURITY,
+	SLV_TCSR,
+	SLV_TLMM,
+	SLV_CRYPTO_0_CFG,
+	SLV_CRYPTO_1_CFG,
+	SLV_IMEM_CFG,
+	SLV_MESSAGE_RAM,
+	SLV_BIMC_CFG,
+	SLV_BOOT_ROM,
+	SLV_CNOC_MNOC_MMSS_CFG,
+	SLV_PMIC_ARB,
+	SLV_SPDM_WRAPPER,
+	SLV_DEHR_CFG,
+	SLV_MPM,
+	SLV_QDSS_CFG,
+	SLV_RBCPR_CFG,
+	SLV_RBCPR_QDSS_APU_CFG,
+	SLV_CNOC_MNOC_CFG,
+	SLV_SNOC_MPU_CFG,
+	SLV_CNOC_ONOC_CFG,
+	SLV_PNOC_CFG,
+	SLV_SNOC_CFG,
+	SLV_EBI1_DLL_CFG,
+	SLV_PHY_APU_CFG,
+	SLV_EBI1_PHY_CFG,
+	SLV_RPM,
+	SLV_CNOC_SNOC,
+	SLV_SERVICE_CNOC,
+	SLV_SNOC_OVNOC,
+	SLV_ONOC_OVNOC,
+	SLV_USB_HS2,
+	SLV_QPIC,
+	SLV_IPS_CFG,
+};
+
+static uint32_t master_iids[NMASTERS];
+static uint32_t slave_iids[NSLAVES];
+
+/* System NOC nodes */
+static int mport_lpass_ahb[] = {MASTER_PORT_LPASS_AHB,};
+static int mport_qdss_bam[] = {MASTER_PORT_QDSS_BAM,};
+static int mport_snoc_cfg[] = {MASTER_PORT_SNOC_CFG,};
+static int mport_gw_bimc_snoc[] = {MASTER_PORT_GW_BIMC_SNOC,};
+static int mport_gw_cnoc_snoc[] = {MASTER_PORT_GW_CNOC_SNOC,};
+static int mport_crypto_core0[] = {MASTER_PORT_CRYPTO_CORE0,};
+static int mport_lpass_proc[] = {MASTER_PORT_LPASS_PROC};
+static int mport_mss[] = {MASTER_PORT_MSS};
+static int mport_mss_nav[] = {MASTER_PORT_MSS_NAV};
+static int mport_ipa[] = {MASTER_PORT_IPA};
+static int mport_gw_pnoc_snoc[] = {MASTER_PORT_GW_PNOC_SNOC};
+static int mport_qdss_etr[] = {MASTER_PORT_QDSS_ETR};
+
+static int sport_kmpss[] = {SLAVE_PORT_KMPSS};
+static int sport_lpass[] = {SLAVE_PORT_LPASS};
+static int sport_gw_snoc_bimc[] = {SLAVE_PORT_GW_SNOC_BIMC_P0};
+static int sport_gw_snoc_cnoc[] = {SLAVE_PORT_GW_SNOC_CNOC};
+static int sport_ocimem[] = {SLAVE_PORT_OCIMEM};
+static int sport_gw_snoc_pnoc[] = {SLAVE_PORT_GW_SNOC_PNOC};
+static int sport_service_snoc[] = {SLAVE_PORT_SERVICE_SNOC};
+static int sport_qdss_stm[] = {SLAVE_PORT_QDSS_STM};
+
+/* BIMC Nodes */
+
+static int mport_kmpss_m0[] = {MASTER_PORT_KMPSS_M0,};
+static int mport_mss_proc[] = {MASTER_PORT_MSS_PROC};
+static int mport_gw_snoc_bimc[] = {MASTER_PORT_GW_SNOC_BIMC_0};
+
+static int sport_ebi1[] = {SLAVE_PORT_EBI1_CH0};
+static int sport_gw_bimc_snoc[] = {SLAVE_PORT_GW_BIMC_SNOC,};
+
+/* Peripheral NOC Nodes */
+static int mport_sdcc_1[] = {MASTER_PORT_SDCC_1,};
+static int mport_sdcc_3[] = {MASTER_PORT_SDCC_3,};
+static int mport_sdcc_2[] = {MASTER_PORT_SDCC_2,};
+static int mport_sdcc_4[] = {MASTER_PORT_SDCC_4,};
+static int mport_tsif[] = {MASTER_PORT_TSIF,};
+static int mport_bam_dma[] = {MASTER_PORT_BAM_DMA,};
+static int mport_blsp_2[] = {MASTER_PORT_BLSP_2,};
+static int mport_usb_hsic[] = {MASTER_PORT_USB_HSIC,};
+static int mport_blsp_1[] = {MASTER_PORT_BLSP_1,};
+static int mport_pnoc_cfg[] = {MASTER_PORT_PNOC_CFG,};
+static int mport_qpic[] = {MASTER_PORT_QPIC,};
+static int mport_gw_snoc_pnoc[] = {MASTER_PORT_GW_SNOC_PNOC,};
+
+static int sport_sdcc_1[] = {SLAVE_PORT_SDCC_1,};
+static int sport_sdcc_3[] = {SLAVE_PORT_SDCC_3,};
+static int sport_sdcc_2[] = {SLAVE_PORT_SDCC_2,};
+static int sport_sdcc_4[] = {SLAVE_PORT_SDCC_4,};
+static int sport_tsif[] = {SLAVE_PORT_TSIF,};
+static int sport_qpic[] = {SLAVE_PORT_QPIC,};
+static int sport_bam_dma[] = {SLAVE_PORT_BAM_DMA,};
+static int sport_blsp_2[] = {SLAVE_PORT_BLSP_2,};
+static int sport_usb_hsic[] = {SLAVE_PORT_USB_HSIC,};
+static int sport_blsp_1[] = {SLAVE_PORT_BLSP_1,};
+static int sport_pdm[] = {SLAVE_PORT_PDM,};
+static int sport_periph_apu_cfg[] = {
+	SLAVE_PORT_PERIPH_APU_CFG,
+};
+static int sport_pnoc_mpu_cfg[] = {SLAVE_PORT_PNOC_MPU_CFG,};
+static int sport_prng[] = {SLAVE_PORT_PRNG,};
+static int sport_gw_pnoc_snoc[] = {SLAVE_PORT_GW_PNOC_SNOC,};
+static int sport_service_pnoc[] = {SLAVE_PORT_SERVICE_PNOC,};
+
+/* Config NOC Nodes */
+static int mport_rpm_inst[] = {MASTER_PORT_RPM_INST,};
+static int mport_rpm_data[] = {MASTER_PORT_RPM_DATA,};
+static int mport_rpm_sys[] = {MASTER_PORT_RPM_SYS,};
+static int mport_dehr[] = {MASTER_PORT_DEHR,};
+static int mport_qdss_dap[] = {MASTER_PORT_QDSS_DAP,};
+static int mport_spdm[] = {MASTER_PORT_SPDM,};
+static int mport_tic[] = {MASTER_PORT_TIC,};
+static int mport_gw_snoc_cnoc[] = {MASTER_PORT_GW_SNOC_CNOC,};
+
+static int sport_clk_ctl[] = {SLAVE_PORT_CLK_CTL,};
+static int sport_cnoc_mss[] = {SLAVE_PORT_CNOC_MSS,};
+static int sport_security[] = {SLAVE_PORT_SECURITY,};
+static int sport_tcsr[] = {SLAVE_PORT_TCSR,};
+static int sport_tlmm[] = {SLAVE_PORT_TLMM,};
+static int sport_crypto_0_cfg[] = {SLAVE_PORT_CRYPTO_0_CFG,};
+static int sport_imem_cfg[] = {SLAVE_PORT_IMEM_CFG,};
+static int sport_ips_cfg[] = {SLAVE_PORT_IPS_CFG,};
+static int sport_message_ram[] = {SLAVE_PORT_MESSAGE_RAM,};
+static int sport_bimc_cfg[] = {SLAVE_PORT_BIMC_CFG,};
+static int sport_boot_rom[] = {SLAVE_PORT_BOOT_ROM,};
+static int sport_pmic_arb[] = {SLAVE_PORT_PMIC_ARB,};
+static int sport_spdm_wrapper[] = {SLAVE_PORT_SPDM_WRAPPER,};
+static int sport_dehr_cfg[] = {SLAVE_PORT_DEHR_CFG,};
+static int sport_mpm[] = {SLAVE_PORT_MPM,};
+static int sport_qdss_cfg[] = {SLAVE_PORT_QDSS_CFG,};
+static int sport_rbcpr_cfg[] = {SLAVE_PORT_RBCPR_CFG,};
+static int sport_rbcpr_qdss_apu_cfg[] = {SLAVE_PORT_RBCPR_QDSS_APU_CFG,};
+static int sport_snoc_mpu_cfg[] = {SLAVE_PORT_SNOC_MPU_CFG,};
+static int sport_pnoc_cfg[] = {SLAVE_PORT_PNOC_CFG,};
+static int sport_snoc_cfg[] = {SLAVE_PORT_SNOC_CFG,};
+static int sport_phy_apu_cfg[] = {SLAVE_PORT_PHY_APU_CFG,};
+static int sport_ebi1_phy_cfg[] = {SLAVE_PORT_EBI1_PHY_CFG,};
+static int sport_rpm[] = {SLAVE_PORT_RPM,};
+static int sport_gw_cnoc_snoc[] = {SLAVE_PORT_GW_CNOC_SNOC,};
+static int sport_service_cnoc[] = {SLAVE_PORT_SERVICE_CNOC,};
+
+static int tier2[] = {MSM_BUS_BW_TIER2,};
+
+/*
+ * QOS Ports defined only when qos ports are different than
+ * master ports
+ **/
+static int qports_crypto_c0[] = {2};
+static int qports_lpass_proc[] = {4};
+static int qports_gw_snoc_bimc[] = {2};
+static int qports_kmpss[] = {0};
+static int qports_lpass_ahb[] = {0};
+static int qports_qdss_bam[] = {1};
+static int qports_gw_pnoc_snoc[] = {8};
+static int qports_ipa[] = {7};
+static int qports_qdss_etr[] = {10};
+
+static struct msm_bus_node_info sys_noc_info[] = {
+	{
+		.id = MSM_BUS_MASTER_LPASS_AHB,
+		.masterp = mport_lpass_ahb,
+		.num_mports = ARRAY_SIZE(mport_lpass_ahb),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.qport = qports_lpass_ahb,
+		.mas_hw_id = MAS_LPASS_AHB,
+		.mode = NOC_QOS_MODE_FIXED,
+		.prio_rd = 2,
+		.prio_wr = 2,
+	},
+	{
+		.id = MSM_BUS_MASTER_QDSS_BAM,
+		.masterp = mport_qdss_bam,
+		.num_mports = ARRAY_SIZE(mport_qdss_bam),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.mode = NOC_QOS_MODE_FIXED,
+		.qport = qports_qdss_bam,
+		.mas_hw_id = MAS_QDSS_BAM,
+	},
+	{
+		.id = MSM_BUS_MASTER_SNOC_CFG,
+		.masterp = mport_snoc_cfg,
+		.num_mports = ARRAY_SIZE(mport_snoc_cfg),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.mas_hw_id = MAS_SNOC_CFG,
+	},
+	{
+		.id = MSM_BUS_FAB_BIMC,
+		.gateway = 1,
+		.slavep = sport_gw_snoc_bimc,
+		.num_sports = ARRAY_SIZE(sport_gw_snoc_bimc),
+		.masterp = mport_gw_bimc_snoc,
+		.num_mports = ARRAY_SIZE(mport_gw_bimc_snoc),
+		.buswidth = 8,
+		.mas_hw_id = MAS_BIMC_SNOC,
+		.slv_hw_id = SLV_SNOC_BIMC,
+	},
+	{
+		.id = MSM_BUS_FAB_CONFIG_NOC,
+		.gateway = 1,
+		.slavep = sport_gw_snoc_cnoc,
+		.num_sports = ARRAY_SIZE(sport_gw_snoc_cnoc),
+		.masterp = mport_gw_cnoc_snoc,
+		.num_mports = ARRAY_SIZE(mport_gw_cnoc_snoc),
+		.buswidth = 8,
+		.mas_hw_id = MAS_CNOC_SNOC,
+		.slv_hw_id = SLV_SNOC_CNOC,
+	},
+	{
+		.id = MSM_BUS_FAB_PERIPH_NOC,
+		.gateway = 1,
+		.slavep = sport_gw_snoc_pnoc,
+		.num_sports = ARRAY_SIZE(sport_gw_snoc_pnoc),
+		.masterp = mport_gw_pnoc_snoc,
+		.num_mports = ARRAY_SIZE(mport_gw_pnoc_snoc),
+		.buswidth = 8,
+		.qport = qports_gw_pnoc_snoc,
+		.mas_hw_id = MAS_PNOC_SNOC,
+		.slv_hw_id = SLV_SNOC_PNOC,
+		.mode = NOC_QOS_MODE_FIXED,
+		.prio_rd = 2,
+		.prio_wr = 2,
+	},
+	{
+		.id = MSM_BUS_MASTER_CRYPTO_CORE0,
+		.masterp = mport_crypto_core0,
+		.num_mports = ARRAY_SIZE(mport_crypto_core0),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.mode = NOC_QOS_MODE_FIXED,
+		.qport = qports_crypto_c0,
+		.mas_hw_id = MAS_CRYPTO_CORE0,
+		.hw_sel = MSM_BUS_NOC,
+	},
+	{
+		.id = MSM_BUS_MASTER_LPASS_PROC,
+		.masterp = mport_lpass_proc,
+		.num_mports = ARRAY_SIZE(mport_lpass_proc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.qport = qports_lpass_proc,
+		.mas_hw_id = MAS_LPASS_PROC,
+		.mode = NOC_QOS_MODE_FIXED,
+		.prio_rd = 2,
+		.prio_wr = 2,
+	},
+	{
+		.id = MSM_BUS_MASTER_MSS,
+		.masterp = mport_mss,
+		.num_mports = ARRAY_SIZE(mport_mss),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.mas_hw_id = MAS_MSS,
+	},
+	{
+		.id = MSM_BUS_MASTER_MSS_NAV,
+		.masterp = mport_mss_nav,
+		.num_mports = ARRAY_SIZE(mport_mss_nav),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.mas_hw_id = MAS_MSS_NAV,
+	},
+	{
+		.id = MSM_BUS_MASTER_IPA,
+		.masterp = mport_ipa,
+		.num_mports = ARRAY_SIZE(mport_ipa),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.mode = NOC_QOS_MODE_FIXED,
+		.qport = qports_ipa,
+		.mas_hw_id = MAS_IPA,
+	},
+	{
+		.id = MSM_BUS_MASTER_QDSS_ETR,
+		.masterp = mport_qdss_etr,
+		.num_mports = ARRAY_SIZE(mport_qdss_etr),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.qport = qports_qdss_etr,
+		.mode = NOC_QOS_MODE_FIXED,
+		.mas_hw_id = MAS_QDSS_ETR,
+	},
+	{
+		.id = MSM_BUS_SLAVE_AMPSS,
+		.slavep = sport_kmpss,
+		.num_sports = ARRAY_SIZE(sport_kmpss),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_APPSS,
+	},
+	{
+		.id = MSM_BUS_SLAVE_LPASS,
+		.slavep = sport_lpass,
+		.num_sports = ARRAY_SIZE(sport_lpass),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_LPASS,
+	},
+	{
+		.id = MSM_BUS_SLAVE_OCIMEM,
+		.slavep = sport_ocimem,
+		.num_sports = ARRAY_SIZE(sport_ocimem),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_OCIMEM,
+	},
+	{
+		.id = MSM_BUS_SLAVE_SERVICE_SNOC,
+		.slavep = sport_service_snoc,
+		.num_sports = ARRAY_SIZE(sport_service_snoc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_SERVICE_SNOC,
+	},
+	{
+		.id = MSM_BUS_SLAVE_QDSS_STM,
+		.slavep = sport_qdss_stm,
+		.num_sports = ARRAY_SIZE(sport_qdss_stm),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_QDSS_STM,
+	},
+};
+
+static struct msm_bus_node_info bimc_info[]  = {
+	{
+		.id = MSM_BUS_MASTER_AMPSS_M0,
+		.masterp = mport_kmpss_m0,
+		.num_mports = ARRAY_SIZE(mport_kmpss_m0),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.hw_sel = MSM_BUS_BIMC,
+		.mode = NOC_QOS_MODE_FIXED,
+		.qport = qports_kmpss,
+		.ws = 10000,
+		.mas_hw_id = MAS_APPSS_PROC,
+		.prio_lvl = 0,
+		.prio_rd = 2,
+		.prio_wr = 2,
+	},
+	{
+		.id = MSM_BUS_MASTER_MSS_PROC,
+		.masterp = mport_mss_proc,
+		.num_mports = ARRAY_SIZE(mport_mss_proc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.hw_sel = MSM_BUS_RPM,
+		.mas_hw_id = MAS_AMSS_PROC,
+	},
+	{
+		.id = MSM_BUS_FAB_SYS_NOC,
+		.gateway = 1,
+		.slavep = sport_gw_bimc_snoc,
+		.num_sports = ARRAY_SIZE(sport_gw_bimc_snoc),
+		.masterp = mport_gw_snoc_bimc,
+		.num_mports = ARRAY_SIZE(mport_gw_snoc_bimc),
+		.qport = qports_gw_snoc_bimc,
+		.buswidth = 8,
+		.ws = 10000,
+		.mas_hw_id = MAS_SNOC_BIMC,
+		.slv_hw_id = SLV_BIMC_SNOC,
+		.mode = NOC_QOS_MODE_BYPASS,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI_CH0,
+		.slavep = sport_ebi1,
+		.num_sports = ARRAY_SIZE(sport_ebi1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_EBI,
+		.mode = NOC_QOS_MODE_BYPASS,
+	},
+};
+
+static struct msm_bus_node_info periph_noc_info[] = {
+	{
+		.id = MSM_BUS_MASTER_PNOC_CFG,
+		.masterp = mport_pnoc_cfg,
+		.num_mports = ARRAY_SIZE(mport_pnoc_cfg),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.mas_hw_id = MAS_PNOC_CFG,
+	},
+	{
+		.id = MSM_BUS_MASTER_QPIC,
+		.masterp = mport_qpic,
+		.num_mports = ARRAY_SIZE(mport_qpic),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.mas_hw_id = MAS_QPIC,
+	},
+	{
+		.id = MSM_BUS_MASTER_SDCC_1,
+		.masterp = mport_sdcc_1,
+		.num_mports = ARRAY_SIZE(mport_sdcc_1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.mas_hw_id = MAS_SDCC_1,
+	},
+	{
+		.id = MSM_BUS_MASTER_SDCC_3,
+		.masterp = mport_sdcc_3,
+		.num_mports = ARRAY_SIZE(mport_sdcc_3),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.mas_hw_id = MAS_SDCC_3,
+	},
+	{
+		.id = MSM_BUS_MASTER_SDCC_4,
+		.masterp = mport_sdcc_4,
+		.num_mports = ARRAY_SIZE(mport_sdcc_4),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.mas_hw_id = MAS_SDCC_4,
+	},
+	{
+		.id = MSM_BUS_MASTER_SDCC_2,
+		.masterp = mport_sdcc_2,
+		.num_mports = ARRAY_SIZE(mport_sdcc_2),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.mas_hw_id = MAS_SDCC_2,
+	},
+	{
+		.id = MSM_BUS_MASTER_TSIF,
+		.masterp = mport_tsif,
+		.num_mports = ARRAY_SIZE(mport_tsif),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.mas_hw_id = MAS_TSIF,
+	},
+	{
+		.id = MSM_BUS_MASTER_BAM_DMA,
+		.masterp = mport_bam_dma,
+		.num_mports = ARRAY_SIZE(mport_bam_dma),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.mas_hw_id = MAS_BAM_DMA,
+	},
+	{
+		.id = MSM_BUS_MASTER_BLSP_2,
+		.masterp = mport_blsp_2,
+		.num_mports = ARRAY_SIZE(mport_blsp_2),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.mas_hw_id = MAS_BLSP_2,
+	},
+	{
+		.id = MSM_BUS_MASTER_USB_HSIC,
+		.masterp = mport_usb_hsic,
+		.num_mports = ARRAY_SIZE(mport_usb_hsic),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.mas_hw_id = MAS_USB_HSIC,
+	},
+	{
+		.id = MSM_BUS_MASTER_BLSP_1,
+		.masterp = mport_blsp_1,
+		.num_mports = ARRAY_SIZE(mport_blsp_1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.mas_hw_id = MAS_BLSP_1,
+	},
+	{
+		.id = MSM_BUS_FAB_SYS_NOC,
+		.gateway = 1,
+		.slavep = sport_gw_pnoc_snoc,
+		.num_sports = ARRAY_SIZE(sport_gw_pnoc_snoc),
+		.masterp = mport_gw_snoc_pnoc,
+		.num_mports = ARRAY_SIZE(mport_gw_snoc_pnoc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_PNOC_SNOC,
+		.mas_hw_id = MAS_SNOC_PNOC,
+	},
+	{
+		.id = MSM_BUS_SLAVE_SDCC_1,
+		.slavep = sport_sdcc_1,
+		.num_sports = ARRAY_SIZE(sport_sdcc_1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_SDCC_1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_SDCC_3,
+		.slavep = sport_sdcc_3,
+		.num_sports = ARRAY_SIZE(sport_sdcc_3),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_SDCC_3,
+	},
+	{
+		.id = MSM_BUS_SLAVE_SDCC_2,
+		.slavep = sport_sdcc_2,
+		.num_sports = ARRAY_SIZE(sport_sdcc_2),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_SDCC_2,
+	},
+	{
+		.id = MSM_BUS_SLAVE_SDCC_4,
+		.slavep = sport_sdcc_4,
+		.num_sports = ARRAY_SIZE(sport_sdcc_4),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_SDCC_4,
+	},
+	{
+		.id = MSM_BUS_SLAVE_TSIF,
+		.slavep = sport_tsif,
+		.num_sports = ARRAY_SIZE(sport_tsif),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_TSIF,
+	},
+	{
+		.id = MSM_BUS_SLAVE_BAM_DMA,
+		.slavep = sport_bam_dma,
+		.num_sports = ARRAY_SIZE(sport_bam_dma),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_BAM_DMA,
+	},
+	{
+		.id = MSM_BUS_SLAVE_QPIC,
+		.masterp = sport_qpic,
+		.num_mports = ARRAY_SIZE(sport_qpic),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.mas_hw_id = SLV_QPIC,
+	},
+	{
+		.id = MSM_BUS_SLAVE_BLSP_2,
+		.slavep = sport_blsp_2,
+		.num_sports = ARRAY_SIZE(sport_blsp_2),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_BLSP_2,
+	},
+	{
+		.id = MSM_BUS_SLAVE_USB_HSIC,
+		.slavep = sport_usb_hsic,
+		.num_sports = ARRAY_SIZE(sport_usb_hsic),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_USB_HSIC,
+	},
+	{
+		.id = MSM_BUS_SLAVE_BLSP_1,
+		.slavep = sport_blsp_1,
+		.num_sports = ARRAY_SIZE(sport_blsp_1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_BLSP_1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PDM,
+		.slavep = sport_pdm,
+		.num_sports = ARRAY_SIZE(sport_pdm),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_PDM,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PERIPH_APU_CFG,
+		.slavep = sport_periph_apu_cfg,
+		.num_sports = ARRAY_SIZE(sport_periph_apu_cfg),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_PERIPH_APU_CFG,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PNOC_MPU_CFG,
+		.slavep = sport_pnoc_mpu_cfg,
+		.num_sports = ARRAY_SIZE(sport_pnoc_mpu_cfg),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_MPU_CFG,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PRNG,
+		.slavep = sport_prng,
+		.num_sports = ARRAY_SIZE(sport_prng),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_PRNG,
+	},
+	{
+		.id = MSM_BUS_SLAVE_SERVICE_PNOC,
+		.slavep = sport_service_pnoc,
+		.num_sports = ARRAY_SIZE(sport_service_pnoc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_SERVICE_PNOC,
+	},
+};
+
+static struct msm_bus_node_info config_noc_info[] = {
+	{
+		.id = MSM_BUS_MASTER_RPM_INST,
+		.masterp = mport_rpm_inst,
+		.num_mports = ARRAY_SIZE(mport_rpm_inst),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.mas_hw_id = MAS_RPM_INST,
+	},
+	{
+		.id = MSM_BUS_MASTER_RPM_DATA,
+		.masterp = mport_rpm_data,
+		.num_mports = ARRAY_SIZE(mport_rpm_data),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.mas_hw_id = MAS_RPM_DATA,
+	},
+	{
+		.id = MSM_BUS_MASTER_RPM_SYS,
+		.masterp = mport_rpm_sys,
+		.num_mports = ARRAY_SIZE(mport_rpm_sys),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.mas_hw_id = MAS_RPM_SYS,
+	},
+	{
+		.id = MSM_BUS_MASTER_DEHR,
+		.masterp = mport_dehr,
+		.num_mports = ARRAY_SIZE(mport_dehr),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.mas_hw_id = MAS_DEHR,
+	},
+	{
+		.id = MSM_BUS_MASTER_QDSS_DAP,
+		.masterp = mport_qdss_dap,
+		.num_mports = ARRAY_SIZE(mport_qdss_dap),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.mas_hw_id = MAS_QDSS_DAP,
+	},
+	{
+		.id = MSM_BUS_MASTER_SPDM,
+		.masterp = mport_spdm,
+		.num_mports = ARRAY_SIZE(mport_spdm),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.mas_hw_id = MAS_SPDM,
+	},
+	{
+		.id = MSM_BUS_MASTER_TIC,
+		.masterp = mport_tic,
+		.num_mports = ARRAY_SIZE(mport_tic),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.mas_hw_id = MAS_TIC,
+	},
+	{
+		.id = MSM_BUS_SLAVE_CLK_CTL,
+		.slavep = sport_clk_ctl,
+		.num_sports = ARRAY_SIZE(sport_clk_ctl),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_CLK_CTL,
+	},
+	{
+		.id = MSM_BUS_SLAVE_CNOC_MSS,
+		.slavep = sport_cnoc_mss,
+		.num_sports = ARRAY_SIZE(sport_cnoc_mss),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_CNOC_MSS,
+	},
+	{
+		.id = MSM_BUS_SLAVE_SECURITY,
+		.slavep = sport_security,
+		.num_sports = ARRAY_SIZE(sport_security),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_SECURITY,
+	},
+	{
+		.id = MSM_BUS_SLAVE_TCSR,
+		.slavep = sport_tcsr,
+		.num_sports = ARRAY_SIZE(sport_tcsr),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_TCSR,
+	},
+	{
+		.id = MSM_BUS_SLAVE_TLMM,
+		.slavep = sport_tlmm,
+		.num_sports = ARRAY_SIZE(sport_tlmm),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_TLMM,
+	},
+	{
+		.id = MSM_BUS_SLAVE_CRYPTO_0_CFG,
+		.slavep = sport_crypto_0_cfg,
+		.num_sports = ARRAY_SIZE(sport_crypto_0_cfg),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_CRYPTO_0_CFG,
+	},
+	{
+		.id = MSM_BUS_SLAVE_IMEM_CFG,
+		.slavep = sport_imem_cfg,
+		.num_sports = ARRAY_SIZE(sport_imem_cfg),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_IMEM_CFG,
+	},
+	{
+		.id = MSM_BUS_SLAVE_IPS_CFG,
+		.slavep = sport_ips_cfg,
+		.num_sports = ARRAY_SIZE(sport_ips_cfg),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_IPS_CFG,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MESSAGE_RAM,
+		.slavep = sport_message_ram,
+		.num_sports = ARRAY_SIZE(sport_message_ram),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_MESSAGE_RAM,
+	},
+	{
+		.id = MSM_BUS_SLAVE_BIMC_CFG,
+		.slavep = sport_bimc_cfg,
+		.num_sports = ARRAY_SIZE(sport_bimc_cfg),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_BIMC_CFG,
+	},
+	{
+		.id = MSM_BUS_SLAVE_BOOT_ROM,
+		.slavep = sport_boot_rom,
+		.num_sports = ARRAY_SIZE(sport_boot_rom),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_BOOT_ROM,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC_ARB,
+		.slavep = sport_pmic_arb,
+		.num_sports = ARRAY_SIZE(sport_pmic_arb),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_PMIC_ARB,
+	},
+	{
+		.id = MSM_BUS_SLAVE_SPDM_WRAPPER,
+		.slavep = sport_spdm_wrapper,
+		.num_sports = ARRAY_SIZE(sport_spdm_wrapper),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_SPDM_WRAPPER,
+	},
+	{
+		.id = MSM_BUS_SLAVE_DEHR_CFG,
+		.slavep = sport_dehr_cfg,
+		.num_sports = ARRAY_SIZE(sport_dehr_cfg),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_DEHR_CFG,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MPM,
+		.slavep = sport_mpm,
+		.num_sports = ARRAY_SIZE(sport_mpm),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_MPM,
+	},
+	{
+		.id = MSM_BUS_SLAVE_QDSS_CFG,
+		.slavep = sport_qdss_cfg,
+		.num_sports = ARRAY_SIZE(sport_qdss_cfg),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_QDSS_CFG,
+	},
+	{
+		.id = MSM_BUS_SLAVE_RBCPR_CFG,
+		.slavep = sport_rbcpr_cfg,
+		.num_sports = ARRAY_SIZE(sport_rbcpr_cfg),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_RBCPR_CFG,
+	},
+	{
+		.id = MSM_BUS_SLAVE_RBCPR_QDSS_APU_CFG,
+		.slavep = sport_rbcpr_qdss_apu_cfg,
+		.num_sports = ARRAY_SIZE(sport_rbcpr_qdss_apu_cfg),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_RBCPR_QDSS_APU_CFG,
+	},
+	{
+		.id = MSM_BUS_FAB_SYS_NOC,
+		.gateway = 1,
+		.slavep = sport_gw_cnoc_snoc,
+		.num_sports = ARRAY_SIZE(sport_gw_cnoc_snoc),
+		.masterp = mport_gw_snoc_cnoc,
+		.num_mports = ARRAY_SIZE(mport_gw_snoc_cnoc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.mas_hw_id = MAS_SNOC_CNOC,
+		.slv_hw_id = SLV_CNOC_SNOC,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PNOC_CFG,
+		.slavep = sport_pnoc_cfg,
+		.num_sports = ARRAY_SIZE(sport_pnoc_cfg),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_PNOC_CFG,
+	},
+	{
+		.id = MSM_BUS_SLAVE_SNOC_MPU_CFG,
+		.slavep = sport_snoc_mpu_cfg,
+		.num_sports = ARRAY_SIZE(sport_snoc_mpu_cfg),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_SNOC_MPU_CFG,
+	},
+	{
+		.id = MSM_BUS_SLAVE_SNOC_CFG,
+		.slavep = sport_snoc_cfg,
+		.num_sports = ARRAY_SIZE(sport_snoc_cfg),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_SNOC_CFG,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PHY_APU_CFG,
+		.slavep = sport_phy_apu_cfg,
+		.num_sports = ARRAY_SIZE(sport_phy_apu_cfg),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_PHY_APU_CFG,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI1_PHY_CFG,
+		.slavep = sport_ebi1_phy_cfg,
+		.num_sports = ARRAY_SIZE(sport_ebi1_phy_cfg),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_EBI1_PHY_CFG,
+	},
+	{
+		.id = MSM_BUS_SLAVE_RPM,
+		.slavep = sport_rpm,
+		.num_sports = ARRAY_SIZE(sport_rpm),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_RPM,
+	},
+	{
+		.id = MSM_BUS_SLAVE_SERVICE_CNOC,
+		.slavep = sport_service_cnoc,
+		.num_sports = ARRAY_SIZE(sport_service_cnoc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slv_hw_id = SLV_SERVICE_CNOC,
+	},
+};
+
+static void msm_bus_board_assign_iids(struct msm_bus_fabric_registration
+	*fabreg, int fabid)
+{
+	int i;
+	for (i = 0; i < fabreg->len; i++) {
+		if (!fabreg->info[i].gateway) {
+			fabreg->info[i].priv_id = fabid + fabreg->info[i].id;
+			if (fabreg->info[i].id < SLAVE_ID_KEY) {
+				WARN(fabreg->info[i].id >= NMASTERS,
+					"id %d exceeds array size!\n",
+					fabreg->info[i].id);
+				master_iids[fabreg->info[i].id] =
+					fabreg->info[i].priv_id;
+			} else {
+				WARN((fabreg->info[i].id - SLAVE_ID_KEY) >=
+					NSLAVES, "id %d exceeds array size!\n",
+					fabreg->info[i].id);
+				slave_iids[fabreg->info[i].id - (SLAVE_ID_KEY)]
+					= fabreg->info[i].priv_id;
+			}
+		} else {
+			fabreg->info[i].priv_id = fabreg->info[i].id;
+		}
+	}
+}
+
+static int msm_bus_board_9625_get_iid(int id)
+{
+	if ((id < SLAVE_ID_KEY && id >= NMASTERS) ||
+		id >= (SLAVE_ID_KEY + NSLAVES)) {
+		MSM_BUS_ERR("Cannot get iid. Invalid id %d passed\n", id);
+		return -EINVAL;
+	}
+
+	return CHECK_ID(((id < SLAVE_ID_KEY) ? master_iids[id] :
+		slave_iids[id - SLAVE_ID_KEY]), id);
+}
+
+int msm_bus_board_rpm_get_il_ids(uint16_t *id)
+{
+	return -ENXIO;
+}
+
+static struct msm_bus_board_algorithm msm_bus_board_algo = {
+	.board_nfab = NFAB_9625,
+	.get_iid = msm_bus_board_9625_get_iid,
+	.assign_iids = msm_bus_board_assign_iids,
+};
+
+struct msm_bus_fabric_registration msm_bus_9625_sys_noc_pdata = {
+	.id = MSM_BUS_FAB_SYS_NOC,
+	.name = "msm_sys_noc",
+	.info = sys_noc_info,
+	.len = ARRAY_SIZE(sys_noc_info),
+	.ahb = 0,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.nmasters = 15,
+	.nslaves = 12,
+	.ntieredslaves = 0,
+	.board_algo = &msm_bus_board_algo,
+	.qos_freq = 4800,
+	.hw_sel = MSM_BUS_NOC,
+	.rpm_enabled = 1,
+};
+
+struct msm_bus_fabric_registration msm_bus_9625_bimc_pdata = {
+	.id = MSM_BUS_FAB_BIMC,
+	.name = "msm_bimc",
+	.info = bimc_info,
+	.len = ARRAY_SIZE(bimc_info),
+	.ahb = 0,
+	.fabclk[DUAL_CTX] = "mem_clk",
+	.fabclk[ACTIVE_CTX] = "mem_a_clk",
+	.nmasters = 7,
+	.nslaves = 4,
+	.ntieredslaves = 0,
+	.board_algo = &msm_bus_board_algo,
+	.qos_freq = 4800,
+	.hw_sel = MSM_BUS_BIMC,
+	.rpm_enabled = 1,
+};
+
+struct msm_bus_fabric_registration msm_bus_9625_periph_noc_pdata = {
+	.id = MSM_BUS_FAB_PERIPH_NOC,
+	.name = "msm_periph_noc",
+	.info = periph_noc_info,
+	.len = ARRAY_SIZE(periph_noc_info),
+	.ahb = 0,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.nmasters = 14,
+	.nslaves = 15,
+	.ntieredslaves = 0,
+	.board_algo = &msm_bus_board_algo,
+	.hw_sel = MSM_BUS_NOC,
+	.rpm_enabled = 1,
+};
+
+struct msm_bus_fabric_registration msm_bus_9625_config_noc_pdata = {
+	.id = MSM_BUS_FAB_CONFIG_NOC,
+	.name = "msm_config_noc",
+	.info = config_noc_info,
+	.len = ARRAY_SIZE(config_noc_info),
+	.ahb = 0,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.nmasters = 8,
+	.nslaves = 30,
+	.ntieredslaves = 0,
+	.board_algo = &msm_bus_board_algo,
+	.hw_sel = MSM_BUS_NOC,
+	.rpm_enabled = 1,
+};
diff --git a/arch/arm/mach-msm/msm_cpr.c b/arch/arm/mach-msm/msm_cpr.c
index c00352d..b68a8db 100644
--- a/arch/arm/mach-msm/msm_cpr.c
+++ b/arch/arm/mach-msm/msm_cpr.c
@@ -50,6 +50,7 @@
 static struct platform_device *cpr_pdev;
 
 static bool enable = 1;
+static bool disable_cpr;
 module_param(enable, bool, 0644);
 MODULE_PARM_DESC(enable, "CPR Enable");
 
@@ -329,12 +330,12 @@
 	cpr_write_reg(cpr, RBIF_CONT_NACK_CMD, 0x1);
 }
 
-static void cpr_irq_set(struct msm_cpr *cpr, uint32_t irq, bool enable)
+static void cpr_irq_set(struct msm_cpr *cpr, uint32_t irq, bool enable_irq)
 {
 	uint32_t irq_enabled;
 
 	irq_enabled = cpr_read_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line));
-	if (enable == 1)
+	if (enable_irq == 1)
 		irq_enabled |= irq;
 	else
 		irq_enabled &= ~irq;
@@ -832,7 +833,7 @@
 
 void msm_cpr_pm_resume(void)
 {
-	if (!enable)
+	if (!enable || disable_cpr)
 		return;
 
 	msm_cpr_resume(&cpr_pdev->dev);
@@ -841,7 +842,7 @@
 
 void msm_cpr_pm_suspend(void)
 {
-	if (!enable)
+	if (!enable || disable_cpr)
 		return;
 
 	msm_cpr_suspend(&cpr_pdev->dev);
@@ -853,7 +854,7 @@
 {
 	struct msm_cpr *cpr;
 
-	if (!enable)
+	if (!enable || disable_cpr)
 		return;
 
 	cpr = platform_get_drvdata(cpr_pdev);
@@ -866,7 +867,7 @@
 {
 	struct msm_cpr *cpr;
 
-	if (!enable)
+	if (!enable || disable_cpr)
 		return;
 
 	cpr = platform_get_drvdata(cpr_pdev);
@@ -893,6 +894,12 @@
 		return -EIO;
 	}
 
+	if (pdata->disable_cpr == true) {
+		pr_err("CPR disabled by modem\n");
+		disable_cpr = true;
+		return -EPERM;
+	}
+
 	cpr = devm_kzalloc(&pdev->dev, sizeof(struct msm_cpr), GFP_KERNEL);
 	if (!cpr) {
 		enable = false;
diff --git a/arch/arm/mach-msm/msm_cpr.h b/arch/arm/mach-msm/msm_cpr.h
index 005d9b1..3d10478 100644
--- a/arch/arm/mach-msm/msm_cpr.h
+++ b/arch/arm/mach-msm/msm_cpr.h
@@ -188,6 +188,7 @@
 	uint32_t max_nom_freq;
 	uint32_t max_freq;
 	uint32_t max_quot;
+	bool disable_cpr;
 	struct msm_cpr_vp_data *vp_data;
 	uint32_t (*get_quot)(uint32_t max_quot, uint32_t max_freq,
 				uint32_t new_freq);
diff --git a/arch/arm/mach-msm/msm_dcvs.c b/arch/arm/mach-msm/msm_dcvs.c
index b2160c5..c1c05af 100644
--- a/arch/arm/mach-msm/msm_dcvs.c
+++ b/arch/arm/mach-msm/msm_dcvs.c
@@ -384,9 +384,6 @@
 static int msm_dcvs_do_freq(void *data)
 {
 	struct dcvs_core *core = (struct dcvs_core *)data;
-	static struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1};
-
-	sched_setscheduler(current, SCHED_FIFO, &param);
 
 	while (!kthread_should_stop()) {
 		wait_event(core->wait_q, !(core->pending_freq == 0 ||
diff --git a/arch/arm/mach-msm/msm_dsps.c b/arch/arm/mach-msm/msm_dsps.c
index 859fc15..0551130 100644
--- a/arch/arm/mach-msm/msm_dsps.c
+++ b/arch/arm/mach-msm/msm_dsps.c
@@ -585,7 +585,7 @@
  *
  * If the DSPS is running, then we must reset DSPS CPU & HW before
  * setting the clocks off.
- * The DSPS reset should be done as part of the pil_put().
+ * The DSPS reset should be done as part of the subsystem_put().
  * The DSPS reset should be used for error recovery if the DSPS firmware
  * has crashed and re-loading the firmware is required.
  */
diff --git a/arch/arm/mach-msm/msm_mem_hole.c b/arch/arm/mach-msm/msm_mem_hole.c
new file mode 100644
index 0000000..736219b
--- /dev/null
+++ b/arch/arm/mach-msm/msm_mem_hole.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ */
+
+/**
+ * This module exists for the express purpose of removing memory
+ * via the msm memory-remove mechanism (see
+ * Documentation/devicetree/bindings/arm/msm/memory-reserve.txt). Compiling
+ * this module into a kernel is essentially the means by which any
+ * nodes in the device tree with compatible =
+ * "qcom,msm-mem-hole" will be "activated", thus providing a
+ * convenient mechanism for enabling/disabling memory removal
+ * (qcom,memory-*).
+ */
+
+#include <linux/module.h>
+
+#define MSM_MEM_HOLE_COMPAT_STR	"qcom,msm-mem-hole"
+
+EXPORT_COMPAT(MSM_MEM_HOLE_COMPAT_STR);
diff --git a/arch/arm/mach-msm/msm_mpdecision.c b/arch/arm/mach-msm/msm_mpdecision.c
index 9f6cc11..a65b3ee 100644
--- a/arch/arm/mach-msm/msm_mpdecision.c
+++ b/arch/arm/mach-msm/msm_mpdecision.c
@@ -356,11 +356,8 @@
 static int __cpuinit msm_mpd_do_hotplug(void *data)
 {
 	int *event = (int *)data;
-	static struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1};
 	int cpu;
 
-	sched_setscheduler(current, SCHED_FIFO, &param);
-
 	while (1) {
 		wait_event(msm_mpd.wait_hpq, *event || kthread_should_stop());
 		if (kthread_should_stop())
@@ -400,13 +397,10 @@
 static int msm_mpd_do_update_scm(void *data)
 {
 	struct msm_mpd_scm_data *scm_data = (struct msm_mpd_scm_data *)data;
-	static struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1};
 	unsigned long flags;
 	enum msm_dcvs_scm_event event;
 	int nr;
 
-	sched_setscheduler(current, SCHED_FIFO, &param);
-
 	while (1) {
 		wait_event(msm_mpd.wait_q,
 			msm_mpd.data.event == MSM_DCVS_SCM_MPD_QOS_TIMER_EXPIRED
diff --git a/arch/arm/mach-msm/msm_qmi_interface.c b/arch/arm/mach-msm/msm_qmi_interface.c
new file mode 100644
index 0000000..4c4635a
--- /dev/null
+++ b/arch/arm/mach-msm/msm_qmi_interface.c
@@ -0,0 +1,694 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/list.h>
+#include <linux/socket.h>
+#include <linux/gfp.h>
+#include <linux/qmi_encdec.h>
+
+#include <mach/msm_qmi_interface.h>
+#include <mach/msm_ipc_router.h>
+
+#include "msm_qmi_interface_priv.h"
+
+static LIST_HEAD(svc_event_nb_list);
+static DEFINE_MUTEX(svc_event_nb_list_lock);
+
+struct elem_info qmi_response_type_v01_ei[] = {
+	{
+		.data_type	= QMI_SIGNED_2_BYTE_ENUM,
+		.elem_len	= 1,
+		.elem_size	= sizeof(uint16_t),
+		.is_array	= NO_ARRAY,
+		.tlv_type	= QMI_COMMON_TLV_TYPE,
+		.offset		= offsetof(struct qmi_response_type_v01,
+					   result),
+		.ei_array	= NULL,
+	},
+	{
+		.data_type      = QMI_SIGNED_2_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint16_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+		.offset         = offsetof(struct qmi_response_type_v01,
+					   error),
+		.ei_array       = NULL,
+	},
+	{
+		.data_type	= QMI_EOTI,
+		.elem_len	= 0,
+		.elem_size	= 0,
+		.is_array	= NO_ARRAY,
+		.tlv_type	= QMI_COMMON_TLV_TYPE,
+		.offset		= 0,
+		.ei_array	= NULL,
+	},
+};
+
+static void qmi_event_notify(unsigned event, void *priv)
+{
+	struct qmi_handle *handle = (struct qmi_handle *)priv;
+	unsigned long flags;
+
+	if (!handle)
+		return;
+
+	mutex_lock(&handle->handle_lock);
+	if (handle->handle_reset) {
+		mutex_unlock(&handle->handle_lock);
+		return;
+	}
+
+	switch (event) {
+	case MSM_IPC_ROUTER_READ_CB:
+		spin_lock_irqsave(&handle->notify_lock, flags);
+		handle->notify(handle, QMI_RECV_MSG, handle->notify_priv);
+		spin_unlock_irqrestore(&handle->notify_lock, flags);
+		break;
+
+	default:
+		break;
+	}
+	mutex_unlock(&handle->handle_lock);
+}
+
+struct qmi_handle *qmi_handle_create(
+	void (*notify)(struct qmi_handle *handle,
+		       enum qmi_event_type event, void *notify_priv),
+	void *notify_priv)
+{
+	struct qmi_handle *temp_handle;
+	struct msm_ipc_port *port_ptr;
+
+	temp_handle = kzalloc(sizeof(struct qmi_handle), GFP_KERNEL);
+	if (!temp_handle) {
+		pr_err("%s: Failure allocating client handle\n", __func__);
+		return NULL;
+	}
+
+	port_ptr = msm_ipc_router_create_port(qmi_event_notify,
+					      (void *)temp_handle);
+	if (!port_ptr) {
+		pr_err("%s: IPC router port creation failed\n", __func__);
+		kfree(temp_handle);
+		return NULL;
+	}
+
+	temp_handle->src_port = port_ptr;
+	temp_handle->next_txn_id = 1;
+	INIT_LIST_HEAD(&temp_handle->txn_list);
+	mutex_init(&temp_handle->handle_lock);
+	spin_lock_init(&temp_handle->notify_lock);
+	temp_handle->notify = notify;
+	temp_handle->notify_priv = notify_priv;
+	temp_handle->handle_reset = 0;
+	init_waitqueue_head(&temp_handle->reset_waitq);
+	return temp_handle;
+}
+EXPORT_SYMBOL(qmi_handle_create);
+
+static void clean_txn_info(struct qmi_handle *handle)
+{
+	struct qmi_txn *txn_handle, *temp_txn_handle;
+
+	list_for_each_entry_safe(txn_handle, temp_txn_handle,
+				 &handle->txn_list, list) {
+		if (txn_handle->type == QMI_ASYNC_TXN) {
+			list_del(&txn_handle->list);
+			kfree(txn_handle);
+		} else if (txn_handle->type == QMI_SYNC_TXN) {
+			wake_up(&txn_handle->wait_q);
+		}
+	}
+}
+
+int qmi_handle_destroy(struct qmi_handle *handle)
+{
+	int rc;
+
+	if (!handle)
+		return -EINVAL;
+
+	mutex_lock(&handle->handle_lock);
+	handle->handle_reset = 1;
+	clean_txn_info(handle);
+	mutex_unlock(&handle->handle_lock);
+
+	rc = wait_event_interruptible(handle->reset_waitq,
+				      list_empty(&handle->txn_list));
+
+	/* TODO: Destroy client owned transaction */
+	msm_ipc_router_close_port((struct msm_ipc_port *)(handle->src_port));
+	kfree(handle->dest_info);
+	kfree(handle);
+	return 0;
+}
+EXPORT_SYMBOL(qmi_handle_destroy);
+
+int qmi_register_ind_cb(struct qmi_handle *handle,
+	void (*ind_cb)(struct qmi_handle *handle,
+		       unsigned int msg_id, void *msg,
+		       unsigned int msg_len, void *ind_cb_priv),
+	void *ind_cb_priv)
+{
+	if (!handle)
+		return -EINVAL;
+
+	mutex_lock(&handle->handle_lock);
+	if (handle->handle_reset) {
+		mutex_unlock(&handle->handle_lock);
+		return -ENETRESET;
+	}
+
+	handle->ind_cb = ind_cb;
+	handle->ind_cb_priv = ind_cb_priv;
+	mutex_unlock(&handle->handle_lock);
+	return 0;
+}
+EXPORT_SYMBOL(qmi_register_ind_cb);
+
+static int qmi_encode_and_send_req(struct qmi_txn **ret_txn_handle,
+	struct qmi_handle *handle, enum txn_type type,
+	struct msg_desc *req_desc, void *req, unsigned int req_len,
+	struct msg_desc *resp_desc, void *resp, unsigned int resp_len,
+	void (*resp_cb)(struct qmi_handle *handle,
+			unsigned int msg_id, void *msg,
+			void *resp_cb_data),
+	void *resp_cb_data)
+{
+	struct qmi_txn *txn_handle;
+	int rc, encoded_req_len;
+	void *encoded_req;
+
+	if (!handle || !handle->dest_info ||
+	    !req_desc || !req || !resp_desc || !resp)
+		return -EINVAL;
+
+	mutex_lock(&handle->handle_lock);
+	if (handle->handle_reset) {
+		mutex_unlock(&handle->handle_lock);
+		return -ENETRESET;
+	}
+
+	/* Allocate Transaction Info */
+	txn_handle = kzalloc(sizeof(struct qmi_txn), GFP_KERNEL);
+	if (!txn_handle) {
+		pr_err("%s: Failed to allocate txn handle\n", __func__);
+		mutex_unlock(&handle->handle_lock);
+		return -ENOMEM;
+	}
+	txn_handle->type = type;
+	INIT_LIST_HEAD(&txn_handle->list);
+	init_waitqueue_head(&txn_handle->wait_q);
+
+	/* Cache the parameters passed & mark it as sync*/
+	txn_handle->handle = handle;
+	txn_handle->resp_desc = resp_desc;
+	txn_handle->resp = resp;
+	txn_handle->resp_len = resp_len;
+	txn_handle->resp_received = 0;
+	txn_handle->resp_cb = resp_cb;
+	txn_handle->resp_cb_data = resp_cb_data;
+
+	/* Encode the request msg */
+	encoded_req_len = req_desc->max_msg_len + QMI_HEADER_SIZE;
+	encoded_req = kmalloc(encoded_req_len, GFP_KERNEL);
+	if (!encoded_req) {
+		pr_err("%s: Failed to allocate req_msg_buf\n", __func__);
+		rc = -ENOMEM;
+		goto encode_and_send_req_err1;
+	}
+	rc = qmi_kernel_encode(req_desc,
+		(void *)(encoded_req + QMI_HEADER_SIZE),
+		req_desc->max_msg_len, req);
+	if (rc < 0) {
+		pr_err("%s: Encode Failure %d\n", __func__, rc);
+		goto encode_and_send_req_err2;
+	}
+	encoded_req_len = rc;
+
+	/* Encode the header & Add to the txn_list */
+	if (!handle->next_txn_id)
+		handle->next_txn_id++;
+	txn_handle->txn_id = handle->next_txn_id++;
+	encode_qmi_header(encoded_req, QMI_REQUEST_CONTROL_FLAG,
+			  txn_handle->txn_id, req_desc->msg_id,
+			  encoded_req_len);
+	encoded_req_len += QMI_HEADER_SIZE;
+	list_add_tail(&txn_handle->list, &handle->txn_list);
+
+	/* Send the request */
+	rc = msm_ipc_router_send_msg((struct msm_ipc_port *)(handle->src_port),
+		(struct msm_ipc_addr *)handle->dest_info,
+		encoded_req, encoded_req_len);
+	if (rc < 0) {
+		pr_err("%s: send_msg failed %d\n", __func__, rc);
+		goto encode_and_send_req_err3;
+	}
+	mutex_unlock(&handle->handle_lock);
+
+	kfree(encoded_req);
+	if (ret_txn_handle)
+		*ret_txn_handle = txn_handle;
+	return 0;
+
+encode_and_send_req_err3:
+	list_del(&txn_handle->list);
+encode_and_send_req_err2:
+	kfree(encoded_req);
+encode_and_send_req_err1:
+	kfree(txn_handle);
+	mutex_unlock(&handle->handle_lock);
+	return rc;
+}
+
+int qmi_send_req_wait(struct qmi_handle *handle,
+		      struct msg_desc *req_desc,
+		      void *req, unsigned int req_len,
+		      struct msg_desc *resp_desc,
+		      void *resp, unsigned int resp_len,
+		      unsigned long timeout_ms)
+{
+	struct qmi_txn *txn_handle = NULL;
+	int rc;
+
+	/* Encode and send the request */
+	rc = qmi_encode_and_send_req(&txn_handle, handle, QMI_SYNC_TXN,
+				     req_desc, req, req_len,
+				     resp_desc, resp, resp_len,
+				     NULL, NULL);
+	if (rc < 0) {
+		pr_err("%s: Error encode & send req: %d\n", __func__, rc);
+		return rc;
+	}
+
+	/* Wait for the response */
+	if (!timeout_ms) {
+		rc = wait_event_interruptible(txn_handle->wait_q,
+					(txn_handle->resp_received ||
+					 handle->handle_reset));
+	} else {
+		rc = wait_event_interruptible_timeout(txn_handle->wait_q,
+					(txn_handle->resp_received ||
+					 handle->handle_reset),
+					msecs_to_jiffies(timeout_ms));
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+	}
+
+	mutex_lock(&handle->handle_lock);
+	if (!txn_handle->resp_received) {
+		pr_err("%s: Response Wait Error %d\n", __func__, rc);
+		if (handle->handle_reset)
+			rc = -ENETRESET;
+		if (rc >= 0)
+			rc = -EFAULT;
+		goto send_req_wait_err;
+	}
+	rc = 0;
+
+send_req_wait_err:
+	list_del(&txn_handle->list);
+	kfree(txn_handle);
+	mutex_unlock(&handle->handle_lock);
+	wake_up(&handle->reset_waitq);
+	return rc;
+}
+EXPORT_SYMBOL(qmi_send_req_wait);
+
+int qmi_send_req_nowait(struct qmi_handle *handle,
+			struct msg_desc *req_desc,
+			void *req, unsigned int req_len,
+			struct msg_desc *resp_desc,
+			void *resp, unsigned int resp_len,
+			void (*resp_cb)(struct qmi_handle *handle,
+					unsigned int msg_id, void *msg,
+					void *resp_cb_data),
+			void *resp_cb_data)
+{
+	return qmi_encode_and_send_req(NULL, handle, QMI_ASYNC_TXN,
+				       req_desc, req, req_len,
+				       resp_desc, resp, resp_len,
+				       resp_cb, resp_cb_data);
+}
+EXPORT_SYMBOL(qmi_send_req_nowait);
+
+static struct qmi_txn *find_txn_handle(struct qmi_handle *handle,
+				       uint16_t txn_id)
+{
+	struct qmi_txn *txn_handle;
+
+	list_for_each_entry(txn_handle, &handle->txn_list, list) {
+		if (txn_handle->txn_id == txn_id)
+			return txn_handle;
+	}
+	return NULL;
+}
+
+static int handle_qmi_response(struct qmi_handle *handle,
+			       unsigned char *resp_msg, uint16_t txn_id,
+			       uint16_t msg_id, uint16_t msg_len)
+{
+	struct qmi_txn *txn_handle;
+	int rc;
+
+	/* Find the transaction handle */
+	txn_handle = find_txn_handle(handle, txn_id);
+	if (!txn_handle) {
+		pr_err("%s Response received for non-existent txn_id %d\n",
+			__func__, txn_id);
+		return -EINVAL;
+	}
+
+	/* Decode the message */
+	rc = qmi_kernel_decode(txn_handle->resp_desc, txn_handle->resp,
+			       (void *)(resp_msg + QMI_HEADER_SIZE), msg_len);
+	if (rc < 0) {
+		pr_err("%s: Response Decode Failure <%d: %d: %d> rc: %d\n",
+			__func__, txn_id, msg_id, msg_len, rc);
+		wake_up(&txn_handle->wait_q);
+		if (txn_handle->type == QMI_ASYNC_TXN) {
+			list_del(&txn_handle->list);
+			kfree(txn_handle);
+		}
+		return rc;
+	}
+
+	/* Handle async or sync resp */
+	switch (txn_handle->type) {
+	case QMI_SYNC_TXN:
+		txn_handle->resp_received = 1;
+		wake_up(&txn_handle->wait_q);
+		rc = 0;
+		break;
+
+	case QMI_ASYNC_TXN:
+		if (txn_handle->resp_cb)
+			txn_handle->resp_cb(txn_handle->handle, msg_id,
+					    txn_handle->resp,
+					    txn_handle->resp_cb_data);
+		list_del(&txn_handle->list);
+		kfree(txn_handle);
+		rc = 0;
+		break;
+
+	default:
+		pr_err("%s: Unrecognized transaction type\n", __func__);
+		return -EFAULT;
+	}
+	return rc;
+}
+
+static int handle_qmi_indication(struct qmi_handle *handle, void *msg,
+				 unsigned int msg_id, unsigned int msg_len)
+{
+	if (handle->ind_cb)
+		handle->ind_cb(handle, msg_id, msg,
+				msg_len, handle->ind_cb_priv);
+	return 0;
+}
+
+int qmi_recv_msg(struct qmi_handle *handle)
+{
+	unsigned int recv_msg_len;
+	unsigned char *recv_msg = NULL;
+	struct msm_ipc_addr src_addr;
+	unsigned char cntl_flag;
+	uint16_t txn_id, msg_id, msg_len;
+	int rc;
+
+	if (!handle)
+		return -EINVAL;
+
+	mutex_lock(&handle->handle_lock);
+	if (handle->handle_reset) {
+		mutex_unlock(&handle->handle_lock);
+		return -ENETRESET;
+	}
+
+	/* Read the messages */
+	rc = msm_ipc_router_read_msg((struct msm_ipc_port *)(handle->src_port),
+				     &src_addr, &recv_msg, &recv_msg_len);
+	if (rc < 0) {
+		pr_err("%s: Read failed %d\n", __func__, rc);
+		mutex_unlock(&handle->handle_lock);
+		return rc;
+	}
+
+	/* Decode the header & Handle the req, resp, indication message */
+	decode_qmi_header(recv_msg, &cntl_flag, &txn_id, &msg_id, &msg_len);
+
+	switch (cntl_flag) {
+	case QMI_RESPONSE_CONTROL_FLAG:
+		rc = handle_qmi_response(handle, recv_msg,
+					 txn_id, msg_id, msg_len);
+		break;
+
+	case QMI_INDICATION_CONTROL_FLAG:
+		rc = handle_qmi_indication(handle, recv_msg, msg_id, msg_len);
+		break;
+
+	default:
+		rc = -EFAULT;
+		pr_err("%s: Unsupported message type %d\n",
+			__func__, cntl_flag);
+		break;
+	}
+	kfree(recv_msg);
+	mutex_unlock(&handle->handle_lock);
+	return rc;
+}
+EXPORT_SYMBOL(qmi_recv_msg);
+
+int qmi_connect_to_service(struct qmi_handle *handle,
+			   uint32_t service_id, uint32_t instance_id)
+{
+	struct msm_ipc_port_name svc_name;
+	struct msm_ipc_server_info svc_info;
+	struct msm_ipc_addr *svc_dest_addr;
+	int rc;
+
+	if (!handle)
+		return -EINVAL;
+
+	svc_dest_addr = kzalloc(sizeof(struct msm_ipc_addr),
+				GFP_KERNEL);
+	if (!svc_dest_addr) {
+		pr_err("%s: Failure allocating memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	svc_name.service = service_id;
+	svc_name.instance = instance_id;
+
+	rc = msm_ipc_router_lookup_server_name(&svc_name, &svc_info, 1, 0xFF);
+	if (rc <= 0) {
+		pr_err("%s: Server not found\n", __func__);
+		return -ENODEV;
+	}
+	svc_dest_addr->addrtype = MSM_IPC_ADDR_ID;
+	svc_dest_addr->addr.port_addr.node_id = svc_info.node_id;
+	svc_dest_addr->addr.port_addr.port_id = svc_info.port_id;
+	mutex_lock(&handle->handle_lock);
+	if (handle->handle_reset) {
+		mutex_unlock(&handle->handle_lock);
+		return -ENETRESET;
+	}
+	handle->dest_info = svc_dest_addr;
+	mutex_unlock(&handle->handle_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(qmi_connect_to_service);
+
+static struct svc_event_nb *find_svc_event_nb_by_name(const char *name)
+{
+	struct svc_event_nb *temp;
+
+	list_for_each_entry(temp, &svc_event_nb_list, list) {
+		if (!strncmp(name, temp->pdriver_name,
+			     sizeof(temp->pdriver_name)))
+			return temp;
+	}
+	return NULL;
+}
+
+static int qmi_svc_event_probe(struct platform_device *pdev)
+{
+	struct svc_event_nb *temp;
+	unsigned long flags;
+
+	mutex_lock(&svc_event_nb_list_lock);
+	temp = find_svc_event_nb_by_name(pdev->name);
+	if (!temp) {
+		mutex_unlock(&svc_event_nb_list_lock);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&temp->nb_lock, flags);
+	temp->svc_avail = 1;
+	raw_notifier_call_chain(&temp->svc_event_rcvr_list,
+				QMI_SERVER_ARRIVE, NULL);
+	spin_unlock_irqrestore(&temp->nb_lock, flags);
+	mutex_unlock(&svc_event_nb_list_lock);
+	return 0;
+}
+
+static int qmi_svc_event_remove(struct platform_device *pdev)
+{
+	struct svc_event_nb *temp;
+	unsigned long flags;
+
+	mutex_lock(&svc_event_nb_list_lock);
+	temp = find_svc_event_nb_by_name(pdev->name);
+	if (!temp) {
+		mutex_unlock(&svc_event_nb_list_lock);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&temp->nb_lock, flags);
+	temp->svc_avail = 0;
+	raw_notifier_call_chain(&temp->svc_event_rcvr_list,
+				QMI_SERVER_EXIT, NULL);
+	spin_unlock_irqrestore(&temp->nb_lock, flags);
+	mutex_unlock(&svc_event_nb_list_lock);
+	return 0;
+}
+
+static struct svc_event_nb *find_svc_event_nb(uint32_t service_id,
+					      uint32_t instance_id)
+{
+	struct svc_event_nb *temp;
+
+	list_for_each_entry(temp, &svc_event_nb_list, list) {
+		if (temp->service_id == service_id &&
+		    temp->instance_id == instance_id)
+			return temp;
+	}
+	return NULL;
+}
+
+static struct svc_event_nb *find_and_add_svc_event_nb(uint32_t service_id,
+						      uint32_t instance_id)
+{
+	struct svc_event_nb *temp;
+	int ret;
+
+	mutex_lock(&svc_event_nb_list_lock);
+	temp = find_svc_event_nb(service_id, instance_id);
+	if (temp) {
+		mutex_unlock(&svc_event_nb_list_lock);
+		return temp;
+	}
+
+	temp = kzalloc(sizeof(struct svc_event_nb), GFP_KERNEL);
+	if (!temp) {
+		mutex_unlock(&svc_event_nb_list_lock);
+		pr_err("%s: Failed to alloc notifier block\n", __func__);
+		return temp;
+	}
+
+	spin_lock_init(&temp->nb_lock);
+	temp->service_id = service_id;
+	temp->instance_id = instance_id;
+	INIT_LIST_HEAD(&temp->list);
+	temp->svc_driver.probe = qmi_svc_event_probe;
+	temp->svc_driver.remove = qmi_svc_event_remove;
+	scnprintf(temp->pdriver_name, sizeof(temp->pdriver_name),
+		  "QMI%08x:%08x", service_id, instance_id);
+	temp->svc_driver.driver.name = temp->pdriver_name;
+	RAW_INIT_NOTIFIER_HEAD(&temp->svc_event_rcvr_list);
+
+	list_add_tail(&temp->list, &svc_event_nb_list);
+	mutex_unlock(&svc_event_nb_list_lock);
+
+	ret = platform_driver_register(&temp->svc_driver);
+	if (ret < 0) {
+		pr_err("%s: Failed pdriver register\n", __func__);
+		mutex_lock(&svc_event_nb_list_lock);
+		list_del(&temp->list);
+		mutex_unlock(&svc_event_nb_list_lock);
+		kfree(temp);
+		temp = NULL;
+	}
+
+	return temp;
+}
+
+int qmi_svc_event_notifier_register(uint32_t service_id,
+				    uint32_t instance_id,
+				    struct notifier_block *nb)
+{
+	struct svc_event_nb *temp;
+	unsigned long flags;
+	int ret;
+
+	temp = find_and_add_svc_event_nb(service_id, instance_id);
+	if (!temp)
+		return -EFAULT;
+
+	mutex_lock(&svc_event_nb_list_lock);
+	temp = find_svc_event_nb(service_id, instance_id);
+	if (!temp) {
+		mutex_unlock(&svc_event_nb_list_lock);
+		return -EFAULT;
+	}
+	spin_lock_irqsave(&temp->nb_lock, flags);
+	if (temp->svc_avail)
+		nb->notifier_call(nb, QMI_SERVER_ARRIVE, NULL);
+
+	ret = raw_notifier_chain_register(&temp->svc_event_rcvr_list, nb);
+	spin_unlock_irqrestore(&temp->nb_lock, flags);
+	mutex_unlock(&svc_event_nb_list_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(qmi_svc_event_notifier_register);
+
+int qmi_svc_event_notifier_unregister(uint32_t service_id,
+				      uint32_t instance_id,
+				      struct notifier_block *nb)
+{
+	int ret;
+	struct svc_event_nb *temp;
+	unsigned long flags;
+
+	mutex_lock(&svc_event_nb_list_lock);
+	temp = find_svc_event_nb(service_id, instance_id);
+	if (!temp) {
+		mutex_unlock(&svc_event_nb_list_lock);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&temp->nb_lock, flags);
+	ret = raw_notifier_chain_unregister(&temp->svc_event_rcvr_list, nb);
+	spin_unlock_irqrestore(&temp->nb_lock, flags);
+	mutex_unlock(&svc_event_nb_list_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(qmi_svc_event_notifier_unregister);
+
+MODULE_DESCRIPTION("MSM QMI Interface");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/msm_qmi_interface_priv.h b/arch/arm/mach-msm/msm_qmi_interface_priv.h
new file mode 100644
index 0000000..58f1ce3
--- /dev/null
+++ b/arch/arm/mach-msm/msm_qmi_interface_priv.h
@@ -0,0 +1,58 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MSM_QMI_INTERFACE_PRIV_H_
+#define _MSM_QMI_INTERFACE_PRIV_H_
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/list.h>
+#include <linux/socket.h>
+#include <linux/gfp.h>
+#include <linux/platform_device.h>
+#include <linux/qmi_encdec.h>
+
+#include <mach/msm_qmi_interface.h>
+
+enum txn_type {
+	QMI_SYNC_TXN = 1,
+	QMI_ASYNC_TXN,
+};
+
+struct qmi_txn {
+	struct list_head list;
+	uint16_t txn_id;
+	enum txn_type type;
+	struct qmi_handle *handle;
+	struct msg_desc *resp_desc;
+	void *resp;
+	unsigned int resp_len;
+	int resp_received;
+	void (*resp_cb)(struct qmi_handle *handle, unsigned int msg_id,
+			void *msg, void *resp_cb_data);
+	void *resp_cb_data;
+	wait_queue_head_t wait_q;
+};
+
+struct svc_event_nb {
+	spinlock_t nb_lock;
+	uint32_t service_id;
+	uint32_t instance_id;
+	char pdriver_name[32];
+	int svc_avail;
+	struct platform_driver svc_driver;
+	struct raw_notifier_head svc_event_rcvr_list;
+	struct list_head list;
+};
+
+#endif
diff --git a/arch/arm/mach-msm/msm_smem_iface.c b/arch/arm/mach-msm/msm_smem_iface.c
index b35467b..5ae5772 100644
--- a/arch/arm/mach-msm/msm_smem_iface.c
+++ b/arch/arm/mach-msm/msm_smem_iface.c
@@ -42,4 +42,5 @@
 	cpr_info->turbo_quot = temp_cpr_info->turbo_quot;
 	cpr_info->pvs_fuse = temp_cpr_info->pvs_fuse;
 	cpr_info->floor_fuse = temp_cpr_info->floor_fuse;
+	cpr_info->disable_cpr = temp_cpr_info->disable_cpr;
 }
diff --git a/arch/arm/mach-msm/msm_smem_iface.h b/arch/arm/mach-msm/msm_smem_iface.h
index a6d6714..2daf76d 100644
--- a/arch/arm/mach-msm/msm_smem_iface.h
+++ b/arch/arm/mach-msm/msm_smem_iface.h
@@ -16,7 +16,6 @@
 #define __ARCH_ARM_MACH_MSM_SMEM_IFACE_H
 
 #include <mach/msm_smsm.h>
-#include "smd_private.h"
 
 #define MAX_KEY_EVENTS 10
 #define MAX_SEC_KEY_PAYLOAD 32
@@ -39,6 +38,7 @@
 	uint8_t turbo_quot; /* CPRFUSE[1:7] : TURBO QUOT*/
 	uint8_t pvs_fuse;   /* TURBO PVS FUSE */
 	uint8_t floor_fuse; /* Vmin Selection. b1: FAB_ID(2), b0: CPR_fuse[0] */
+	bool    disable_cpr;
 };
 
 struct boot_info_for_apps {
@@ -49,7 +49,7 @@
 	uint16_t boot_keys_pressed[MAX_KEY_EVENTS]; /* Log of key presses */
 	uint32_t timetick; /* Modem tick timer value before apps out of reset */
 	struct cpr_info_type cpr_info;
-	uint8_t PAD[24];
+	uint8_t PAD[23];
 };
 
 void msm_smem_get_cpr_info(struct cpr_info_type *cpr_info);
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index e5892c3..37dec30 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -119,7 +119,7 @@
 	int hw_interconnect;
 } ocmem_client_table[OCMEM_CLIENT_MAX] = {
 	{OCMEM_GRAPHICS, PRIO_GFX, OCMEM_PERFORMANCE, OCMEM_PORT},
-	{OCMEM_VIDEO, PRIO_VIDEO, OCMEM_PERFORMANCE, OCMEM_PORT},
+	{OCMEM_VIDEO, PRIO_VIDEO, OCMEM_PERFORMANCE, OCMEM_OCMEMNOC},
 	{OCMEM_CAMERA, NO_PRIO, OCMEM_PERFORMANCE, OCMEM_OCMEMNOC},
 	{OCMEM_HP_AUDIO, PRIO_HP_AUDIO, OCMEM_PASSIVE, OCMEM_BLOCKED},
 	{OCMEM_VOICE, PRIO_VOICE, OCMEM_PASSIVE, OCMEM_BLOCKED},
@@ -157,6 +157,16 @@
 		return 0;
 }
 
+static inline int is_iface_access(int id)
+{
+	return ocmem_client_table[id].hw_interconnect == OCMEM_OCMEMNOC ? 1 : 0;
+}
+
+static inline int is_remapped_access(int id)
+{
+	return ocmem_client_table[id].hw_interconnect == OCMEM_SYSNOC ? 1 : 0;
+}
+
 static inline int is_blocked(int id)
 {
 	return ocmem_client_table[id].hw_interconnect == OCMEM_BLOCKED ? 1 : 0;
@@ -223,9 +233,9 @@
 
 	switch (hw_interconnect) {
 	case OCMEM_PORT:
+	case OCMEM_OCMEMNOC:
 		ret_addr = phys_to_offset(addr);
 		break;
-	case OCMEM_OCMEMNOC:
 	case OCMEM_SYSNOC:
 		ret_addr = addr;
 		break;
@@ -244,9 +254,9 @@
 
 	switch (hw_interconnect) {
 	case OCMEM_PORT:
+	case OCMEM_OCMEMNOC:
 		ret_addr = offset_to_phys(addr);
 		break;
-	case OCMEM_OCMEMNOC:
 	case OCMEM_SYSNOC:
 		ret_addr = addr;
 		break;
@@ -588,16 +598,20 @@
 	if (rc < 0)
 		goto core_clock_fail;
 
-	rc = ocmem_enable_iface_clock();
 
-	if (rc < 0)
-		goto iface_clock_fail;
+	if (is_iface_access(req->owner)) {
+		rc = ocmem_enable_iface_clock();
 
-	rc = ocmem_enable_br_clock();
+		if (rc < 0)
+			goto iface_clock_fail;
+	}
 
-	if (rc < 0)
-		goto br_clock_fail;
+	if (is_remapped_access(req->owner)) {
+		rc = ocmem_enable_br_clock();
 
+		if (rc < 0)
+			goto br_clock_fail;
+	}
 
 	rc = ocmem_lock(req->owner, phys_to_offset(req->req_start), req->req_sz,
 							get_mode(req->owner));
@@ -622,9 +636,11 @@
 process_map_fail:
 	ocmem_unlock(req->owner, phys_to_offset(req->req_start), req->req_sz);
 lock_failed:
-	ocmem_disable_br_clock();
+	if (is_remapped_access(req->owner))
+		ocmem_disable_br_clock();
 br_clock_fail:
-	ocmem_disable_iface_clock();
+	if (is_iface_access(req->owner))
+		ocmem_disable_iface_clock();
 iface_clock_fail:
 	ocmem_disable_core_clock();
 core_clock_fail:
@@ -651,8 +667,10 @@
 		goto unlock_failed;
 	}
 
-	ocmem_disable_br_clock();
-	ocmem_disable_iface_clock();
+	if (is_remapped_access(req->owner))
+		ocmem_disable_br_clock();
+	if (is_iface_access(req->owner))
+		ocmem_disable_iface_clock();
 	ocmem_disable_core_clock();
 	pr_debug("ocmem: Unmapped request %p\n", req);
 	return 0;
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index 4ff34bf..65e05a9 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -12,28 +12,33 @@
 
 #include <linux/module.h>
 #include <linux/string.h>
-#include <linux/device.h>
 #include <linux/firmware.h>
 #include <linux/io.h>
-#include <linux/debugfs.h>
 #include <linux/elf.h>
 #include <linux/mutex.h>
 #include <linux/memblock.h>
 #include <linux/slab.h>
-#include <linux/atomic.h>
 #include <linux/suspend.h>
 #include <linux/rwsem.h>
 #include <linux/sysfs.h>
 #include <linux/workqueue.h>
 #include <linux/jiffies.h>
 #include <linux/wakelock.h>
+#include <linux/err.h>
+#include <linux/msm_ion.h>
+#include <linux/list.h>
+#include <linux/list_sort.h>
 
 #include <asm/uaccess.h>
 #include <asm/setup.h>
-#include <mach/peripheral-loader.h>
 
 #include "peripheral-loader.h"
 
+#define pil_err(desc, fmt, ...)						\
+	dev_err(desc->dev, "%s: " fmt, desc->name, ##__VA_ARGS__)
+#define pil_info(desc, fmt, ...)					\
+	dev_info(desc->dev, "%s: " fmt, desc->name, ##__VA_ARGS__)
+
 /**
  * proxy_timeout - Override for proxy vote timeouts
  * -1: Use driver-specified timeout
@@ -43,146 +48,376 @@
 static int proxy_timeout_ms = -1;
 module_param(proxy_timeout_ms, int, S_IRUGO | S_IWUSR);
 
-enum pil_state {
-	PIL_OFFLINE,
-	PIL_ONLINE,
+/**
+ * struct pil_mdt - Representation of <name>.mdt file in memory
+ * @hdr: ELF32 header
+ * @phdr: ELF32 program headers
+ */
+struct pil_mdt {
+	struct elf32_hdr hdr;
+	struct elf32_phdr phdr[];
 };
 
-static const char *pil_states[] = {
-	[PIL_OFFLINE] = "OFFLINE",
-	[PIL_ONLINE] = "ONLINE",
+/**
+ * struct pil_seg - memory map representing one segment
+ * @next: points to next seg mentor NULL if last segment
+ * @paddr: start address of segment
+ * @sz: size of segment
+ * @filesz: size of segment on disk
+ * @num: segment number
+ * @relocated: true if segment is relocated, false otherwise
+ *
+ * Loosely based on an elf program header. Contains all necessary information
+ * to load and initialize a segment of the image in memory.
+ */
+struct pil_seg {
+	phys_addr_t paddr;
+	unsigned long sz;
+	unsigned long filesz;
+	int num;
+	struct list_head list;
+	bool relocated;
 };
 
-struct pil_device {
-	struct pil_desc *desc;
-	int count;
-	enum pil_state state;
-	struct mutex lock;
-	struct device dev;
-	struct module *owner;
-#ifdef CONFIG_DEBUG_FS
-	struct dentry *dentry;
-#endif
+/**
+ * struct pil_priv - Private state for a pil_desc
+ * @proxy: work item used to run the proxy unvoting routine
+ * @wlock: wakelock to prevent suspend during pil_boot
+ * @wname: name of @wlock
+ * @desc: pointer to pil_desc this is private data for
+ * @seg: list of segments sorted by physical address
+ * @entry_addr: physical address where processor starts booting at
+ * @base_addr: smallest start address among all segments that are relocatable
+ * @region_start: address where relocatable region starts or lowest address
+ * for non-relocatable images
+ * @region_end: address where relocatable region ends or highest address for
+ * non-relocatable images
+ * @region: region allocated for relocatable images
+ *
+ * This struct contains data for a pil_desc that should not be exposed outside
+ * of this file. This structure points to the descriptor and the descriptor
+ * points to this structure so that PIL drivers can't access the private
+ * data of a descriptor but this file can access both.
+ */
+struct pil_priv {
 	struct delayed_work proxy;
 	struct wake_lock wlock;
-	char wake_name[32];
+	char wname[32];
+	struct pil_desc *desc;
+	struct list_head segs;
+	phys_addr_t entry_addr;
+	phys_addr_t base_addr;
+	phys_addr_t region_start;
+	phys_addr_t region_end;
+	struct ion_handle *region;
 };
 
-#define to_pil_device(d) container_of(d, struct pil_device, dev)
+static struct ion_client *ion;
 
-static ssize_t name_show(struct device *dev, struct device_attribute *attr,
-		char *buf)
+/**
+ * pil_get_entry_addr() - Retrieve the entry address of a peripheral image
+ * @desc: descriptor from pil_desc_init()
+ *
+ * Returns the physical address where the image boots at or 0 if unknown.
+ */
+phys_addr_t pil_get_entry_addr(struct pil_desc *desc)
 {
-	return snprintf(buf, PAGE_SIZE, "%s\n", to_pil_device(dev)->desc->name);
+	return desc->priv ? desc->priv->entry_addr : 0;
 }
-
-static ssize_t state_show(struct device *dev, struct device_attribute *attr,
-		char *buf)
-{
-	enum pil_state state = to_pil_device(dev)->state;
-	return snprintf(buf, PAGE_SIZE, "%s\n", pil_states[state]);
-}
-
-static struct device_attribute pil_attrs[] = {
-	__ATTR_RO(name),
-	__ATTR_RO(state),
-	{ },
-};
-
-struct bus_type pil_bus_type = {
-	.name		= "pil",
-	.dev_attrs	= pil_attrs,
-};
-
-static int __find_peripheral(struct device *dev, void *data)
-{
-	struct pil_device *pdev = to_pil_device(dev);
-	return !strncmp(pdev->desc->name, data, INT_MAX);
-}
-
-static struct pil_device *find_peripheral(const char *str)
-{
-	struct device *dev;
-
-	if (!str)
-		return NULL;
-
-	dev = bus_find_device(&pil_bus_type, NULL, (void *)str,
-			__find_peripheral);
-	return dev ? to_pil_device(dev) : NULL;
-}
+EXPORT_SYMBOL(pil_get_entry_addr);
 
 static void pil_proxy_work(struct work_struct *work)
 {
-	struct pil_device *pil;
+	struct delayed_work *delayed = to_delayed_work(work);
+	struct pil_priv *priv = container_of(delayed, struct pil_priv, proxy);
+	struct pil_desc *desc = priv->desc;
 
-	pil = container_of(work, struct pil_device, proxy.work);
-	pil->desc->ops->proxy_unvote(pil->desc);
-	wake_unlock(&pil->wlock);
+	desc->ops->proxy_unvote(desc);
+	wake_unlock(&priv->wlock);
+	module_put(desc->owner);
 }
 
-static int pil_proxy_vote(struct pil_device *pil)
+static int pil_proxy_vote(struct pil_desc *desc)
 {
 	int ret = 0;
+	struct pil_priv *priv = desc->priv;
 
-	if (pil->desc->ops->proxy_vote) {
-		wake_lock(&pil->wlock);
-		ret = pil->desc->ops->proxy_vote(pil->desc);
+	if (desc->ops->proxy_vote) {
+		wake_lock(&priv->wlock);
+		ret = desc->ops->proxy_vote(desc);
 		if (ret)
-			wake_unlock(&pil->wlock);
+			wake_unlock(&priv->wlock);
 	}
 	return ret;
 }
 
-static void pil_proxy_unvote(struct pil_device *pil, unsigned long timeout)
+static void pil_proxy_unvote(struct pil_desc *desc, unsigned long timeout)
 {
+	struct pil_priv *priv = desc->priv;
+
 	if (proxy_timeout_ms >= 0)
 		timeout = proxy_timeout_ms;
 
-	if (timeout && pil->desc->ops->proxy_unvote)
-		schedule_delayed_work(&pil->proxy, msecs_to_jiffies(timeout));
+	if (timeout && desc->ops->proxy_unvote) {
+		if (WARN_ON(!try_module_get(desc->owner)))
+			return;
+		schedule_delayed_work(&priv->proxy, msecs_to_jiffies(timeout));
+	}
+}
+
+static bool segment_is_relocatable(const struct elf32_phdr *p)
+{
+	return !!(p->p_flags & BIT(27));
+}
+
+static phys_addr_t pil_reloc(const struct pil_priv *priv, phys_addr_t addr)
+{
+	return addr - priv->base_addr + priv->region_start;
+}
+
+static struct pil_seg *pil_init_seg(const struct pil_desc *desc,
+				  const struct elf32_phdr *phdr, int num)
+{
+	bool reloc = segment_is_relocatable(phdr);
+	const struct pil_priv *priv = desc->priv;
+	struct pil_seg *seg;
+
+	if (!reloc && memblock_overlaps_memory(phdr->p_paddr, phdr->p_memsz)) {
+		pil_err(desc, "kernel memory would be overwritten [%#08lx, %#08lx)\n",
+			(unsigned long)phdr->p_paddr,
+			(unsigned long)(phdr->p_paddr + phdr->p_memsz));
+		return ERR_PTR(-EPERM);
+	}
+
+	seg = kmalloc(sizeof(*seg), GFP_KERNEL);
+	if (!seg)
+		return ERR_PTR(-ENOMEM);
+	seg->num = num;
+	seg->paddr = reloc ? pil_reloc(priv, phdr->p_paddr) : phdr->p_paddr;
+	seg->filesz = phdr->p_filesz;
+	seg->sz = phdr->p_memsz;
+	seg->relocated = reloc;
+	INIT_LIST_HEAD(&seg->list);
+
+	return seg;
+}
+
+#define segment_is_hash(flag) (((flag) & (0x7 << 24)) == (0x2 << 24))
+
+static int segment_is_loadable(const struct elf32_phdr *p)
+{
+	return (p->p_type == PT_LOAD) && !segment_is_hash(p->p_flags) &&
+		p->p_memsz;
+}
+
+static void pil_dump_segs(const struct pil_priv *priv)
+{
+	struct pil_seg *seg;
+
+	list_for_each_entry(seg, &priv->segs, list) {
+		pil_info(priv->desc, "%d: %#08zx %#08lx\n", seg->num,
+				seg->paddr, seg->paddr + seg->sz);
+	}
+}
+
+/*
+ * Ensure the entry address lies within the image limits and if the image is
+ * relocatable ensure it lies within a relocatable segment.
+ */
+static int pil_init_entry_addr(struct pil_priv *priv, const struct pil_mdt *mdt)
+{
+	struct pil_seg *seg;
+	phys_addr_t entry = mdt->hdr.e_entry;
+	bool image_relocated = priv->region;
+
+	if (image_relocated)
+		entry = pil_reloc(priv, entry);
+	priv->entry_addr = entry;
+
+	if (priv->desc->flags & PIL_SKIP_ENTRY_CHECK)
+		return 0;
+
+	list_for_each_entry(seg, &priv->segs, list) {
+		if (entry >= seg->paddr && entry < seg->paddr + seg->sz) {
+			if (!image_relocated)
+				return 0;
+			else if (seg->relocated)
+				return 0;
+		}
+	}
+	pil_err(priv->desc, "entry address %08zx not within range\n", entry);
+	pil_dump_segs(priv);
+	return -EADDRNOTAVAIL;
+}
+
+static int pil_alloc_region(struct pil_priv *priv, phys_addr_t min_addr,
+				phys_addr_t max_addr, size_t align)
+{
+	struct ion_handle *region;
+	int ret;
+	unsigned int mask;
+	size_t size = round_up(max_addr - min_addr, align);
+
+	if (!ion) {
+		WARN_ON_ONCE("No ION client, can't support relocation\n");
+		return -ENOMEM;
+	}
+
+	/* Force alignment due to linker scripts not getting it right */
+	if (align > SZ_1M) {
+		mask = ION_HEAP(ION_PIL2_HEAP_ID);
+		align = SZ_4M;
+	} else {
+		mask = ION_HEAP(ION_PIL1_HEAP_ID);
+		align = SZ_1M;
+	}
+
+	region = ion_alloc(ion, size, align, mask, 0);
+	if (IS_ERR(region)) {
+		pil_err(priv->desc, "Failed to allocate relocatable region\n");
+		return PTR_ERR(region);
+	}
+
+	ret = ion_phys(ion, region, (ion_phys_addr_t *)&priv->region_start,
+			&size);
+	if (ret) {
+		ion_free(ion, region);
+		return ret;
+	}
+
+	priv->region = region;
+	priv->region_end = priv->region_start + size;
+	priv->base_addr = min_addr;
+
+	return 0;
+}
+
+static int pil_setup_region(struct pil_priv *priv, const struct pil_mdt *mdt)
+{
+	const struct elf32_phdr *phdr;
+	phys_addr_t min_addr_r, min_addr_n, max_addr_r, max_addr_n, start, end;
+	size_t align = 0;
+	int i, ret = 0;
+	bool relocatable = false;
+
+	min_addr_n = min_addr_r = (phys_addr_t)ULLONG_MAX;
+	max_addr_n = max_addr_r = 0;
+
+	/* Find the image limits */
+	for (i = 0; i < mdt->hdr.e_phnum; i++) {
+		phdr = &mdt->phdr[i];
+		if (!segment_is_loadable(phdr))
+			continue;
+
+		start = phdr->p_paddr;
+		end = start + phdr->p_memsz;
+
+		if (segment_is_relocatable(phdr)) {
+			min_addr_r = min(min_addr_r, start);
+			max_addr_r = max(max_addr_r, end);
+			/*
+			 * Lowest relocatable segment dictates alignment of
+			 * relocatable region
+			 */
+			if (min_addr_r == start)
+				align = phdr->p_align;
+			relocatable = true;
+		} else {
+			min_addr_n = min(min_addr_n, start);
+			max_addr_n = max(max_addr_n, end);
+		}
+
+	}
+
+	if (relocatable) {
+		ret = pil_alloc_region(priv, min_addr_r, max_addr_r, align);
+	} else {
+		priv->region_start = min_addr_n;
+		priv->region_end = max_addr_n;
+		priv->base_addr = min_addr_n;
+	}
+
+	return ret;
+}
+
+static int pil_cmp_seg(void *priv, struct list_head *a, struct list_head *b)
+{
+	struct pil_seg *seg_a = list_entry(a, struct pil_seg, list);
+	struct pil_seg *seg_b = list_entry(b, struct pil_seg, list);
+
+	return seg_a->paddr - seg_b->paddr;
+}
+
+static int pil_init_mmap(struct pil_desc *desc, const struct pil_mdt *mdt)
+{
+	struct pil_priv *priv = desc->priv;
+	const struct elf32_phdr *phdr;
+	struct pil_seg *seg;
+	int i, ret;
+
+	ret = pil_setup_region(priv, mdt);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < mdt->hdr.e_phnum; i++) {
+		phdr = &mdt->phdr[i];
+		if (!segment_is_loadable(phdr))
+			continue;
+
+		seg = pil_init_seg(desc, phdr, i);
+		if (IS_ERR(seg))
+			return PTR_ERR(seg);
+
+		list_add_tail(&seg->list, &priv->segs);
+	}
+	list_sort(NULL, &priv->segs, pil_cmp_seg);
+
+	return pil_init_entry_addr(priv, mdt);
+}
+
+static void pil_release_mmap(struct pil_desc *desc)
+{
+	struct pil_priv *priv = desc->priv;
+	struct pil_seg *p, *tmp;
+
+	if (priv->region)
+		ion_free(ion, priv->region);
+	list_for_each_entry_safe(p, tmp, &priv->segs, list) {
+		list_del(&p->list);
+		kfree(p);
+	}
 }
 
 #define IOMAP_SIZE SZ_4M
 
-static int load_segment(const struct elf32_phdr *phdr, unsigned num,
-		struct pil_device *pil)
+static int pil_load_seg(struct pil_desc *desc, struct pil_seg *seg)
 {
 	int ret = 0, count, paddr;
 	char fw_name[30];
 	const struct firmware *fw = NULL;
 	const u8 *data;
+	int num = seg->num;
 
-	if (memblock_overlaps_memory(phdr->p_paddr, phdr->p_memsz)) {
-		dev_err(&pil->dev, "%s: kernel memory would be overwritten "
-			"[%#08lx, %#08lx)\n", pil->desc->name,
-			(unsigned long)phdr->p_paddr,
-			(unsigned long)(phdr->p_paddr + phdr->p_memsz));
-		return -EPERM;
-	}
-
-	if (phdr->p_filesz) {
+	if (seg->filesz) {
 		snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d",
-				pil->desc->name, num);
-		ret = request_firmware(&fw, fw_name, &pil->dev);
+				desc->name, num);
+		ret = request_firmware(&fw, fw_name, desc->dev);
 		if (ret) {
-			dev_err(&pil->dev, "%s: Failed to locate blob %s\n",
-					pil->desc->name, fw_name);
+			pil_err(desc, "Failed to locate blob %s\n", fw_name);
 			return ret;
 		}
 
-		if (fw->size != phdr->p_filesz) {
-			dev_err(&pil->dev, "%s: Blob size %u doesn't match "
-					"%u\n", pil->desc->name, fw->size,
-					phdr->p_filesz);
+		if (fw->size != seg->filesz) {
+			pil_err(desc, "Blob size %u doesn't match %lu\n",
+					fw->size, seg->filesz);
 			ret = -EPERM;
 			goto release_fw;
 		}
 	}
 
 	/* Load the segment into memory */
-	count = phdr->p_filesz;
-	paddr = phdr->p_paddr;
+	count = seg->filesz;
+	paddr = seg->paddr;
 	data = fw ? fw->data : NULL;
 	while (count > 0) {
 		int size;
@@ -191,8 +426,7 @@
 		size = min_t(size_t, IOMAP_SIZE, count);
 		buf = ioremap(paddr, size);
 		if (!buf) {
-			dev_err(&pil->dev, "%s: Failed to map memory\n",
-					pil->desc->name);
+			pil_err(desc, "Failed to map memory\n");
 			ret = -ENOMEM;
 			goto release_fw;
 		}
@@ -205,7 +439,7 @@
 	}
 
 	/* Zero out trailing memory */
-	count = phdr->p_memsz - phdr->p_filesz;
+	count = seg->sz - seg->filesz;
 	while (count > 0) {
 		int size;
 		u8 __iomem *buf;
@@ -213,8 +447,7 @@
 		size = min_t(size_t, IOMAP_SIZE, count);
 		buf = ioremap(paddr, size);
 		if (!buf) {
-			dev_err(&pil->dev, "%s: Failed to map memory\n",
-					pil->desc->name);
+			pil_err(desc, "Failed to map memory\n");
 			ret = -ENOMEM;
 			goto release_fw;
 		}
@@ -225,12 +458,10 @@
 		paddr += size;
 	}
 
-	if (pil->desc->ops->verify_blob) {
-		ret = pil->desc->ops->verify_blob(pil->desc, phdr->p_paddr,
-					  phdr->p_memsz);
+	if (desc->ops->verify_blob) {
+		ret = desc->ops->verify_blob(desc, seg->paddr, seg->sz);
 		if (ret)
-			dev_err(&pil->dev, "%s: Blob%u failed verification\n",
-				pil->desc->name, num);
+			pil_err(desc, "Blob%u failed verification\n", num);
 	}
 
 release_fw:
@@ -238,423 +469,180 @@
 	return ret;
 }
 
-#define segment_is_hash(flag) (((flag) & (0x7 << 24)) == (0x2 << 24))
-
-static int segment_is_loadable(const struct elf32_phdr *p)
-{
-	return (p->p_type == PT_LOAD) && !segment_is_hash(p->p_flags);
-}
-
-/* Sychronize request_firmware() with suspend */
+/* Synchronize request_firmware() with suspend */
 static DECLARE_RWSEM(pil_pm_rwsem);
 
-static int load_image(struct pil_device *pil)
+/**
+ * pil_boot() - Load a peripheral image into memory and boot it
+ * @desc: descriptor from pil_desc_init()
+ *
+ * Returns 0 on success or -ERROR on failure.
+ */
+int pil_boot(struct pil_desc *desc)
 {
-	int i, ret;
+	int ret;
 	char fw_name[30];
-	struct elf32_hdr *ehdr;
-	const struct elf32_phdr *phdr;
+	const struct pil_mdt *mdt;
+	const struct elf32_hdr *ehdr;
+	struct pil_seg *seg;
 	const struct firmware *fw;
-	unsigned long proxy_timeout = pil->desc->proxy_timeout;
+	unsigned long proxy_timeout = desc->proxy_timeout;
+	struct pil_priv *priv = desc->priv;
+
+	/* Reinitialize for new image */
+	pil_release_mmap(desc);
 
 	down_read(&pil_pm_rwsem);
-	snprintf(fw_name, sizeof(fw_name), "%s.mdt", pil->desc->name);
-	ret = request_firmware(&fw, fw_name, &pil->dev);
+	snprintf(fw_name, sizeof(fw_name), "%s.mdt", desc->name);
+	ret = request_firmware(&fw, fw_name, desc->dev);
 	if (ret) {
-		dev_err(&pil->dev, "%s: Failed to locate %s\n",
-				pil->desc->name, fw_name);
+		pil_err(desc, "Failed to locate %s\n", fw_name);
 		goto out;
 	}
 
 	if (fw->size < sizeof(*ehdr)) {
-		dev_err(&pil->dev, "%s: Not big enough to be an elf header\n",
-				pil->desc->name);
+		pil_err(desc, "Not big enough to be an elf header\n");
 		ret = -EIO;
 		goto release_fw;
 	}
 
-	ehdr = (struct elf32_hdr *)fw->data;
+	mdt = (const struct pil_mdt *)fw->data;
+	ehdr = &mdt->hdr;
+
 	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
-		dev_err(&pil->dev, "%s: Not an elf header\n", pil->desc->name);
+		pil_err(desc, "Not an elf header\n");
 		ret = -EIO;
 		goto release_fw;
 	}
 
 	if (ehdr->e_phnum == 0) {
-		dev_err(&pil->dev, "%s: No loadable segments\n",
-				pil->desc->name);
+		pil_err(desc, "No loadable segments\n");
 		ret = -EIO;
 		goto release_fw;
 	}
 	if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
 	    sizeof(struct elf32_hdr) > fw->size) {
-		dev_err(&pil->dev, "%s: Program headers not within mdt\n",
-				pil->desc->name);
+		pil_err(desc, "Program headers not within mdt\n");
 		ret = -EIO;
 		goto release_fw;
 	}
 
-	ret = pil->desc->ops->init_image(pil->desc, fw->data, fw->size);
+	ret = pil_init_mmap(desc, mdt);
+	if (ret)
+		goto release_fw;
+
+	if (desc->ops->init_image)
+		ret = desc->ops->init_image(desc, fw->data, fw->size);
 	if (ret) {
-		dev_err(&pil->dev, "%s: Invalid firmware metadata\n",
-				pil->desc->name);
+		pil_err(desc, "Invalid firmware metadata\n");
 		goto release_fw;
 	}
 
-	phdr = (const struct elf32_phdr *)(fw->data + sizeof(struct elf32_hdr));
-	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
-		if (!segment_is_loadable(phdr))
-			continue;
+	if (desc->ops->mem_setup)
+		ret = desc->ops->mem_setup(desc, priv->region_start,
+				priv->region_end - priv->region_start);
+	if (ret) {
+		pil_err(desc, "Memory setup error\n");
+		goto release_fw;
+	}
 
-		ret = load_segment(phdr, i, pil);
-		if (ret) {
-			dev_err(&pil->dev, "%s: Failed to load segment %d\n",
-					pil->desc->name, i);
+	list_for_each_entry(seg, &desc->priv->segs, list) {
+		ret = pil_load_seg(desc, seg);
+		if (ret)
 			goto release_fw;
-		}
 	}
 
-	ret = pil_proxy_vote(pil);
+	ret = pil_proxy_vote(desc);
 	if (ret) {
-		dev_err(&pil->dev, "%s: Failed to proxy vote\n",
-					pil->desc->name);
+		pil_err(desc, "Failed to proxy vote\n");
 		goto release_fw;
 	}
 
-	ret = pil->desc->ops->auth_and_reset(pil->desc);
+	ret = desc->ops->auth_and_reset(desc);
 	if (ret) {
-		dev_err(&pil->dev, "%s: Failed to bring out of reset\n",
-				pil->desc->name);
+		pil_err(desc, "Failed to bring out of reset\n");
 		proxy_timeout = 0; /* Remove proxy vote immediately on error */
 		goto err_boot;
 	}
-	dev_info(&pil->dev, "%s: Brought out of reset\n", pil->desc->name);
+	pil_info(desc, "Brought out of reset\n");
 err_boot:
-	pil_proxy_unvote(pil, proxy_timeout);
+	pil_proxy_unvote(desc, proxy_timeout);
 release_fw:
 	release_firmware(fw);
 out:
 	up_read(&pil_pm_rwsem);
+	if (ret)
+		pil_release_mmap(desc);
 	return ret;
 }
-
-static void pil_set_state(struct pil_device *pil, enum pil_state state)
-{
-	if (pil->state != state) {
-		pil->state = state;
-		sysfs_notify(&pil->dev.kobj, NULL, "state");
-	}
-}
+EXPORT_SYMBOL(pil_boot);
 
 /**
- * pil_get() - Load a peripheral into memory and take it out of reset
- * @name: pointer to a string containing the name of the peripheral to load
- *
- * This function returns a pointer if it succeeds. If an error occurs an
- * ERR_PTR is returned.
- *
- * If PIL is not enabled in the kernel, the value %NULL will be returned.
+ * pil_shutdown() - Shutdown a peripheral
+ * @desc: descriptor from pil_desc_init()
  */
-void *pil_get(const char *name)
+void pil_shutdown(struct pil_desc *desc)
 {
-	int ret;
-	struct pil_device *pil;
-	struct pil_device *pil_d;
-	void *retval;
-
-	if (!name)
-		return NULL;
-
-	pil = retval = find_peripheral(name);
-	if (!pil)
-		return ERR_PTR(-ENODEV);
-	if (!try_module_get(pil->owner)) {
-		put_device(&pil->dev);
-		return ERR_PTR(-ENODEV);
-	}
-
-	pil_d = pil_get(pil->desc->depends_on);
-	if (IS_ERR(pil_d)) {
-		retval = pil_d;
-		goto err_depends;
-	}
-
-	mutex_lock(&pil->lock);
-	if (!pil->count) {
-		ret = load_image(pil);
-		if (ret) {
-			retval = ERR_PTR(ret);
-			goto err_load;
-		}
-	}
-	pil->count++;
-	pil_set_state(pil, PIL_ONLINE);
-	mutex_unlock(&pil->lock);
-out:
-	return retval;
-err_load:
-	mutex_unlock(&pil->lock);
-	pil_put(pil_d);
-err_depends:
-	put_device(&pil->dev);
-	module_put(pil->owner);
-	goto out;
-}
-EXPORT_SYMBOL(pil_get);
-
-static void pil_shutdown(struct pil_device *pil)
-{
-	pil->desc->ops->shutdown(pil->desc);
-	if (proxy_timeout_ms == 0 && pil->desc->ops->proxy_unvote)
-		pil->desc->ops->proxy_unvote(pil->desc);
+	struct pil_priv *priv = desc->priv;
+	desc->ops->shutdown(desc);
+	if (proxy_timeout_ms == 0 && desc->ops->proxy_unvote)
+		desc->ops->proxy_unvote(desc);
 	else
-		flush_delayed_work(&pil->proxy);
-
-	pil_set_state(pil, PIL_OFFLINE);
+		flush_delayed_work(&priv->proxy);
 }
+EXPORT_SYMBOL(pil_shutdown);
 
 /**
- * pil_put() - Inform PIL the peripheral no longer needs to be active
- * @peripheral_handle: pointer from a previous call to pil_get()
+ * pil_desc_init() - Initialize a pil descriptor
+ * @desc: descriptor to intialize
  *
- * This doesn't imply that a peripheral is shutdown or in reset since another
- * driver could be using the peripheral.
+ * Initialize a pil descriptor for use by other pil functions. This function
+ * must be called before calling pil_boot() or pil_shutdown().
+ *
+ * Returns 0 for success and -ERROR on failure.
  */
-void pil_put(void *peripheral_handle)
+int pil_desc_init(struct pil_desc *desc)
 {
-	struct pil_device *pil_d, *pil = peripheral_handle;
-
-	if (IS_ERR_OR_NULL(pil))
-		return;
-
-	mutex_lock(&pil->lock);
-	if (WARN(!pil->count, "%s: %s: Reference count mismatch\n",
-			pil->desc->name, __func__))
-		goto err_out;
-	if (!--pil->count)
-		pil_shutdown(pil);
-	mutex_unlock(&pil->lock);
-
-	pil_d = find_peripheral(pil->desc->depends_on);
-	module_put(pil->owner);
-	if (pil_d) {
-		pil_put(pil_d);
-		put_device(&pil_d->dev);
-	}
-	put_device(&pil->dev);
-	return;
-err_out:
-	mutex_unlock(&pil->lock);
-	return;
-}
-EXPORT_SYMBOL(pil_put);
-
-void pil_force_shutdown(const char *name)
-{
-	struct pil_device *pil;
-
-	pil = find_peripheral(name);
-	if (!pil) {
-		pr_err("%s: Couldn't find %s\n", __func__, name);
-		return;
-	}
-
-	mutex_lock(&pil->lock);
-	if (!WARN(!pil->count, "%s: %s: Reference count mismatch\n",
-			pil->desc->name, __func__))
-		pil_shutdown(pil);
-	mutex_unlock(&pil->lock);
-
-	put_device(&pil->dev);
-}
-EXPORT_SYMBOL(pil_force_shutdown);
-
-int pil_force_boot(const char *name)
-{
-	int ret = -EINVAL;
-	struct pil_device *pil;
-
-	pil = find_peripheral(name);
-	if (!pil) {
-		pr_err("%s: Couldn't find %s\n", __func__, name);
-		return -EINVAL;
-	}
-
-	mutex_lock(&pil->lock);
-	if (!WARN(!pil->count, "%s: %s: Reference count mismatch\n",
-			pil->desc->name, __func__))
-		ret = load_image(pil);
-	if (!ret)
-		pil_set_state(pil, PIL_ONLINE);
-	mutex_unlock(&pil->lock);
-	put_device(&pil->dev);
-
-	return ret;
-}
-EXPORT_SYMBOL(pil_force_boot);
-
-#ifdef CONFIG_DEBUG_FS
-static int msm_pil_debugfs_open(struct inode *inode, struct file *filp)
-{
-	filp->private_data = inode->i_private;
-	return 0;
-}
-
-static ssize_t msm_pil_debugfs_read(struct file *filp, char __user *ubuf,
-		size_t cnt, loff_t *ppos)
-{
-	int r;
-	char buf[40];
-	struct pil_device *pil = filp->private_data;
-
-	mutex_lock(&pil->lock);
-	r = snprintf(buf, sizeof(buf), "%d\n", pil->count);
-	mutex_unlock(&pil->lock);
-	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
-}
-
-static ssize_t msm_pil_debugfs_write(struct file *filp,
-		const char __user *ubuf, size_t cnt, loff_t *ppos)
-{
-	struct pil_device *pil = filp->private_data;
-	char buf[4];
-
-	if (cnt > sizeof(buf))
-		return -EINVAL;
-
-	if (copy_from_user(&buf, ubuf, cnt))
-		return -EFAULT;
-
-	if (!strncmp(buf, "get", 3)) {
-		if (IS_ERR(pil_get(pil->desc->name)))
-			return -EIO;
-	} else if (!strncmp(buf, "put", 3))
-		pil_put(pil);
-	else
-		return -EINVAL;
-
-	return cnt;
-}
-
-static const struct file_operations msm_pil_debugfs_fops = {
-	.open	= msm_pil_debugfs_open,
-	.read	= msm_pil_debugfs_read,
-	.write	= msm_pil_debugfs_write,
-};
-
-static struct dentry *pil_base_dir;
-
-static int __init msm_pil_debugfs_init(void)
-{
-	pil_base_dir = debugfs_create_dir("pil", NULL);
-	if (!pil_base_dir) {
-		pil_base_dir = NULL;
-		return -ENOMEM;
-	}
-
-	return 0;
-}
-
-static void __exit msm_pil_debugfs_exit(void)
-{
-	debugfs_remove_recursive(pil_base_dir);
-}
-
-static int msm_pil_debugfs_add(struct pil_device *pil)
-{
-	if (!pil_base_dir)
-		return -ENOMEM;
-
-	pil->dentry = debugfs_create_file(pil->desc->name, S_IRUGO | S_IWUSR,
-				pil_base_dir, pil, &msm_pil_debugfs_fops);
-	return !pil->dentry ? -ENOMEM : 0;
-}
-
-static void msm_pil_debugfs_remove(struct pil_device *pil)
-{
-	debugfs_remove(pil->dentry);
-}
-#else
-static int __init msm_pil_debugfs_init(void) { return 0; };
-static void __exit msm_pil_debugfs_exit(void) { return 0; };
-static int msm_pil_debugfs_add(struct pil_device *pil) { return 0; }
-static void msm_pil_debugfs_remove(struct pil_device *pil) { }
-#endif
-
-static void pil_device_release(struct device *dev)
-{
-	struct pil_device *pil = to_pil_device(dev);
-	wake_lock_destroy(&pil->wlock);
-	mutex_destroy(&pil->lock);
-	kfree(pil);
-}
-
-struct pil_device *msm_pil_register(struct pil_desc *desc)
-{
-	int err;
-	static atomic_t pil_count = ATOMIC_INIT(-1);
-	struct pil_device *pil;
+	struct pil_priv *priv;
 
 	/* Ignore users who don't make any sense */
+	WARN(desc->ops->proxy_unvote && !desc->proxy_timeout,
+			"A proxy timeout of 0 was specified.\n");
 	if (WARN(desc->ops->proxy_unvote && !desc->ops->proxy_vote,
-				"invalid proxy voting. ignoring\n"))
+				"Invalid proxy voting. Ignoring\n"))
 		((struct pil_reset_ops *)desc->ops)->proxy_unvote = NULL;
 
-	WARN(desc->ops->proxy_unvote && !desc->proxy_timeout,
-		"A proxy timeout of 0 ms was specified for %s. Specify one in "
-		"desc->proxy_timeout.\n", desc->name);
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	desc->priv = priv;
+	priv->desc = desc;
 
-	pil = kzalloc(sizeof(*pil), GFP_KERNEL);
-	if (!pil)
-		return ERR_PTR(-ENOMEM);
+	snprintf(priv->wname, sizeof(priv->wname), "pil-%s", desc->name);
+	wake_lock_init(&priv->wlock, WAKE_LOCK_SUSPEND, priv->wname);
+	INIT_DELAYED_WORK(&priv->proxy, pil_proxy_work);
+	INIT_LIST_HEAD(&priv->segs);
 
-	mutex_init(&pil->lock);
-	pil->desc = desc;
-	pil->owner = desc->owner;
-	pil->dev.parent = desc->dev;
-	pil->dev.bus = &pil_bus_type;
-	pil->dev.release = pil_device_release;
-
-	snprintf(pil->wake_name, sizeof(pil->wake_name), "pil-%s", desc->name);
-	wake_lock_init(&pil->wlock, WAKE_LOCK_SUSPEND, pil->wake_name);
-	INIT_DELAYED_WORK(&pil->proxy, pil_proxy_work);
-
-	dev_set_name(&pil->dev, "pil%d", atomic_inc_return(&pil_count));
-	err = device_register(&pil->dev);
-	if (err) {
-		put_device(&pil->dev);
-		wake_lock_destroy(&pil->wlock);
-		mutex_destroy(&pil->lock);
-		kfree(pil);
-		return ERR_PTR(err);
-	}
-
-	err = msm_pil_debugfs_add(pil);
-	if (err) {
-		device_unregister(&pil->dev);
-		return ERR_PTR(err);
-	}
-
-	return pil;
+	return 0;
 }
-EXPORT_SYMBOL(msm_pil_register);
+EXPORT_SYMBOL(pil_desc_init);
 
-void msm_pil_unregister(struct pil_device *pil)
+/**
+ * pil_desc_release() - Release a pil descriptor
+ * @desc: descriptor to free
+ */
+void pil_desc_release(struct pil_desc *desc)
 {
-	if (IS_ERR_OR_NULL(pil))
-		return;
+	struct pil_priv *priv = desc->priv;
 
-	if (get_device(&pil->dev)) {
-		mutex_lock(&pil->lock);
-		WARN_ON(pil->count);
-		flush_delayed_work_sync(&pil->proxy);
-		msm_pil_debugfs_remove(pil);
-		device_unregister(&pil->dev);
-		mutex_unlock(&pil->lock);
-		put_device(&pil->dev);
+	if (priv) {
+		flush_delayed_work(&priv->proxy);
+		wake_lock_destroy(&priv->wlock);
 	}
+	desc->priv = NULL;
+	kfree(priv);
 }
-EXPORT_SYMBOL(msm_pil_unregister);
+EXPORT_SYMBOL(pil_desc_release);
 
 static int pil_pm_notify(struct notifier_block *b, unsigned long event, void *p)
 {
@@ -675,19 +663,18 @@
 
 static int __init msm_pil_init(void)
 {
-	int ret = msm_pil_debugfs_init();
-	if (ret)
-		return ret;
-	register_pm_notifier(&pil_pm_notifier);
-	return bus_register(&pil_bus_type);
+	ion = msm_ion_client_create(UINT_MAX, "pil");
+	if (IS_ERR(ion)) /* Can't support relocatable images */
+		ion = NULL;
+	return register_pm_notifier(&pil_pm_notifier);
 }
-subsys_initcall(msm_pil_init);
+device_initcall(msm_pil_init);
 
 static void __exit msm_pil_exit(void)
 {
-	bus_unregister(&pil_bus_type);
 	unregister_pm_notifier(&pil_pm_notifier);
-	msm_pil_debugfs_exit();
+	if (ion)
+		ion_client_destroy(ion);
 }
 module_exit(msm_pil_exit);
 
diff --git a/arch/arm/mach-msm/peripheral-loader.h b/arch/arm/mach-msm/peripheral-loader.h
index 405b73f..1c2faf7 100644
--- a/arch/arm/mach-msm/peripheral-loader.h
+++ b/arch/arm/mach-msm/peripheral-loader.h
@@ -14,28 +14,33 @@
 
 struct device;
 struct module;
+struct pil_priv;
 
 /**
  * struct pil_desc - PIL descriptor
  * @name: string used for pil_get()
- * @depends_on: booted before this peripheral
  * @dev: parent device
  * @ops: callback functions
  * @owner: module the descriptor belongs to
  * @proxy_timeout: delay in ms until proxy vote is removed
+ * @flags: bitfield for image flags
+ * @priv: DON'T USE - internal only
  */
 struct pil_desc {
 	const char *name;
-	const char *depends_on;
 	struct device *dev;
 	const struct pil_reset_ops *ops;
 	struct module *owner;
 	unsigned long proxy_timeout;
+	unsigned long flags;
+#define PIL_SKIP_ENTRY_CHECK	BIT(0)
+	struct pil_priv *priv;
 };
 
 /**
  * struct pil_reset_ops - PIL operations
  * @init_image: prepare an image for authentication
+ * @mem_setup: prepare the image memory region
  * @verify_blob: authenticate a program segment, called once for each loadable
  *		 program segment (optional)
  * @proxy_vote: make proxy votes before auth_and_reset (optional)
@@ -46,6 +51,7 @@
 struct pil_reset_ops {
 	int (*init_image)(struct pil_desc *pil, const u8 *metadata,
 			  size_t size);
+	int (*mem_setup)(struct pil_desc *pil, phys_addr_t addr, size_t size);
 	int (*verify_blob)(struct pil_desc *pil, u32 phy_addr, size_t size);
 	int (*proxy_vote)(struct pil_desc *pil);
 	int (*auth_and_reset)(struct pil_desc *pil);
@@ -53,17 +59,21 @@
 	int (*shutdown)(struct pil_desc *pil);
 };
 
-struct pil_device;
-
 #ifdef CONFIG_MSM_PIL
-extern struct pil_device *msm_pil_register(struct pil_desc *desc);
-extern void msm_pil_unregister(struct pil_device *pil);
+extern int pil_desc_init(struct pil_desc *desc);
+extern int pil_boot(struct pil_desc *desc);
+extern void pil_shutdown(struct pil_desc *desc);
+extern void pil_desc_release(struct pil_desc *desc);
+extern phys_addr_t pil_get_entry_addr(struct pil_desc *desc);
 #else
-static inline struct pil_device *msm_pil_register(struct pil_desc *desc)
+static inline int pil_desc_init(struct pil_desc *desc) { return 0; }
+static inline int pil_boot(struct pil_desc *desc) { return 0; }
+static inline void pil_shutdown(struct pil_desc *desc) { }
+static inline void pil_desc_release(struct pil_desc *desc) { }
+static inline phys_addr_t pil_get_entry_addr(struct pil_desc *desc)
 {
-	return NULL;
+	return 0;
 }
-static inline void msm_pil_unregister(struct pil_device *pil) { }
 #endif
 
 #endif
diff --git a/arch/arm/mach-msm/pil-dsps.c b/arch/arm/mach-msm/pil-dsps.c
index c074086..519e1c9 100644
--- a/arch/arm/mach-msm/pil-dsps.c
+++ b/arch/arm/mach-msm/pil-dsps.c
@@ -13,34 +13,31 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/elf.h>
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/atomic.h>
 #include <linux/interrupt.h>
 
-#include <mach/msm_iomap.h>
 #include <mach/subsystem_restart.h>
 #include <mach/msm_smsm.h>
-#include <mach/peripheral-loader.h>
 
 #include "peripheral-loader.h"
 #include "scm-pas.h"
 #include "ramdump.h"
 
-#define PPSS_RESET			(MSM_CLK_CTL_BASE + 0x2594)
+#define PPSS_RESET			0x2594
 #define PPSS_RESET_PROC_RESET		0x2
 #define PPSS_RESET_RESET		0x1
-#define PPSS_PROC_CLK_CTL		(MSM_CLK_CTL_BASE + 0x2588)
+#define PPSS_PROC_CLK_CTL		0x2588
 #define CLK_BRANCH_ENA			0x10
-#define PPSS_HCLK_CTL			(MSM_CLK_CTL_BASE + 0x2580)
-#define CLK_HALT_DFAB_STATE		(MSM_CLK_CTL_BASE + 0x2FC8)
+#define PPSS_HCLK_CTL			0x2580
+#define CLK_HALT_DFAB_STATE		0x2FC8
 
 #define PPSS_WDOG_UNMASKED_INT_EN	0x1808
 
 struct dsps_data {
-	struct pil_device *pil;
+	void __iomem *base;
 	struct pil_desc desc;
 	struct subsys_device *subsys;
 	struct subsys_desc subsys_desc;
@@ -58,33 +55,41 @@
 };
 
 #define desc_to_drv(d) container_of(d, struct dsps_data, subsys_desc)
+#define pil_to_drv(d) container_of(d, struct dsps_data, desc)
 
 static int init_image_dsps(struct pil_desc *pil, const u8 *metadata,
 				     size_t size)
 {
+	struct dsps_data *drv = pil_to_drv(pil);
+
 	/* Bring memory and bus interface out of reset */
-	writel_relaxed(PPSS_RESET_PROC_RESET, PPSS_RESET);
-	writel_relaxed(CLK_BRANCH_ENA, PPSS_HCLK_CTL);
+	writel_relaxed(PPSS_RESET_PROC_RESET, drv->base + PPSS_RESET);
+	writel_relaxed(CLK_BRANCH_ENA, drv->base + PPSS_HCLK_CTL);
 	mb();
 	return 0;
 }
 
 static int reset_dsps(struct pil_desc *pil)
 {
-	writel_relaxed(CLK_BRANCH_ENA, PPSS_PROC_CLK_CTL);
-	while (readl_relaxed(CLK_HALT_DFAB_STATE) & BIT(18))
+	struct dsps_data *drv = pil_to_drv(pil);
+
+	writel_relaxed(CLK_BRANCH_ENA, drv->base + PPSS_PROC_CLK_CTL);
+	while (readl_relaxed(drv->base + CLK_HALT_DFAB_STATE) & BIT(18))
 		cpu_relax();
 	/* Bring DSPS out of reset */
-	writel_relaxed(0x0, PPSS_RESET);
+	writel_relaxed(0x0, drv->base + PPSS_RESET);
 	return 0;
 }
 
 static int shutdown_dsps(struct pil_desc *pil)
 {
-	writel_relaxed(PPSS_RESET_PROC_RESET | PPSS_RESET_RESET, PPSS_RESET);
+	struct dsps_data *drv = pil_to_drv(pil);
+
+	writel_relaxed(PPSS_RESET_PROC_RESET | PPSS_RESET_RESET,
+			drv->base + PPSS_RESET);
 	usleep_range(1000, 2000);
-	writel_relaxed(PPSS_RESET_PROC_RESET, PPSS_RESET);
-	writel_relaxed(0x0, PPSS_PROC_CLK_CTL);
+	writel_relaxed(PPSS_RESET_PROC_RESET, drv->base + PPSS_RESET);
+	writel_relaxed(0x0, drv->base + PPSS_PROC_CLK_CTL);
 	return 0;
 }
 
@@ -165,19 +170,15 @@
 
 static int dsps_start(const struct subsys_desc *desc)
 {
-	void *ret;
 	struct dsps_data *drv = desc_to_drv(desc);
 
-	ret = pil_get(drv->desc.name);
-	if (IS_ERR(ret))
-		return PTR_ERR(ret);
-	return 0;
+	return pil_boot(&drv->desc);
 }
 
 static void dsps_stop(const struct subsys_desc *desc)
 {
 	struct dsps_data *drv = desc_to_drv(desc);
-	pil_put(drv->pil);
+	pil_shutdown(&drv->desc);
 }
 
 static int dsps_shutdown(const struct subsys_desc *desc)
@@ -188,7 +189,7 @@
 		writel_relaxed(0, drv->ppss_base + PPSS_WDOG_UNMASKED_INT_EN);
 		mb(); /* Make sure wdog is disabled before shutting down */
 	}
-	pil_force_shutdown(drv->desc.name);
+	pil_shutdown(&drv->desc);
 	return 0;
 }
 
@@ -196,7 +197,7 @@
 {
 	struct dsps_data *drv = desc_to_drv(desc);
 
-	pil_force_boot(drv->desc.name);
+	pil_boot(&drv->desc);
 	atomic_set(&drv->crash_in_progress, 0);
 	enable_irq(drv->wdog_irq);
 
@@ -253,8 +254,8 @@
 {
 	struct dsps_data *drv;
 	struct pil_desc *desc;
-	int ret;
 	struct resource *res;
+	int ret;
 
 	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
 	if (!drv)
@@ -262,6 +263,13 @@
 	platform_set_drvdata(pdev, drv);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EINVAL;
+	drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!drv->base)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 	if (res) {
 		drv->ppss_base = devm_ioremap(&pdev->dev, res->start,
 					      resource_size(res));
@@ -273,6 +281,7 @@
 	desc->name = pdev->dev.platform_data;
 	desc->dev = &pdev->dev;
 	desc->owner = THIS_MODULE;
+	desc->flags = PIL_SKIP_ENTRY_CHECK;
 	if (pas_supported(PAS_DSPS) > 0) {
 		desc->ops = &pil_dsps_ops_trusted;
 		dev_info(&pdev->dev, "using secure boot\n");
@@ -280,9 +289,9 @@
 		desc->ops = &pil_dsps_ops;
 		dev_info(&pdev->dev, "using non-secure boot\n");
 	}
-	drv->pil = msm_pil_register(desc);
-	if (IS_ERR(drv->pil))
-		return PTR_ERR(drv->pil);
+	ret = pil_desc_init(desc);
+	if (ret)
+		return ret;
 
 	drv->fw_ramdump_segments[0].address = 0x12000000;
 	drv->fw_ramdump_segments[0].size = 0x28000;
@@ -292,7 +301,7 @@
 	drv->fw_ramdump_segments[2].size = 0x4000;
 	drv->fw_ramdump_segments[3].address = 0x8fe00000;
 	drv->fw_ramdump_segments[3].size = 0x100000;
-	drv->ramdump_dev = create_ramdump_device("dsps");
+	drv->ramdump_dev = create_ramdump_device("dsps", &pdev->dev);
 	if (!drv->ramdump_dev) {
 		ret = -ENOMEM;
 		goto err_ramdump;
@@ -300,7 +309,7 @@
 
 	drv->smem_ramdump_segments[0].address = PHYS_OFFSET - SZ_2M;
 	drv->smem_ramdump_segments[0].size =  SZ_2M;
-	drv->smem_ramdump_dev = create_ramdump_device("smem-dsps");
+	drv->smem_ramdump_dev = create_ramdump_device("smem-dsps", &pdev->dev);
 	if (!drv->smem_ramdump_dev) {
 		ret = -ENOMEM;
 		goto err_smem_ramdump;
@@ -350,7 +359,7 @@
 err_smem_ramdump:
 	destroy_ramdump_device(drv->ramdump_dev);
 err_ramdump:
-	msm_pil_unregister(drv->pil);
+	pil_desc_release(desc);
 	return ret;
 }
 
@@ -362,7 +371,7 @@
 	subsys_unregister(drv->subsys);
 	destroy_ramdump_device(drv->smem_ramdump_dev);
 	destroy_ramdump_device(drv->ramdump_dev);
-	msm_pil_unregister(drv->pil);
+	pil_desc_release(&drv->desc);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/pil-gss.c b/arch/arm/mach-msm/pil-gss.c
index 0c8f4e3..a6d13d0 100644
--- a/arch/arm/mach-msm/pil-gss.c
+++ b/arch/arm/mach-msm/pil-gss.c
@@ -14,7 +14,6 @@
 #include <linux/kernel.h>
 #include <linux/err.h>
 #include <linux/io.h>
-#include <linux/elf.h>
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -25,13 +24,11 @@
 #include <linux/reboot.h>
 #include <linux/interrupt.h>
 
-#include <mach/msm_iomap.h>
 #include <mach/msm_xo.h>
 #include <mach/socinfo.h>
 #include <mach/msm_bus_board.h>
 #include <mach/msm_bus.h>
 #include <mach/subsystem_restart.h>
-#include <mach/peripheral-loader.h>
 
 #include "peripheral-loader.h"
 #include "scm-pas.h"
@@ -46,13 +43,13 @@
 #define GSS_CSR_POWER_UP_DOWN	0x18
 #define GSS_CSR_CFG_HID		0x2C
 
-#define GSS_SLP_CLK_CTL		(MSM_CLK_CTL_BASE + 0x2C60)
-#define GSS_RESET		(MSM_CLK_CTL_BASE + 0x2C64)
-#define GSS_CLAMP_ENA		(MSM_CLK_CTL_BASE + 0x2C68)
-#define GSS_CXO_SRC_CTL		(MSM_CLK_CTL_BASE + 0x2C74)
+#define GSS_SLP_CLK_CTL		0x2C60
+#define GSS_RESET		0x2C64
+#define GSS_CLAMP_ENA		0x2C68
+#define GSS_CXO_SRC_CTL		0x2C74
 
-#define PLL5_STATUS		(MSM_CLK_CTL_BASE + 0x30F8)
-#define PLL_ENA_GSS		(MSM_CLK_CTL_BASE + 0x3480)
+#define PLL5_STATUS		0x30F8
+#define PLL_ENA_GSS		0x3480
 
 #define PLL5_VOTE		BIT(5)
 #define PLL_STATUS		BIT(16)
@@ -67,9 +64,9 @@
 struct gss_data {
 	void __iomem *base;
 	void __iomem *qgic2_base;
-	unsigned long start_addr;
+	void __iomem *cbase;
 	struct clk *xo;
-	struct pil_device *pil;
+	struct pil_desc pil_desc;
 	struct miscdevice misc_dev;
 	struct subsys_device *subsys;
 	struct subsys_desc subsys_desc;
@@ -80,15 +77,6 @@
 	struct ramdump_device *smem_ramdump_dev;
 };
 
-static int pil_gss_init_image(struct pil_desc *pil, const u8 *metadata,
-		size_t size)
-{
-	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
-	struct gss_data *drv = dev_get_drvdata(pil->dev);
-	drv->start_addr = ehdr->e_entry;
-	return 0;
-}
-
 static int make_gss_proxy_votes(struct pil_desc *pil)
 {
 	int ret;
@@ -111,14 +99,15 @@
 static void gss_init(struct gss_data *drv)
 {
 	void __iomem *base = drv->base;
+	void __iomem *cbase = drv->cbase;
 
 	/* Supply clocks to GSS. */
-	writel_relaxed(XO_CLK_BRANCH_ENA, GSS_CXO_SRC_CTL);
-	writel_relaxed(SLP_CLK_BRANCH_ENA, GSS_SLP_CLK_CTL);
+	writel_relaxed(XO_CLK_BRANCH_ENA, cbase + GSS_CXO_SRC_CTL);
+	writel_relaxed(SLP_CLK_BRANCH_ENA, cbase + GSS_SLP_CLK_CTL);
 
 	/* Deassert GSS reset and clamps. */
-	writel_relaxed(0x0, GSS_RESET);
-	writel_relaxed(0x0, GSS_CLAMP_ENA);
+	writel_relaxed(0x0, cbase + GSS_RESET);
+	writel_relaxed(0x0, cbase + GSS_CLAMP_ENA);
 	mb();
 
 	/*
@@ -159,6 +148,7 @@
 {
 	struct gss_data *drv = dev_get_drvdata(pil->dev);
 	void __iomem *base = drv->base;
+	void __iomem *cbase = drv->cbase;
 	u32 regval;
 	int ret;
 
@@ -175,8 +165,8 @@
 	 * Vote PLL on in GSS's voting register and wait for it to enable.
 	 * The PLL must be enable to switch the GFMUX to a low-power source.
 	 */
-	writel_relaxed(PLL5_VOTE, PLL_ENA_GSS);
-	while ((readl_relaxed(PLL5_STATUS) & PLL_STATUS) == 0)
+	writel_relaxed(PLL5_VOTE, cbase + PLL_ENA_GSS);
+	while ((readl_relaxed(cbase + PLL5_STATUS) & PLL_STATUS) == 0)
 		cpu_relax();
 
 	/* Perform one-time GSS initialization. */
@@ -201,7 +191,7 @@
 	writel_relaxed(0x1F, base + GSS_CSR_CLK_ENABLE);
 
 	/* Clear GSS PLL votes. */
-	writel_relaxed(0, PLL_ENA_GSS);
+	writel_relaxed(0, cbase + PLL_ENA_GSS);
 	mb();
 
 	clk_disable_unprepare(drv->xo);
@@ -213,7 +203,8 @@
 {
 	struct gss_data *drv = dev_get_drvdata(pil->dev);
 	void __iomem *base = drv->base;
-	unsigned long start_addr = drv->start_addr;
+	unsigned long start_addr = pil_get_entry_addr(pil);
+	void __iomem *cbase = drv->cbase;
 	int ret;
 
 	/* Unhalt bus port. */
@@ -224,8 +215,8 @@
 	}
 
 	/* Vote PLL on in GSS's voting register and wait for it to enable. */
-	writel_relaxed(PLL5_VOTE, PLL_ENA_GSS);
-	while ((readl_relaxed(PLL5_STATUS) & PLL_STATUS) == 0)
+	writel_relaxed(PLL5_VOTE, cbase + PLL_ENA_GSS);
+	while ((readl_relaxed(cbase + PLL5_STATUS) & PLL_STATUS) == 0)
 		cpu_relax();
 
 	/* Perform GSS initialization. */
@@ -258,7 +249,6 @@
 }
 
 static struct pil_reset_ops pil_gss_ops = {
-	.init_image = pil_gss_init_image,
 	.auth_and_reset = pil_gss_reset,
 	.shutdown = pil_gss_shutdown,
 	.proxy_vote = make_gss_proxy_votes,
@@ -373,14 +363,10 @@
 
 static int gss_start(const struct subsys_desc *desc)
 {
-	void *ret;
 	struct gss_data *drv;
 
 	drv = container_of(desc, struct gss_data, subsys_desc);
-	ret = pil_get("gss");
-	if (IS_ERR(ret))
-		return PTR_ERR(ret);
-	return 0;
+	return pil_boot(&drv->pil_desc);
 }
 
 static void gss_stop(const struct subsys_desc *desc)
@@ -388,14 +374,14 @@
 	struct gss_data *drv;
 
 	drv = container_of(desc, struct gss_data, subsys_desc);
-	pil_put(drv->pil);
+	pil_shutdown(&drv->pil_desc);
 }
 
 static int gss_shutdown(const struct subsys_desc *desc)
 {
 	struct gss_data *drv = container_of(desc, struct gss_data, subsys_desc);
 
-	pil_force_shutdown("gss");
+	pil_shutdown(&drv->pil_desc);
 	disable_irq_nosync(drv->irq);
 
 	return 0;
@@ -405,7 +391,7 @@
 {
 	struct gss_data *drv = container_of(desc, struct gss_data, subsys_desc);
 
-	pil_force_boot("gss");
+	pil_boot(&drv->pil_desc);
 	enable_irq(drv->irq);
 	return 0;
 }
@@ -467,8 +453,10 @@
 	struct gss_data *drv = container_of(c, struct gss_data, misc_dev);
 
 	drv->subsys_handle = subsystem_get("gss");
-	if (!drv->subsys_handle)
-		pr_debug("%s - subsystem_get returned NULL\n", __func__);
+	if (IS_ERR(drv->subsys_handle)) {
+		pr_debug("%s - subsystem_get returned error\n", __func__);
+		return PTR_ERR(drv->subsys_handle);
+	}
 
 	return 0;
 }
@@ -497,30 +485,26 @@
 	struct pil_desc *desc;
 	int ret;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		return -EINVAL;
-
 	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
 	if (!drv)
 		return -ENOMEM;
 	platform_set_drvdata(pdev, drv);
 
-	drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	drv->base = devm_request_and_ioremap(&pdev->dev, res);
 	if (!drv->base)
 		return -ENOMEM;
 
-	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
-	if (!desc)
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	drv->qgic2_base = devm_request_and_ioremap(&pdev->dev, res);
+	if (!drv->qgic2_base)
 		return -ENOMEM;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
 	if (!res)
 		return -EINVAL;
-
-	drv->qgic2_base = devm_ioremap(&pdev->dev, res->start,
-					resource_size(res));
-	if (!drv->qgic2_base)
+	drv->cbase = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!drv->cbase)
 		return -ENOMEM;
 
 	drv->xo = devm_clk_get(&pdev->dev, "xo");
@@ -531,6 +515,7 @@
 	if (drv->irq < 0)
 		return drv->irq;
 
+	desc = &drv->pil_desc;
 	desc->name = "gss";
 	desc->dev = &pdev->dev;
 	desc->owner = THIS_MODULE;
@@ -543,14 +528,13 @@
 		desc->ops = &pil_gss_ops;
 		dev_info(&pdev->dev, "using non-secure boot\n");
 	}
+	ret = pil_desc_init(desc);
+	if (ret)
+		return ret;
+
 	/* Force into low power mode because hardware doesn't do this */
 	desc->ops->shutdown(desc);
 
-	drv->pil = msm_pil_register(desc);
-	if (IS_ERR(drv->pil)) {
-		return PTR_ERR(drv->pil);
-	}
-
 	ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
 			smsm_state_cb, drv);
 	if (ret < 0)
@@ -579,13 +563,13 @@
 	if (ret)
 		goto err_misc;
 
-	drv->ramdump_dev = create_ramdump_device("gss");
+	drv->ramdump_dev = create_ramdump_device("gss", &pdev->dev);
 	if (!drv->ramdump_dev) {
 		ret = -ENOMEM;
 		goto err_ramdump;
 	}
 
-	drv->smem_ramdump_dev = create_ramdump_device("smem-gss");
+	drv->smem_ramdump_dev = create_ramdump_device("smem-gss", &pdev->dev);
 	if (!drv->smem_ramdump_dev) {
 		ret = -ENOMEM;
 		goto err_smem;
@@ -605,7 +589,7 @@
 err_misc:
 	subsys_unregister(drv->subsys);
 err_subsys:
-	msm_pil_unregister(drv->pil);
+	pil_desc_release(desc);
 	return ret;
 }
 
@@ -617,7 +601,7 @@
 	destroy_ramdump_device(drv->ramdump_dev);
 	misc_deregister(&drv->misc_dev);
 	subsys_unregister(drv->subsys);
-	msm_pil_unregister(drv->pil);
+	pil_desc_release(&drv->pil_desc);
 
 	return 0;
 }
diff --git a/arch/arm/mach-msm/pil-mba.c b/arch/arm/mach-msm/pil-mba.c
deleted file mode 100644
index daafd1d..0000000
--- a/arch/arm/mach-msm/pil-mba.c
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
- * 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
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/iopoll.h>
-#include <linux/ioport.h>
-#include <linux/elf.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/of.h>
-#include <linux/interrupt.h>
-
-#include <mach/subsystem_restart.h>
-#include <mach/msm_smsm.h>
-#include <mach/peripheral-loader.h>
-
-#include "peripheral-loader.h"
-#include "ramdump.h"
-
-#define RMB_MBA_COMMAND			0x08
-#define RMB_MBA_STATUS			0x0C
-#define RMB_PMI_META_DATA		0x10
-#define RMB_PMI_CODE_START		0x14
-#define RMB_PMI_CODE_LENGTH		0x18
-
-#define CMD_META_DATA_READY		0x1
-#define CMD_LOAD_READY			0x2
-
-#define STATUS_META_DATA_AUTH_SUCCESS	0x3
-#define STATUS_AUTH_COMPLETE		0x4
-
-#define PROXY_TIMEOUT_MS		10000
-#define POLL_INTERVAL_US		50
-
-#define MAX_SSR_REASON_LEN 81U
-
-static int modem_auth_timeout_ms = 10000;
-module_param(modem_auth_timeout_ms, int, S_IRUGO | S_IWUSR);
-
-struct mba_data {
-	void __iomem *reg_base;
-	void __iomem *metadata_base;
-	unsigned long metadata_phys;
-	struct pil_device *pil;
-	struct pil_desc desc;
-	struct subsys_device *subsys;
-	struct subsys_desc subsys_desc;
-	struct clk *xo;
-	void *ramdump_dev;
-	void *smem_ramdump_dev;
-	bool crash_shutdown;
-	bool ignore_errors;
-	u32 img_length;
-};
-
-static int pil_mba_make_proxy_votes(struct pil_desc *pil)
-{
-	int ret;
-	struct mba_data *drv = dev_get_drvdata(pil->dev);
-
-	ret = clk_prepare_enable(drv->xo);
-	if (ret) {
-		dev_err(pil->dev, "Failed to enable XO\n");
-		return ret;
-	}
-	return 0;
-}
-
-static void pil_mba_remove_proxy_votes(struct pil_desc *pil)
-{
-	struct mba_data *drv = dev_get_drvdata(pil->dev);
-	clk_disable_unprepare(drv->xo);
-}
-
-static int pil_mba_init_image(struct pil_desc *pil,
-			      const u8 *metadata, size_t size)
-{
-	struct mba_data *drv = dev_get_drvdata(pil->dev);
-	s32 status;
-	int ret;
-
-	/* Copy metadata to assigned shared buffer location */
-	memcpy(drv->metadata_base, metadata, size);
-
-	/* Initialize length counter to 0 */
-	writel_relaxed(0, drv->reg_base + RMB_PMI_CODE_LENGTH);
-	drv->img_length = 0;
-
-	/* Pass address of meta-data to the MBA and perform authentication */
-	writel_relaxed(drv->metadata_phys, drv->reg_base + RMB_PMI_META_DATA);
-	writel_relaxed(CMD_META_DATA_READY, drv->reg_base + RMB_MBA_COMMAND);
-	ret = readl_poll_timeout(drv->reg_base + RMB_MBA_STATUS, status,
-		status == STATUS_META_DATA_AUTH_SUCCESS || status < 0,
-		POLL_INTERVAL_US, modem_auth_timeout_ms * 1000);
-	if (ret) {
-		dev_err(pil->dev, "MBA authentication timed out\n");
-	} else if (status < 0) {
-		dev_err(pil->dev, "MBA returned error %d\n", status);
-		ret = -EINVAL;
-	}
-
-	return ret;
-}
-
-static int pil_mba_verify_blob(struct pil_desc *pil, u32 phy_addr,
-			       size_t size)
-{
-	struct mba_data *drv = dev_get_drvdata(pil->dev);
-	s32 status;
-
-	/* Begin image authentication */
-	if (drv->img_length == 0) {
-		writel_relaxed(phy_addr, drv->reg_base + RMB_PMI_CODE_START);
-		writel_relaxed(CMD_LOAD_READY, drv->reg_base + RMB_MBA_COMMAND);
-	}
-	/* Increment length counter */
-	drv->img_length += size;
-	writel_relaxed(drv->img_length, drv->reg_base + RMB_PMI_CODE_LENGTH);
-
-	status = readl_relaxed(drv->reg_base + RMB_MBA_STATUS);
-	if (status < 0) {
-		dev_err(pil->dev, "MBA returned error %d\n", status);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int pil_mba_auth(struct pil_desc *pil)
-{
-	struct mba_data *drv = dev_get_drvdata(pil->dev);
-	int ret;
-	s32 status;
-
-	/* Wait for all segments to be authenticated or an error to occur */
-	ret = readl_poll_timeout(drv->reg_base + RMB_MBA_STATUS, status,
-			status == STATUS_AUTH_COMPLETE || status < 0,
-			50, modem_auth_timeout_ms * 1000);
-	if (ret) {
-		dev_err(pil->dev, "MBA authentication timed out\n");
-	} else if (status < 0) {
-		dev_err(pil->dev, "MBA returned error %d\n", status);
-		ret = -EINVAL;
-	}
-
-	return ret;
-}
-
-static int pil_mba_shutdown(struct pil_desc *pil)
-{
-	return 0;
-}
-
-static struct pil_reset_ops pil_mba_ops = {
-	.init_image = pil_mba_init_image,
-	.proxy_vote = pil_mba_make_proxy_votes,
-	.proxy_unvote = pil_mba_remove_proxy_votes,
-	.verify_blob = pil_mba_verify_blob,
-	.auth_and_reset = pil_mba_auth,
-	.shutdown = pil_mba_shutdown,
-};
-
-#define subsys_to_drv(d) container_of(d, struct mba_data, subsys_desc)
-
-static void log_modem_sfr(void)
-{
-	u32 size;
-	char *smem_reason, reason[MAX_SSR_REASON_LEN];
-
-	smem_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size);
-	if (!smem_reason || !size) {
-		pr_err("modem subsystem failure reason: (unknown, smem_get_entry failed).\n");
-		return;
-	}
-	if (!smem_reason[0]) {
-		pr_err("modem subsystem failure reason: (unknown, empty string found).\n");
-		return;
-	}
-
-	strlcpy(reason, smem_reason, min(size, sizeof(reason)));
-	pr_err("modem subsystem failure reason: %s.\n", reason);
-
-	smem_reason[0] = '\0';
-	wmb();
-}
-
-static void restart_modem(struct mba_data *drv)
-{
-	log_modem_sfr();
-	drv->ignore_errors = true;
-	subsystem_restart_dev(drv->subsys);
-}
-
-static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
-{
-	struct mba_data *drv = data;
-
-	/* Ignore if we're the one that set SMSM_RESET */
-	if (drv->crash_shutdown)
-		return;
-
-	if (new_state & SMSM_RESET) {
-		pr_err("Probable fatal error on the modem.\n");
-		restart_modem(drv);
-	}
-}
-
-static int modem_shutdown(const struct subsys_desc *subsys)
-{
-	pil_force_shutdown("modem");
-	pil_force_shutdown("mba");
-	return 0;
-}
-
-static int modem_powerup(const struct subsys_desc *subsys)
-{
-	struct mba_data *drv = subsys_to_drv(subsys);
-	/*
-	 * At this time, the modem is shutdown. Therefore this function cannot
-	 * run concurrently with either the watchdog bite error handler or the
-	 * SMSM callback, making it safe to unset the flag below.
-	 */
-	drv->ignore_errors = 0;
-	pil_force_boot("mba");
-	pil_force_boot("modem");
-	return 0;
-}
-
-static void modem_crash_shutdown(const struct subsys_desc *subsys)
-{
-	struct mba_data *drv = subsys_to_drv(subsys);
-	drv->crash_shutdown = true;
-	smsm_reset_modem(SMSM_RESET);
-}
-
-static struct ramdump_segment modem_segments[] = {
-	{0x08400000, 0x0D100000 - 0x08400000},
-};
-
-static struct ramdump_segment smem_segments[] = {
-	{0x0FA00000, 0x0FC00000 - 0x0FA00000},
-};
-
-static int modem_ramdump(int enable, const struct subsys_desc *subsys)
-{
-	struct mba_data *drv = subsys_to_drv(subsys);
-	int ret;
-
-	if (!enable)
-		return 0;
-
-	pil_force_boot("mba");
-
-	ret = do_ramdump(drv->ramdump_dev, modem_segments,
-				ARRAY_SIZE(modem_segments));
-	if (ret < 0) {
-		pr_err("Unable to dump modem fw memory (rc = %d).\n", ret);
-		goto out;
-	}
-
-	ret = do_ramdump(drv->smem_ramdump_dev, smem_segments,
-		ARRAY_SIZE(smem_segments));
-	if (ret < 0) {
-		pr_err("Unable to dump smem memory (rc = %d).\n", ret);
-		goto out;
-	}
-
-out:
-	pil_force_shutdown("mba");
-	return ret;
-}
-
-static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
-{
-	struct mba_data *drv = dev_id;
-	if (drv->ignore_errors)
-		return IRQ_HANDLED;
-	pr_err("Watchdog bite received from modem software!\n");
-	restart_modem(drv);
-	return IRQ_HANDLED;
-}
-
-static int mss_start(const struct subsys_desc *desc)
-{
-	void *ret;
-	struct mba_data *drv = subsys_to_drv(desc);
-
-	ret = pil_get(drv->desc.name);
-	if (IS_ERR(ret))
-		return PTR_ERR(ret);
-	return 0;
-}
-
-static void mss_stop(const struct subsys_desc *desc)
-{
-	struct mba_data *drv = subsys_to_drv(desc);
-	pil_put(drv->pil);
-}
-
-static int __devinit pil_mba_driver_probe(struct platform_device *pdev)
-{
-	struct mba_data *drv;
-	struct resource *res;
-	struct pil_desc *desc;
-	int ret, irq;
-
-	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
-	if (!drv)
-		return -ENOMEM;
-	platform_set_drvdata(pdev, drv);
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
-		return irq;
-
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb_base");
-	if (!res)
-		return -EINVAL;
-	drv->reg_base = devm_ioremap(&pdev->dev, res->start,
-				     resource_size(res));
-	if (!drv->reg_base)
-		return -ENOMEM;
-
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-					    "metadata_base");
-	if (res) {
-		drv->metadata_base = devm_ioremap(&pdev->dev, res->start,
-						  resource_size(res));
-		if (!drv->metadata_base)
-			return -ENOMEM;
-		drv->metadata_phys = res->start;
-	}
-
-	desc = &drv->desc;
-	ret = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
-				      &desc->name);
-	if (ret)
-		return ret;
-
-	of_property_read_string(pdev->dev.of_node, "qcom,depends-on",
-				      &desc->depends_on);
-
-	drv->xo = devm_clk_get(&pdev->dev, "xo");
-	if (IS_ERR(drv->xo))
-		return PTR_ERR(drv->xo);
-
-	desc->dev = &pdev->dev;
-	desc->ops = &pil_mba_ops;
-	desc->owner = THIS_MODULE;
-	desc->proxy_timeout = PROXY_TIMEOUT_MS;
-
-	drv->pil = msm_pil_register(desc);
-	if (IS_ERR(drv->pil))
-		return PTR_ERR(drv->pil);
-
-	drv->subsys_desc.name = desc->name;
-	drv->subsys_desc.dev = &pdev->dev;
-	drv->subsys_desc.owner = THIS_MODULE;
-	drv->subsys_desc.shutdown = modem_shutdown;
-	drv->subsys_desc.powerup = modem_powerup;
-	drv->subsys_desc.ramdump = modem_ramdump;
-	drv->subsys_desc.crash_shutdown = modem_crash_shutdown;
-	drv->subsys_desc.start = mss_start;
-	drv->subsys_desc.stop = mss_stop;
-
-	drv->ramdump_dev = create_ramdump_device("modem");
-	if (!drv->ramdump_dev) {
-		pr_err("%s: Unable to create a modem ramdump device.\n",
-			__func__);
-		ret = -ENOMEM;
-		goto err_ramdump;
-	}
-
-	drv->smem_ramdump_dev = create_ramdump_device("smem-modem");
-	if (!drv->smem_ramdump_dev) {
-		pr_err("%s: Unable to create an smem ramdump device.\n",
-			__func__);
-		ret = -ENOMEM;
-		goto err_ramdump_smem;
-	}
-
-	drv->subsys = subsys_register(&drv->subsys_desc);
-	if (IS_ERR(drv->subsys)) {
-		goto err_subsys;
-		ret = PTR_ERR(drv->subsys);
-	}
-
-	ret = devm_request_irq(&pdev->dev, irq, modem_wdog_bite_irq,
-				IRQF_TRIGGER_RISING, "modem_wdog", drv);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Unable to request watchdog IRQ.\n");
-		goto err_irq;
-	}
-
-	ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
-		smsm_state_cb, drv);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Unable to register SMSM callback!\n");
-		goto err_irq;
-	}
-
-	return 0;
-
-err_irq:
-	subsys_unregister(drv->subsys);
-err_subsys:
-	destroy_ramdump_device(drv->smem_ramdump_dev);
-err_ramdump_smem:
-	destroy_ramdump_device(drv->ramdump_dev);
-err_ramdump:
-	msm_pil_unregister(drv->pil);
-	return ret;
-}
-
-static int __devexit pil_mba_driver_exit(struct platform_device *pdev)
-{
-	struct mba_data *drv = platform_get_drvdata(pdev);
-	smsm_state_cb_deregister(SMSM_MODEM_STATE, SMSM_RESET,
-			smsm_state_cb, drv);
-	subsys_unregister(drv->subsys);
-	destroy_ramdump_device(drv->smem_ramdump_dev);
-	destroy_ramdump_device(drv->ramdump_dev);
-	msm_pil_unregister(drv->pil);
-	return 0;
-}
-
-static struct of_device_id mba_match_table[] = {
-	{ .compatible = "qcom,pil-mba" },
-	{}
-};
-
-struct platform_driver pil_mba_driver = {
-	.probe = pil_mba_driver_probe,
-	.remove = __devexit_p(pil_mba_driver_exit),
-	.driver = {
-		.name = "pil-mba",
-		.of_match_table = mba_match_table,
-		.owner = THIS_MODULE,
-	},
-};
-
-static int __init pil_mba_init(void)
-{
-	return platform_driver_register(&pil_mba_driver);
-}
-module_init(pil_mba_init);
-
-static void __exit pil_mba_exit(void)
-{
-	platform_driver_unregister(&pil_mba_driver);
-}
-module_exit(pil_mba_exit);
-
-MODULE_DESCRIPTION("Support for modem boot using the Modem Boot Authenticator");
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-modem.c b/arch/arm/mach-msm/pil-modem.c
index ad27cd1..d3c832b 100644
--- a/arch/arm/mach-msm/pil-modem.c
+++ b/arch/arm/mach-msm/pil-modem.c
@@ -15,7 +15,6 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/ioport.h>
-#include <linux/elf.h>
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/clk.h>
@@ -23,10 +22,8 @@
 #include <linux/interrupt.h>
 #include <linux/reboot.h>
 
-#include <mach/msm_iomap.h>
 #include <mach/subsystem_restart.h>
 #include <mach/msm_smsm.h>
-#include <mach/peripheral-loader.h>
 
 #include "modem_notifier.h"
 #include "peripheral-loader.h"
@@ -34,37 +31,38 @@
 #include "ramdump.h"
 
 #define MARM_BOOT_CONTROL		0x0010
-#define MARM_RESET			(MSM_CLK_CTL_BASE + 0x2BD4)
-#define MAHB0_SFAB_PORT_RESET		(MSM_CLK_CTL_BASE + 0x2304)
-#define MARM_CLK_BRANCH_ENA_VOTE	(MSM_CLK_CTL_BASE + 0x3000)
-#define MARM_CLK_SRC0_NS		(MSM_CLK_CTL_BASE + 0x2BC0)
-#define MARM_CLK_SRC1_NS		(MSM_CLK_CTL_BASE + 0x2BC4)
-#define MARM_CLK_SRC_CTL		(MSM_CLK_CTL_BASE + 0x2BC8)
-#define MARM_CLK_CTL			(MSM_CLK_CTL_BASE + 0x2BCC)
-#define SFAB_MSS_S_HCLK_CTL		(MSM_CLK_CTL_BASE + 0x2C00)
-#define MSS_MODEM_CXO_CLK_CTL		(MSM_CLK_CTL_BASE + 0x2C44)
-#define MSS_SLP_CLK_CTL			(MSM_CLK_CTL_BASE + 0x2C60)
-#define MSS_MARM_SYS_REF_CLK_CTL	(MSM_CLK_CTL_BASE + 0x2C64)
-#define MAHB0_CLK_CTL			(MSM_CLK_CTL_BASE + 0x2300)
-#define MAHB1_CLK_CTL			(MSM_CLK_CTL_BASE + 0x2BE4)
-#define MAHB2_CLK_CTL			(MSM_CLK_CTL_BASE + 0x2C20)
-#define MAHB1_NS			(MSM_CLK_CTL_BASE + 0x2BE0)
-#define MARM_CLK_FS			(MSM_CLK_CTL_BASE + 0x2BD0)
-#define MAHB2_CLK_FS			(MSM_CLK_CTL_BASE + 0x2C24)
-#define PLL_ENA_MARM			(MSM_CLK_CTL_BASE + 0x3500)
-#define PLL8_STATUS			(MSM_CLK_CTL_BASE + 0x3158)
-#define CLK_HALT_MSS_SMPSS_MISC_STATE	(MSM_CLK_CTL_BASE + 0x2FDC)
-#define MSS_MODEM_RESET			(MSM_CLK_CTL_BASE + 0x2C48)
+#define MARM_RESET			0x2BD4
+#define MAHB0_SFAB_PORT_RESET		0x2304
+#define MARM_CLK_BRANCH_ENA_VOTE	0x3000
+#define MARM_CLK_SRC0_NS		0x2BC0
+#define MARM_CLK_SRC1_NS		0x2BC4
+#define MARM_CLK_SRC_CTL		0x2BC8
+#define MARM_CLK_CTL			0x2BCC
+#define SFAB_MSS_S_HCLK_CTL		0x2C00
+#define MSS_MODEM_CXO_CLK_CTL		0x2C44
+#define MSS_SLP_CLK_CTL			0x2C60
+#define MSS_MARM_SYS_REF_CLK_CTL	0x2C64
+#define MAHB0_CLK_CTL			0x2300
+#define MAHB1_CLK_CTL			0x2BE4
+#define MAHB2_CLK_CTL			0x2C20
+#define MAHB1_NS			0x2BE0
+#define MARM_CLK_FS			0x2BD0
+#define MAHB2_CLK_FS			0x2C24
+#define PLL_ENA_MARM			0x3500
+#define PLL8_STATUS			0x3158
+#define CLK_HALT_MSS_SMPSS_MISC_STATE	0x2FDC
+#define MSS_MODEM_RESET			0x2C48
 
 struct modem_data {
 	void __iomem *base;
 	void __iomem *wdog;
-	unsigned long start_addr;
+	void __iomem *cbase;
 	struct pil_device *pil;
 	struct clk *xo;
 	struct notifier_block notifier;
 	int ignore_smsm_ack;
 	int irq;
+	struct pil_desc pil_desc;
 	struct subsys_device *subsys;
 	struct subsys_desc subsys_desc;
 	struct delayed_work unlock_work;
@@ -91,90 +89,82 @@
 	clk_disable_unprepare(drv->xo);
 }
 
-static int modem_init_image(struct pil_desc *pil, const u8 *metadata,
-		size_t size)
-{
-	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
-	struct modem_data *drv = dev_get_drvdata(pil->dev);
-	drv->start_addr = ehdr->e_entry;
-	return 0;
-}
-
 static int modem_reset(struct pil_desc *pil)
 {
 	u32 reg;
 	const struct modem_data *drv = dev_get_drvdata(pil->dev);
+	unsigned long start_addr = pil_get_entry_addr(pil);
 
 	/* Put modem AHB0,1,2 clocks into reset */
-	writel_relaxed(BIT(0) | BIT(1), MAHB0_SFAB_PORT_RESET);
-	writel_relaxed(BIT(7), MAHB1_CLK_CTL);
-	writel_relaxed(BIT(7), MAHB2_CLK_CTL);
+	writel_relaxed(BIT(0) | BIT(1), drv->cbase + MAHB0_SFAB_PORT_RESET);
+	writel_relaxed(BIT(7), drv->cbase + MAHB1_CLK_CTL);
+	writel_relaxed(BIT(7), drv->cbase + MAHB2_CLK_CTL);
 
 	/* Vote for pll8 on behalf of the modem */
-	reg = readl_relaxed(PLL_ENA_MARM);
+	reg = readl_relaxed(drv->cbase + PLL_ENA_MARM);
 	reg |= BIT(8);
-	writel_relaxed(reg, PLL_ENA_MARM);
+	writel_relaxed(reg, drv->cbase + PLL_ENA_MARM);
 
 	/* Wait for PLL8 to enable */
-	while (!(readl_relaxed(PLL8_STATUS) & BIT(16)))
+	while (!(readl_relaxed(drv->cbase + PLL8_STATUS) & BIT(16)))
 		cpu_relax();
 
 	/* Set MAHB1 divider to Div-5 to run MAHB1,2 and sfab at 79.8 Mhz*/
-	writel_relaxed(0x4, MAHB1_NS);
+	writel_relaxed(0x4, drv->cbase + MAHB1_NS);
 
 	/* Vote for modem AHB1 and 2 clocks to be on on behalf of the modem */
-	reg = readl_relaxed(MARM_CLK_BRANCH_ENA_VOTE);
+	reg = readl_relaxed(drv->cbase + MARM_CLK_BRANCH_ENA_VOTE);
 	reg |= BIT(0) | BIT(1);
-	writel_relaxed(reg, MARM_CLK_BRANCH_ENA_VOTE);
+	writel_relaxed(reg, drv->cbase + MARM_CLK_BRANCH_ENA_VOTE);
 
 	/* Source marm_clk off of PLL8 */
-	reg = readl_relaxed(MARM_CLK_SRC_CTL);
+	reg = readl_relaxed(drv->cbase + MARM_CLK_SRC_CTL);
 	if ((reg & 0x1) == 0) {
-		writel_relaxed(0x3, MARM_CLK_SRC1_NS);
+		writel_relaxed(0x3, drv->cbase + MARM_CLK_SRC1_NS);
 		reg |= 0x1;
 	} else {
-		writel_relaxed(0x3, MARM_CLK_SRC0_NS);
+		writel_relaxed(0x3, drv->cbase + MARM_CLK_SRC0_NS);
 		reg &= ~0x1;
 	}
-	writel_relaxed(reg | 0x2, MARM_CLK_SRC_CTL);
+	writel_relaxed(reg | 0x2, drv->cbase + MARM_CLK_SRC_CTL);
 
 	/*
 	 * Force core on and periph on signals to remain active during halt
 	 * for marm_clk and mahb2_clk
 	 */
-	writel_relaxed(0x6F, MARM_CLK_FS);
-	writel_relaxed(0x6F, MAHB2_CLK_FS);
+	writel_relaxed(0x6F, drv->cbase + MARM_CLK_FS);
+	writel_relaxed(0x6F, drv->cbase + MAHB2_CLK_FS);
 
 	/*
 	 * Enable all of the marm_clk branches, cxo sourced marm branches,
 	 * and sleep clock branches
 	 */
-	writel_relaxed(0x10, MARM_CLK_CTL);
-	writel_relaxed(0x10, MAHB0_CLK_CTL);
-	writel_relaxed(0x10, SFAB_MSS_S_HCLK_CTL);
-	writel_relaxed(0x10, MSS_MODEM_CXO_CLK_CTL);
-	writel_relaxed(0x10, MSS_SLP_CLK_CTL);
-	writel_relaxed(0x10, MSS_MARM_SYS_REF_CLK_CTL);
+	writel_relaxed(0x10, drv->cbase + MARM_CLK_CTL);
+	writel_relaxed(0x10, drv->cbase + MAHB0_CLK_CTL);
+	writel_relaxed(0x10, drv->cbase + SFAB_MSS_S_HCLK_CTL);
+	writel_relaxed(0x10, drv->cbase + MSS_MODEM_CXO_CLK_CTL);
+	writel_relaxed(0x10, drv->cbase + MSS_SLP_CLK_CTL);
+	writel_relaxed(0x10, drv->cbase + MSS_MARM_SYS_REF_CLK_CTL);
 
 	/* Wait for above clocks to be turned on */
-	while (readl_relaxed(CLK_HALT_MSS_SMPSS_MISC_STATE) & (BIT(7) | BIT(8) |
-				BIT(9) | BIT(10) | BIT(4) | BIT(6)))
+	while (readl_relaxed(drv->cbase + CLK_HALT_MSS_SMPSS_MISC_STATE) &
+			(BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(4) | BIT(6)))
 		cpu_relax();
 
 	/* Take MAHB0,1,2 clocks out of reset */
-	writel_relaxed(0x0, MAHB2_CLK_CTL);
-	writel_relaxed(0x0, MAHB1_CLK_CTL);
-	writel_relaxed(0x0, MAHB0_SFAB_PORT_RESET);
+	writel_relaxed(0x0, drv->cbase + MAHB2_CLK_CTL);
+	writel_relaxed(0x0, drv->cbase + MAHB1_CLK_CTL);
+	writel_relaxed(0x0, drv->cbase + MAHB0_SFAB_PORT_RESET);
 	mb();
 
 	/* Setup exception vector table base address */
-	writel_relaxed(drv->start_addr | 0x1, drv->base + MARM_BOOT_CONTROL);
+	writel_relaxed(start_addr | 0x1, drv->base + MARM_BOOT_CONTROL);
 
 	/* Wait for vector table to be setup */
 	mb();
 
 	/* Bring modem out of reset */
-	writel_relaxed(0x0, MARM_RESET);
+	writel_relaxed(0x0, drv->cbase + MARM_RESET);
 
 	return 0;
 }
@@ -182,44 +172,44 @@
 static int modem_pil_shutdown(struct pil_desc *pil)
 {
 	u32 reg;
+	const struct modem_data *drv = dev_get_drvdata(pil->dev);
 
 	/* Put modem into reset */
-	writel_relaxed(0x1, MARM_RESET);
+	writel_relaxed(0x1, drv->cbase + MARM_RESET);
 	mb();
 
 	/* Put modem AHB0,1,2 clocks into reset */
-	writel_relaxed(BIT(0) | BIT(1), MAHB0_SFAB_PORT_RESET);
-	writel_relaxed(BIT(7), MAHB1_CLK_CTL);
-	writel_relaxed(BIT(7), MAHB2_CLK_CTL);
+	writel_relaxed(BIT(0) | BIT(1), drv->cbase + MAHB0_SFAB_PORT_RESET);
+	writel_relaxed(BIT(7), drv->cbase + MAHB1_CLK_CTL);
+	writel_relaxed(BIT(7), drv->cbase + MAHB2_CLK_CTL);
 	mb();
 
 	/*
 	 * Disable all of the marm_clk branches, cxo sourced marm branches,
 	 * and sleep clock branches
 	 */
-	writel_relaxed(0x0, MARM_CLK_CTL);
-	writel_relaxed(0x0, MAHB0_CLK_CTL);
-	writel_relaxed(0x0, SFAB_MSS_S_HCLK_CTL);
-	writel_relaxed(0x0, MSS_MODEM_CXO_CLK_CTL);
-	writel_relaxed(0x0, MSS_SLP_CLK_CTL);
-	writel_relaxed(0x0, MSS_MARM_SYS_REF_CLK_CTL);
+	writel_relaxed(0x0, drv->cbase + MARM_CLK_CTL);
+	writel_relaxed(0x0, drv->cbase + MAHB0_CLK_CTL);
+	writel_relaxed(0x0, drv->cbase + SFAB_MSS_S_HCLK_CTL);
+	writel_relaxed(0x0, drv->cbase + MSS_MODEM_CXO_CLK_CTL);
+	writel_relaxed(0x0, drv->cbase + MSS_SLP_CLK_CTL);
+	writel_relaxed(0x0, drv->cbase + MSS_MARM_SYS_REF_CLK_CTL);
 
 	/* Disable marm_clk */
-	reg = readl_relaxed(MARM_CLK_SRC_CTL);
+	reg = readl_relaxed(drv->cbase + MARM_CLK_SRC_CTL);
 	reg &= ~0x2;
-	writel_relaxed(reg, MARM_CLK_SRC_CTL);
+	writel_relaxed(reg, drv->cbase + MARM_CLK_SRC_CTL);
 
 	/* Clear modem's votes for ahb clocks */
-	writel_relaxed(0x0, MARM_CLK_BRANCH_ENA_VOTE);
+	writel_relaxed(0x0, drv->cbase + MARM_CLK_BRANCH_ENA_VOTE);
 
 	/* Clear modem's votes for PLLs */
-	writel_relaxed(0x0, PLL_ENA_MARM);
+	writel_relaxed(0x0, drv->cbase + PLL_ENA_MARM);
 
 	return 0;
 }
 
 static struct pil_reset_ops pil_modem_ops = {
-	.init_image = modem_init_image,
 	.auth_and_reset = modem_reset,
 	.shutdown = modem_pil_shutdown,
 	.proxy_vote = make_modem_proxy_votes,
@@ -284,7 +274,7 @@
 
 	drv = container_of(dwork, struct modem_data, unlock_work);
 	/* The unlock didn't work, clear the reset */
-	writel_relaxed(0x0, MSS_MODEM_RESET);
+	writel_relaxed(0x0, drv->cbase + MSS_MODEM_RESET);
 	mb();
 
 	subsystem_restart_dev(drv->subsys);
@@ -316,7 +306,7 @@
 
 		pr_err("Modem AHB locked up. Trying to free up modem!\n");
 
-		writel_relaxed(0x3, MSS_MODEM_RESET);
+		writel_relaxed(0x3, drv->cbase + MSS_MODEM_RESET);
 		/*
 		 * If we are still alive (allowing for the 5 second
 		 * delayed-panic-reboot), the modem is either still wedged or
@@ -344,14 +334,10 @@
 
 static int modem_start(const struct subsys_desc *subsys)
 {
-	void *ret;
 	struct modem_data *drv;
 
 	drv = container_of(subsys, struct modem_data, subsys_desc);
-	ret = pil_get("modem");
-	if (IS_ERR(ret))
-		return PTR_ERR(ret);
-	return 0;
+	return pil_boot(&drv->pil_desc);
 }
 
 static void modem_stop(const struct subsys_desc *subsys)
@@ -359,7 +345,7 @@
 	struct modem_data *drv;
 
 	drv = container_of(subsys, struct modem_data, subsys_desc);
-	pil_put(drv->pil);
+	pil_shutdown(&drv->pil_desc);
 }
 
 static int modem_shutdown(const struct subsys_desc *subsys)
@@ -389,7 +375,7 @@
 	/* Wait here to allow the modem to clean up caches, etc. */
 	msleep(20);
 
-	pil_force_shutdown("modem");
+	pil_shutdown(&drv->pil_desc);
 	disable_irq_nosync(drv->irq);
 
 	return 0;
@@ -401,7 +387,7 @@
 	int ret;
 
 	drv = container_of(subsys, struct modem_data, subsys_desc);
-	ret = pil_force_boot("modem");
+	ret = pil_boot(&drv->pil_desc);
 	enable_irq(drv->irq);
 
 	return ret;
@@ -431,10 +417,6 @@
 	struct pil_desc *desc;
 	int ret;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		return -EINVAL;
-
 	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
 	if (!drv)
 		return -ENOMEM;
@@ -444,28 +426,30 @@
 	if (drv->irq < 0)
 		return drv->irq;
 
-	drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
-	if (!drv->base)
-		return -ENOMEM;
-
 	drv->xo = devm_clk_get(&pdev->dev, "xo");
 	if (IS_ERR(drv->xo))
 		return PTR_ERR(drv->xo);
 
-	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
-	if (!desc)
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	drv->base = devm_request_and_ioremap(&pdev->dev, res);
+	if (!drv->base)
 		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	if (!res)
-		return -EINVAL;
-
-	drv->wdog = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	drv->wdog = devm_request_and_ioremap(&pdev->dev, res);
 	if (!drv->wdog)
 		return -ENOMEM;
 
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	if (!res)
+		return -EINVAL;
+
+	drv->cbase = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!drv->cbase)
+		return -ENOMEM;
+
+	desc = &drv->pil_desc;
 	desc->name = "modem";
-	desc->depends_on = "q6";
 	desc->dev = &pdev->dev;
 	desc->owner = THIS_MODULE;
 	desc->proxy_timeout = 10000;
@@ -477,9 +461,9 @@
 		desc->ops = &pil_modem_ops;
 		dev_info(&pdev->dev, "using non-secure boot\n");
 	}
-	drv->pil = msm_pil_register(desc);
-	if (IS_ERR(drv->pil))
-		return PTR_ERR(drv->pil);
+	ret = pil_desc_init(desc);
+	if (ret)
+		return ret;
 
 	drv->notifier.notifier_call = modem_notif_handler,
 	ret = modem_register_notifier(&drv->notifier);
@@ -487,7 +471,7 @@
 		goto err_notify;
 
 	drv->subsys_desc.name = "modem";
-	drv->subsys_desc.depends_on = "q6";
+	drv->subsys_desc.depends_on = "adsp";
 	drv->subsys_desc.dev = &pdev->dev;
 	drv->subsys_desc.owner = THIS_MODULE;
 	drv->subsys_desc.start = modem_start;
@@ -506,7 +490,7 @@
 		goto err_subsys;
 	}
 
-	drv->ramdump_dev = create_ramdump_device("modem");
+	drv->ramdump_dev = create_ramdump_device("modem", &pdev->dev);
 	if (!drv->ramdump_dev) {
 		ret = -ENOMEM;
 		goto err_ramdump;
@@ -525,7 +509,7 @@
 err_subsys:
 	modem_unregister_notifier(&drv->notifier);
 err_notify:
-	msm_pil_unregister(drv->pil);
+	pil_desc_release(desc);
 	return ret;
 }
 
@@ -536,7 +520,7 @@
 	destroy_ramdump_device(drv->ramdump_dev);
 	subsys_unregister(drv->subsys);
 	modem_unregister_notifier(&drv->notifier);
-	msm_pil_unregister(drv->pil);
+	pil_desc_release(&drv->pil_desc);
 
 	return 0;
 }
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index 04b3a21..49fe182 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -13,7 +13,6 @@
 #include <linux/kernel.h>
 #include <linux/err.h>
 #include <linux/io.h>
-#include <linux/elf.h>
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -27,9 +26,7 @@
 #include <linux/workqueue.h>
 #include <linux/wcnss_wlan.h>
 
-#include <mach/peripheral-loader.h>
 #include <mach/subsystem_restart.h>
-#include <mach/peripheral-loader.h>
 #include <mach/msm_smsm.h>
 
 #include "peripheral-loader.h"
@@ -74,7 +71,6 @@
 	void __iomem *base;
 	void __iomem *reset_base;
 	void __iomem *axi_halt_base;
-	unsigned long start_addr;
 	struct pil_device *pil;
 	struct pil_desc desc;
 	struct subsys_device *subsys;
@@ -116,22 +112,13 @@
 	clk_disable_unprepare(drv->cxo);
 }
 
-static int pil_pronto_init_image(struct pil_desc *pil, const u8 *metadata,
-		size_t size)
-{
-	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
-	struct pronto_data *drv = dev_get_drvdata(pil->dev);
-	drv->start_addr = ehdr->e_entry;
-	return 0;
-}
-
 static int pil_pronto_reset(struct pil_desc *pil)
 {
 	u32 reg;
 	int rc;
 	struct pronto_data *drv = dev_get_drvdata(pil->dev);
 	void __iomem *base = drv->base;
-	unsigned long start_addr = drv->start_addr;
+	unsigned long start_addr = pil_get_entry_addr(pil);
 
 	/* Deassert reset to subsystem and wait for propagation */
 	reg = readl_relaxed(drv->reset_base);
@@ -234,7 +221,6 @@
 }
 
 static struct pil_reset_ops pil_pronto_ops = {
-	.init_image = pil_pronto_init_image,
 	.auth_and_reset = pil_pronto_reset,
 	.shutdown = pil_pronto_shutdown,
 	.proxy_vote = pil_pronto_make_proxy_vote,
@@ -245,19 +231,14 @@
 
 static int pronto_start(const struct subsys_desc *desc)
 {
-	void *ret;
 	struct pronto_data *drv = subsys_to_drv(desc);
-
-	ret = pil_get(drv->desc.name);
-	if (IS_ERR(ret))
-		return PTR_ERR(ret);
-	return 0;
+	return pil_boot(&drv->desc);
 }
 
 static void pronto_stop(const struct subsys_desc *desc)
 {
 	struct pronto_data *drv = subsys_to_drv(desc);
-	pil_put(drv->pil);
+	pil_shutdown(&drv->desc);
 }
 
 static void log_wcnss_sfr(void)
@@ -338,7 +319,7 @@
 {
 	struct pronto_data *drv = subsys_to_drv(subsys);
 
-	pil_force_shutdown("wcnss");
+	pil_shutdown(&drv->desc);
 	flush_delayed_work(&drv->cancel_vote_work);
 	wcnss_flush_delayed_boot_votes();
 	disable_irq_nosync(drv->irq);
@@ -358,7 +339,9 @@
 					WCNSS_WLAN_SWITCH_ON);
 	if (!ret) {
 		msleep(1000);
-		pil_force_boot("wcnss");
+		ret = pil_boot(&drv->desc);
+		if (ret)
+			return ret;
 	}
 	drv->restart_inprogress = false;
 	enable_irq(drv->irq);
@@ -389,10 +372,6 @@
 	int ret;
 	uint32_t regval;
 
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pmu_base");
-	if (!res)
-		return -EINVAL;
-
 	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
 	if (!drv)
 		return -ENOMEM;
@@ -402,23 +381,20 @@
 	if (drv->irq < 0)
 		return drv->irq;
 
-	drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pmu_base");
+	drv->base = devm_request_and_ioremap(&pdev->dev, res);
 	if (!drv->base)
 		return -ENOMEM;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clk_base");
-	if (!res)
-		return -EINVAL;
-
-	drv->reset_base = devm_ioremap(&pdev->dev, res->start,
-					resource_size(res));
+	drv->reset_base = devm_request_and_ioremap(&pdev->dev, res);
+	if (!drv->reset_base)
+		return -ENOMEM;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "halt_base");
-	if (!res)
-		return -EINVAL;
-
-	drv->axi_halt_base = devm_ioremap(&pdev->dev, res->start,
-					  resource_size(res));
+	drv->axi_halt_base = devm_request_and_ioremap(&pdev->dev, res);
+	if (!drv->axi_halt_base)
+		return -ENOMEM;
 
 	desc = &drv->desc;
 	ret = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
@@ -456,9 +432,9 @@
 	if (IS_ERR(drv->cxo))
 		return PTR_ERR(drv->cxo);
 
-	drv->pil = msm_pil_register(desc);
-	if (IS_ERR(drv->pil))
-		return PTR_ERR(drv->pil);
+	ret = pil_desc_init(desc);
+	if (ret)
+		return ret;
 
 	ret = smsm_state_cb_register(SMSM_WCNSS_STATE, SMSM_RESET,
 					smsm_state_cb_hdlr, drv);
@@ -502,7 +478,7 @@
 	smsm_state_cb_deregister(SMSM_WCNSS_STATE, SMSM_RESET,
 					smsm_state_cb_hdlr, drv);
 err_smsm:
-	msm_pil_unregister(drv->pil);
+	pil_desc_release(desc);
 	return ret;
 }
 
@@ -512,7 +488,7 @@
 	subsys_unregister(drv->subsys);
 	smsm_state_cb_deregister(SMSM_WCNSS_STATE, SMSM_RESET,
 					smsm_state_cb_hdlr, drv);
-	msm_pil_unregister(drv->pil);
+	pil_desc_release(&drv->desc);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/pil-q6v3.c b/arch/arm/mach-msm/pil-q6v3.c
index 9de9c60..d7e712c 100644
--- a/arch/arm/mach-msm/pil-q6v3.c
+++ b/arch/arm/mach-msm/pil-q6v3.c
@@ -16,16 +16,13 @@
 #include <linux/io.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
-#include <linux/elf.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/workqueue.h>
 #include <linux/interrupt.h>
 
-#include <mach/msm_iomap.h>
 #include <mach/subsystem_restart.h>
 #include <mach/scm.h>
-#include <mach/peripheral-loader.h>
 
 #include "ramdump.h"
 #include "peripheral-loader.h"
@@ -35,7 +32,7 @@
 #define QDSP6SS_STRAP_TCM	0x001C
 #define QDSP6SS_STRAP_AHB	0x0020
 
-#define LCC_Q6_FUNC		(MSM_LPASS_CLK_CTL_BASE + 0x001C)
+#define LCC_Q6_FUNC		0x001C
 #define LV_EN			BIT(27)
 #define STOP_CORE		BIT(26)
 #define CLAMP_IO		BIT(25)
@@ -71,9 +68,9 @@
 /**
  * struct q6v3_data - LPASS driver data
  * @base: register base
+ * @cbase: clock base
  * @wk_base: wakeup register base
  * @wd_base: watchdog register base
- * @start_addr: address that processor starts running at
  * @irq: watchdog irq
  * @pil: peripheral handle
  * @subsys: subsystem restart handle
@@ -84,11 +81,11 @@
  */
 struct q6v3_data {
 	void __iomem *base;
+	void __iomem *cbase;
 	void __iomem *wk_base;
 	void __iomem *wd_base;
-	unsigned long start_addr;
 	int irq;
-	struct pil_device *pil;
+	struct pil_desc pil_desc;
 	struct subsys_device *subsys;
 	struct subsys_desc subsys_desc;
 	struct work_struct fatal_wrk;
@@ -96,15 +93,6 @@
 	struct ramdump_device *ramdump_dev;
 };
 
-static int pil_q6v3_init_image(struct pil_desc *pil, const u8 *metadata,
-		size_t size)
-{
-	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
-	struct q6v3_data *drv = dev_get_drvdata(pil->dev);
-	drv->start_addr = ehdr->e_entry;
-	return 0;
-}
-
 static void pil_q6v3_remove_proxy_votes(struct pil_desc *pil)
 {
 	struct q6v3_data *drv = dev_get_drvdata(pil->dev);
@@ -128,13 +116,14 @@
 {
 	u32 reg;
 	struct q6v3_data *drv = dev_get_drvdata(pil->dev);
+	unsigned long start_addr = pil_get_entry_addr(pil);
 
 	/* Put Q6 into reset */
-	reg = readl_relaxed(LCC_Q6_FUNC);
+	reg = readl_relaxed(drv->cbase + LCC_Q6_FUNC);
 	reg |= Q6SS_SS_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES | STOP_CORE |
 		CORE_ARES;
 	reg &= ~CORE_GFM4_CLK_EN;
-	writel_relaxed(reg, LCC_Q6_FUNC);
+	writel_relaxed(reg, drv->cbase + LCC_Q6_FUNC);
 
 	/* Wait 8 AHB cycles for Q6 to be fully reset (AHB = 1.5Mhz) */
 	usleep_range(20, 30);
@@ -142,17 +131,17 @@
 	/* Turn on Q6 memory */
 	reg |= CORE_GFM4_CLK_EN | CORE_L1_MEM_CORE_EN | CORE_TCM_MEM_CORE_EN |
 		CORE_TCM_MEM_PERPH_EN;
-	writel_relaxed(reg, LCC_Q6_FUNC);
+	writel_relaxed(reg, drv->cbase + LCC_Q6_FUNC);
 
 	/* Turn on Q6 core clocks and take core out of reset */
 	reg &= ~(CLAMP_IO | Q6SS_SS_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES |
 			CORE_ARES);
-	writel_relaxed(reg, LCC_Q6_FUNC);
+	writel_relaxed(reg, drv->cbase + LCC_Q6_FUNC);
 
 	/* Wait for clocks to be enabled */
 	mb();
 	/* Program boot address */
-	writel_relaxed((drv->start_addr >> 12) & 0xFFFFF,
+	writel_relaxed((start_addr >> 12) & 0xFFFFF,
 			drv->base + QDSP6SS_RST_EVB);
 
 	writel_relaxed(Q6_STRAP_TCM_CONFIG | Q6_STRAP_TCM_BASE,
@@ -165,7 +154,7 @@
 
 	/* Start Q6 instruction execution */
 	reg &= ~STOP_CORE;
-	writel_relaxed(reg, LCC_Q6_FUNC);
+	writel_relaxed(reg, drv->cbase + LCC_Q6_FUNC);
 
 	return 0;
 }
@@ -173,13 +162,14 @@
 static int pil_q6v3_shutdown(struct pil_desc *pil)
 {
 	u32 reg;
+	struct q6v3_data *drv = dev_get_drvdata(pil->dev);
 
 	/* Put Q6 into reset */
-	reg = readl_relaxed(LCC_Q6_FUNC);
+	reg = readl_relaxed(drv->cbase + LCC_Q6_FUNC);
 	reg |= Q6SS_SS_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES | STOP_CORE |
 		CORE_ARES;
 	reg &= ~CORE_GFM4_CLK_EN;
-	writel_relaxed(reg, LCC_Q6_FUNC);
+	writel_relaxed(reg, drv->cbase + LCC_Q6_FUNC);
 
 	/* Wait 8 AHB cycles for Q6 to be fully reset (AHB = 1.5Mhz) */
 	usleep_range(20, 30);
@@ -187,16 +177,15 @@
 	/* Turn off Q6 memory */
 	reg &= ~(CORE_L1_MEM_CORE_EN | CORE_TCM_MEM_CORE_EN |
 		CORE_TCM_MEM_PERPH_EN);
-	writel_relaxed(reg, LCC_Q6_FUNC);
+	writel_relaxed(reg, drv->cbase + LCC_Q6_FUNC);
 
 	reg |= CLAMP_IO;
-	writel_relaxed(reg, LCC_Q6_FUNC);
+	writel_relaxed(reg, drv->cbase + LCC_Q6_FUNC);
 
 	return 0;
 }
 
 static struct pil_reset_ops pil_q6v3_ops = {
-	.init_image = pil_q6v3_init_image,
 	.auth_and_reset = pil_q6v3_reset,
 	.shutdown = pil_q6v3_shutdown,
 	.proxy_vote = pil_q6v3_make_proxy_votes,
@@ -250,14 +239,10 @@
 
 static int lpass_q6_start(const struct subsys_desc *subsys)
 {
-	void *ret;
 	struct q6v3_data *drv;
 
 	drv = container_of(subsys, struct q6v3_data, subsys_desc);
-	ret = pil_get("q6");
-	if (IS_ERR(ret))
-		return PTR_ERR(ret);
-	return 0;
+	return pil_boot(&drv->pil_desc);
 }
 
 static void lpass_q6_stop(const struct subsys_desc *subsys)
@@ -265,7 +250,7 @@
 	struct q6v3_data *drv;
 
 	drv = container_of(subsys, struct q6v3_data, subsys_desc);
-	pil_put(drv->pil);
+	pil_shutdown(&drv->pil_desc);
 }
 
 static int lpass_q6_shutdown(const struct subsys_desc *subsys)
@@ -277,7 +262,7 @@
 	writel_relaxed(0x0, drv->wd_base + 0x24);
 	mb();
 
-	pil_force_shutdown("q6");
+	pil_shutdown(&drv->pil_desc);
 	disable_irq_nosync(drv->irq);
 
 	return 0;
@@ -289,7 +274,7 @@
 	int ret;
 
 	drv = container_of(subsys, struct q6v3_data, subsys_desc);
-	ret = pil_force_boot("q6");
+	ret = pil_boot(&drv->pil_desc);
 	enable_irq(drv->irq);
 	return ret;
 }
@@ -338,33 +323,31 @@
 	struct pil_desc *desc;
 	int ret;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		return -EINVAL;
-
 	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
 	if (!drv)
 		return -ENOMEM;
 	platform_set_drvdata(pdev, drv);
 
-	drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	drv->base = devm_request_and_ioremap(&pdev->dev, res);
 	if (!drv->base)
 		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	if (!res)
-		return -EINVAL;
-
-	drv->wk_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	drv->wk_base = devm_request_and_ioremap(&pdev->dev, res);
 	if (!drv->wk_base)
 		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	drv->wd_base = devm_request_and_ioremap(&pdev->dev, res);
+	if (!drv->wd_base)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
 	if (!res)
 		return -EINVAL;
-
-	drv->wd_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
-	if (!drv->wd_base)
+	drv->cbase = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!drv->cbase)
 		return -ENOMEM;
 
 	drv->irq = platform_get_irq(pdev, 0);
@@ -375,10 +358,7 @@
 	if (IS_ERR(drv->pll))
 		return PTR_ERR(drv->pll);
 
-	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
-	if (!drv)
-		return -ENOMEM;
-
+	desc = &drv->pil_desc;
 	desc->name = "q6";
 	desc->dev = &pdev->dev;
 	desc->owner = THIS_MODULE;
@@ -392,11 +372,11 @@
 		dev_info(&pdev->dev, "using non-secure boot\n");
 	}
 
-	drv->pil = msm_pil_register(desc);
-	if (IS_ERR(drv->pil))
-		return PTR_ERR(drv->pil);
+	ret = pil_desc_init(desc);
+	if (ret)
+		return ret;
 
-	drv->subsys_desc.name = "lpass";
+	drv->subsys_desc.name = "adsp";
 	drv->subsys_desc.dev = &pdev->dev;
 	drv->subsys_desc.owner = THIS_MODULE;
 	drv->subsys_desc.start = lpass_q6_start;
@@ -408,7 +388,7 @@
 
 	INIT_WORK(&drv->fatal_wrk, q6_fatal_fn);
 
-	drv->ramdump_dev = create_ramdump_device("lpass");
+	drv->ramdump_dev = create_ramdump_device("lpass", &pdev->dev);
 	if (!drv->ramdump_dev) {
 		ret = -ENOMEM;
 		goto err_ramdump;
@@ -433,7 +413,7 @@
 err_subsys:
 	destroy_ramdump_device(drv->ramdump_dev);
 err_ramdump:
-	msm_pil_unregister(drv->pil);
+	pil_desc_release(desc);
 	return ret;
 }
 
@@ -442,7 +422,7 @@
 	struct q6v3_data *drv = platform_get_drvdata(pdev);
 	subsys_unregister(drv->subsys);
 	destroy_ramdump_device(drv->ramdump_dev);
-	msm_pil_unregister(drv->pil);
+	pil_desc_release(&drv->pil_desc);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/pil-q6v4-lpass.c b/arch/arm/mach-msm/pil-q6v4-lpass.c
index 8164d64..1e6c1f6 100644
--- a/arch/arm/mach-msm/pil-q6v4-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v4-lpass.c
@@ -22,7 +22,6 @@
 #include <linux/delay.h>
 
 #include <mach/scm.h>
-#include <mach/peripheral-loader.h>
 #include <mach/subsystem_restart.h>
 #include <mach/subsystem_notif.h>
 
@@ -43,7 +42,6 @@
 	void *ramdump_dev;
 	struct work_struct work;
 	int loadable;
-	void *pil;
 };
 
 static int pil_q6v4_lpass_boot(struct pil_desc *pil)
@@ -71,7 +69,6 @@
 }
 
 static struct pil_reset_ops pil_q6v4_lpass_ops = {
-	.init_image = pil_q6v4_init_image,
 	.auth_and_reset = pil_q6v4_lpass_boot,
 	.shutdown = pil_q6v4_lpass_shutdown,
 	.proxy_vote = pil_q6v4_make_proxy_votes,
@@ -197,19 +194,17 @@
 {
 	struct lpass_q6v4 *drv = subsys_to_lpass(desc);
 
-	if (drv->loadable) {
-		drv->pil = pil_get("q6");
-		if (IS_ERR(drv->pil))
-			return PTR_ERR(drv->pil);
-	}
+	if (drv->loadable)
+		return pil_boot(&drv->q6.desc);
 	return 0;
 }
 
 static void lpass_stop(const struct subsys_desc *desc)
 {
 	struct lpass_q6v4 *drv = subsys_to_lpass(desc);
+
 	if (drv->loadable)
-		pil_put(drv->pil);
+		pil_shutdown(&drv->q6.desc);
 }
 
 static int lpass_shutdown(const struct subsys_desc *subsys)
@@ -218,7 +213,7 @@
 
 	send_q6_nmi();
 	if (drv->loadable)
-		pil_force_shutdown("q6");
+		pil_shutdown(&drv->q6.desc);
 	disable_irq_nosync(drv->q6.wdog_irq);
 
 	return 0;
@@ -230,7 +225,7 @@
 	int ret = 0;
 
 	if (drv->loadable)
-		ret = pil_force_boot("q6");
+		ret = pil_boot(&drv->q6.desc);
 	enable_irq(drv->q6.wdog_irq);
 
 	return ret;
@@ -291,10 +286,7 @@
 	drv->loadable = !!pdata; /* No pdata = don't use PIL */
 	if (drv->loadable) {
 		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-		if (!res)
-			return -EINVAL;
-		q6->base = devm_ioremap(&pdev->dev, res->start,
-				resource_size(res));
+		q6->base = devm_request_and_ioremap(&pdev->dev, res);
 		if (!q6->base)
 			return -ENOMEM;
 
@@ -320,12 +312,12 @@
 			dev_info(&pdev->dev, "using non-secure boot\n");
 		}
 
-		q6->pil = msm_pil_register(desc);
-		if (IS_ERR(q6->pil))
-			return PTR_ERR(q6->pil);
+		ret = pil_desc_init(desc);
+		if (ret)
+			return ret;
 	}
 
-	drv->subsys_desc.name = "lpass";
+	drv->subsys_desc.name = "adsp";
 	drv->subsys_desc.dev = &pdev->dev;
 	drv->subsys_desc.owner = THIS_MODULE;
 	drv->subsys_desc.start = lpass_start;
@@ -337,7 +329,7 @@
 
 	INIT_WORK(&drv->work, lpass_fatal_fn);
 
-	drv->ramdump_dev = create_ramdump_device("lpass");
+	drv->ramdump_dev = create_ramdump_device("lpass", &pdev->dev);
 	if (!drv->ramdump_dev) {
 		ret = -ENOMEM;
 		goto err_ramdump;
@@ -348,6 +340,8 @@
 		ret = PTR_ERR(drv->subsys);
 		goto err_subsys;
 	}
+	if (!drv->loadable)
+		subsys_default_online(drv->subsys);
 
 	ret = devm_request_irq(&pdev->dev, q6->wdog_irq, lpass_wdog_bite_irq,
 			IRQF_TRIGGER_RISING, dev_name(&pdev->dev), drv);
@@ -383,7 +377,7 @@
 	destroy_ramdump_device(drv->ramdump_dev);
 err_ramdump:
 	if (drv->loadable)
-		msm_pil_unregister(q6->pil);
+		pil_desc_release(desc);
 	return ret;
 }
 
@@ -397,7 +391,7 @@
 	subsys_unregister(drv->subsys);
 	destroy_ramdump_device(drv->ramdump_dev);
 	if (drv->loadable)
-		msm_pil_unregister(drv->q6.pil);
+		pil_desc_release(&drv->q6.desc);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/pil-q6v4-mss.c b/arch/arm/mach-msm/pil-q6v4-mss.c
index fe8c3b1..ee01f04 100644
--- a/arch/arm/mach-msm/pil-q6v4-mss.c
+++ b/arch/arm/mach-msm/pil-q6v4-mss.c
@@ -20,10 +20,8 @@
 #include <linux/clk.h>
 #include <linux/interrupt.h>
 
-#include <mach/msm_iomap.h>
 #include <mach/subsystem_restart.h>
 #include <mach/msm_smsm.h>
-#include <mach/peripheral-loader.h>
 
 #include "smd_private.h"
 #include "ramdump.h"
@@ -31,16 +29,17 @@
 #include "pil-q6v4.h"
 #include "scm-pas.h"
 
-#define MSS_S_HCLK_CTL		(MSM_CLK_CTL_BASE + 0x2C70)
-#define MSS_SLP_CLK_CTL		(MSM_CLK_CTL_BASE + 0x2C60)
-#define SFAB_MSS_M_ACLK_CTL	(MSM_CLK_CTL_BASE + 0x2340)
-#define SFAB_MSS_S_HCLK_CTL	(MSM_CLK_CTL_BASE + 0x2C00)
-#define MSS_RESET		(MSM_CLK_CTL_BASE + 0x2C64)
+#define MSS_S_HCLK_CTL		0x2C70
+#define MSS_SLP_CLK_CTL		0x2C60
+#define SFAB_MSS_M_ACLK_CTL	0x2340
+#define SFAB_MSS_S_HCLK_CTL	0x2C00
+#define MSS_RESET		0x2C64
 
 struct q6v4_modem {
 	struct q6v4_data q6_fw;
 	struct q6v4_data q6_sw;
 	void __iomem *modem_base;
+	void __iomem *cbase;
 	void *fw_ramdump_dev;
 	void *sw_ramdump_dev;
 	void *smem_ramdump_dev;
@@ -55,21 +54,22 @@
 static unsigned pil_q6v4_modem_count;
 
 /* Bring modem subsystem out of reset */
-static void pil_q6v4_init_modem(void __iomem *base, void __iomem *jtag_clk)
+static void pil_q6v4_init_modem(void __iomem *base, void __iomem *cbase,
+				void __iomem *jtag_clk)
 {
 	mutex_lock(&pil_q6v4_modem_lock);
 	if (!pil_q6v4_modem_count) {
 		/* Enable MSS clocks */
-		writel_relaxed(0x10, SFAB_MSS_M_ACLK_CTL);
-		writel_relaxed(0x10, SFAB_MSS_S_HCLK_CTL);
-		writel_relaxed(0x10, MSS_S_HCLK_CTL);
-		writel_relaxed(0x10, MSS_SLP_CLK_CTL);
+		writel_relaxed(0x10, cbase + SFAB_MSS_M_ACLK_CTL);
+		writel_relaxed(0x10, cbase + SFAB_MSS_S_HCLK_CTL);
+		writel_relaxed(0x10, cbase + MSS_S_HCLK_CTL);
+		writel_relaxed(0x10, cbase + MSS_SLP_CLK_CTL);
 		/* Wait for clocks to enable */
 		mb();
 		udelay(10);
 
 		/* De-assert MSS reset */
-		writel_relaxed(0x0, MSS_RESET);
+		writel_relaxed(0x0, cbase + MSS_RESET);
 		mb();
 		udelay(10);
 		/* Enable MSS */
@@ -85,13 +85,13 @@
 }
 
 /* Put modem subsystem back into reset */
-static void pil_q6v4_shutdown_modem(void)
+static void pil_q6v4_shutdown_modem(struct q6v4_modem *mdm)
 {
 	mutex_lock(&pil_q6v4_modem_lock);
 	if (pil_q6v4_modem_count)
 		pil_q6v4_modem_count--;
 	if (pil_q6v4_modem_count == 0)
-		writel_relaxed(0x1, MSS_RESET);
+		writel_relaxed(0x1, mdm->cbase + MSS_RESET);
 	mutex_unlock(&pil_q6v4_modem_lock);
 }
 
@@ -105,25 +105,25 @@
 	if (err)
 		return err;
 
-	pil_q6v4_init_modem(mdm->modem_base, drv->jtag_clk_reg);
+	pil_q6v4_init_modem(mdm->modem_base, mdm->cbase, drv->jtag_clk_reg);
 	return pil_q6v4_boot(pil);
 }
 
 static int pil_q6v4_modem_shutdown(struct pil_desc *pil)
 {
 	struct q6v4_data *drv = pil_to_q6v4_data(pil);
+	struct q6v4_modem *mdm = dev_get_drvdata(pil->dev);
 	int ret;
 
 	ret = pil_q6v4_shutdown(pil);
 	if (ret)
 		return ret;
-	pil_q6v4_shutdown_modem();
+	pil_q6v4_shutdown_modem(mdm);
 	pil_q6v4_power_down(drv);
 	return 0;
 }
 
 static struct pil_reset_ops pil_q6v4_modem_ops = {
-	.init_image = pil_q6v4_init_image,
 	.auth_and_reset = pil_q6v4_modem_boot,
 	.shutdown = pil_q6v4_modem_shutdown,
 	.proxy_vote = pil_q6v4_make_proxy_votes,
@@ -173,20 +173,26 @@
 static int modem_start(const struct subsys_desc *desc)
 {
 	struct q6v4_modem *drv = desc_to_modem(desc);
+	int ret = 0;
 
 	if (drv->loadable) {
-		drv->pil = pil_get("modem");
-		if (IS_ERR(drv->pil))
-			return PTR_ERR(drv->pil);
+		ret = pil_boot(&drv->q6_fw.desc);
+		if (ret)
+			return ret;
+		ret = pil_boot(&drv->q6_sw.desc);
+		if (ret)
+			pil_shutdown(&drv->q6_fw.desc);
 	}
-	return 0;
+	return ret;
 }
 
 static void modem_stop(const struct subsys_desc *desc)
 {
 	struct q6v4_modem *drv = desc_to_modem(desc);
-	if (drv->loadable)
-		pil_put(drv->pil);
+	if (drv->loadable) {
+		pil_shutdown(&drv->q6_sw.desc);
+		pil_shutdown(&drv->q6_fw.desc);
+	}
 }
 
 static int modem_shutdown(const struct subsys_desc *subsys)
@@ -199,8 +205,8 @@
 	mb();
 
 	if (drv->loadable) {
-		pil_force_shutdown("modem");
-		pil_force_shutdown("modem_fw");
+		pil_shutdown(&drv->q6_sw.desc);
+		pil_shutdown(&drv->q6_fw.desc);
 	}
 
 	disable_irq_nosync(drv->q6_fw.wdog_irq);
@@ -212,10 +218,17 @@
 static int modem_powerup(const struct subsys_desc *subsys)
 {
 	struct q6v4_modem *drv = desc_to_modem(subsys);
+	int ret;
 
 	if (drv->loadable) {
-		pil_force_boot("modem_fw");
-		pil_force_boot("modem");
+		ret = pil_boot(&drv->q6_fw.desc);
+		if (ret)
+			return ret;
+		ret = pil_boot(&drv->q6_sw.desc);
+		if (ret) {
+			pil_shutdown(&drv->q6_fw.desc);
+			return ret;
+		}
 	}
 	enable_irq(drv->q6_fw.wdog_irq);
 	enable_irq(drv->q6_sw.wdog_irq);
@@ -299,20 +312,13 @@
 	struct pil_desc *desc;
 	struct resource *res;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 1 + (i * 2));
-	if (!res)
-		return -EINVAL;
-
-	drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 2 + (i * 2));
+	drv->base = devm_request_and_ioremap(&pdev->dev, res);
 	if (!drv->base)
 		return -ENOMEM;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 2 + (i * 2));
-	if (!res)
-		return -EINVAL;
-
-	drv->wdog_base = devm_ioremap(&pdev->dev, res->start,
-			resource_size(res));
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 3 + (i * 2));
+	drv->wdog_base = devm_request_and_ioremap(&pdev->dev, res);
 	if (!drv->wdog_base)
 		return -ENOMEM;
 
@@ -327,7 +333,6 @@
 
 	desc = &drv->desc;
 	desc->name = pdata->name;
-	desc->depends_on = pdata->depends;
 	desc->dev = &pdev->dev;
 	desc->owner = THIS_MODULE;
 	desc->proxy_timeout = 10000;
@@ -396,27 +401,29 @@
 		}
 
 		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-		if (!res)
-			return -EINVAL;
-
-		drv->modem_base = devm_ioremap(&pdev->dev, res->start,
-				resource_size(res));
+		drv->modem_base = devm_request_and_ioremap(&pdev->dev, res);
 		if (!drv->modem_base)
 			return -ENOMEM;
 
-		drv_fw->pil = msm_pil_register(&drv_fw->desc);
-		if (IS_ERR(drv_fw->pil))
-			return PTR_ERR(drv_fw->pil);
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+		if (!res)
+			return -EINVAL;
+		drv->cbase = devm_ioremap(&pdev->dev, res->start,
+					  resource_size(res));
+		if (!drv->cbase)
+			return -ENOMEM;
 
-		drv_sw->pil = msm_pil_register(&drv_sw->desc);
-		if (IS_ERR(drv_sw->pil)) {
-			ret = PTR_ERR(drv_sw->pil);
+		ret = pil_desc_init(&drv_fw->desc);
+		if (ret)
+			return ret;
+
+		ret = pil_desc_init(&drv_sw->desc);
+		if (ret)
 			goto err_pil_sw;
-		}
 	}
 
 	drv->subsys_desc.name = "modem";
-	drv->subsys_desc.depends_on = "lpass";
+	drv->subsys_desc.depends_on = "adsp";
 	drv->subsys_desc.dev = &pdev->dev;
 	drv->subsys_desc.owner = THIS_MODULE;
 	drv->subsys_desc.start = modem_start;
@@ -426,19 +433,19 @@
 	drv->subsys_desc.ramdump = modem_ramdump;
 	drv->subsys_desc.crash_shutdown = modem_crash_shutdown;
 
-	drv->fw_ramdump_dev = create_ramdump_device("modem_fw");
+	drv->fw_ramdump_dev = create_ramdump_device("modem_fw", &pdev->dev);
 	if (!drv->fw_ramdump_dev) {
 		ret = -ENOMEM;
 		goto err_fw_ramdump;
 	}
 
-	drv->sw_ramdump_dev = create_ramdump_device("modem_sw");
+	drv->sw_ramdump_dev = create_ramdump_device("modem_sw", &pdev->dev);
 	if (!drv->sw_ramdump_dev) {
 		ret = -ENOMEM;
 		goto err_sw_ramdump;
 	}
 
-	drv->smem_ramdump_dev = create_ramdump_device("smem-modem");
+	drv->smem_ramdump_dev = create_ramdump_device("smem-modem", &pdev->dev);
 	if (!drv->smem_ramdump_dev) {
 		ret = -ENOMEM;
 		goto err_smem_ramdump;
@@ -449,6 +456,8 @@
 		ret = PTR_ERR(drv->subsys);
 		goto err_subsys;
 	}
+	if (!drv->loadable)
+		subsys_default_online(drv->subsys);
 
 	ret = devm_request_irq(&pdev->dev, drv_fw->wdog_irq,
 			modem_wdog_bite_irq, IRQF_TRIGGER_RISING,
@@ -478,9 +487,9 @@
 	destroy_ramdump_device(drv->fw_ramdump_dev);
 err_fw_ramdump:
 	if (drv->loadable)
-		msm_pil_unregister(drv_sw->pil);
+		pil_desc_release(&drv_sw->desc);
 err_pil_sw:
-	msm_pil_unregister(drv_fw->pil);
+	pil_desc_release(&drv_fw->desc);
 	return ret;
 }
 
@@ -495,8 +504,8 @@
 	destroy_ramdump_device(drv->sw_ramdump_dev);
 	destroy_ramdump_device(drv->fw_ramdump_dev);
 	if (drv->loadable) {
-		msm_pil_unregister(drv->q6_sw.pil);
-		msm_pil_unregister(drv->q6_fw.pil);
+		pil_desc_release(&drv->q6_sw.desc);
+		pil_desc_release(&drv->q6_fw.desc);
 	}
 	return 0;
 }
diff --git a/arch/arm/mach-msm/pil-q6v4.c b/arch/arm/mach-msm/pil-q6v4.c
index 47033fc..7f04c64 100644
--- a/arch/arm/mach-msm/pil-q6v4.c
+++ b/arch/arm/mach-msm/pil-q6v4.c
@@ -16,7 +16,6 @@
 #include <linux/io.h>
 #include <linux/ioport.h>
 #include <linux/regulator/consumer.h>
-#include <linux/elf.h>
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/clk.h>
@@ -52,16 +51,6 @@
 #define Q6SS_CLK_ENA		BIT(1)
 #define Q6SS_SRC_SWITCH_CLK_OVR	BIT(8)
 
-int pil_q6v4_init_image(struct pil_desc *pil, const u8 *metadata,
-		size_t size)
-{
-	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
-	struct q6v4_data *drv = pil_to_q6v4_data(pil);
-	drv->start_addr = ehdr->e_entry;
-	return 0;
-}
-EXPORT_SYMBOL(pil_q6v4_init_image);
-
 int pil_q6v4_make_proxy_votes(struct pil_desc *pil)
 {
 	const struct q6v4_data *drv = pil_to_q6v4_data(pil);
@@ -141,6 +130,7 @@
 {
 	u32 reg, err;
 	const struct q6v4_data *drv = pil_to_q6v4_data(pil);
+	unsigned long start_addr = pil_get_entry_addr(pil);
 
 	/* Enable Q6 ACLK */
 	writel_relaxed(0x10, drv->aclk_reg);
@@ -156,7 +146,7 @@
 	writel_relaxed(reg, drv->base + QDSP6SS_RESET);
 
 	/* Program boot address */
-	writel_relaxed((drv->start_addr >> 8) & 0xFFFFFF,
+	writel_relaxed((start_addr >> 8) & 0xFFFFFF,
 			drv->base + QDSP6SS_RST_EVB);
 
 	/* Program TCM and AHB address ranges */
diff --git a/arch/arm/mach-msm/pil-q6v4.h b/arch/arm/mach-msm/pil-q6v4.h
index 0395bed..86e55ea 100644
--- a/arch/arm/mach-msm/pil-q6v4.h
+++ b/arch/arm/mach-msm/pil-q6v4.h
@@ -21,7 +21,6 @@
 	void __iomem *aclk_reg;
 	void __iomem *jtag_clk_reg;
 	const char *name;
-	const char *depends;
 	const unsigned pas_id;
 	int bus_port;
 };
@@ -36,7 +35,6 @@
 struct q6v4_data {
 	void __iomem *base;
 	void __iomem *wdog_base;
-	unsigned long start_addr;
 	unsigned long strap_tcm_base;
 	unsigned long strap_ahb_upper;
 	unsigned long strap_ahb_lower;
@@ -51,14 +49,11 @@
 	bool vreg_enabled;
 	struct clk *xo;
 
-	struct pil_device *pil;
 	struct pil_desc desc;
 };
 
 #define pil_to_q6v4_data(p) container_of(p, struct q6v4_data, desc)
 
-extern int pil_q6v4_init_image(struct pil_desc *pil, const u8 *metadata,
-		size_t size);
 extern int pil_q6v4_make_proxy_votes(struct pil_desc *pil);
 extern void pil_q6v4_remove_proxy_votes(struct pil_desc *pil);
 extern int pil_q6v4_power_up(struct q6v4_data *drv);
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index 3c68da0..662377d 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -26,7 +26,6 @@
 #include <mach/subsystem_restart.h>
 #include <mach/subsystem_notif.h>
 #include <mach/scm.h>
-#include <mach/peripheral-loader.h>
 
 #include "peripheral-loader.h"
 #include "pil-q6v5.h"
@@ -119,6 +118,7 @@
 static int pil_lpass_reset(struct pil_desc *pil)
 {
 	struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
+	unsigned long start_addr = pil_get_entry_addr(pil);
 	int ret;
 
 	ret = pil_lpass_enable_clks(drv);
@@ -126,7 +126,7 @@
 		return ret;
 
 	/* Program Image Address */
-	writel_relaxed(((drv->start_addr >> 4) & 0x0FFFFFF0),
+	writel_relaxed((start_addr >> 4) & 0x0FFFFFF0,
 				drv->reg_base + QDSP6SS_RST_EVB);
 
 	ret = pil_q6v5_reset(pil);
@@ -141,7 +141,6 @@
 }
 
 static struct pil_reset_ops pil_lpass_ops = {
-	.init_image = pil_q6v5_init_image,
 	.proxy_vote = pil_q6v5_make_proxy_votes,
 	.proxy_unvote = pil_q6v5_remove_proxy_votes,
 	.auth_and_reset = pil_lpass_reset,
@@ -286,7 +285,7 @@
 	send_q6_nmi();
 	/* The write needs to go through before the q6 is shutdown. */
 	mb();
-	pil_force_shutdown("adsp");
+	pil_shutdown(&drv->q6->desc);
 	disable_irq_nosync(drv->wdog_irq);
 
 	return 0;
@@ -302,7 +301,7 @@
 		msleep(10000);
 	}
 
-	ret = pil_force_boot("adsp");
+	ret = pil_boot(&drv->q6->desc);
 	enable_irq(drv->wdog_irq);
 
 	return ret;
@@ -339,19 +338,15 @@
 
 static int lpass_start(const struct subsys_desc *desc)
 {
-	void *ret;
 	struct lpass_data *drv = subsys_to_drv(desc);
 
-	ret = pil_get(drv->q6->desc.name);
-	if (IS_ERR(ret))
-		return PTR_ERR(ret);
-	return 0;
+	return pil_boot(&drv->q6->desc);
 }
 
 static void lpass_stop(const struct subsys_desc *desc)
 {
 	struct lpass_data *drv = subsys_to_drv(desc);
-	pil_put(drv->q6->pil);
+	pil_shutdown(&drv->q6->desc);
 }
 
 static int __devinit pil_lpass_driver_probe(struct platform_device *pdev)
@@ -403,9 +398,9 @@
 		dev_info(&pdev->dev, "using non-secure boot\n");
 	}
 
-	drv->q6->pil = msm_pil_register(desc);
-	if (IS_ERR(drv->q6->pil))
-		return PTR_ERR(drv->q6->pil);
+	ret = pil_desc_init(desc);
+	if (ret)
+		return ret;
 
 	drv->subsys_desc.name = desc->name;
 	drv->subsys_desc.owner = THIS_MODULE;
@@ -419,7 +414,7 @@
 
 	INIT_WORK(&drv->work, adsp_fatal_fn);
 
-	drv->ramdump_dev = create_ramdump_device("adsp");
+	drv->ramdump_dev = create_ramdump_device("adsp", &pdev->dev);
 	if (!drv->ramdump_dev) {
 		ret = -ENOMEM;
 		goto err_ramdump;
@@ -464,7 +459,7 @@
 err_subsys:
 	destroy_ramdump_device(drv->ramdump_dev);
 err_ramdump:
-	msm_pil_unregister(drv->q6->pil);
+	pil_desc_release(desc);
 	return 0;
 }
 
@@ -477,7 +472,7 @@
 			adsp_smsm_state_cb, drv);
 	subsys_unregister(drv->subsys);
 	destroy_ramdump_device(drv->ramdump_dev);
-	msm_pil_unregister(drv->q6->pil);
+	pil_desc_release(&drv->q6->desc);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index f3c731f..7652d74 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -17,18 +17,22 @@
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/ioport.h>
-#include <linux/elf.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/of.h>
 #include <linux/regulator/consumer.h>
+#include <linux/interrupt.h>
 
+#include <mach/subsystem_restart.h>
 #include <mach/clk.h>
+#include <mach/msm_smsm.h>
 
 #include "peripheral-loader.h"
 #include "pil-q6v5.h"
+#include "ramdump.h"
+#include "sysmon.h"
 
 /* Q6 Register Offsets */
 #define QDSP6SS_RST_EVB			0x010
@@ -38,9 +42,6 @@
 #define MSS_MODEM_HALT_BASE		0x200
 #define MSS_NC_HALT_BASE		0x280
 
-/* MSS_CLAMP_IO Register Value */
-#define MSS_IO_UNCLAMP_ALL		0x40
-
 /* RMB Status Register Values */
 #define STATUS_PBL_SUCCESS		0x1
 #define STATUS_XPU_UNLOCKED		0x1
@@ -49,14 +50,48 @@
 /* PBL/MBA interface registers */
 #define RMB_MBA_IMAGE			0x00
 #define RMB_PBL_STATUS			0x04
+#define RMB_MBA_COMMAND			0x08
 #define RMB_MBA_STATUS			0x0C
+#define RMB_PMI_META_DATA		0x10
+#define RMB_PMI_CODE_START		0x14
+#define RMB_PMI_CODE_LENGTH		0x18
 
 #define PROXY_TIMEOUT_MS		10000
 #define POLL_INTERVAL_US		50
 
+#define CMD_META_DATA_READY		0x1
+#define CMD_LOAD_READY			0x2
+
+#define STATUS_META_DATA_AUTH_SUCCESS	0x3
+#define STATUS_AUTH_COMPLETE		0x4
+
+#define MAX_SSR_REASON_LEN 81U
+
+struct mba_data {
+	void __iomem *metadata_base;
+	void __iomem *rmb_base;
+	void __iomem *io_clamp_reg;
+	unsigned long metadata_phys;
+	struct pil_desc desc;
+	struct subsys_device *subsys;
+	struct subsys_desc subsys_desc;
+	void *adsp_state_notifier;
+	u32 img_length;
+	struct q6v5_data *q6;
+	int self_auth;
+	void *ramdump_dev;
+	void *smem_ramdump_dev;
+	bool crash_shutdown;
+	bool ignore_errors;
+	int is_loadable;
+};
+
 static int pbl_mba_boot_timeout_ms = 100;
 module_param(pbl_mba_boot_timeout_ms, int, S_IRUGO | S_IWUSR);
 
+static int modem_auth_timeout_ms = 10000;
+module_param(modem_auth_timeout_ms, int, S_IRUGO | S_IWUSR);
+
 static int pil_mss_power_up(struct q6v5_data *drv)
 {
 	int ret;
@@ -108,11 +143,12 @@
 static int wait_for_mba_ready(struct q6v5_data *drv)
 {
 	struct device *dev = drv->desc.dev;
+	struct mba_data *mba = platform_get_drvdata(to_platform_device(dev));
 	int ret;
 	u32 status;
 
 	/* Wait for PBL completion. */
-	ret = readl_poll_timeout(drv->rmb_base + RMB_PBL_STATUS, status,
+	ret = readl_poll_timeout(mba->rmb_base + RMB_PBL_STATUS, status,
 		status != 0, POLL_INTERVAL_US, pbl_mba_boot_timeout_ms * 1000);
 	if (ret) {
 		dev_err(dev, "PBL boot timed out\n");
@@ -124,7 +160,7 @@
 	}
 
 	/* Wait for MBA completion. */
-	ret = readl_poll_timeout(drv->rmb_base + RMB_MBA_STATUS, status,
+	ret = readl_poll_timeout(mba->rmb_base + RMB_MBA_STATUS, status,
 		status != 0, POLL_INTERVAL_US, pbl_mba_boot_timeout_ms * 1000);
 	if (ret) {
 		dev_err(dev, "MBA boot timed out\n");
@@ -171,6 +207,9 @@
 static int pil_mss_reset(struct pil_desc *pil)
 {
 	struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
+	struct platform_device *pdev = to_platform_device(pil->dev);
+	struct mba_data *mba = platform_get_drvdata(pdev);
+	unsigned long start_addr = pil_get_entry_addr(pil);
 	int ret;
 
 	/* Deassert reset to subsystem and wait for propagation */
@@ -191,24 +230,21 @@
 		goto err_clks;
 
 	/* Program Image Address */
-	if (drv->self_auth) {
-		writel_relaxed(drv->start_addr, drv->rmb_base + RMB_MBA_IMAGE);
+	if (mba->self_auth) {
+		writel_relaxed(start_addr, mba->rmb_base + RMB_MBA_IMAGE);
 		/* Ensure write to RMB base occurs before reset is released. */
 		mb();
 	} else {
-		writel_relaxed((drv->start_addr >> 4) & 0x0FFFFFF0,
+		writel_relaxed((start_addr >> 4) & 0x0FFFFFF0,
 				drv->reg_base + QDSP6SS_RST_EVB);
 	}
 
-	/* De-assert MSS IO clamps */
-	writel_relaxed(MSS_IO_UNCLAMP_ALL, drv->io_clamp_reg);
-
 	ret = pil_q6v5_reset(pil);
 	if (ret)
 		goto err_q6v5_reset;
 
 	/* Wait for MBA to start. Check for PBL and MBA errors while waiting. */
-	if (drv->self_auth) {
+	if (mba->self_auth) {
 		ret = wait_for_mba_ready(drv);
 		if (ret)
 			goto err_auth;
@@ -229,90 +265,494 @@
 }
 
 static struct pil_reset_ops pil_mss_ops = {
-	.init_image = pil_q6v5_init_image,
 	.proxy_vote = pil_q6v5_make_proxy_votes,
 	.proxy_unvote = pil_q6v5_remove_proxy_votes,
 	.auth_and_reset = pil_mss_reset,
 	.shutdown = pil_mss_shutdown,
 };
 
-static int __devinit pil_mss_driver_probe(struct platform_device *pdev)
+static int pil_mba_make_proxy_votes(struct pil_desc *pil)
 {
-	struct q6v5_data *drv;
-	struct pil_desc *desc;
+	int ret;
+	struct mba_data *drv = dev_get_drvdata(pil->dev);
+
+	ret = clk_prepare_enable(drv->q6->xo);
+	if (ret) {
+		dev_err(pil->dev, "Failed to enable XO\n");
+		return ret;
+	}
+	return 0;
+}
+
+static void pil_mba_remove_proxy_votes(struct pil_desc *pil)
+{
+	struct mba_data *drv = dev_get_drvdata(pil->dev);
+	clk_disable_unprepare(drv->q6->xo);
+}
+
+static int pil_mba_init_image(struct pil_desc *pil,
+			      const u8 *metadata, size_t size)
+{
+	struct mba_data *drv = dev_get_drvdata(pil->dev);
+	s32 status;
+	int ret;
+
+	/* Copy metadata to assigned shared buffer location */
+	memcpy(drv->metadata_base, metadata, size);
+
+	/* Initialize length counter to 0 */
+	writel_relaxed(0, drv->rmb_base + RMB_PMI_CODE_LENGTH);
+	drv->img_length = 0;
+
+	/* Pass address of meta-data to the MBA and perform authentication */
+	writel_relaxed(drv->metadata_phys, drv->rmb_base + RMB_PMI_META_DATA);
+	writel_relaxed(CMD_META_DATA_READY, drv->rmb_base + RMB_MBA_COMMAND);
+	ret = readl_poll_timeout(drv->rmb_base + RMB_MBA_STATUS, status,
+		status == STATUS_META_DATA_AUTH_SUCCESS || status < 0,
+		POLL_INTERVAL_US, modem_auth_timeout_ms * 1000);
+	if (ret) {
+		dev_err(pil->dev, "MBA authentication of headers timed out\n");
+	} else if (status < 0) {
+		dev_err(pil->dev, "MBA returned error %d for headers\n",
+				status);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int pil_mba_verify_blob(struct pil_desc *pil, u32 phy_addr,
+			       size_t size)
+{
+	struct mba_data *drv = dev_get_drvdata(pil->dev);
+	s32 status;
+
+	/* Begin image authentication */
+	if (drv->img_length == 0) {
+		writel_relaxed(phy_addr, drv->rmb_base + RMB_PMI_CODE_START);
+		writel_relaxed(CMD_LOAD_READY, drv->rmb_base + RMB_MBA_COMMAND);
+	}
+	/* Increment length counter */
+	drv->img_length += size;
+	writel_relaxed(drv->img_length, drv->rmb_base + RMB_PMI_CODE_LENGTH);
+
+	status = readl_relaxed(drv->rmb_base + RMB_MBA_STATUS);
+	if (status < 0) {
+		dev_err(pil->dev, "MBA returned error %d\n", status);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int pil_mba_auth(struct pil_desc *pil)
+{
+	struct mba_data *drv = dev_get_drvdata(pil->dev);
+	int ret;
+	s32 status;
+
+	/* Wait for all segments to be authenticated or an error to occur */
+	ret = readl_poll_timeout(drv->rmb_base + RMB_MBA_STATUS, status,
+			status == STATUS_AUTH_COMPLETE || status < 0,
+			50, modem_auth_timeout_ms * 1000);
+	if (ret) {
+		dev_err(pil->dev, "MBA authentication of image timed out\n");
+	} else if (status < 0) {
+		dev_err(pil->dev, "MBA returned error %d for image\n", status);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static struct pil_reset_ops pil_mba_ops = {
+	.init_image = pil_mba_init_image,
+	.proxy_vote = pil_mba_make_proxy_votes,
+	.proxy_unvote = pil_mba_remove_proxy_votes,
+	.verify_blob = pil_mba_verify_blob,
+	.auth_and_reset = pil_mba_auth,
+};
+
+#define subsys_to_drv(d) container_of(d, struct mba_data, subsys_desc)
+
+static void log_modem_sfr(void)
+{
+	u32 size;
+	char *smem_reason, reason[MAX_SSR_REASON_LEN];
+
+	smem_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size);
+	if (!smem_reason || !size) {
+		pr_err("modem subsystem failure reason: (unknown, smem_get_entry failed).\n");
+		return;
+	}
+	if (!smem_reason[0]) {
+		pr_err("modem subsystem failure reason: (unknown, empty string found).\n");
+		return;
+	}
+
+	strlcpy(reason, smem_reason, min(size, sizeof(reason)));
+	pr_err("modem subsystem failure reason: %s.\n", reason);
+
+	smem_reason[0] = '\0';
+	wmb();
+}
+
+static void restart_modem(struct mba_data *drv)
+{
+	log_modem_sfr();
+	drv->ignore_errors = true;
+	subsystem_restart_dev(drv->subsys);
+}
+
+static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
+{
+	struct mba_data *drv = data;
+
+	/* Ignore if we're the one that set SMSM_RESET */
+	if (drv->crash_shutdown)
+		return;
+
+	if (new_state & SMSM_RESET) {
+		pr_err("Probable fatal error on the modem.\n");
+		restart_modem(drv);
+	}
+}
+
+static int modem_shutdown(const struct subsys_desc *subsys)
+{
+	struct mba_data *drv = subsys_to_drv(subsys);
+
+	if (!drv->is_loadable)
+		return -ENODEV;
+	/* MBA doesn't support shutdown */
+	pil_shutdown(&drv->q6->desc);
+	return 0;
+}
+
+static int modem_powerup(const struct subsys_desc *subsys)
+{
+	struct mba_data *drv = subsys_to_drv(subsys);
+	int ret;
+
+	if (!drv->is_loadable)
+		return -ENODEV;
+	/*
+	 * At this time, the modem is shutdown. Therefore this function cannot
+	 * run concurrently with either the watchdog bite error handler or the
+	 * SMSM callback, making it safe to unset the flag below.
+	 */
+	drv->ignore_errors = false;
+	ret = pil_boot(&drv->q6->desc);
+	if (ret)
+		return ret;
+	ret = pil_boot(&drv->desc);
+	if (ret)
+		pil_shutdown(&drv->q6->desc);
+	return ret;
+}
+
+static void modem_crash_shutdown(const struct subsys_desc *subsys)
+{
+	struct mba_data *drv = subsys_to_drv(subsys);
+	drv->crash_shutdown = true;
+	smsm_reset_modem(SMSM_RESET);
+}
+
+static struct ramdump_segment modem_segments[] = {
+	{0x08400000, 0x0D100000 - 0x08400000},
+};
+
+static struct ramdump_segment smem_segments[] = {
+	{0x0FA00000, 0x0FC00000 - 0x0FA00000},
+};
+
+static int modem_ramdump(int enable, const struct subsys_desc *subsys)
+{
+	struct mba_data *drv = subsys_to_drv(subsys);
+	int ret;
+
+	if (!enable)
+		return 0;
+
+	ret = pil_boot(&drv->q6->desc);
+	if (ret)
+		return ret;
+
+	ret = do_ramdump(drv->ramdump_dev, modem_segments,
+				ARRAY_SIZE(modem_segments));
+	if (ret < 0) {
+		pr_err("Unable to dump modem fw memory (rc = %d).\n", ret);
+		goto out;
+	}
+
+	ret = do_ramdump(drv->smem_ramdump_dev, smem_segments,
+		ARRAY_SIZE(smem_segments));
+	if (ret < 0) {
+		pr_err("Unable to dump smem memory (rc = %d).\n", ret);
+		goto out;
+	}
+
+out:
+	pil_shutdown(&drv->q6->desc);
+	return ret;
+}
+
+static int adsp_state_notifier_fn(struct notifier_block *this,
+				unsigned long code, void *ss_handle)
+{
+	int ret;
+	ret = sysmon_send_event(SYSMON_SS_MODEM, "adsp", code);
+	if (ret < 0)
+		pr_err("%s: sysmon_send_event failed (%d).", __func__, ret);
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block adsp_state_notifier_block = {
+	.notifier_call = adsp_state_notifier_fn,
+};
+
+static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
+{
+	struct mba_data *drv = dev_id;
+	if (drv->ignore_errors)
+		return IRQ_HANDLED;
+	pr_err("Watchdog bite received from modem software!\n");
+	restart_modem(drv);
+	return IRQ_HANDLED;
+}
+
+static int mss_start(const struct subsys_desc *desc)
+{
+	int ret;
+	struct mba_data *drv = subsys_to_drv(desc);
+
+	if (!drv->is_loadable)
+		return -ENODEV;
+
+	ret = pil_boot(&drv->q6->desc);
+	if (ret)
+		return ret;
+	ret = pil_boot(&drv->desc);
+	if (ret)
+		pil_shutdown(&drv->q6->desc);
+	return ret;
+}
+
+static void mss_stop(const struct subsys_desc *desc)
+{
+	struct mba_data *drv = subsys_to_drv(desc);
+
+	if (!drv->is_loadable)
+		return;
+
+	/* MBA doesn't support shutdown */
+	pil_shutdown(&drv->q6->desc);
+}
+
+static int __devinit pil_subsys_init(struct mba_data *drv,
+					struct platform_device *pdev)
+{
+	int irq, ret;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	drv->subsys_desc.name = "modem";
+	drv->subsys_desc.dev = &pdev->dev;
+	drv->subsys_desc.owner = THIS_MODULE;
+	drv->subsys_desc.shutdown = modem_shutdown;
+	drv->subsys_desc.powerup = modem_powerup;
+	drv->subsys_desc.ramdump = modem_ramdump;
+	drv->subsys_desc.crash_shutdown = modem_crash_shutdown;
+	drv->subsys_desc.start = mss_start;
+	drv->subsys_desc.stop = mss_stop;
+
+	drv->subsys = subsys_register(&drv->subsys_desc);
+	if (IS_ERR(drv->subsys)) {
+		ret = PTR_ERR(drv->subsys);
+		goto err_subsys;
+	}
+
+	drv->ramdump_dev = create_ramdump_device("modem", &pdev->dev);
+	if (!drv->ramdump_dev) {
+		pr_err("%s: Unable to create a modem ramdump device.\n",
+			__func__);
+		ret = -ENOMEM;
+		goto err_ramdump;
+	}
+
+	drv->smem_ramdump_dev = create_ramdump_device("smem-modem", &pdev->dev);
+	if (!drv->smem_ramdump_dev) {
+		pr_err("%s: Unable to create an smem ramdump device.\n",
+			__func__);
+		ret = -ENOMEM;
+		goto err_ramdump_smem;
+	}
+
+	ret = devm_request_irq(&pdev->dev, irq, modem_wdog_bite_irq,
+				IRQF_TRIGGER_RISING, "modem_wdog", drv);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Unable to request watchdog IRQ.\n");
+		goto err_irq;
+	}
+
+	ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
+		smsm_state_cb, drv);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Unable to register SMSM callback!\n");
+		goto err_irq;
+	}
+
+	drv->adsp_state_notifier = subsys_notif_register_notifier("adsp",
+						&adsp_state_notifier_block);
+	if (IS_ERR(drv->adsp_state_notifier)) {
+		ret = PTR_ERR(drv->adsp_state_notifier);
+		dev_err(&pdev->dev, "%s: Registration with the SSR notification driver failed (%d)",
+			__func__, ret);
+		goto err_smsm;
+	}
+
+	return 0;
+
+err_smsm:
+	smsm_state_cb_deregister(SMSM_MODEM_STATE, SMSM_RESET, smsm_state_cb,
+			drv);
+err_irq:
+	destroy_ramdump_device(drv->smem_ramdump_dev);
+err_ramdump_smem:
+	destroy_ramdump_device(drv->ramdump_dev);
+err_ramdump:
+	subsys_unregister(drv->subsys);
+err_subsys:
+	return ret;
+}
+
+static int __devinit pil_mss_loadable_init(struct mba_data *drv,
+					struct platform_device *pdev)
+{
+	struct q6v5_data *q6;
+	struct pil_desc *q6_desc, *mba_desc;
 	struct resource *res;
 	int ret;
 
-	drv = pil_q6v5_init(pdev);
-	if (IS_ERR(drv))
-		return PTR_ERR(drv);
-	platform_set_drvdata(pdev, drv);
+	q6 = pil_q6v5_init(pdev);
+	if (IS_ERR(q6))
+		return PTR_ERR(q6);
+	drv->q6 = q6;
 
-	desc = &drv->desc;
-	desc->ops = &pil_mss_ops;
-	desc->owner = THIS_MODULE;
-	desc->proxy_timeout = PROXY_TIMEOUT_MS;
+	q6_desc = &q6->desc;
+	q6_desc->ops = &pil_mss_ops;
+	q6_desc->owner = THIS_MODULE;
+	q6_desc->proxy_timeout = PROXY_TIMEOUT_MS;
 
 	of_property_read_u32(pdev->dev.of_node, "qcom,pil-self-auth",
 			     &drv->self_auth);
 	if (drv->self_auth) {
 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 						    "rmb_base");
-		drv->rmb_base = devm_ioremap(&pdev->dev, res->start,
-					     resource_size(res));
+		drv->rmb_base = devm_request_and_ioremap(&pdev->dev, res);
 		if (!drv->rmb_base)
 			return -ENOMEM;
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+					    "metadata_base");
+		if (res) {
+			drv->metadata_base = devm_ioremap(&pdev->dev,
+						res->start, resource_size(res));
+			if (!drv->metadata_base)
+				return -ENOMEM;
+			drv->metadata_phys = res->start;
+		}
 	}
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "restart_reg");
-	drv->restart_reg = devm_ioremap(&pdev->dev, res->start,
-					resource_size(res));
-	if (!drv->restart_reg)
+	q6->restart_reg = devm_request_and_ioremap(&pdev->dev, res);
+	if (!q6->restart_reg)
 		return -ENOMEM;
 
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clamp_reg");
-	drv->io_clamp_reg = devm_ioremap(&pdev->dev, res->start,
-					resource_size(res));
-	if (!drv->io_clamp_reg)
-		return -ENOMEM;
+	q6->vreg = devm_regulator_get(&pdev->dev, "vdd_mss");
+	if (IS_ERR(q6->vreg))
+		return PTR_ERR(q6->vreg);
 
-	drv->vreg = devm_regulator_get(&pdev->dev, "vdd_mss");
-	if (IS_ERR(drv->vreg))
-		return PTR_ERR(drv->vreg);
-
-	ret = regulator_set_voltage(drv->vreg, 1050000, 1050000);
+	ret = regulator_set_voltage(q6->vreg, 1050000, 1050000);
 	if (ret)
 		dev_err(&pdev->dev, "Failed to set regulator's voltage.\n");
 
-	ret = regulator_set_optimum_mode(drv->vreg, 100000);
+	ret = regulator_set_optimum_mode(q6->vreg, 100000);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Failed to set regulator's mode.\n");
 		return ret;
 	}
 
-	drv->ahb_clk = devm_clk_get(&pdev->dev, "iface_clk");
-	if (IS_ERR(drv->ahb_clk))
-		return PTR_ERR(drv->ahb_clk);
+	q6->ahb_clk = devm_clk_get(&pdev->dev, "iface_clk");
+	if (IS_ERR(q6->ahb_clk))
+		return PTR_ERR(q6->ahb_clk);
 
-	drv->axi_clk = devm_clk_get(&pdev->dev, "bus_clk");
-	if (IS_ERR(drv->axi_clk))
-		return PTR_ERR(drv->axi_clk);
+	q6->axi_clk = devm_clk_get(&pdev->dev, "bus_clk");
+	if (IS_ERR(q6->axi_clk))
+		return PTR_ERR(q6->axi_clk);
 
-	drv->rom_clk = devm_clk_get(&pdev->dev, "mem_clk");
-	if (IS_ERR(drv->rom_clk))
-		return PTR_ERR(drv->rom_clk);
+	q6->rom_clk = devm_clk_get(&pdev->dev, "mem_clk");
+	if (IS_ERR(q6->rom_clk))
+		return PTR_ERR(q6->rom_clk);
 
-	drv->pil = msm_pil_register(desc);
-	if (IS_ERR(drv->pil))
-		return PTR_ERR(drv->pil);
+	ret = pil_desc_init(q6_desc);
+	if (ret)
+		return ret;
+
+	mba_desc = &drv->desc;
+	mba_desc->name = "modem";
+	mba_desc->dev = &pdev->dev;
+	mba_desc->ops = &pil_mba_ops;
+	mba_desc->owner = THIS_MODULE;
+	mba_desc->proxy_timeout = PROXY_TIMEOUT_MS;
+
+	ret = pil_desc_init(mba_desc);
+	if (ret)
+		goto err_mba_desc;
 
 	return 0;
+
+err_mba_desc:
+	pil_desc_release(q6_desc);
+	return ret;
+
+}
+
+static int __devinit pil_mss_driver_probe(struct platform_device *pdev)
+{
+	struct mba_data *drv;
+	int ret;
+
+	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+	if (!drv)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, drv);
+
+	of_property_read_u32(pdev->dev.of_node, "qcom,is_loadable",
+				&drv->is_loadable);
+	if (drv->is_loadable) {
+		ret = pil_mss_loadable_init(drv, pdev);
+		if (ret)
+			return ret;
+	}
+
+	return pil_subsys_init(drv, pdev);
 }
 
 static int __devexit pil_mss_driver_exit(struct platform_device *pdev)
 {
-	struct q6v5_data *drv = platform_get_drvdata(pdev);
-	msm_pil_unregister(drv->pil);
+	struct mba_data *drv = platform_get_drvdata(pdev);
+
+	subsys_notif_unregister_notifier(drv->adsp_state_notifier,
+						&adsp_state_notifier_block);
+	smsm_state_cb_deregister(SMSM_MODEM_STATE, SMSM_RESET,
+			smsm_state_cb, drv);
+	subsys_unregister(drv->subsys);
+	destroy_ramdump_device(drv->smem_ramdump_dev);
+	destroy_ramdump_device(drv->ramdump_dev);
+	pil_desc_release(&drv->desc);
+	pil_desc_release(&drv->q6->desc);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/pil-q6v5.c b/arch/arm/mach-msm/pil-q6v5.c
index 70a12de..ab88749 100644
--- a/arch/arm/mach-msm/pil-q6v5.c
+++ b/arch/arm/mach-msm/pil-q6v5.c
@@ -16,7 +16,6 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
-#include <linux/elf.h>
 #include <linux/err.h>
 #include <linux/of.h>
 #include <linux/clk.h>
@@ -100,16 +99,6 @@
 }
 EXPORT_SYMBOL(pil_q6v5_halt_axi_port);
 
-int pil_q6v5_init_image(struct pil_desc *pil, const u8 *metadata,
-			       size_t size)
-{
-	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
-	struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
-	drv->start_addr = ehdr->e_entry;
-	return 0;
-}
-EXPORT_SYMBOL(pil_q6v5_init_image);
-
 void pil_q6v5_shutdown(struct pil_desc *pil)
 {
 	u32 val;
@@ -205,12 +194,10 @@
 		return ERR_PTR(-ENOMEM);
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6_base");
-	if (!res)
-		return ERR_PTR(-EINVAL);
-	drv->reg_base = devm_ioremap(&pdev->dev, res->start,
-				     resource_size(res));
+	drv->reg_base = devm_request_and_ioremap(&pdev->dev, res);
 	if (!drv->reg_base)
 		return ERR_PTR(-ENOMEM);
+
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "halt_base");
 	drv->axi_halt_base = devm_ioremap(&pdev->dev, res->start,
 					  resource_size(res));
diff --git a/arch/arm/mach-msm/pil-q6v5.h b/arch/arm/mach-msm/pil-q6v5.h
index f176d2d..ecdaf9b 100644
--- a/arch/arm/mach-msm/pil-q6v5.h
+++ b/arch/arm/mach-msm/pil-q6v5.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -29,22 +29,15 @@
 	struct clk *reg_clk;	/* CPU access registers */
 	struct clk *rom_clk;	/* Boot ROM */
 	void __iomem *axi_halt_base;
-	void __iomem *rmb_base;
 	void __iomem *restart_reg;
-	void __iomem *io_clamp_reg;
-	unsigned long start_addr;
 	struct regulator *vreg;
 	bool is_booted;
-	int self_auth;
-	struct pil_device *pil;
 	struct pil_desc desc;
 };
 
 int pil_q6v5_make_proxy_votes(struct pil_desc *pil);
 void pil_q6v5_remove_proxy_votes(struct pil_desc *pil);
 void pil_q6v5_halt_axi_port(struct pil_desc *pil, void __iomem *halt_base);
-int pil_q6v5_init_image(struct pil_desc *pil, const u8 *metadata,
-			size_t size);
 void pil_q6v5_shutdown(struct pil_desc *pil);
 int pil_q6v5_reset(struct pil_desc *pil);
 struct q6v5_data *pil_q6v5_init(struct platform_device *pdev);
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index a0e39ea..7993090 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -13,7 +13,6 @@
 #include <linux/kernel.h>
 #include <linux/err.h>
 #include <linux/io.h>
-#include <linux/elf.h>
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -23,9 +22,7 @@
 #include <linux/interrupt.h>
 #include <linux/wcnss_wlan.h>
 
-#include <mach/msm_iomap.h>
 #include <mach/subsystem_restart.h>
-#include <mach/peripheral-loader.h>
 
 #include "peripheral-loader.h"
 #include "scm-pas.h"
@@ -54,19 +51,18 @@
 
 #define RIVA_PMU_CCPU_BOOT_REMAP_ADDR	0xA0
 
-#define RIVA_PLL_MODE			(MSM_CLK_CTL_BASE + 0x31A0)
+#define RIVA_PLL_MODE			0x31A0
 #define PLL_MODE_OUTCTRL		BIT(0)
 #define PLL_MODE_BYPASSNL		BIT(1)
 #define PLL_MODE_RESET_N		BIT(2)
 #define PLL_MODE_REF_XO_SEL		0x30
 #define PLL_MODE_REF_XO_SEL_CXO		(2 << 4)
 #define PLL_MODE_REF_XO_SEL_RF		(3 << 4)
-#define RIVA_PLL_L_VAL			(MSM_CLK_CTL_BASE + 0x31A4)
-#define RIVA_PLL_M_VAL			(MSM_CLK_CTL_BASE + 0x31A8)
-#define RIVA_PLL_N_VAL			(MSM_CLK_CTL_BASE + 0x31Ac)
-#define RIVA_PLL_CONFIG			(MSM_CLK_CTL_BASE + 0x31B4)
-#define RIVA_PLL_STATUS			(MSM_CLK_CTL_BASE + 0x31B8)
-#define RIVA_RESET			(MSM_CLK_CTL_BASE + 0x35E0)
+#define RIVA_PLL_L_VAL			0x31A4
+#define RIVA_PLL_M_VAL			0x31A8
+#define RIVA_PLL_N_VAL			0x31Ac
+#define RIVA_PLL_CONFIG			0x31B4
+#define RIVA_RESET			0x35E0
 
 #define RIVA_PMU_ROOT_CLK_SEL		0xC8
 #define RIVA_PMU_ROOT_CLK_SEL_3		BIT(2)
@@ -84,10 +80,10 @@
 
 struct riva_data {
 	void __iomem *base;
-	unsigned long start_addr;
+	void __iomem *cbase;
 	struct clk *xo;
 	struct regulator *pll_supply;
-	struct pil_device *pil;
+	struct pil_desc pil_desc;
 	int irq;
 	int crash;
 	int rst_in_progress;
@@ -133,21 +129,13 @@
 	clk_disable_unprepare(drv->xo);
 }
 
-static int pil_riva_init_image(struct pil_desc *pil, const u8 *metadata,
-		size_t size)
-{
-	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
-	struct riva_data *drv = dev_get_drvdata(pil->dev);
-	drv->start_addr = ehdr->e_entry;
-	return 0;
-}
-
 static int pil_riva_reset(struct pil_desc *pil)
 {
 	u32 reg, sel;
 	struct riva_data *drv = dev_get_drvdata(pil->dev);
 	void __iomem *base = drv->base;
-	unsigned long start_addr = drv->start_addr;
+	unsigned long start_addr = pil_get_entry_addr(pil);
+	void __iomem *cbase = drv->cbase;
 	bool use_cxo = cxo_is_needed(drv);
 
 	/* Enable A2XB bridge */
@@ -156,26 +144,26 @@
 	writel_relaxed(reg, base + RIVA_PMU_A2XB_CFG);
 
 	/* Program PLL 13 to 960 MHz */
-	reg = readl_relaxed(RIVA_PLL_MODE);
+	reg = readl_relaxed(cbase + RIVA_PLL_MODE);
 	reg &= ~(PLL_MODE_BYPASSNL | PLL_MODE_OUTCTRL | PLL_MODE_RESET_N);
-	writel_relaxed(reg, RIVA_PLL_MODE);
+	writel_relaxed(reg, cbase + RIVA_PLL_MODE);
 
 	if (use_cxo)
-		writel_relaxed(0x40000C00 | 50, RIVA_PLL_L_VAL);
+		writel_relaxed(0x40000C00 | 50, cbase + RIVA_PLL_L_VAL);
 	else
-		writel_relaxed(0x40000C00 | 40, RIVA_PLL_L_VAL);
-	writel_relaxed(0, RIVA_PLL_M_VAL);
-	writel_relaxed(1, RIVA_PLL_N_VAL);
-	writel_relaxed(0x01495227, RIVA_PLL_CONFIG);
+		writel_relaxed(0x40000C00 | 40, cbase + RIVA_PLL_L_VAL);
+	writel_relaxed(0, cbase + RIVA_PLL_M_VAL);
+	writel_relaxed(1, cbase + RIVA_PLL_N_VAL);
+	writel_relaxed(0x01495227, cbase + RIVA_PLL_CONFIG);
 
-	reg = readl_relaxed(RIVA_PLL_MODE);
+	reg = readl_relaxed(cbase + RIVA_PLL_MODE);
 	reg &= ~(PLL_MODE_REF_XO_SEL);
 	reg |= use_cxo ? PLL_MODE_REF_XO_SEL_CXO : PLL_MODE_REF_XO_SEL_RF;
-	writel_relaxed(reg, RIVA_PLL_MODE);
+	writel_relaxed(reg, cbase + RIVA_PLL_MODE);
 
 	/* Enable PLL 13 */
 	reg |= PLL_MODE_BYPASSNL;
-	writel_relaxed(reg, RIVA_PLL_MODE);
+	writel_relaxed(reg, cbase + RIVA_PLL_MODE);
 
 	/*
 	 * H/W requires a 5us delay between disabling the bypass and
@@ -185,9 +173,9 @@
 	usleep_range(10, 20);
 
 	reg |= PLL_MODE_RESET_N;
-	writel_relaxed(reg, RIVA_PLL_MODE);
+	writel_relaxed(reg, cbase + RIVA_PLL_MODE);
 	reg |= PLL_MODE_OUTCTRL;
-	writel_relaxed(reg, RIVA_PLL_MODE);
+	writel_relaxed(reg, cbase + RIVA_PLL_MODE);
 
 	/* Wait for PLL to settle */
 	mb();
@@ -241,20 +229,22 @@
 
 static int pil_riva_shutdown(struct pil_desc *pil)
 {
+	struct riva_data *drv = dev_get_drvdata(pil->dev);
+	void __iomem *cbase = drv->cbase;
+
 	/* Assert reset to Riva */
-	writel_relaxed(1, RIVA_RESET);
+	writel_relaxed(1, cbase + RIVA_RESET);
 	mb();
 	usleep_range(1000, 2000);
 
 	/* Deassert reset to Riva */
-	writel_relaxed(0, RIVA_RESET);
+	writel_relaxed(0, cbase + RIVA_RESET);
 	mb();
 
 	return 0;
 }
 
 static struct pil_reset_ops pil_riva_ops = {
-	.init_image = pil_riva_init_image,
 	.auth_and_reset = pil_riva_reset,
 	.shutdown = pil_riva_shutdown,
 	.proxy_vote = pil_riva_make_proxy_vote,
@@ -374,15 +364,10 @@
 
 static int riva_start(const struct subsys_desc *desc)
 {
-	void *ret;
 	struct riva_data *drv;
 
 	drv = container_of(desc, struct riva_data, subsys_desc);
-
-	ret = pil_get("wcnss");
-	if (IS_ERR(ret))
-		return PTR_ERR(ret);
-	return 0;
+	return pil_boot(&drv->pil_desc);
 }
 
 static void riva_stop(const struct subsys_desc *desc)
@@ -390,7 +375,7 @@
 	struct riva_data *drv;
 
 	drv = container_of(desc, struct riva_data, subsys_desc);
-	pil_put(drv->pil);
+	pil_shutdown(&drv->pil_desc);
 }
 
 static int riva_shutdown(const struct subsys_desc *desc)
@@ -398,7 +383,7 @@
 	struct riva_data *drv;
 
 	drv = container_of(desc, struct riva_data, subsys_desc);
-	pil_force_shutdown("wcnss");
+	pil_shutdown(&drv->pil_desc);
 	flush_delayed_work(&drv->cancel_work);
 	wcnss_flush_delayed_boot_votes();
 	disable_irq_nosync(drv->irq);
@@ -418,7 +403,7 @@
 		ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
 					WCNSS_WLAN_SWITCH_ON);
 		if (!ret)
-			pil_force_boot("wcnss");
+			pil_boot(&drv->pil_desc);
 	}
 	drv->rst_in_progress = 0;
 	enable_irq(drv->irq);
@@ -467,21 +452,20 @@
 	struct pil_desc *desc;
 	int ret;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		return -EINVAL;
-
 	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
 	if (!drv)
 		return -ENOMEM;
 	platform_set_drvdata(pdev, drv);
 
-	drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	drv->base = devm_request_and_ioremap(&pdev->dev, res);
 	if (!drv->base)
 		return -ENOMEM;
 
-	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
-	if (!desc)
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	drv->cbase = devm_request_and_ioremap(&pdev->dev, res);
+	if (!drv->cbase)
 		return -ENOMEM;
 
 	drv->pll_supply = devm_regulator_get(&pdev->dev, "pll_vdd");
@@ -509,6 +493,11 @@
 	if (drv->irq < 0)
 		return drv->irq;
 
+	drv->xo = devm_clk_get(&pdev->dev, "cxo");
+	if (IS_ERR(drv->xo))
+		return PTR_ERR(drv->xo);
+
+	desc = &drv->pil_desc;
 	desc->name = "wcnss";
 	desc->dev = &pdev->dev;
 	desc->owner = THIS_MODULE;
@@ -521,14 +510,7 @@
 		desc->ops = &pil_riva_ops;
 		dev_info(&pdev->dev, "using non-secure boot\n");
 	}
-
-	drv->xo = devm_clk_get(&pdev->dev, "cxo");
-	if (IS_ERR(drv->xo))
-		return PTR_ERR(drv->xo);
-
-	drv->pil = msm_pil_register(desc);
-	if (IS_ERR(drv->pil))
-		return PTR_ERR(drv->pil);
+	ret = pil_desc_init(desc);
 
 	ret = smsm_state_cb_register(SMSM_WCNSS_STATE, SMSM_RESET,
 					smsm_state_cb_hdlr, drv);
@@ -547,7 +529,7 @@
 
 	INIT_DELAYED_WORK(&drv->cancel_work, riva_post_bootup);
 
-	drv->ramdump_dev = create_ramdump_device("riva");
+	drv->ramdump_dev = create_ramdump_device("riva", &pdev->dev);
 	if (!drv->ramdump_dev) {
 		ret = -ENOMEM;
 		goto err_ramdump;
@@ -573,7 +555,7 @@
 	smsm_state_cb_deregister(SMSM_WCNSS_STATE, SMSM_RESET,
 					smsm_state_cb_hdlr, drv);
 err_smsm:
-	msm_pil_unregister(drv->pil);
+	pil_desc_release(desc);
 	return ret;
 }
 
@@ -585,7 +567,7 @@
 	destroy_ramdump_device(drv->ramdump_dev);
 	smsm_state_cb_deregister(SMSM_WCNSS_STATE, SMSM_RESET,
 					smsm_state_cb_hdlr, drv);
-	msm_pil_unregister(drv->pil);
+	pil_desc_release(&drv->pil_desc);
 
 	return 0;
 }
diff --git a/arch/arm/mach-msm/pil-tzapps.c b/arch/arm/mach-msm/pil-tzapps.c
index be78fab..8658e6e 100644
--- a/arch/arm/mach-msm/pil-tzapps.c
+++ b/arch/arm/mach-msm/pil-tzapps.c
@@ -13,17 +13,15 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/elf.h>
 #include <linux/err.h>
 
-#include <mach/peripheral-loader.h>
 #include <mach/subsystem_restart.h>
 
 #include "peripheral-loader.h"
 #include "scm-pas.h"
 
 struct tzapps_data {
-	struct pil_device *pil;
+	struct pil_desc pil_desc;
 	struct subsys_device *subsys;
 	struct subsys_desc subsys_desc;
 };
@@ -54,44 +52,39 @@
 
 static int tzapps_start(const struct subsys_desc *desc)
 {
-	void *ret;
+	struct tzapps_data *drv = subsys_to_drv(desc);
 
-	ret = pil_get("tzapps");
-	if (IS_ERR(ret))
-		return PTR_ERR(ret);
-	return 0;
+	return pil_boot(&drv->pil_desc);
 }
 
 static void tzapps_stop(const struct subsys_desc *desc)
 {
 	struct tzapps_data *drv = subsys_to_drv(desc);
-	pil_put(drv->pil);
+	pil_shutdown(&drv->pil_desc);
 }
 
 static int __devinit pil_tzapps_driver_probe(struct platform_device *pdev)
 {
 	struct pil_desc *desc;
 	struct tzapps_data *drv;
+	int ret;
 
 	if (pas_supported(PAS_TZAPPS) < 0)
 		return -ENOSYS;
 
-	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
-	if (!desc)
-		return -ENOMEM;
-
 	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
 	if (!drv)
 		return -ENOMEM;
 	platform_set_drvdata(pdev, drv);
 
+	desc = &drv->pil_desc;
 	desc->name = "tzapps";
 	desc->dev = &pdev->dev;
 	desc->ops = &pil_tzapps_ops;
 	desc->owner = THIS_MODULE;
-	drv->pil = msm_pil_register(desc);
-	if (IS_ERR(drv->pil))
-		return PTR_ERR(drv->pil);
+	ret = pil_desc_init(desc);
+	if (ret)
+		return ret;
 
 	drv->subsys_desc.name = "tzapps";
 	drv->subsys_desc.dev = &pdev->dev;
@@ -101,7 +94,7 @@
 
 	drv->subsys = subsys_register(&drv->subsys_desc);
 	if (IS_ERR(drv->subsys)) {
-		msm_pil_unregister(drv->pil);
+		pil_desc_release(desc);
 		return PTR_ERR(drv->subsys);
 	}
 	return 0;
@@ -111,7 +104,7 @@
 {
 	struct tzapps_data *drv = platform_get_drvdata(pdev);
 	subsys_unregister(drv->subsys);
-	msm_pil_unregister(drv->pil);
+	pil_desc_release(&drv->pil_desc);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/pil-venus.c b/arch/arm/mach-msm/pil-venus.c
index e3125cf..47799cc 100644
--- a/arch/arm/mach-msm/pil-venus.c
+++ b/arch/arm/mach-msm/pil-venus.c
@@ -13,7 +13,6 @@
 #include <linux/kernel.h>
 #include <linux/err.h>
 #include <linux/io.h>
-#include <linux/elf.h>
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -29,7 +28,6 @@
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
 #include <mach/subsystem_restart.h>
-#include <mach/peripheral-loader.h>
 
 #include "peripheral-loader.h"
 #include "scm-pas.h"
@@ -67,11 +65,10 @@
 struct venus_data {
 	void __iomem *venus_wrapper_base;
 	void __iomem *venus_vbif_base;
-	struct pil_device *pil;
+	struct pil_desc desc;
 	struct subsys_device *subsys;
 	struct subsys_desc subsys_desc;
 	struct regulator *gdsc;
-	phys_addr_t start_addr;
 	struct clk *clks[ARRAY_SIZE(clk_names)];
 	struct device *iommu_fw_ctx;
 	struct iommu_domain *iommu_fw_domain;
@@ -184,22 +181,29 @@
 	regulator_disable(drv->gdsc);
 }
 
-static int pil_venus_init_image(struct pil_desc *pil, const u8 *metadata,
-		size_t size)
+static int pil_venus_mem_setup(struct pil_desc *pil, phys_addr_t addr,
+			       size_t size)
 {
-	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
+	int domain;
 	struct venus_data *drv = dev_get_drvdata(pil->dev);
 
-	drv->start_addr = ehdr->e_entry;
-
-	if (drv->start_addr < drv->fw_min_paddr ||
-	    drv->start_addr >= drv->fw_max_paddr) {
-		dev_err(pil->dev, "fw start addr is not within valid range\n");
-		return -EINVAL;
+	/* TODO: unregister? */
+	if (!drv->venus_domain_num) {
+		size = round_up(size, SZ_4K);
+		domain = venus_register_domain(size);
+		if (domain < 0) {
+			dev_err(pil->dev, "Venus fw iommu domain register failed\n");
+			return -ENODEV;
+		}
+		drv->iommu_fw_domain = msm_get_iommu_domain(domain);
+		if (!drv->iommu_fw_domain) {
+			dev_err(pil->dev, "No iommu fw domain found\n");
+			return -ENODEV;
+		}
+		drv->venus_domain_num = domain;
+		drv->fw_sz = size;
 	}
 
-	drv->fw_sz = drv->fw_max_paddr - drv->start_addr;
-
 	return 0;
 }
 
@@ -208,7 +212,7 @@
 	int rc;
 	struct venus_data *drv = dev_get_drvdata(pil->dev);
 	void __iomem *wrapper_base = drv->venus_wrapper_base;
-	phys_addr_t pa = drv->start_addr;
+	phys_addr_t pa = pil_get_entry_addr(pil);
 	unsigned long iova;
 
 	/*
@@ -327,7 +331,7 @@
 }
 
 static struct pil_reset_ops pil_venus_ops = {
-	.init_image = pil_venus_init_image,
+	.mem_setup = pil_venus_mem_setup,
 	.auth_and_reset = pil_venus_reset,
 	.shutdown = pil_venus_shutdown,
 	.proxy_vote = pil_venus_make_proxy_vote,
@@ -389,19 +393,15 @@
 
 static int venus_start(const struct subsys_desc *desc)
 {
-	void *ret;
 	struct venus_data *drv = subsys_to_drv(desc);
 
-	ret = pil_get(drv->subsys_desc.name);
-	if (IS_ERR(ret))
-		return PTR_ERR(ret);
-	return 0;
+	return pil_boot(&drv->desc);
 }
 
 static void venus_stop(const struct subsys_desc *desc)
 {
 	struct venus_data *drv = subsys_to_drv(desc);
-	pil_put(drv->pil);
+	pil_shutdown(&drv->desc);
 }
 
 static int __devinit pil_venus_probe(struct platform_device *pdev)
@@ -411,27 +411,20 @@
 	struct pil_desc *desc;
 	int rc;
 
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-					    "wrapper_base");
-	if (!res)
-		return -EINVAL;
-
 	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
 	if (!drv)
 		return -ENOMEM;
 	platform_set_drvdata(pdev, drv);
 
-	drv->venus_wrapper_base = devm_ioremap(&pdev->dev, res->start,
-					resource_size(res));
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+					    "wrapper_base");
+	drv->venus_wrapper_base = devm_request_and_ioremap(&pdev->dev, res);
 	if (!drv->venus_wrapper_base)
 		return -ENOMEM;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vbif_base");
-	if (!res)
-		return -EINVAL;
-
-	drv->venus_vbif_base = devm_ioremap(&pdev->dev, res->start,
-					resource_size(res));
+	drv->venus_vbif_base = devm_request_and_ioremap(&pdev->dev, res);
 	if (!drv->venus_vbif_base)
 		return -ENOMEM;
 
@@ -451,45 +444,7 @@
 		return -ENODEV;
 	}
 
-	/* Get fw address boundaries */
-	rc = of_property_read_u32(pdev->dev.of_node,
-				  "qcom,firmware-max-paddr",
-				  &drv->fw_max_paddr);
-	if (rc) {
-		dev_err(&pdev->dev, "Failed to get fw max paddr\n");
-		return rc;
-	}
-
-	rc = of_property_read_u32(pdev->dev.of_node,
-				  "qcom,firmware-min-paddr",
-				  &drv->fw_min_paddr);
-	if (rc) {
-		dev_err(&pdev->dev, "Failed to get fw min paddr\n");
-		return rc;
-	}
-
-	if (drv->fw_max_paddr <= drv->fw_min_paddr) {
-		dev_err(&pdev->dev, "Invalid fw max paddr or min paddr\n");
-		return -EINVAL;
-	}
-
-	drv->venus_domain_num =
-		venus_register_domain(drv->fw_max_paddr - drv->fw_min_paddr);
-	if (drv->venus_domain_num < 0) {
-		dev_err(&pdev->dev, "Venus fw iommu domain register failed\n");
-		return -ENODEV;
-	}
-
-	drv->iommu_fw_domain = msm_get_iommu_domain(drv->venus_domain_num);
-	if (!drv->iommu_fw_domain) {
-		dev_err(&pdev->dev, "No iommu fw domain found\n");
-		return -ENODEV;
-	}
-
-	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
-	if (!desc)
-		return -ENOMEM;
-
+	desc = &drv->desc;
 	rc = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
 				      &desc->name);
 	if (rc)
@@ -507,9 +462,9 @@
 		dev_info(&pdev->dev, "using non-secure boot\n");
 	}
 
-	drv->pil = msm_pil_register(desc);
-	if (IS_ERR(drv->pil))
-		return PTR_ERR(drv->pil);
+	rc = pil_desc_init(desc);
+	if (rc)
+		return rc;
 
 	drv->subsys_desc.name = desc->name;
 	drv->subsys_desc.owner = THIS_MODULE;
@@ -519,7 +474,7 @@
 
 	drv->subsys = subsys_register(&drv->subsys_desc);
 	if (IS_ERR(drv->subsys)) {
-		msm_pil_unregister(drv->pil);
+		pil_desc_release(desc);
 		return PTR_ERR(drv->subsys);
 	}
 
@@ -530,7 +485,7 @@
 {
 	struct venus_data *drv = platform_get_drvdata(pdev);
 	subsys_unregister(drv->subsys);
-	msm_pil_unregister(drv->pil);
+	pil_desc_release(&drv->desc);
 
 	return 0;
 }
diff --git a/arch/arm/mach-msm/pil-vidc.c b/arch/arm/mach-msm/pil-vidc.c
index b2609b1..42bb51c 100644
--- a/arch/arm/mach-msm/pil-vidc.c
+++ b/arch/arm/mach-msm/pil-vidc.c
@@ -13,11 +13,9 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/elf.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 
-#include <mach/peripheral-loader.h>
 #include <mach/subsystem_restart.h>
 
 #include "peripheral-loader.h"
@@ -26,7 +24,7 @@
 struct vidc_data {
 	struct clk *smmu_iface;
 	struct clk *core;
-	struct pil_device *pil;
+	struct pil_desc pil_desc;
 	struct subsys_device *subsys;
 	struct subsys_desc subsys_desc;
 };
@@ -72,32 +70,25 @@
 
 static int vidc_start(const struct subsys_desc *desc)
 {
-	void *ret;
-
-	ret = pil_get("vidc");
-	if (IS_ERR(ret))
-		return PTR_ERR(ret);
-	return 0;
+	struct vidc_data *drv = subsys_to_drv(desc);
+	return pil_boot(&drv->pil_desc);
 }
 
 static void vidc_stop(const struct subsys_desc *desc)
 {
 	struct vidc_data *drv = subsys_to_drv(desc);
-	pil_put(drv->pil);
+	pil_shutdown(&drv->pil_desc);
 }
 
 static int __devinit pil_vidc_driver_probe(struct platform_device *pdev)
 {
 	struct pil_desc *desc;
 	struct vidc_data *drv;
+	int ret;
 
 	if (pas_supported(PAS_VIDC) < 0)
 		return -ENOSYS;
 
-	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
-	if (!desc)
-		return -ENOMEM;
-
 	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
 	if (!drv)
 		return -ENOMEM;
@@ -111,13 +102,14 @@
 	if (IS_ERR(drv->core))
 		return PTR_ERR(drv->core);
 
+	desc = &drv->pil_desc;
 	desc->name = "vidc";
 	desc->dev = &pdev->dev;
 	desc->ops = &pil_vidc_ops;
 	desc->owner = THIS_MODULE;
-	drv->pil = msm_pil_register(desc);
-	if (IS_ERR(drv->pil))
-		return PTR_ERR(drv->pil);
+	ret = pil_desc_init(desc);
+	if (ret)
+		return ret;
 
 	drv->subsys_desc.name = "vidc";
 	drv->subsys_desc.dev = &pdev->dev;
@@ -127,7 +119,7 @@
 
 	drv->subsys = subsys_register(&drv->subsys_desc);
 	if (IS_ERR(drv->subsys)) {
-		msm_pil_unregister(drv->pil);
+		pil_desc_release(desc);
 		return PTR_ERR(drv->subsys);
 	}
 	return 0;
@@ -137,7 +129,7 @@
 {
 	struct vidc_data *drv = platform_get_drvdata(pdev);
 	subsys_unregister(drv->subsys);
-	msm_pil_unregister(drv->pil);
+	pil_desc_release(&drv->pil_desc);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/platsmp-8910.c b/arch/arm/mach-msm/platsmp-8910.c
index 5d055bd..af2f496 100644
--- a/arch/arm/mach-msm/platsmp-8910.c
+++ b/arch/arm/mach-msm/platsmp-8910.c
@@ -32,7 +32,7 @@
  * control for which core is the next to come out of the secondary
  * boot "holding pen"
  */
-volatile int __cpuinitdata pen_release = -1;
+volatile int pen_release = -1;
 
 /*
  * Write pen_release in a way that is guaranteed to be visible to all
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index 5f05f98..0933d20 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -103,8 +103,7 @@
 	if (!base_ptr)
 		return -ENODEV;
 
-	if (machine_is_msm8974_sim() || machine_is_mpq8092_sim() ||
-	    machine_is_msm8226_sim()) {
+	if (machine_is_msm8974_sim() || machine_is_mpq8092_sim()) {
 		writel_relaxed(0x800, base_ptr+0x04);
 		writel_relaxed(0x3FFF, base_ptr+0x14);
 	}
@@ -179,8 +178,7 @@
 	if (cpu_is_msm8x60())
 		return scorpion_release_secondary();
 
-	if (machine_is_msm8974_sim() || machine_is_mpq8092_sim() ||
-	    machine_is_msm8226_sim())
+	if (machine_is_msm8974_sim() || machine_is_mpq8092_sim())
 		return krait_release_secondary_sim(0xf9088000, cpu);
 
 	if (soc_class_is_msm8960() || soc_class_is_msm8930() ||
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index f55d509..550bb56 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -35,7 +35,7 @@
 #include <asm/hardware/gic.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
-#include <asm/hardware/cache-l2x0.h>
+#include <asm/outercache.h>
 #ifdef CONFIG_VFP
 #include <asm/vfp.h>
 #endif
@@ -51,7 +51,8 @@
 #include "timer.h"
 #include "pm-boot.h"
 #include <mach/event_timer.h>
-
+#define CREATE_TRACE_POINTS
+#include "trace_msm_low_power.h"
 /******************************************************************************
  * Debug Definitions
  *****************************************************************************/
@@ -114,6 +115,7 @@
 		"standalone_power_collapse",
 };
 
+static struct msm_pm_init_data_type msm_pm_init_data;
 static struct hrtimer pm_hrtimer;
 static struct msm_pm_sleep_ops pm_sleep_ops;
 /*
@@ -473,7 +475,6 @@
 }
 
 static void *msm_pm_idle_rs_limits;
-static bool msm_pm_use_qtimer;
 
 static void msm_pm_swfi(void)
 {
@@ -499,24 +500,6 @@
 	msm_pm_config_hw_after_retention();
 }
 
-#ifdef CONFIG_CACHE_L2X0
-static inline bool msm_pm_l2x0_power_collapse(void)
-{
-	bool collapsed = 0;
-
-	l2cc_suspend();
-	collapsed = msm_pm_collapse();
-	l2cc_resume();
-
-	return collapsed;
-}
-#else
-static inline bool msm_pm_l2x0_power_collapse(void)
-{
-	return msm_pm_collapse();
-}
-#endif
-
 static bool __ref msm_pm_spm_power_collapse(
 	unsigned int cpu, bool from_idle, bool notify_rpm)
 {
@@ -547,7 +530,7 @@
 #ifdef CONFIG_VFP
 	vfp_pm_suspend();
 #endif
-	collapsed = msm_pm_l2x0_power_collapse();
+	collapsed = msm_pm_collapse();
 
 	msm_pm_boot_config_after_pc(cpu);
 
@@ -576,11 +559,13 @@
 {
 	unsigned int cpu = smp_processor_id();
 	unsigned int avsdscr_setting;
+	unsigned int avscsr_enable;
 	bool collapsed;
 
 	avsdscr_setting = avs_get_avsdscr();
-	avs_disable();
+	avscsr_enable = avs_disable();
 	collapsed = msm_pm_spm_power_collapse(cpu, from_idle, false);
+	avs_enable(avscsr_enable);
 	avs_reset_delays(avsdscr_setting);
 	return collapsed;
 }
@@ -590,6 +575,7 @@
 	unsigned int cpu = smp_processor_id();
 	unsigned long saved_acpuclk_rate;
 	unsigned int avsdscr_setting;
+	unsigned int avscsr_enable;
 	bool collapsed;
 
 	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
@@ -601,7 +587,7 @@
 		pr_info("CPU%u: %s: pre power down\n", cpu, __func__);
 
 	avsdscr_setting = avs_get_avsdscr();
-	avs_disable();
+	avscsr_enable = avs_disable();
 
 	if (cpu_online(cpu))
 		saved_acpuclk_rate = acpuclk_power_collapse();
@@ -643,6 +629,7 @@
 	}
 
 
+	avs_enable(avscsr_enable);
 	avs_reset_delays(avsdscr_setting);
 	msm_pm_config_hw_after_power_up();
 	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
@@ -657,14 +644,11 @@
 {
 	if (cpu_is_apq8064())
 		msm_pm_save_cp15 = true;
-
-	if (cpu_is_msm8974())
-		msm_pm_use_qtimer = true;
 }
 
 static int64_t msm_pm_timer_enter_idle(void)
 {
-	if (msm_pm_use_qtimer)
+	if (msm_pm_init_data.use_sync_timer)
 		return ktime_to_ns(tick_nohz_get_sleep_length());
 
 	return msm_timer_enter_idle();
@@ -672,7 +656,7 @@
 
 static void msm_pm_timer_exit_idle(bool timer_halted)
 {
-	if (msm_pm_use_qtimer)
+	if (msm_pm_init_data.use_sync_timer)
 		return;
 
 	msm_timer_exit_idle((int) timer_halted);
@@ -682,7 +666,7 @@
 {
 	int64_t time = 0;
 
-	if (msm_pm_use_qtimer)
+	if (msm_pm_init_data.use_sync_timer)
 		return sched_clock();
 
 	time = msm_timer_get_sclk_time(period);
@@ -694,7 +678,7 @@
 
 static int64_t msm_pm_timer_exit_suspend(int64_t time, int64_t period)
 {
-	if (msm_pm_use_qtimer)
+	if (msm_pm_init_data.use_sync_timer)
 		return sched_clock() - time;
 
 	if (time != 0) {
@@ -741,6 +725,51 @@
 	return;
 }
 
+static inline void msm_pm_ftrace_lpm_enter(unsigned int cpu,
+		uint32_t latency, uint32_t sleep_us,
+		uint32_t wake_up,
+		enum msm_pm_sleep_mode mode)
+{
+	switch (mode) {
+	case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
+		trace_msm_pm_enter_wfi(cpu, latency, sleep_us, wake_up);
+		break;
+	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
+		trace_msm_pm_enter_spc(cpu, latency, sleep_us, wake_up);
+		break;
+	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
+		trace_msm_pm_enter_pc(cpu, latency, sleep_us, wake_up);
+		break;
+	case MSM_PM_SLEEP_MODE_RETENTION:
+		trace_msm_pm_enter_ret(cpu, latency, sleep_us, wake_up);
+		break;
+	default:
+		break;
+	}
+}
+
+static inline void msm_pm_ftrace_lpm_exit(unsigned int cpu,
+		enum msm_pm_sleep_mode mode,
+		bool success)
+{
+	switch (mode) {
+	case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
+		trace_msm_pm_exit_wfi(cpu, success);
+		break;
+	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
+		trace_msm_pm_exit_spc(cpu, success);
+		break;
+	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
+		trace_msm_pm_exit_pc(cpu, success);
+		break;
+	case MSM_PM_SLEEP_MODE_RETENTION:
+		trace_msm_pm_exit_ret(cpu, success);
+		break;
+	default:
+		break;
+	}
+}
+
 int msm_pm_idle_prepare(struct cpuidle_device *dev,
 		struct cpuidle_driver *drv, int index)
 {
@@ -845,6 +874,11 @@
 
 	if (modified_time_us && !dev->cpu)
 		msm_pm_set_timer(modified_time_us);
+
+	msm_pm_ftrace_lpm_enter(dev->cpu, time_param.latency_us,
+			time_param.sleep_us, time_param.next_event_us,
+			ret);
+
 	return ret;
 }
 
@@ -852,6 +886,7 @@
 {
 	int64_t time;
 	int exit_stat;
+	bool collapsed = 1;
 
 	if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
 		pr_info("CPU%u: %s: mode %d\n",
@@ -871,7 +906,7 @@
 		break;
 
 	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
-		msm_pm_power_collapse_standalone(true);
+		collapsed = msm_pm_power_collapse_standalone(true);
 		exit_stat = MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
 		break;
 
@@ -882,8 +917,6 @@
 		int ret = -ENODEV;
 		int notify_rpm =
 			(sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE);
-		int collapsed;
-
 		timer_expiration = msm_pm_timer_enter_idle();
 
 		sleep_delay = (uint32_t) msm_pm_convert_and_cap_time(
@@ -918,6 +951,8 @@
 
 	time = ktime_to_ns(ktime_get()) - time;
 	msm_pm_add_stat(exit_stat, time);
+	msm_pm_ftrace_lpm_exit(smp_processor_id(), sleep_mode,
+				collapsed);
 
 	do_div(time, 1000);
 	return (int) time;
@@ -1165,3 +1200,73 @@
 }
 
 late_initcall(msm_pm_init);
+
+static void __devinit msm_pm_set_flush_fn(uint32_t pc_mode)
+{
+	msm_pm_disable_l2_fn = NULL;
+	msm_pm_enable_l2_fn = NULL;
+	msm_pm_flush_l2_fn = outer_flush_all;
+
+	if (pc_mode == MSM_PM_PC_NOTZ_L2_EXT) {
+		msm_pm_disable_l2_fn = outer_disable;
+		msm_pm_enable_l2_fn = outer_resume;
+	}
+}
+
+static int __devinit msm_pm_8x60_probe(struct platform_device *pdev)
+{
+	char *key = NULL;
+	uint32_t val = 0;
+	int ret = 0;
+
+	if (!pdev->dev.of_node) {
+		struct msm_pm_init_data_type *d = pdev->dev.platform_data;
+
+		if (!d)
+			goto pm_8x60_probe_done;
+
+		msm_pm_init_data.pc_mode = d->pc_mode;
+		msm_pm_set_flush_fn(msm_pm_init_data.pc_mode);
+		msm_pm_init_data.use_sync_timer = d->use_sync_timer;
+	} else {
+		key = "qcom,pc-mode";
+		ret = of_property_read_u32(pdev->dev.of_node, key, &val);
+
+		if (ret) {
+			pr_debug("%s: Cannot read %s,defaulting to 0",
+					__func__, key);
+			val = MSM_PM_PC_TZ_L2_INT;
+			ret = 0;
+		}
+
+		msm_pm_init_data.pc_mode = val;
+		msm_pm_set_flush_fn(msm_pm_init_data.pc_mode);
+
+		key = "qcom,use-sync-timer";
+		msm_pm_init_data.use_sync_timer =
+			of_property_read_bool(pdev->dev.of_node, key);
+	}
+
+pm_8x60_probe_done:
+	return ret;
+}
+
+static struct of_device_id msm_pm_8x60_table[] = {
+		{.compatible = "qcom,pm-8x60"},
+		{},
+};
+
+static struct platform_driver msm_pm_8x60_driver = {
+		.probe = msm_pm_8x60_probe,
+		.driver = {
+			.name = "pm-8x60",
+			.owner = THIS_MODULE,
+			.of_match_table = msm_pm_8x60_table,
+		},
+};
+
+static int __init msm_pm_8x60_init(void)
+{
+	return platform_driver_register(&msm_pm_8x60_driver);
+}
+module_init(msm_pm_8x60_init);
diff --git a/arch/arm/mach-msm/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
index 7bc4fe0..f32e149 100644
--- a/arch/arm/mach-msm/pm-boot.c
+++ b/arch/arm/mach-msm/pm-boot.c
@@ -158,13 +158,17 @@
 			msm_pm_boot_after_pc
 				= msm_pm_config_rst_vector_after_pc;
 		} else {
+			uint32_t mpa5_boot_remap_addr[2] = {0x34, 0x4C};
+			uint32_t mpa5_cfg_ctl[2] = {0x30, 0x48};
+
 			warm_boot_ptr = ioremap_nocache(
 						MSM8625_WARM_BOOT_PHYS, SZ_64);
 			ret = msm_pm_boot_reset_vector_init(warm_boot_ptr);
 
 			entry = virt_to_phys(msm_pm_boot_entry);
 
-			/* Below sequence is a work around for cores
+			/*
+			 * Below sequence is a work around for cores
 			 * to come out of GDFS properly on 8625 target.
 			 * On 8625 while cores coming out of GDFS observed
 			 * the memory corruption at very first memory read.
@@ -176,7 +180,8 @@
 			msm_pm_reset_vector[4] = 0xE12FFF10; /* bx  r0 */
 			msm_pm_reset_vector[5] = entry; /* 0x14 */
 
-			/* Here upper 16bits[16:31] used by CORE1
+			/*
+			 * Here upper 16bits[16:31] used by CORE1
 			 * lower 16bits[0:15] used by CORE0
 			 */
 			entry = (MSM8625_WARM_BOOT_PHYS |
@@ -184,17 +189,30 @@
 
 			/* write 'entry' to boot remapper register */
 			__raw_writel(entry, (pdata->v_addr +
-						MPA5_BOOT_REMAP_ADDR));
+						mpa5_boot_remap_addr[0]));
 
-			/* Enable boot remapper for C0 [bit:25th] */
+			/*
+			 * Enable boot remapper for C0 [bit:25th]
+			 * Enable boot remapper for C1 [bit:26th]
+			 */
 			__raw_writel(readl_relaxed(pdata->v_addr +
-					MPA5_CFG_CTL_REG) | BIT(25),
-					pdata->v_addr + MPA5_CFG_CTL_REG);
+					mpa5_cfg_ctl[0]) | (0x3 << 25),
+					pdata->v_addr + mpa5_cfg_ctl[0]);
 
-			/* Enable boot remapper for C1 [bit:26th] */
-			__raw_writel(readl_relaxed(pdata->v_addr +
-					MPA5_CFG_CTL_REG) | BIT(26),
-					pdata->v_addr + MPA5_CFG_CTL_REG);
+			/* 8x25Q changes */
+			if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 3) {
+				/* write 'entry' to boot remapper register */
+				__raw_writel(entry, (pdata->v_addr +
+						mpa5_boot_remap_addr[1]));
+
+				/*
+				 * Enable boot remapper for C2 [bit:25th]
+				 * Enable boot remapper for C3 [bit:26th]
+				 */
+				__raw_writel(readl_relaxed(pdata->v_addr +
+					mpa5_cfg_ctl[1]) | (0x3 << 25),
+					pdata->v_addr + mpa5_cfg_ctl[1]);
+			}
 			msm_pm_boot_before_pc = msm_pm_write_boot_vector;
 		}
 		break;
diff --git a/arch/arm/mach-msm/pm-boot.h b/arch/arm/mach-msm/pm-boot.h
index 30b67c21..e39ca75 100644
--- a/arch/arm/mach-msm/pm-boot.h
+++ b/arch/arm/mach-msm/pm-boot.h
@@ -15,7 +15,6 @@
 
 /* 8x25 specific macros */
 #define MPA5_CFG_CTL_REG	0x30
-#define MPA5_BOOT_REMAP_ADDR	0x34
 /* end */
 
 enum {
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 51256ca..faefe34 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -87,6 +87,20 @@
 			bool notify_rpm, bool collapsed);
 };
 
+enum msm_pm_pc_mode_type {
+	MSM_PM_PC_TZ_L2_INT = 0,   /*Power collapse terminates in TZ;
+					integrated L2 cache controller */
+	MSM_PM_PC_NOTZ_L2_EXT = 1, /* Power collapse doesn't terminate in
+					TZ; external L2 cache controller */
+	MSM_PM_PC_TZ_L2_EXT = 2,   /* Power collapse terminates in TZ;
+					external L2 cache controller */
+};
+
+struct msm_pm_init_data_type {
+	enum msm_pm_pc_mode_type pc_mode;
+	bool use_sync_timer;
+};
+
 struct msm_pm_cpr_ops {
 	void (*cpr_suspend)(void);
 	void (*cpr_resume)(void);
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index 427e39f..ae2a4bc 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -482,66 +482,71 @@
  * Program the top csr from core0 context to put the
  * core1 into GDFS, as core1 is not running yet.
  */
-static void configure_top_csr(void)
+static void msm_pm_configure_top_csr(void)
 {
+	/*
+	 * Enable TCSR for core
+	 * Set reset bit for SPM
+	 * Set CLK_OFF bit
+	 * Set clamps bit
+	 * Set power_up bit
+	 * Disable TSCR for core
+	 */
+	uint32_t bit_pos[][6] = {
+		/* c2 */
+		{17, 15, 13, 16, 14, 17},
+		/* c1 & c3*/
+		{22, 20, 18, 21, 19, 22},
+	};
+	uint32_t mpa5_cfg_ctl[2] = {0x30, 0x48};
 	void __iomem *base_ptr;
 	unsigned int value = 0;
+	unsigned int cpu;
+	int i;
 
-	base_ptr = core_reset_base(1);
-	if (!base_ptr)
-		return;
-
-	/* bring the core1 out of reset */
-	__raw_writel(0x3, base_ptr);
-	mb();
-	/*
-	 * override DBGNOPOWERDN and program the GDFS
-	 * count val
-	 */
-
-	 __raw_writel(0x00030002, (MSM_CFG_CTL_BASE + 0x38));
-	mb();
-
-	/* Initialize the SPM0 and SPM1 registers */
+	/* Initialize all the SPM registers */
 	msm_spm_reinit();
 
-	/* enable TCSR for core1 */
-	value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
-	value |= BIT(22);
-	__raw_writel(value,  MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
-	mb();
+	for_each_possible_cpu(cpu) {
+		/* skip for C0 */
+		if (!cpu)
+			continue;
 
-	/* set reset bit for SPM1 */
-	value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
-	value |= BIT(20);
-	__raw_writel(value,  MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
-	mb();
+		base_ptr = core_reset_base(cpu);
+		if (!base_ptr)
+			return;
 
-	/* set CLK_OFF bit */
-	value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
-	value |= BIT(18);
-	__raw_writel(value,  MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
-	mb();
+		/* bring the core out of reset */
+		__raw_writel(0x3, base_ptr);
+		mb();
 
-	/* set clamps bit */
-	value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
-	value |= BIT(21);
-	__raw_writel(value,  MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
-	mb();
+		/*
+		 * i == 0, Enable TCSR for core
+		 * i == 1, Set reset bit for SPM
+		 * i == 2, Set CLK_OFF bit
+		 * i == 3, Set clamps bit
+		 * i == 4, Set power_up bit
+		 */
+		for (i = 0; i < 5; i++) {
+			value = __raw_readl(MSM_CFG_CTL_BASE +
+							mpa5_cfg_ctl[cpu/2]);
+			value |= BIT(bit_pos[cpu%2][i]);
+			__raw_writel(value,  MSM_CFG_CTL_BASE +
+							mpa5_cfg_ctl[cpu/2]);
+			mb();
+		}
 
-	/* set power_up bit */
-	value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
-	value |= BIT(19);
-	__raw_writel(value,  MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
-	mb();
+		/* i == 5, Disable TCSR for core */
+		value = __raw_readl(MSM_CFG_CTL_BASE +
+						mpa5_cfg_ctl[cpu/2]);
+		value &= ~BIT(bit_pos[cpu%2][i]);
+		__raw_writel(value,  MSM_CFG_CTL_BASE +
+						mpa5_cfg_ctl[cpu/2]);
+		mb();
 
-	/* Disable TSCR for core0 */
-	value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
-	value &= ~BIT(22);
-	__raw_writel(value,  MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
-	mb();
-	__raw_writel(0x0, base_ptr);
-	mb();
+		__raw_writel(0x0, base_ptr);
+		mb();
+	}
 }
 
 /*
@@ -569,7 +574,7 @@
 			/*
 			 * Program the top csr to put the core1 into GDFS.
 			 */
-			configure_top_csr();
+			msm_pm_configure_top_csr();
 		}
 	} else {
 		__raw_writel(0, APPS_PWRDOWN);
@@ -981,17 +986,38 @@
 		/*
 		 * on system reset, default value of MPA5_GDFS_CNT_VAL
 		 * is = 0x0, later modem reprogram this value to
-		 * 0x00030004. Once APPS did a power collapse and
-		 * coming out of it expected value of this register
-		 * always be 0x00030004. Incase if APPS sees the value
-		 * as 0x00030002 consider this case as a modem early
-		 * exit.
+		 * 0x00030004/0x000F0004(8x25Q). Once APPS did
+		 * a power collapse and coming out of it expected value
+		 * of this register always be 0x00030004/0x000F0004(8x25Q).
+		 * Incase if APPS sees the value as 0x00030002/0x000F0002(8x25Q)
+		 * consider this case as a modem early exit.
 		 */
 		val = __raw_readl(MSM_CFG_CTL_BASE + 0x38);
-		if (val != 0x00030002)
-			power_collapsed = 1;
-		else
-			modem_early_exit = 1;
+
+		/* 8x25Q */
+		if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 3) {
+			if (val != 0x000F0002) {
+				power_collapsed = 1;
+				/*
+				 * override DBGNOPOWERDN and program the GDFS
+				 * count val
+				 */
+				 __raw_writel(0x000F0002,
+						 (MSM_CFG_CTL_BASE + 0x38));
+			} else
+				modem_early_exit = 1;
+		} else {
+			if (val != 0x00030002) {
+				power_collapsed = 1;
+				/*
+				 * override DBGNOPOWERDN and program the GDFS
+				 * count val
+				 */
+				 __raw_writel(0x00030002,
+						 (MSM_CFG_CTL_BASE + 0x38));
+			} else
+				modem_early_exit = 1;
+		}
 	}
 
 #ifdef CONFIG_CACHE_L2X0
@@ -1684,12 +1710,16 @@
 
 		/*
 		 * Configure the MPA5_GDFS_CNT_VAL register for
-		 * DBGPWRUPEREQ_OVERRIDE[17:16] = Override the
+		 * DBGPWRUPEREQ_OVERRIDE[19:16] = Override the
 		 * DBGNOPOWERDN for each cpu.
 		 * MPA5_GDFS_CNT_VAL[9:0] = Delay counter for
 		 * GDFS control.
 		 */
-		val = 0x00030002;
+		if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 3)
+			val = 0x000F0002;
+		else
+			val = 0x00030002;
+
 		__raw_writel(val, (MSM_CFG_CTL_BASE + 0x38));
 
 		l2x0_base_addr = MSM_L2CC_BASE;
diff --git a/arch/arm/mach-msm/pmu.c b/arch/arm/mach-msm/pmu.c
index 5e339da..c426ff9 100644
--- a/arch/arm/mach-msm/pmu.c
+++ b/arch/arm/mach-msm/pmu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -11,8 +11,65 @@
  */
 
 #include <linux/platform_device.h>
+#include <linux/irq.h>
 #include <asm/pmu.h>
 #include <mach/irqs.h>
+#include <mach/socinfo.h>
+
+#if defined(CONFIG_ARCH_MSM_KRAITMP) || defined(CONFIG_ARCH_MSM_SCORPIONMP) \
+	|| defined(CONFIG_ARCH_MSM8625)
+static DEFINE_PER_CPU(u32, pmu_irq_cookie);
+
+static void enable_irq_callback(void *info)
+{
+	int irq = *(unsigned int *)info;
+	enable_percpu_irq(irq, IRQ_TYPE_EDGE_RISING);
+}
+
+static void disable_irq_callback(void *info)
+{
+	int irq = *(unsigned int *)info;
+	disable_percpu_irq(irq);
+}
+
+static int
+multicore_request_irq(int irq, irq_handler_t *handle_irq)
+{
+	int err = 0;
+	int cpu;
+
+	err = request_percpu_irq(irq, *handle_irq, "l1-armpmu",
+			&pmu_irq_cookie);
+
+	if (!err) {
+		for_each_cpu(cpu, cpu_online_mask) {
+			smp_call_function_single(cpu,
+					enable_irq_callback, &irq, 1);
+		}
+	}
+
+	return err;
+}
+
+static void
+multicore_free_irq(int irq)
+{
+	int cpu;
+
+	if (irq >= 0) {
+		for_each_cpu(cpu, cpu_online_mask) {
+			smp_call_function_single(cpu,
+					disable_irq_callback, &irq, 1);
+		}
+		free_percpu_irq(irq, &pmu_irq_cookie);
+	}
+}
+
+static struct arm_pmu_platdata multicore_data = {
+	.request_pmu_irq = multicore_request_irq,
+	.free_pmu_irq = multicore_free_irq,
+};
+#endif
 
 static struct resource cpu_pmu_resource[] = {
 	{
@@ -47,6 +104,29 @@
 	.num_resources	= ARRAY_SIZE(cpu_pmu_resource),
 };
 
+/*
+ * The 8625 is a special case. Due to the requirement of a single
+ * kernel image for the 7x27a and 8625 (which share IRQ headers),
+ * this target breaks the uniformity of IRQ names.
+ * See the file - arch/arm/mach-msm/include/mach/irqs-8625.h
+ */
+#ifdef CONFIG_ARCH_MSM8625
+static struct resource msm8625_cpu_pmu_resource[] = {
+	{
+		.start = MSM8625_INT_ARMQC_PERFMON,
+		.end = MSM8625_INT_ARMQC_PERFMON,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm8625_cpu_pmu_device = {
+	.name		= "cpu-arm-pmu",
+	.id		= ARM_PMU_DEVICE_CPU,
+	.resource	= msm8625_cpu_pmu_resource,
+	.num_resources	= ARRAY_SIZE(msm8625_cpu_pmu_resource),
+};
+#endif
+
 static struct platform_device *pmu_devices[] = {
 	&cpu_pmu_device,
 #ifdef CONFIG_CPU_HAS_L2_PMU
@@ -56,6 +136,28 @@
 
 static int __init msm_pmu_init(void)
 {
+	/*
+	 * For the targets we know are multicore's set the request/free IRQ
+	 * handlers to call the percpu API.
+	 * Defaults to unicore API {request,free}_irq().
+	 * See arch/arm/kernel/perf_event.c
+	 */
+#if defined(CONFIG_ARCH_MSM_KRAITMP) || defined(CONFIG_ARCH_MSM_SCORPIONMP)
+	cpu_pmu_device.dev.platform_data = &multicore_data;
+#endif
+
+	/*
+	 * The 7x27a and 8625 require a single kernel image.
+	 * So we need to check if we're on an 8625 at runtime
+	 * and point to the appropriate 'struct resource'.
+	 */
+#ifdef CONFIG_ARCH_MSM8625
+	if (cpu_is_msm8625()) {
+		pmu_devices[0] = &msm8625_cpu_pmu_device;
+		msm8625_cpu_pmu_device.dev.platform_data = &multicore_data;
+	}
+#endif
+
 	return platform_add_devices(pmu_devices, ARRAY_SIZE(pmu_devices));
 }
 
diff --git a/arch/arm/mach-msm/qdsp6v2/Makefile b/arch/arm/mach-msm/qdsp6v2/Makefile
index 0f17a0b..66d6bda 100644
--- a/arch/arm/mach-msm/qdsp6v2/Makefile
+++ b/arch/arm/mach-msm/qdsp6v2/Makefile
@@ -27,4 +27,3 @@
 obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
 obj-$(CONFIG_MSM_ADSP_LOADER) += adsp-loader.o
 obj-$(CONFIG_MSM_ULTRASOUND_A) += ultrasound/version_a/
-obj-m += adsprpc.o
diff --git a/arch/arm/mach-msm/qdsp6v2/adsp-loader.c b/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
index 9924b52..c28e403 100644
--- a/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
+++ b/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
@@ -17,7 +17,7 @@
 #include <linux/err.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
-#include <mach/peripheral-loader.h>
+#include <mach/subsystem_restart.h>
 #include <mach/qdsp6v2/apr.h>
 
 #define Q6_PIL_GET_DELAY_MS 100
@@ -37,7 +37,7 @@
 
 	platform_set_drvdata(pdev, priv);
 
-	priv->pil_h = pil_get("adsp");
+	priv->pil_h = subsystem_get("adsp");
 	if (IS_ERR(priv->pil_h)) {
 		pr_err("%s: pil get adsp failed, error:%d\n", __func__, rc);
 		devm_kfree(&pdev->dev, priv);
@@ -62,7 +62,7 @@
 	struct adsp_loader_private *priv;
 
 	priv = platform_get_drvdata(pdev);
-	pil_put(priv->pil_h);
+	subsystem_put(priv->pil_h);
 	pr_info("%s: Q6/ADSP image is unloaded\n", __func__);
 
 	return 0;
diff --git a/arch/arm/mach-msm/qdsp6v2/apr.c b/arch/arm/mach-msm/qdsp6v2/apr.c
index 8ac1fea..39bec8e 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr.c
@@ -27,7 +27,7 @@
 #include <linux/device.h>
 #include <linux/slab.h>
 #include <asm/mach-types.h>
-#include <mach/peripheral-loader.h>
+#include <mach/subsystem_restart.h>
 #include <mach/msm_smd.h>
 #include <mach/qdsp6v2/apr.h>
 #include <mach/qdsp6v2/apr_tal.h>
@@ -223,7 +223,7 @@
 	int rc = 0;
 	mutex_lock(&q6.lock);
 	if (apr_get_q6_state() == APR_SUBSYS_UP) {
-		q6.pil = pil_get("q6");
+		q6.pil = subsystem_get("adsp");
 		if (IS_ERR(q6.pil)) {
 			rc = PTR_ERR(q6.pil);
 			pr_err("APR: Unable to load q6 image, error:%d\n", rc);
@@ -231,8 +231,11 @@
 			apr_set_q6_state(APR_SUBSYS_LOADED);
 			pr_debug("APR: Image is loaded, stated\n");
 		}
-	} else
+	} else if (apr_get_q6_state() == APR_SUBSYS_LOADED) {
+		pr_debug("APR: q6 image already loaded\n");
+	} else {
 		pr_debug("APR: cannot load state %d\n", apr_get_q6_state());
+	}
 	mutex_unlock(&q6.lock);
 	return rc;
 }
@@ -658,8 +661,8 @@
 		pr_debug("L-notify: Bootup started\n");
 		break;
 	case SUBSYS_AFTER_POWERUP:
-		if (apr_cmpxchg_q6_state(APR_SUBSYS_DOWN, APR_SUBSYS_UP) ==
-					     APR_SUBSYS_DOWN)
+		if (apr_cmpxchg_q6_state(APR_SUBSYS_DOWN,
+				APR_SUBSYS_LOADED) == APR_SUBSYS_DOWN)
 			wake_up(&dsp_wait);
 		pr_debug("L-Notify: Bootup Completed\n");
 		break;
@@ -703,7 +706,7 @@
 	init_waitqueue_head(&dsp_wait);
 	init_waitqueue_head(&modem_wait);
 	subsys_notif_register_notifier("modem", &mnb);
-	subsys_notif_register_notifier("lpass", &lnb);
+	subsys_notif_register_notifier(apr_get_lpass_subsys_name(), &lnb);
 	return ret;
 }
 late_initcall(apr_late_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/apr_v1.c b/arch/arm/mach-msm/qdsp6v2/apr_v1.c
index 9535968..870bbb4 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr_v1.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr_v1.c
@@ -19,7 +19,8 @@
 #include <mach/qdsp6v2/apr.h>
 #include <mach/qdsp6v2/apr_tal.h>
 #include <mach/qdsp6v2/dsp_debug.h>
-#include <mach/peripheral-loader.h>
+
+static const char *lpass_subsys_name = "lpass";
 
 struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
 			     uint32_t src_port, void *priv)
@@ -131,3 +132,8 @@
 	apr_set_q6_state(APR_SUBSYS_UP);
 	apr_set_modem_state(APR_SUBSYS_UP);
 }
+
+const char *apr_get_lpass_subsys_name(void)
+{
+	return lpass_subsys_name;
+}
diff --git a/arch/arm/mach-msm/qdsp6v2/apr_v2.c b/arch/arm/mach-msm/qdsp6v2/apr_v2.c
index 1ef189f..ed494e4 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr_v2.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr_v2.c
@@ -19,6 +19,8 @@
 #include <mach/qdsp6v2/apr_tal.h>
 #include <mach/qdsp6v2/dsp_debug.h>
 
+static const char *lpass_subsys_name = "adsp";
+
 struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
 			     uint32_t src_port, void *priv)
 {
@@ -48,7 +50,7 @@
 			pr_err("%s: adsp not up\n", __func__);
 			return NULL;
 		}
-		pr_info("%s: Lpass Up\n", __func__);
+		pr_info("%s: adsp Up\n", __func__);
 	} else if ((dest_id == APR_DEST_MODEM) &&
 		   (apr_get_modem_state() == APR_SUBSYS_DOWN)) {
 		pr_info("%s: Wait for modem to bootup\n", __func__);
@@ -125,3 +127,8 @@
 	apr_set_q6_state(APR_SUBSYS_DOWN);
 	apr_set_modem_state(APR_SUBSYS_UP);
 }
+
+const char *apr_get_lpass_subsys_name(void)
+{
+	return lpass_subsys_name;
+}
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index d6abdda..fb0ace7 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -779,6 +779,8 @@
 		__func__, audio, buf_node, buf_node->paddr,
 		buf_node->buf.data_len,
 		audio->buf_cfg.meta_info_enable);
+	pr_debug("%s[%p]: flags = 0x%x\n", __func__, audio,
+		buf_node->meta_info.meta_in.nflags);
 
 	ac = audio->ac;
 	/* Offset with  appropriate meta */
@@ -798,6 +800,11 @@
 		param.flags = 0;
 	else
 		param.flags = 0xFF00;
+
+	if ((buf_node != NULL) &&
+		(buf_node->meta_info.meta_in.nflags & AUDIO_DEC_EOF_SET))
+		param.flags |= AUDIO_DEC_EOF_SET;
+
 	param.uid = param.paddr;
 	/* Read command will populate paddr as token */
 	buf_node->token = param.paddr;
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
index b2829c3..dedf991 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
@@ -36,6 +36,7 @@
 #define ADRV_STATUS_FSYNC 0x00000008
 #define ADRV_STATUS_PAUSE 0x00000010
 #define AUDIO_DEC_EOS_SET  0x00000001
+#define AUDIO_DEC_EOF_SET  0x00000010
 #define AUDIO_EVENT_NUM		10
 
 #define __CONTAINS(r, v, l) ({                                  \
diff --git a/arch/arm/mach-msm/ramdump.c b/arch/arm/mach-msm/ramdump.c
index 21e81dd..e33ec48 100644
--- a/arch/arm/mach-msm/ramdump.c
+++ b/arch/arm/mach-msm/ramdump.c
@@ -181,7 +181,7 @@
 	.poll = ramdump_poll
 };
 
-void *create_ramdump_device(const char *dev_name)
+void *create_ramdump_device(const char *dev_name, struct device *parent)
 {
 	int ret;
 	struct ramdump_device *rd_dev;
@@ -207,6 +207,7 @@
 	rd_dev->device.minor = MISC_DYNAMIC_MINOR;
 	rd_dev->device.name = rd_dev->name;
 	rd_dev->device.fops = &ramdump_file_ops;
+	rd_dev->device.parent = parent;
 
 	init_waitqueue_head(&rd_dev->dump_wait_q);
 
diff --git a/arch/arm/mach-msm/ramdump.h b/arch/arm/mach-msm/ramdump.h
index 9006010..3e5bfaf 100644
--- a/arch/arm/mach-msm/ramdump.h
+++ b/arch/arm/mach-msm/ramdump.h
@@ -13,12 +13,14 @@
 #ifndef _RAMDUMP_HEADER
 #define _RAMDUMP_HEADER
 
+struct device;
+
 struct ramdump_segment {
 	unsigned long address;
 	unsigned long size;
 };
 
-void *create_ramdump_device(const char *dev_name);
+void *create_ramdump_device(const char *dev_name, struct device *parent);
 void destroy_ramdump_device(void *dev);
 int do_ramdump(void *handle, struct ramdump_segment *segments,
 		int nsegments);
diff --git a/arch/arm/mach-msm/rpm-notifier.h b/arch/arm/mach-msm/rpm-notifier.h
index 33086c6..b9815a5 100644
--- a/arch/arm/mach-msm/rpm-notifier.h
+++ b/arch/arm/mach-msm/rpm-notifier.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -47,4 +47,12 @@
  * msm_rpm_exit_sleep - Notify RPM driver about resuming from power collapse
  */
 void msm_rpm_exit_sleep(void);
+
+/**
+ * msm_rpm_waiting_for_ack - Indicate if there is RPM message
+ *				pending acknowledgement.
+ * returns true for pending messages and false otherwise
+ */
+bool msm_rpm_waiting_for_ack(void);
+
 #endif /*__ARCH_ARM_MACH_MSM_RPM_NOTIF_H */
diff --git a/arch/arm/mach-msm/rpm-regulator.c b/arch/arm/mach-msm/rpm-regulator.c
index 01543a2..4e5281d 100644
--- a/arch/arm/mach-msm/rpm-regulator.c
+++ b/arch/arm/mach-msm/rpm-regulator.c
@@ -19,7 +19,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/platform_device.h>
 #include <linux/wakelock.h>
@@ -299,12 +298,9 @@
 }
 
 static bool requires_tcxo_workaround;
-static bool tcxo_workaround_noirq;
 static struct clk *tcxo_handle;
 static struct wake_lock tcxo_wake_lock;
 static DEFINE_MUTEX(tcxo_mutex);
-/* Spin lock needed for sleep-selectable regulators. */
-static DEFINE_SPINLOCK(tcxo_noirq_lock);
 static bool tcxo_is_enabled;
 /*
  * TCXO must be kept on for at least the duration of its warmup (4 ms);
@@ -314,19 +310,10 @@
 
 static void tcxo_get_handle(void)
 {
-	int rc;
-
 	if (!tcxo_handle) {
 		tcxo_handle = clk_get_sys("rpm-regulator", "vref_buff");
-		if (IS_ERR(tcxo_handle)) {
+		if (IS_ERR(tcxo_handle))
 			tcxo_handle = NULL;
-		} else {
-			rc = clk_prepare(tcxo_handle);
-			if (rc) {
-				clk_put(tcxo_handle);
-				tcxo_handle = NULL;
-			}
-		}
 	}
 }
 
@@ -342,7 +329,7 @@
 	int rc;
 
 	if (tcxo_handle && !tcxo_is_enabled) {
-		rc = clk_enable(tcxo_handle);
+		rc = clk_prepare_enable(tcxo_handle);
 		if (!rc) {
 			tcxo_is_enabled = true;
 			wake_lock(&tcxo_wake_lock);
@@ -355,21 +342,13 @@
 
 static void tcxo_delayed_disable_work(struct work_struct *work)
 {
-	unsigned long flags = 0;
+	mutex_lock(&tcxo_mutex);
 
-	if (tcxo_workaround_noirq)
-		spin_lock_irqsave(&tcxo_noirq_lock, flags);
-	else
-		mutex_lock(&tcxo_mutex);
-
-	clk_disable(tcxo_handle);
+	clk_disable_unprepare(tcxo_handle);
 	tcxo_is_enabled = false;
 	wake_unlock(&tcxo_wake_lock);
 
-	if (tcxo_workaround_noirq)
-		spin_unlock_irqrestore(&tcxo_noirq_lock, flags);
-	else
-		mutex_unlock(&tcxo_mutex);
+	mutex_unlock(&tcxo_mutex);
 }
 
 static DECLARE_DELAYED_WORK(tcxo_disable_work, tcxo_delayed_disable_work);
@@ -387,8 +366,8 @@
 				msecs_to_jiffies(TCXO_WARMUP_TIME_MS) + 1);
 }
 
-/* Spin lock needed for sleep-selectable regulators. */
-static DEFINE_SPINLOCK(rpm_noirq_lock);
+/* Mutex lock needed for sleep-selectable regulators. */
+static DEFINE_MUTEX(rpm_sleep_sel_lock);
 
 static int voltage_from_req(struct vreg *vreg)
 {
@@ -421,7 +400,6 @@
 {
 	struct msm_rpm_iv_pair *prev_req;
 	int rc = 0, max_uV_vote = 0;
-	unsigned long flags = 0;
 	bool tcxo_enabled = false;
 	bool voltage_increased = false;
 	unsigned prev0, prev1;
@@ -470,17 +448,19 @@
 		if (requires_tcxo_workaround && vreg->requires_cxo
 		    && (set == MSM_RPM_CTX_SET_0)
 		    && (GET_PART(vreg, uV) > GET_PART_PREV_ACT(vreg, uV))) {
+			mutex_lock(&tcxo_mutex);
+			if (!tcxo_handle)
+				tcxo_get_handle();
 			voltage_increased = true;
-			spin_lock_irqsave(&tcxo_noirq_lock, flags);
 			tcxo_enabled = tcxo_enable();
 		}
 
-		rc = msm_rpmrs_set_noirq(set, vreg->req, cnt);
+		rc = msm_rpmrs_set(set, vreg->req, cnt);
 		if (rc) {
 			vreg->req[0].value = prev0;
 			vreg->req[1].value = prev1;
 
-			vreg_err(vreg, "msm_rpmrs_set_noirq failed - "
+			vreg_err(vreg, "msm_rpmrs_set failed - "
 				"set=%s, id=%d, rc=%d\n",
 				(set == MSM_RPM_CTX_SET_0 ? "active" : "sleep"),
 				vreg->req[0].id, rc);
@@ -502,7 +482,7 @@
 		if (voltage_increased) {
 			if (tcxo_enabled)
 				tcxo_delayed_disable();
-			spin_unlock_irqrestore(&tcxo_noirq_lock, flags);
+			mutex_unlock(&tcxo_mutex);
 		}
 	} else if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_DUPLICATE) {
 		rpm_regulator_duplicate(vreg, set, cnt);
@@ -511,19 +491,18 @@
 	return rc;
 }
 
-static int vreg_set_noirq(struct vreg *vreg, enum rpm_vreg_voter voter,
+static int vreg_set_sleep_sel(struct vreg *vreg, enum rpm_vreg_voter voter,
 			  int sleep, unsigned mask0, unsigned val0,
 			  unsigned mask1, unsigned val1, unsigned cnt,
 			  int update_voltage)
 {
 	unsigned int s_mask[2] = {mask0, mask1}, s_val[2] = {val0, val1};
-	unsigned long flags;
 	int rc;
 
 	if (voter < 0 || voter >= RPM_VREG_VOTER_COUNT)
 		return -EINVAL;
 
-	spin_lock_irqsave(&rpm_noirq_lock, flags);
+	mutex_lock(&rpm_sleep_sel_lock);
 
 	/*
 	 * Send sleep set request first so that subsequent set_mode, etc calls
@@ -559,7 +538,7 @@
 	rc = vreg_send_request(vreg, voter, MSM_RPM_CTX_SET_0, mask0, val0,
 					mask1, val1, cnt, update_voltage);
 
-	spin_unlock_irqrestore(&rpm_noirq_lock, flags);
+	mutex_unlock(&rpm_sleep_sel_lock);
 
 	return rc;
 }
@@ -575,10 +554,8 @@
  * Returns 0 on success or errno.
  *
  * This function is used to vote for the voltage of a regulator without
- * using the regulator framework.  It is needed by consumers which hold spin
- * locks or have interrupts disabled because the regulator framework can sleep.
- * It is also needed by consumers which wish to only vote for active set
- * regulator voltage.
+ * using the regulator framework.  It is needed for consumers which wish to only
+ * vote for active set regulator voltage.
  *
  * If sleep_also == 0, then a sleep-set value of 0V will be voted for.
  *
@@ -693,10 +670,10 @@
 		    = vreg->part->enable_state.mask;
 	}
 
-	rc = vreg_set_noirq(vreg, voter, sleep_also, mask[0], val[0], mask[1],
-			    val[1], vreg->part->request_len, 1);
+	rc = vreg_set_sleep_sel(vreg, voter, sleep_also, mask[0], val[0],
+				mask[1], val[1], vreg->part->request_len, 1);
 	if (rc)
-		vreg_err(vreg, "vreg_set_noirq failed, rc=%d\n", rc);
+		vreg_err(vreg, "vreg_set_sleep_sel failed, rc=%d\n", rc);
 
 	return rc;
 }
@@ -743,10 +720,10 @@
 	val[vreg->part->freq.word] = freq << vreg->part->freq.shift;
 	mask[vreg->part->freq.word] = vreg->part->freq.mask;
 
-	rc = vreg_set_noirq(vreg, RPM_VREG_VOTER_REG_FRAMEWORK, 1, mask[0],
+	rc = vreg_set_sleep_sel(vreg, RPM_VREG_VOTER_REG_FRAMEWORK, 1, mask[0],
 			   val[0], mask[1], val[1], vreg->part->request_len, 0);
 	if (rc)
-		vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
+		vreg_err(vreg, "vreg_set_sleep_sel failed, rc=%d\n", rc);
 
 	return rc;
 }
@@ -1018,10 +995,8 @@
 static int vreg_store(struct vreg *vreg, unsigned mask0, unsigned val0,
 		unsigned mask1, unsigned val1)
 {
-	unsigned long flags = 0;
-
 	if (vreg->pdata.sleep_selectable)
-		spin_lock_irqsave(&rpm_noirq_lock, flags);
+		mutex_lock(&rpm_sleep_sel_lock);
 
 	vreg->req[0].value &= ~mask0;
 	vreg->req[0].value |= val0 & mask0;
@@ -1030,7 +1005,7 @@
 	vreg->req[1].value |= val1 & mask1;
 
 	if (vreg->pdata.sleep_selectable)
-		spin_unlock_irqrestore(&rpm_noirq_lock, flags);
+		mutex_unlock(&rpm_sleep_sel_lock);
 
 	return 0;
 }
@@ -1039,7 +1014,6 @@
 		unsigned mask1, unsigned val1, unsigned cnt)
 {
 	unsigned prev0 = 0, prev1 = 0;
-	unsigned long flags = 0;
 	bool tcxo_enabled = false;
 	bool voltage_increased = false;
 	int rc;
@@ -1049,7 +1023,7 @@
 	 * just the active set values.
 	 */
 	if (vreg->pdata.sleep_selectable)
-		return vreg_set_noirq(vreg, RPM_VREG_VOTER_REG_FRAMEWORK, 1,
+		return vreg_set_sleep_sel(vreg, RPM_VREG_VOTER_REG_FRAMEWORK, 1,
 					mask0, val0, mask1, val1, cnt, 1);
 
 	prev0 = vreg->req[0].value;
@@ -1071,21 +1045,14 @@
 	/* Enable CXO clock if necessary for TCXO workaround. */
 	if (requires_tcxo_workaround && vreg->requires_cxo
 	    && (GET_PART(vreg, uV) > GET_PART_PREV_ACT(vreg, uV))) {
+		mutex_lock(&tcxo_mutex);
 		if (!tcxo_handle)
 			tcxo_get_handle();
-		if (tcxo_workaround_noirq)
-			spin_lock_irqsave(&tcxo_noirq_lock, flags);
-		else
-			mutex_lock(&tcxo_mutex);
-
 		voltage_increased = true;
 		tcxo_enabled = tcxo_enable();
 	}
 
-	if (voltage_increased && tcxo_workaround_noirq)
-		rc = msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_0, vreg->req, cnt);
-	else
-		rc = msm_rpm_set(MSM_RPM_CTX_SET_0, vreg->req, cnt);
+	rc = msm_rpm_set(MSM_RPM_CTX_SET_0, vreg->req, cnt);
 
 	if (rc) {
 		vreg->req[0].value = prev0;
@@ -1107,11 +1074,7 @@
 	if (voltage_increased) {
 		if (tcxo_enabled)
 			tcxo_delayed_disable();
-
-		if (tcxo_workaround_noirq)
-			spin_unlock_irqrestore(&tcxo_noirq_lock, flags);
-		else
-			mutex_unlock(&tcxo_mutex);
+		mutex_unlock(&tcxo_mutex);
 	}
 
 	return rc;
@@ -1794,7 +1757,6 @@
 	struct rpm_regulator_platform_data *platform_data;
 	static struct rpm_regulator_consumer_mapping *prev_consumer_map;
 	static int prev_consumer_map_len;
-	struct vreg *vreg;
 	int rc = 0;
 	int i, id;
 
@@ -1880,18 +1842,6 @@
 				"rpm_regulator_tcxo");
 	}
 
-	if (requires_tcxo_workaround && !tcxo_workaround_noirq) {
-		for (i = 0; i < platform_data->num_regulators; i++) {
-			vreg = rpm_vreg_get_vreg(
-					platform_data->init_data[i].id);
-			if (vreg && vreg->requires_cxo
-			    && platform_data->init_data[i].sleep_selectable) {
-				tcxo_workaround_noirq = true;
-				break;
-			}
-		}
-	}
-
 	/* Initialize all of the regulators listed in the platform data. */
 	for (i = 0; i < platform_data->num_regulators; i++) {
 		rc = rpm_vreg_init_regulator(&platform_data->init_data[i],
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index f97eb9a..6d1d038 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -354,6 +354,18 @@
 	}
 }
 
+bool msm_rpm_waiting_for_ack(void)
+{
+	bool ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&msm_rpm_list_lock, flags);
+	ret = list_empty(&msm_rpm_wait_list);
+	spin_unlock_irqrestore(&msm_rpm_list_lock, flags);
+
+	return !ret;
+}
+
 static struct msm_rpm_wait_data *msm_rpm_get_entry_from_msg_id(uint32_t msg_id)
 {
 	struct list_head *ptr;
diff --git a/arch/arm/mach-msm/rpm_stats.c b/arch/arm/mach-msm/rpm_stats.c
index a831bd5..9a8b8ec 100644
--- a/arch/arm/mach-msm/rpm_stats.c
+++ b/arch/arm/mach-msm/rpm_stats.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -22,11 +22,14 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/of.h>
 #include <asm/uaccess.h>
-
+#include <asm/arch_timer.h>
 #include <mach/msm_iomap.h>
 #include "rpm_stats.h"
 
+
 enum {
 	ID_COUNTER,
 	ID_ACCUM_TIME_SCLK,
@@ -39,21 +42,111 @@
 };
 
 #define SCLK_HZ 32768
+#define MSM_ARCH_TIMER_FREQ 19200000
+
 struct msm_rpmstats_record{
 	char		name[32];
 	uint32_t	id;
 	uint32_t	val;
 };
-
 struct msm_rpmstats_private_data{
 	void __iomem *reg_base;
 	u32 num_records;
 	u32 read_idx;
 	u32 len;
-	char buf[128];
+	char buf[256];
 	struct msm_rpmstats_platform_data *platform_data;
 };
 
+struct msm_rpm_stats_data_v2 {
+	u32 stat_type;
+	u32 count;
+	u64 last_entered_at;
+	u64 last_exited_at;
+};
+
+static inline u64 get_time_in_sec(u64 counter)
+{
+	do_div(counter, MSM_ARCH_TIMER_FREQ);
+	return counter;
+}
+
+static inline u64 get_time_in_msec(u64 counter)
+{
+	do_div(counter, MSM_ARCH_TIMER_FREQ);
+	counter *= MSEC_PER_SEC;
+	return counter;
+}
+
+static inline int msm_rpmstats_append_data_to_buf(char *buf,
+		struct msm_rpm_stats_data_v2 *data, int buflength)
+{
+	char stat_type[5];
+	u64 time_in_last_mode;
+	u64 time_since_last_mode;
+
+	stat_type[4] = 0;
+	memcpy(stat_type, &data->stat_type, sizeof(u32));
+
+	time_in_last_mode = data->last_exited_at - data->last_entered_at;
+	time_in_last_mode = get_time_in_msec(time_in_last_mode);
+	time_since_last_mode = arch_counter_get_cntpct() - data->last_exited_at;
+	time_since_last_mode = get_time_in_sec(time_since_last_mode);
+
+	return  snprintf(buf , buflength,
+		"RPM Mode:%s\n\t count:%d\n time in last mode(msec):%llu\n"
+		"time since last mode(sec):%llu\n",
+		stat_type, data->count, time_in_last_mode,
+		time_since_last_mode);
+}
+
+static inline u32 msm_rpmstats_read_long_register_v2(void __iomem *regbase,
+		int index, int offset)
+{
+	return readl_relaxed(regbase + offset +
+			index * sizeof(struct msm_rpm_stats_data_v2));
+}
+
+static inline u64 msm_rpmstats_read_quad_register_v2(void __iomem *regbase,
+		int index, int offset)
+{
+	u64 dst;
+	memcpy_fromio(&dst,
+		regbase + offset + index * sizeof(struct msm_rpm_stats_data_v2),
+		8);
+	return dst;
+}
+
+static inline int msm_rpmstats_copy_stats_v2(
+			struct msm_rpmstats_private_data *prvdata)
+{
+	void __iomem *reg;
+	struct msm_rpm_stats_data_v2 data;
+	int i, length;
+
+	reg = prvdata->reg_base;
+
+	for (i = 0, length = 0; i < prvdata->num_records; i++) {
+
+		data.stat_type = msm_rpmstats_read_long_register_v2(reg, i,
+				offsetof(struct msm_rpm_stats_data_v2,
+					stat_type));
+		data.count = msm_rpmstats_read_long_register_v2(reg, i,
+				offsetof(struct msm_rpm_stats_data_v2, count));
+		data.last_entered_at = msm_rpmstats_read_quad_register_v2(reg,
+				i, offsetof(struct msm_rpm_stats_data_v2,
+					last_entered_at));
+		data.last_exited_at = msm_rpmstats_read_quad_register_v2(reg,
+				i, offsetof(struct msm_rpm_stats_data_v2,
+					last_exited_at));
+
+		length += msm_rpmstats_append_data_to_buf(prvdata->buf + length,
+				&data, sizeof(prvdata->buf) - length);
+		prvdata->read_idx++;
+	}
+	return length;
+}
+
 static inline unsigned long  msm_rpmstats_read_register(void __iomem *regbase,
 		int index, int offset)
 {
@@ -133,13 +226,19 @@
 	if (!bufu || count < 0)
 		return -EINVAL;
 
-	if (!prvdata->num_records)
-		prvdata->num_records = readl_relaxed(prvdata->reg_base);
+	if (prvdata->platform_data->version == 1) {
+		if (!prvdata->num_records)
+			prvdata->num_records = readl_relaxed(prvdata->reg_base);
+	}
 
 	if ((*ppos >= prvdata->len)
-			&& (prvdata->read_idx < prvdata->num_records)) {
-		prvdata->len = msm_rpmstats_copy_stats(prvdata);
-		*ppos = 0;
+		&& (prvdata->read_idx < prvdata->num_records)) {
+			if (prvdata->platform_data->version == 1)
+				prvdata->len = msm_rpmstats_copy_stats(prvdata);
+			else if (prvdata->platform_data->version == 2)
+				prvdata->len = msm_rpmstats_copy_stats_v2(
+						prvdata);
+			*ppos = 0;
 	}
 
 	return simple_read_from_buffer(bufu, count, ppos,
@@ -160,7 +259,8 @@
 		return -ENOMEM;
 	prvdata = file->private_data;
 
-	prvdata->reg_base = ioremap(pdata->phys_addr_base, pdata->phys_size);
+	prvdata->reg_base = ioremap_nocache(pdata->phys_addr_base,
+					pdata->phys_size);
 	if (!prvdata->reg_base) {
 		kfree(file->private_data);
 		prvdata = NULL;
@@ -172,6 +272,9 @@
 
 	prvdata->read_idx = prvdata->num_records =  prvdata->len = 0;
 	prvdata->platform_data = pdata;
+	if (pdata->version == 2)
+		prvdata->num_records = 2;
+
 	return 0;
 }
 
@@ -196,18 +299,53 @@
 
 static  int __devinit msm_rpmstats_probe(struct platform_device *pdev)
 {
-	struct dentry *dent;
+	struct dentry *dent = NULL;
 	struct msm_rpmstats_platform_data *pdata;
+	struct msm_rpmstats_platform_data *pd;
+	struct resource *res = NULL;
+	struct device_node *node = NULL;
+	int ret = 0;
 
-	pdata = pdev->dev.platform_data;
-	if (!pdata)
+	if (!pdev)
 		return -EINVAL;
-	dent = debugfs_create_file("rpm_stats", S_IRUGO, NULL,
-			pdev->dev.platform_data, &msm_rpmstats_fops);
 
-	if (!dent) {
-		pr_err("%s: ERROR debugfs_create_file failed\n", __func__);
+	pdata = kzalloc(sizeof(struct msm_rpmstats_platform_data), GFP_KERNEL);
+
+	if (!pdata)
 		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (!res)
+		return -EINVAL;
+
+	pdata->phys_addr_base  = res->start;
+
+	pdata->phys_size = resource_size(res);
+	node = pdev->dev.of_node;
+	if (pdev->dev.platform_data) {
+		pd = pdev->dev.platform_data;
+		pdata->version = pd->version;
+
+	} else if (node)
+		ret = of_property_read_u32(node,
+			"qcom,sleep-stats-version", &pdata->version);
+
+	if (!ret) {
+
+		dent = debugfs_create_file("rpm_stats", S_IRUGO, NULL,
+				pdata, &msm_rpmstats_fops);
+
+		if (!dent) {
+			pr_err("%s: ERROR debugfs_create_file failed\n",
+					__func__);
+			kfree(pdata);
+			return -ENOMEM;
+		}
+
+	} else {
+		kfree(pdata);
+		return -EINVAL;
 	}
 	platform_set_drvdata(pdev, dent);
 	return 0;
@@ -222,12 +360,19 @@
 	platform_set_drvdata(pdev, NULL);
 	return 0;
 }
+
+static struct of_device_id rpm_stats_table[] = {
+	       {.compatible = "qcom,rpm-stats"},
+	       {},
+};
+
 static struct platform_driver msm_rpmstats_driver = {
 	.probe	= msm_rpmstats_probe,
 	.remove = __devexit_p(msm_rpmstats_remove),
 	.driver = {
 		.name = "msm_rpm_stat",
 		.owner = THIS_MODULE,
+		.of_match_table = rpm_stats_table,
 	},
 };
 static int __init msm_rpmstats_init(void)
diff --git a/arch/arm/mach-msm/rpm_stats.h b/arch/arm/mach-msm/rpm_stats.h
index a3beaa4..c1dfe34 100644
--- a/arch/arm/mach-msm/rpm_stats.h
+++ b/arch/arm/mach-msm/rpm_stats.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -19,6 +19,7 @@
 struct msm_rpmstats_platform_data {
 	phys_addr_t phys_addr_base;
 	u32 phys_size;
+	u32 version;
 };
 
 struct msm_rpm_master_stats_platform_data {
diff --git a/arch/arm/mach-msm/scm-pas.c b/arch/arm/mach-msm/scm-pas.c
index 43436e5..e248917 100644
--- a/arch/arm/mach-msm/scm-pas.c
+++ b/arch/arm/mach-msm/scm-pas.c
@@ -24,6 +24,7 @@
 #include "scm-pas.h"
 
 #define PAS_INIT_IMAGE_CMD	1
+#define PAS_MEM_SETUP_CMD	2
 #define PAS_AUTH_AND_RESET_CMD	5
 #define PAS_SHUTDOWN_CMD	6
 #define PAS_IS_SUPPORTED_CMD	7
@@ -55,6 +56,28 @@
 }
 EXPORT_SYMBOL(pas_init_image);
 
+int pas_mem_setup(enum pas_id id, u32 start_addr, u32 len)
+{
+	int ret;
+	struct pas_init_image_req {
+		u32	proc;
+		u32	start_addr;
+		u32	len;
+	} request;
+	u32 scm_ret = 0;
+
+	request.proc = id;
+	request.start_addr = start_addr;
+	request.len = len;
+
+	ret = scm_call(SCM_SVC_PIL, PAS_MEM_SETUP_CMD, &request,
+			sizeof(request), &scm_ret, sizeof(scm_ret));
+	if (ret)
+		return ret;
+	return scm_ret;
+}
+EXPORT_SYMBOL(pas_mem_setup);
+
 static struct msm_bus_paths scm_pas_bw_tbl[] = {
 	{
 		.vectors = (struct msm_bus_vectors[]){
@@ -204,11 +227,7 @@
 		}
 	}
 
-	/* TODO : Remove once bus scaling driver is in place */
-	if (!cpu_is_msm8226())
-		scm_perf_client = msm_bus_scale_register_client(
-				&scm_pas_bus_pdata);
-
+	scm_perf_client = msm_bus_scale_register_client(&scm_pas_bus_pdata);
 	if (!scm_perf_client)
 		pr_warn("unable to register bus client\n");
 
diff --git a/arch/arm/mach-msm/scm-pas.h b/arch/arm/mach-msm/scm-pas.h
index 8da1d75..6441a18 100644
--- a/arch/arm/mach-msm/scm-pas.h
+++ b/arch/arm/mach-msm/scm-pas.h
@@ -27,6 +27,7 @@
 
 #ifdef CONFIG_MSM_PIL
 extern int pas_init_image(enum pas_id id, const u8 *metadata, size_t size);
+extern int pas_mem_setup(enum pas_id id, u32 start_addr, u32 len);
 extern int pas_auth_and_reset(enum pas_id id);
 extern int pas_shutdown(enum pas_id id);
 extern int pas_supported(enum pas_id id);
@@ -36,6 +37,10 @@
 {
 	return 0;
 }
+static inline int pas_mem_setup(enum pas_id id, u32 start_addr, u32 len)
+{
+	return 0;
+}
 static inline int pas_auth_and_reset(enum pas_id id)
 {
 	return 0;
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index c6da910..b1dd1db 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -706,7 +706,7 @@
  */
 static struct edge_to_pid edge_to_pids[] = {
 	[SMD_APPS_MODEM] = {SMD_APPS, SMD_MODEM, "modem"},
-	[SMD_APPS_QDSP] = {SMD_APPS, SMD_Q6, "q6"},
+	[SMD_APPS_QDSP] = {SMD_APPS, SMD_Q6, "adsp"},
 	[SMD_MODEM_QDSP] = {SMD_MODEM, SMD_Q6},
 	[SMD_APPS_DSPS] = {SMD_APPS, SMD_DSPS, "dsps"},
 	[SMD_MODEM_DSPS] = {SMD_MODEM, SMD_DSPS},
@@ -1016,6 +1016,7 @@
 	notify_dsp_smd();
 	notify_dsps_smd();
 	notify_wcnss_smd();
+	notify_rpm_smd();
 
 	/* change all remote states to CLOSED */
 	mutex_lock(&smd_probe_lock);
@@ -1031,6 +1032,7 @@
 	notify_dsp_smd();
 	notify_dsps_smd();
 	notify_wcnss_smd();
+	notify_rpm_smd();
 
 	SMD_DBG("%s: finished reset\n", __func__);
 }
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index 928e59b..73ebdf6 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -34,14 +34,14 @@
 #include <linux/wakelock.h>
 
 #include <mach/msm_smd.h>
-#include <mach/peripheral-loader.h>
+#include <mach/subsystem_restart.h>
 #include <mach/msm_ipc_logging.h>
 
 #include "smd_private.h"
 #ifdef CONFIG_ARCH_FSM9XXX
 #define NUM_SMD_PKT_PORTS 4
 #else
-#define NUM_SMD_PKT_PORTS 15
+#define NUM_SMD_PKT_PORTS 24
 #endif
 
 #define PDRIVER_NAME_MAX_SIZE 32
@@ -711,6 +711,15 @@
 	"smdcntl6",
 	"smdcntl7",
 	"smd22",
+	"smdcnt_rev0",
+	"smdcnt_rev1",
+	"smdcnt_rev2",
+	"smdcnt_rev3",
+	"smdcnt_rev4",
+	"smdcnt_rev5",
+	"smdcnt_rev6",
+	"smdcnt_rev7",
+	"smdcnt_rev8",
 	"smd_sns_dsps",
 	"apr_apps2",
 	"smdcntl8",
@@ -729,6 +738,15 @@
 	"DATA13_CNTL",
 	"DATA14_CNTL",
 	"DATA22",
+	"DATA23_CNTL",
+	"DATA24_CNTL",
+	"DATA25_CNTL",
+	"DATA26_CNTL",
+	"DATA27_CNTL",
+	"DATA28_CNTL",
+	"DATA29_CNTL",
+	"DATA30_CNTL",
+	"DATA31_CNTL",
 	"SENSOR",
 	"apr_apps2",
 	"DATA40_CNTL",
@@ -747,6 +765,15 @@
 	SMD_APPS_MODEM,
 	SMD_APPS_MODEM,
 	SMD_APPS_MODEM,
+	SMD_APPS_MODEM,
+	SMD_APPS_MODEM,
+	SMD_APPS_MODEM,
+	SMD_APPS_MODEM,
+	SMD_APPS_MODEM,
+	SMD_APPS_MODEM,
+	SMD_APPS_MODEM,
+	SMD_APPS_MODEM,
+	SMD_APPS_MODEM,
 	SMD_APPS_DSPS,
 	SMD_APPS_QDSP,
 	SMD_APPS_MODEM,
@@ -823,12 +850,11 @@
 		peripheral = smd_edge_to_subsystem(
 				smd_ch_edge[smd_pkt_devp->i]);
 		if (peripheral) {
-			smd_pkt_devp->pil = pil_get(peripheral);
+			smd_pkt_devp->pil = subsystem_get(peripheral);
 			if (IS_ERR(smd_pkt_devp->pil)) {
 				r = PTR_ERR(smd_pkt_devp->pil);
-				pr_err("%s failed on smd_pkt_dev id:%d -"
-				       " pil_get failed for %s\n", __func__,
-					smd_pkt_devp->i, peripheral);
+				pr_err("%s failed on smd_pkt_dev id:%d - subsystem_get failed for %s\n",
+					__func__, smd_pkt_devp->i, peripheral);
 				goto release_pd;
 			}
 
@@ -908,7 +934,7 @@
 	}
 release_pil:
 	if (peripheral && (r < 0))
-		pil_put(smd_pkt_devp->pil);
+		subsystem_put(smd_pkt_devp->pil);
 
 release_pd:
 	if (r < 0) {
@@ -952,7 +978,7 @@
 		platform_driver_unregister(&smd_pkt_devp->driver);
 		smd_pkt_devp->driver.probe = NULL;
 		if (smd_pkt_devp->pil)
-			pil_put(smd_pkt_devp->pil);
+			subsystem_put(smd_pkt_devp->pil);
 		smd_pkt_devp->has_reset = 0;
 		smd_pkt_devp->do_reset_notification = 0;
 		smd_pkt_devp->wakelock_locked = 0;
diff --git a/arch/arm/mach-msm/smd_rpcrouter.c b/arch/arm/mach-msm/smd_rpcrouter.c
index 80a639c..1bea82a 100644
--- a/arch/arm/mach-msm/smd_rpcrouter.c
+++ b/arch/arm/mach-msm/smd_rpcrouter.c
@@ -306,6 +306,10 @@
 	struct msm_rpc_reply *reply, *reply_tmp;
 	unsigned long flags;
 
+	if (!xprt_info) {
+		pr_err("%s: Invalid xprt_info\n", __func__);
+		return;
+	}
 	spin_lock_irqsave(&local_endpoints_lock, flags);
 	/* remove all partial packets received */
 	list_for_each_entry(ept, &local_endpoints, list) {
@@ -2154,6 +2158,7 @@
 	while (!list_empty(&xprt_info_list)) {
 		xprt_info = list_first_entry(&xprt_info_list,
 					struct rpcrouter_xprt_info, list);
+		modem_reset_cleanup(xprt_info);
 		xprt_info->abort_data_read = 1;
 		wake_up(&xprt_info->read_wait);
 		rpcrouter_send_control_msg(xprt_info, &ctl);
@@ -2164,6 +2169,8 @@
 		flush_workqueue(xprt_info->workqueue);
 		destroy_workqueue(xprt_info->workqueue);
 		wake_lock_destroy(&xprt_info->wakelock);
+		/*free memory*/
+		xprt_info->xprt->priv = 0;
 		kfree(xprt_info);
 
 		mutex_lock(&xprt_info_list_lock);
diff --git a/arch/arm/mach-msm/smd_rpcrouter_device.c b/arch/arm/mach-msm/smd_rpcrouter_device.c
index e84d213..7b51beb 100644
--- a/arch/arm/mach-msm/smd_rpcrouter_device.c
+++ b/arch/arm/mach-msm/smd_rpcrouter_device.c
@@ -1,7 +1,7 @@
 /* arch/arm/mach-msm/smd_rpcrouter_device.c
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-2012, Code Aurora Forum. All rights reserved.
  * Author: San Mehat <san@android.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -34,7 +34,7 @@
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 
-#include <mach/peripheral-loader.h>
+#include <mach/subsystem_restart.h>
 #include "smd_rpcrouter.h"
 
 /* Support 64KB of data plus some space for headers */
@@ -61,7 +61,7 @@
 static void msm_rpcrouter_unload_modem(void *pil)
 {
 	if (pil)
-		pil_put(pil);
+		subsystem_put(pil);
 }
 
 static void *msm_rpcrouter_load_modem(void)
@@ -69,7 +69,7 @@
 	void *pil;
 	int rc;
 
-	pil = pil_get("modem");
+	pil = subsystem_get("modem");
 	if (IS_ERR(pil))
 		pr_err("%s: modem load failed\n", __func__);
 	else {
diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c
index 44ef822..881da18 100644
--- a/arch/arm/mach-msm/smd_tty.c
+++ b/arch/arm/mach-msm/smd_tty.c
@@ -30,7 +30,7 @@
 #include <linux/tty_flip.h>
 
 #include <mach/msm_smd.h>
-#include <mach/peripheral-loader.h>
+#include <mach/subsystem_restart.h>
 #include <mach/socinfo.h>
 
 #include "smd_private.h"
@@ -245,7 +245,7 @@
 	if (info->open_count++ == 0) {
 		peripheral = smd_edge_to_subsystem(smd_tty[n].smd->edge);
 		if (peripheral) {
-			info->pil = pil_get(peripheral);
+			info->pil = subsystem_get(peripheral);
 			if (IS_ERR(info->pil)) {
 				res = PTR_ERR(info->pil);
 				goto out;
@@ -325,7 +325,7 @@
 
 release_pil:
 	if (res < 0)
-		pil_put(info->pil);
+		subsystem_put(info->pil);
 	else
 		smd_disable_read_intr(info->ch);
 out:
@@ -357,7 +357,7 @@
 		if (info->ch) {
 			smd_close(info->ch);
 			info->ch = 0;
-			pil_put(info->pil);
+			subsystem_put(info->pil);
 		}
 	}
 	mutex_unlock(&smd_tty_lock);
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 62085f6..6cb9339 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -260,6 +260,7 @@
 	[128] = MSM_CPU_8625,
 	[129] = MSM_CPU_8625,
 	[137] = MSM_CPU_8625,
+	[167] = MSM_CPU_8625,
 
 	/* 8064 MPQ ID */
 	[130] = MSM_CPU_8064,
diff --git a/arch/arm/mach-msm/spm.c b/arch/arm/mach-msm/spm.c
index 8337fd1..ea0b56c 100644
--- a/arch/arm/mach-msm/spm.c
+++ b/arch/arm/mach-msm/spm.c
@@ -132,6 +132,11 @@
 /******************************************************************************
  * Public functions
  *****************************************************************************/
+/**
+ * msm_spm_set_low_power_mode() - Configure SPM start address for low power mode
+ * @mode: SPM LPM mode to enter
+ * @notify_rpm: Notify RPM in this mode
+ */
 int msm_spm_set_low_power_mode(unsigned int mode, bool notify_rpm)
 {
 	struct msm_spm_device *dev = &__get_cpu_var(msm_spm_devices);
@@ -185,6 +190,11 @@
 	return 0;
 }
 
+/**
+ * msm_spm_set_vdd(): Set core voltage
+ * @cpu: core id
+ * @vlevel: Encoded PMIC data.
+ */
 int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel)
 {
 	struct msm_spm_device *dev;
@@ -235,6 +245,11 @@
 	return -EIO;
 }
 
+/**
+ * msm_spm_get_vdd(): Get core voltage
+ * @cpu: core id
+ * @return: Returns encoded PMIC data.
+ */
 unsigned int msm_spm_get_vdd(unsigned int cpu)
 {
 	struct msm_spm_device *dev = &per_cpu(msm_spm_devices, cpu);
@@ -253,6 +268,11 @@
 	mb();
 }
 
+/**
+ * msm_spm_init(): Board initalization function
+ * @data: platform specific SPM register configuration data
+ * @nr_devs: Number of SPM devices being initialized
+ */
 int __init msm_spm_init(struct msm_spm_platform_data *data, int nr_devs)
 {
 	unsigned int cpu;
diff --git a/arch/arm/mach-msm/spm.h b/arch/arm/mach-msm/spm.h
index 4cdfcf8..a353ce0 100644
--- a/arch/arm/mach-msm/spm.h
+++ b/arch/arm/mach-msm/spm.h
@@ -127,93 +127,29 @@
 
 /* Public functions */
 
-/**
- * msm_spm_set_low_power_mode() - Configure SPM start address for low power mode
- * @mode: SPM LPM mode to enter
- * @notify_rpm: Notify RPM in this mode
- */
 int msm_spm_set_low_power_mode(unsigned int mode, bool notify_rpm);
-
-/**
- * msm_spm_set_vdd(): Set core voltage
- * @cpu: core id
- * @vlevel: Encoded PMIC data.
- */
 int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel);
-
-/**
- * msm_spm_get_vdd(): Get core voltage
- * @cpu: core id
- * @return: Returns encoded PMIC data.
- */
 unsigned int msm_spm_get_vdd(unsigned int cpu);
-
-/**
- * msm_spm_turn_on_cpu_rail(): Power on cpu rail before turning on core
- * @cpu: core id
- */
 int msm_spm_turn_on_cpu_rail(unsigned int cpu);
 
 /* Internal low power management specific functions */
 
-/**
- * msm_spm_reinit(): Reinitialize SPM registers
- */
 void msm_spm_reinit(void);
-
-/**
- * msm_spm_init(): Board initalization function
- * @data: platform specific SPM register configuration data
- * @nr_devs: Number of SPM devices being initialized
- */
 int msm_spm_init(struct msm_spm_platform_data *data, int nr_devs);
-
-/**
- * msm_spm_device_init(): Device tree initialization function
- */
 int msm_spm_device_init(void);
 
 #if defined(CONFIG_MSM_L2_SPM)
 
 /* Public functions */
 
-/**
- * msm_spm_l2_set_low_power_mode(): Configure L2 SPM start address
- *                                  for low power mode
- * @mode: SPM LPM mode to enter
- * @notify_rpm: Notify RPM in this mode
- */
 int msm_spm_l2_set_low_power_mode(unsigned int mode, bool notify_rpm);
-
-/**
- * msm_spm_apcs_set_vdd(): Set Apps processor core sub-system voltage
- * @vlevel: Encoded PMIC data.
- */
 int msm_spm_apcs_set_vdd(unsigned int vlevel);
-
-/**
- * msm_spm_apcs_set_phase(): Set number of SMPS phases.
- * phase_cnt: Number of phases to be set active
- */
 int msm_spm_apcs_set_phase(unsigned int phase_cnt);
-
-/** msm_spm_enable_fts_lpm() : Enable FTS to switch to low power
- *                             when the cores are in low power modes
- * @mode: The mode configuration for FTS
- */
 int msm_spm_enable_fts_lpm(uint32_t mode);
 
 /* Internal low power management specific functions */
 
-/**
- * msm_spm_l2_init(): Board initialization function
- * @data: SPM target specific register configuration
- */
 int msm_spm_l2_init(struct msm_spm_platform_data *data);
-
-/**
- * msm_spm_l2_reinit(): Reinitialize L2 SPM registers
- */
 void msm_spm_l2_reinit(void);
 
 #else
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 3fe3bd7..b378d3b 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -57,6 +57,11 @@
 	info->err = msm_spm_drv_set_vdd(&dev->reg_data, info->vlevel);
 }
 
+/**
+ * msm_spm_set_vdd(): Set core voltage
+ * @cpu: core id
+ * @vlevel: Encoded PMIC data.
+ */
 int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel)
 {
 	struct msm_spm_vdd_info info;
@@ -91,6 +96,11 @@
 }
 EXPORT_SYMBOL(msm_spm_set_vdd);
 
+/**
+ * msm_spm_get_vdd(): Get core voltage
+ * @cpu: core id
+ * @return: Returns encoded PMIC data.
+ */
 unsigned int msm_spm_get_vdd(unsigned int cpu)
 {
 	struct msm_spm_device *dev;
@@ -166,6 +176,10 @@
 	return ret;
 }
 
+/**
+ * msm_spm_turn_on_cpu_rail(): Power on cpu rail before turning on core
+ * @cpu: core id
+ */
 int msm_spm_turn_on_cpu_rail(unsigned int cpu)
 {
 	uint32_t val = 0;
@@ -208,6 +222,11 @@
 }
 EXPORT_SYMBOL(msm_spm_reinit);
 
+/**
+ * msm_spm_set_low_power_mode() - Configure SPM start address for low power mode
+ * @mode: SPM LPM mode to enter
+ * @notify_rpm: Notify RPM in this mode
+ */
 int msm_spm_set_low_power_mode(unsigned int mode, bool notify_rpm)
 {
 	struct msm_spm_device *dev = &__get_cpu_var(msm_cpu_spm_device);
@@ -215,7 +234,11 @@
 }
 EXPORT_SYMBOL(msm_spm_set_low_power_mode);
 
-/* Board file init function */
+/**
+ * msm_spm_init(): Board initalization function
+ * @data: platform specific SPM register configuration data
+ * @nr_devs: Number of SPM devices being initialized
+ */
 int __init msm_spm_init(struct msm_spm_platform_data *data, int nr_devs)
 {
 	unsigned int cpu;
@@ -238,6 +261,12 @@
 
 #ifdef CONFIG_MSM_L2_SPM
 
+/**
+ * msm_spm_l2_set_low_power_mode(): Configure L2 SPM start address
+ *                                  for low power mode
+ * @mode: SPM LPM mode to enter
+ * @notify_rpm: Notify RPM in this mode
+ */
 int msm_spm_l2_set_low_power_mode(unsigned int mode, bool notify_rpm)
 {
 	return msm_spm_dev_set_low_power_mode(
@@ -251,12 +280,20 @@
 }
 EXPORT_SYMBOL(msm_spm_l2_reinit);
 
+/**
+ * msm_spm_apcs_set_vdd(): Set Apps processor core sub-system voltage
+ * @vlevel: Encoded PMIC data.
+ */
 int msm_spm_apcs_set_vdd(unsigned int vlevel)
 {
 	return msm_spm_drv_set_vdd(&msm_spm_l2_device.reg_data, vlevel);
 }
 EXPORT_SYMBOL(msm_spm_apcs_set_vdd);
 
+/**
+ * msm_spm_apcs_set_phase(): Set number of SMPS phases.
+ * phase_cnt: Number of phases to be set active
+ */
 int msm_spm_apcs_set_phase(unsigned int phase_cnt)
 {
 	return msm_spm_drv_set_pmic_data(&msm_spm_l2_device.reg_data,
@@ -264,6 +301,10 @@
 }
 EXPORT_SYMBOL(msm_spm_apcs_set_phase);
 
+/** msm_spm_enable_fts_lpm() : Enable FTS to switch to low power
+ *                             when the cores are in low power modes
+ * @mode: The mode configuration for FTS
+ */
 int msm_spm_enable_fts_lpm(uint32_t mode)
 {
 	return msm_spm_drv_set_pmic_data(&msm_spm_l2_device.reg_data,
@@ -271,7 +312,10 @@
 }
 EXPORT_SYMBOL(msm_spm_enable_fts_lpm);
 
-/* Board file init function */
+/**
+ * msm_spm_l2_init(): Board initialization function
+ * @data: SPM target specific register configuration
+ */
 int __init msm_spm_l2_init(struct msm_spm_platform_data *data)
 {
 	return msm_spm_dev_init(&msm_spm_l2_device, data);
@@ -453,6 +497,9 @@
 	},
 };
 
+/**
+ * msm_spm_device_init(): Device tree initialization function
+ */
 int __init msm_spm_device_init(void)
 {
 	return platform_driver_register(&msm_spm_device_driver);
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index e5cc4ec..ea9337d 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -33,7 +33,6 @@
 
 #include <asm/current.h>
 
-#include <mach/peripheral-loader.h>
 #include <mach/socinfo.h>
 #include <mach/subsystem_notif.h>
 #include <mach/subsystem_restart.h>
@@ -178,6 +177,20 @@
 	spin_unlock_irqrestore(&subsys->track.s_lock, flags);
 }
 
+/**
+ * subsytem_default_online() - Mark a subsystem as online by default
+ * @dev: subsystem to mark as online
+ *
+ * Marks a subsystem as "online" without increasing the reference count
+ * on the subsystem. This is typically used by subsystems that are already
+ * online when the kernel boots up.
+ */
+void subsys_default_online(struct subsys_device *dev)
+{
+	subsys_set_state(dev, SUBSYS_ONLINE);
+}
+EXPORT_SYMBOL(subsys_default_online);
+
 static struct device_attribute subsys_attrs[] = {
 	__ATTR_RO(name),
 	__ATTR_RO(state),
@@ -214,7 +227,7 @@
 
 /* MSM 8x60 restart ordering info */
 static const char * const _order_8x60_all[] = {
-	"external_modem",  "modem", "lpass"
+	"external_modem",  "modem", "adsp"
 };
 DEFINE_SINGLE_RESTART_ORDER(orders_8x60_all, _order_8x60_all);
 
@@ -671,6 +684,18 @@
 	}
 
 	name = dev->desc->name;
+
+	/*
+	 * If a system reboot/shutdown is underway, ignore subsystem errors.
+	 * However, print a message so that we know that a subsystem behaved
+	 * unexpectedly here.
+	 */
+	if (system_state == SYSTEM_RESTART
+		|| system_state == SYSTEM_POWER_OFF) {
+		pr_err("%s crashed during a system poweroff/shutdown.\n", name);
+		return -EBUSY;
+	}
+
 	pr_info("Restart sequence requested for %s, restart_level = %d.\n",
 		name, restart_level);
 
@@ -813,7 +838,6 @@
 	subsys->dev.parent = desc->dev;
 	subsys->dev.bus = &subsys_bus_type;
 	subsys->dev.release = subsys_device_release;
-	subsys->track.state = SUBSYS_ONLINE; /* Until proper refcounting */
 
 	subsys->notify = subsys_notif_add_subsys(desc->name);
 	subsys->restart_order = update_restart_order(subsys);
diff --git a/arch/arm/mach-msm/sysmon.c b/arch/arm/mach-msm/sysmon.c
index 02ba5ea..112daca 100644
--- a/arch/arm/mach-msm/sysmon.c
+++ b/arch/arm/mach-msm/sysmon.c
@@ -43,6 +43,7 @@
 	struct completion	resp_ready;
 	char			rx_buf[RX_BUF_SIZE];
 	enum transports		transport;
+	struct device		*dev;
 };
 
 static struct sysmon_subsys subsys[SYSMON_NUM_SS] = {
@@ -138,6 +139,9 @@
 	char tx_buf[TX_BUF_SIZE];
 	int ret;
 
+	if (ss->dev == NULL)
+		return -ENODEV;
+
 	if (dest_ss < 0 || dest_ss >= SYSMON_NUM_SS ||
 	    notif < 0 || notif >= SUBSYS_NOTIF_TYPE_COUNT ||
 	    event_ss == NULL)
@@ -178,6 +182,9 @@
 	size_t prefix_len = ARRAY_SIZE(expect) - 1;
 	int ret;
 
+	if (ss->dev == NULL)
+		return -ENODEV;
+
 	if (dest_ss < 0 || dest_ss >= SYSMON_NUM_SS)
 		return -EINVAL;
 
@@ -214,6 +221,9 @@
 	size_t prefix_len = ARRAY_SIZE(expect) - 1;
 	int ret;
 
+	if (ss->dev == NULL)
+		return -ENODEV;
+
 	if (dest_ss < 0 || dest_ss >= SYSMON_NUM_SS ||
 	    buf == NULL || len == 0)
 		return -EINVAL;
@@ -293,6 +303,7 @@
 	default:
 		return -EINVAL;
 	}
+	ss->dev = &pdev->dev;
 
 	return 0;
 }
@@ -301,6 +312,9 @@
 {
 	struct sysmon_subsys *ss = &subsys[pdev->id];
 
+	ss->dev = NULL;
+
+	mutex_lock(&ss->lock);
 	switch (ss->transport) {
 	case TRANSPORT_SMD:
 		smd_close(ss->chan);
@@ -309,6 +323,7 @@
 		hsic_sysmon_close(HSIC_SYSMON_DEV_EXT_MODEM);
 		break;
 	}
+	mutex_unlock(&ss->lock);
 
 	return 0;
 }
diff --git a/arch/arm/mach-msm/trace_msm_low_power.h b/arch/arm/mach-msm/trace_msm_low_power.h
new file mode 100644
index 0000000..4e9da85
--- /dev/null
+++ b/arch/arm/mach-msm/trace_msm_low_power.h
@@ -0,0 +1,154 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM msm_low_power
+
+#if !defined(_TRACE_MSM_LOW_POWER_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_MSM_LOW_POWER_H_
+
+#include <linux/tracepoint.h>
+
+DECLARE_EVENT_CLASS(msm_pm_enter,
+
+	TP_PROTO(unsigned int cpu, uint32_t latency,
+		uint32_t sleep_us, uint32_t wake_up),
+
+	TP_ARGS(cpu, latency, sleep_us, wake_up),
+
+	TP_STRUCT__entry(
+		__field(unsigned int, cpu)
+		__field(uint32_t, latency)
+		__field(uint32_t, sleep_us)
+		__field(uint32_t, wake_up)
+	),
+
+	TP_fast_assign(
+		__entry->cpu = cpu;
+		__entry->latency = latency;
+		__entry->sleep_us = sleep_us;
+		__entry->wake_up = wake_up;
+	),
+
+	TP_printk("cpu: %u latency: %uus sleep: %uus wake_up: %u",
+		__entry->cpu,
+		__entry->latency,
+		__entry->sleep_us,
+		__entry->wake_up)
+);
+
+DEFINE_EVENT(msm_pm_enter, msm_pm_enter_pc,
+
+	TP_PROTO(unsigned int cpu, uint32_t latency,
+		uint32_t sleep_us, uint32_t wake_up),
+
+	TP_ARGS(cpu, latency, sleep_us, wake_up)
+);
+
+DEFINE_EVENT(msm_pm_enter, msm_pm_enter_ret,
+
+	TP_PROTO(unsigned int cpu, uint32_t latency,
+		uint32_t sleep_us, uint32_t wake_up),
+
+	TP_ARGS(cpu, latency, sleep_us, wake_up)
+);
+
+DEFINE_EVENT(msm_pm_enter, msm_pm_enter_spc,
+
+	TP_PROTO(unsigned int cpu, uint32_t latency,
+		uint32_t sleep_us, uint32_t wake_up),
+
+	TP_ARGS(cpu, latency, sleep_us, wake_up)
+);
+
+DEFINE_EVENT(msm_pm_enter, msm_pm_enter_wfi,
+
+	TP_PROTO(unsigned int cpu, uint32_t latency,
+		uint32_t sleep_us, uint32_t wake_up),
+
+	TP_ARGS(cpu, latency, sleep_us, wake_up)
+);
+
+DECLARE_EVENT_CLASS(msm_pm_exit,
+
+	TP_PROTO(unsigned int cpu, bool success),
+
+	TP_ARGS(cpu, success),
+
+	TP_STRUCT__entry(
+		__field(unsigned int , cpu)
+		__field(int, success)
+	),
+
+	TP_fast_assign(
+		__entry->cpu = cpu;
+		__entry->success = success;
+	),
+
+	TP_printk("cpu:%u success:%d",
+			__entry->cpu,
+			__entry->success)
+);
+
+DEFINE_EVENT(msm_pm_exit, msm_pm_exit_pc,
+
+	TP_PROTO(unsigned int cpu, bool success),
+
+	TP_ARGS(cpu, success)
+);
+
+DEFINE_EVENT(msm_pm_exit, msm_pm_exit_ret,
+
+	TP_PROTO(unsigned int cpu, bool success),
+
+	TP_ARGS(cpu, success)
+);
+
+DEFINE_EVENT(msm_pm_exit, msm_pm_exit_spc,
+
+	TP_PROTO(unsigned int cpu, bool success),
+
+	TP_ARGS(cpu, success)
+);
+
+DEFINE_EVENT(msm_pm_exit, msm_pm_exit_wfi,
+
+	TP_PROTO(unsigned int cpu, bool success),
+
+	TP_ARGS(cpu, success)
+);
+
+TRACE_EVENT(lpm_resources,
+
+	TP_PROTO(uint32_t sleep_value , char *name),
+
+	TP_ARGS(sleep_value, name),
+
+	TP_STRUCT__entry(
+		__field(uint32_t , sleep_value)
+		__string(name, name)
+	),
+
+	TP_fast_assign(
+		__entry->sleep_value = sleep_value;
+		__assign_str(name, name);
+	),
+
+	TP_printk("name:%s sleep_value:%d",
+			 __get_str(name),
+			__entry->sleep_value)
+);
+#endif
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE trace_msm_low_power
+#include <trace/define_trace.h>
diff --git a/arch/arm/mach-msm/wdog_debug.c b/arch/arm/mach-msm/wdog_debug.c
index 08dd9ce..8b39d26 100644
--- a/arch/arm/mach-msm/wdog_debug.c
+++ b/arch/arm/mach-msm/wdog_debug.c
@@ -43,6 +43,11 @@
 	value = readl_relaxed(wdog_data->base + GCC_WDOG_DEBUG_OFFSET);
 	value &= ~BIT(WDOG_DEBUG_EN);
 	writel_relaxed(value, wdog_data->base + GCC_WDOG_DEBUG_OFFSET);
+
+	/* Ensure the WDOG_DEBUG_EN status has changed */
+	while (readl_relaxed(wdog_data->base + GCC_WDOG_DEBUG_OFFSET) &
+		BIT(WDOG_DEBUG_EN))
+			;
 }
 EXPORT_SYMBOL(msm_disable_wdog_debug);
 
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 8404601..afaa39d 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -314,7 +314,8 @@
 core_initcall(consistent_init);
 
 static void *__alloc_from_contiguous(struct device *dev, size_t size,
-				     pgprot_t prot, struct page **ret_page);
+				     pgprot_t prot, struct page **ret_page,
+				     bool no_kernel_mapping);
 
 static struct arm_vmregion_head coherent_head = {
 	.vm_lock	= __SPIN_LOCK_UNLOCKED(&coherent_head.vm_lock),
@@ -343,7 +344,7 @@
 	if (!IS_ENABLED(CONFIG_CMA))
 		return 0;
 
-	ptr = __alloc_from_contiguous(NULL, size, prot, &page);
+	ptr = __alloc_from_contiguous(NULL, size, prot, &page, false);
 	if (ptr) {
 		coherent_head.vm_start = (unsigned long) ptr;
 		coherent_head.vm_end = (unsigned long) ptr + size;
@@ -522,12 +523,27 @@
 	return 0;
 }
 
-static void __dma_remap(struct page *page, size_t size, pgprot_t prot)
+static int __dma_clear_pte(pte_t *pte, pgtable_t token, unsigned long addr,
+			    void *data)
+{
+	pte_clear(&init_mm, addr, pte);
+	return 0;
+}
+
+static void __dma_remap(struct page *page, size_t size, pgprot_t prot,
+			bool no_kernel_map)
 {
 	unsigned long start = (unsigned long) page_address(page);
 	unsigned end = start + size;
+	int (*func)(pte_t *pte, pgtable_t token, unsigned long addr,
+			    void *data);
 
-	apply_to_page_range(&init_mm, start, size, __dma_update_pte, &prot);
+	if (no_kernel_map)
+		func = __dma_clear_pte;
+	else
+		func = __dma_update_pte;
+
+	apply_to_page_range(&init_mm, start, size, func, &prot);
 	dsb();
 	flush_tlb_kernel_range(start, end);
 }
@@ -604,7 +620,8 @@
 }
 
 static void *__alloc_from_contiguous(struct device *dev, size_t size,
-				     pgprot_t prot, struct page **ret_page)
+				     pgprot_t prot, struct page **ret_page,
+				     bool no_kernel_mapping)
 {
 	unsigned long order = get_order(size);
 	size_t count = size >> PAGE_SHIFT;
@@ -615,7 +632,7 @@
 		return NULL;
 
 	__dma_clear_buffer(page, size);
-	__dma_remap(page, size, prot);
+	__dma_remap(page, size, prot, no_kernel_mapping);
 
 	*ret_page = page;
 	return page_address(page);
@@ -624,15 +641,20 @@
 static void __free_from_contiguous(struct device *dev, struct page *page,
 				   size_t size)
 {
-	__dma_remap(page, size, pgprot_kernel);
+	__dma_remap(page, size, pgprot_kernel, false);
 	dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT);
 }
 
 static inline pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot)
 {
-	prot = dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs) ?
-			    pgprot_writecombine(prot) :
-			    pgprot_dmacoherent(prot);
+	if (dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs))
+		prot = pgprot_writecombine(prot);
+	else if (dma_get_attr(DMA_ATTR_STRONGLY_ORDERED, attrs))
+		prot = pgprot_stronglyordered(prot);
+	/* if non-consistent just pass back what was given */
+	else if (!dma_get_attr(DMA_ATTR_NON_CONSISTENT, attrs))
+		prot = pgprot_dmacoherent(prot);
+
 	return prot;
 }
 
@@ -644,7 +666,7 @@
 
 #define __alloc_remap_buffer(dev, size, gfp, prot, ret, c)	NULL
 #define __alloc_from_pool(dev, size, ret_page, c)		NULL
-#define __alloc_from_contiguous(dev, size, prot, ret)		NULL
+#define __alloc_from_contiguous(dev, size, prot, ret, w)	NULL
 #define __free_from_pool(cpu_addr, size)			0
 #define __free_from_contiguous(dev, page, size)			do { } while (0)
 #define __dma_free_remap(cpu_addr, size)			do { } while (0)
@@ -667,7 +689,8 @@
 
 
 static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
-			 gfp_t gfp, pgprot_t prot, const void *caller)
+			 gfp_t gfp, pgprot_t prot, const void *caller,
+			 bool no_kernel_mapping)
 {
 	u64 mask = get_coherent_dma_mask(dev);
 	struct page *page;
@@ -707,7 +730,8 @@
 	else if (gfp & GFP_ATOMIC)
 		addr = __alloc_from_pool(dev, size, &page, caller);
 	else
-		addr = __alloc_from_contiguous(dev, size, prot, &page);
+		addr = __alloc_from_contiguous(dev, size, prot, &page,
+						no_kernel_mapping);
 
 	if (addr)
 		*handle = pfn_to_dma(dev, page_to_pfn(page));
@@ -724,12 +748,14 @@
 {
 	pgprot_t prot = __get_dma_pgprot(attrs, pgprot_kernel);
 	void *memory;
+	bool no_kernel_mapping = dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING,
+					attrs);
 
 	if (dma_alloc_from_coherent(dev, size, handle, &memory))
 		return memory;
 
 	return __dma_alloc(dev, size, handle, gfp, prot,
-			   __builtin_return_address(0));
+			   __builtin_return_address(0), no_kernel_mapping);
 }
 
 /*
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index b5d38d5..8994d6d 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -571,7 +571,6 @@
 	pm_callback_t callback = NULL;
 	char *info = NULL;
 	int error = 0;
-	bool put = false;
 
 	TRACE_DEVICE(dev);
 	TRACE_RESUME(0);
@@ -589,7 +588,6 @@
 		goto Unlock;
 
 	pm_runtime_enable(dev);
-	put = true;
 
 	if (dev->pm_domain) {
 		info = "power domain ";
@@ -642,9 +640,6 @@
 
 	TRACE_RESUME(error);
 
-	if (put)
-		pm_runtime_put_sync(dev);
-
 	return error;
 }
 
@@ -779,6 +774,8 @@
 	}
 
 	device_unlock(dev);
+
+	pm_runtime_put_sync(dev);
 }
 
 /**
@@ -1064,12 +1061,16 @@
 	if (async_error)
 		return 0;
 
-	pm_runtime_get_noresume(dev);
+	/*
+	 * If a device configured to wake up the system from sleep states
+	 * has been suspended at run time and there's a resume request pending
+	 * for it, this is equivalent to the device signaling wakeup, so the
+	 * system suspend operation should be aborted.
+	 */
 	if (pm_runtime_barrier(dev) && device_may_wakeup(dev))
 		pm_wakeup_event(dev, 0);
 
 	if (pm_wakeup_pending()) {
-		pm_runtime_put_sync(dev);
 		async_error = -EBUSY;
 		return 0;
 	}
@@ -1142,12 +1143,10 @@
 
 	complete_all(&dev->power.completion);
 
-	if (error) {
-		pm_runtime_put_sync(dev);
+	if (error)
 		async_error = error;
-	} else if (dev->power.is_suspended) {
+	else if (dev->power.is_suspended)
 		__pm_runtime_disable(dev, false);
-	}
 
 	return error;
 }
@@ -1240,6 +1239,14 @@
 	char *info = NULL;
 	int error = 0;
 
+	/*
+	 * If a device's parent goes into runtime suspend at the wrong time,
+	 * it won't be possible to resume the device.  To prevent this we
+	 * block runtime suspend here, during the prepare phase, and allow
+	 * it again during the complete phase.
+	 */
+	pm_runtime_get_noresume(dev);
+
 	device_lock(dev);
 
 	dev->power.wakeup_path = device_may_wakeup(dev);
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 00a07a0..0b3ffef 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -649,6 +649,16 @@
           block.  Or some systems may want the iMem to be dedicated to a
           different function.
 
+config MSM_ADSPRPC
+        tristate "Qualcomm ADSP RPC driver"
+        depends on MSM_AUDIO_QDSP6 || MSM_AUDIO_QDSP6V2
+        default m
+        help
+          Provides a communication mechanism that allows for clients to
+          make remote method invocations across processor boundary to
+          applications DSP processor. Say M if you want to enable this
+          module.
+
 config MMC_GENERIC_CSDIO
 	tristate "Generic sdio driver"
 	default n
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index c38c26c..8032f0b 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -66,4 +66,5 @@
 obj-$(CONFIG_TILE_SROM)		+= tile-srom.o
 obj-$(CONFIG_MSM_ROTATOR)	+= msm_rotator.o
 obj-$(CONFIG_MMC_GENERIC_CSDIO)	+= csdio.o
-obj-$(CONFIG_DIAG_CHAR)		+= diag/
\ No newline at end of file
+obj-$(CONFIG_DIAG_CHAR)		+= diag/
+obj-$(CONFIG_MSM_ADSPRPC)       += adsprpc.o
diff --git a/arch/arm/mach-msm/qdsp6v2/adsprpc.c b/drivers/char/adsprpc.c
similarity index 100%
rename from arch/arm/mach-msm/qdsp6v2/adsprpc.c
rename to drivers/char/adsprpc.c
diff --git a/arch/arm/mach-msm/qdsp6v2/adsprpc.h b/drivers/char/adsprpc.h
similarity index 100%
rename from arch/arm/mach-msm/qdsp6v2/adsprpc.h
rename to drivers/char/adsprpc.h
diff --git a/arch/arm/mach-msm/qdsp6v2/adsprpc_shared.h b/drivers/char/adsprpc_shared.h
similarity index 100%
rename from arch/arm/mach-msm/qdsp6v2/adsprpc_shared.h
rename to drivers/char/adsprpc_shared.h
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 7c0c0b9..5cd5ce9 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -35,6 +35,8 @@
 unsigned int dci_max_clients = 10;
 unsigned char dci_cumulative_log_mask[DCI_LOG_MASK_SIZE];
 unsigned char dci_cumulative_event_mask[DCI_EVENT_MASK_SIZE];
+struct mutex dci_log_mask_mutex;
+struct mutex dci_event_mask_mutex;
 
 #define DCI_CHK_CAPACITY(entry, new_data_len)				\
 ((entry->data_len + new_data_len > entry->total_capacity) ? 1 : 0)	\
@@ -91,14 +93,15 @@
 			read_bytes += 5 + dci_pkt_len;
 			buf += 5 + dci_pkt_len; /* advance to next DCI pkt */
 		}
-		driver->in_busy_dci = 1;
 		/* wake up all sleeping DCI clients which have some data */
 		for (i = 0; i < MAX_DCI_CLIENTS; i++)
 			if (driver->dci_client_tbl[i].client &&
-					 driver->dci_client_tbl[i].data_len)
+				driver->dci_client_tbl[i].data_len) {
+				driver->in_busy_dci = 1;
 				diag_update_sleeping_process(
 					driver->dci_client_tbl[i].client->tgid,
 						 DCI_DATA_TYPE);
+			}
 	}
 }
 
@@ -224,6 +227,8 @@
 							dropped_events++;
 						return;
 					}
+					driver->dci_client_tbl[i].
+							received_events++;
 					*(int *)(entry->dci_data+
 					entry->data_len) = DCI_EVENT_TYPE;
 					memcpy(entry->dci_data+
@@ -281,6 +286,7 @@
 								dropped_logs++;
 						return;
 				}
+				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,
@@ -378,14 +384,6 @@
 		}
 	}
 	mutex_lock(&driver->dci_mutex);
-	if (new_dci_client)
-		driver->num_dci_client++;
-	if (driver->num_dci_client > MAX_DCI_CLIENTS) {
-		pr_info("diag: Max DCI Client limit reached\n");
-		driver->num_dci_client--;
-		mutex_unlock(&driver->dci_mutex);
-		return ret;
-	}
 	/* Make an entry in kernel DCI table */
 	driver->dci_tag++;
 	for (i = 0; i < dci_max_reg; i++) {
@@ -483,7 +481,7 @@
 		temp += 4;
 
 		head_log_mask_ptr = driver->dci_client_tbl[i].dci_log_mask;
-		pr_info("diag: head of dci log mask %p\n", head_log_mask_ptr);
+		pr_debug("diag: head of dci log mask %p\n", head_log_mask_ptr);
 		count = 0; /* iterator for extracting log codes */
 		while (count < num_codes) {
 			log_code = *(uint16_t *)temp;
@@ -500,11 +498,11 @@
 			while (log_mask_ptr) {
 				if (*log_mask_ptr == equip_id) {
 					found = 1;
-					pr_info("diag: find equip id = %x at %p\n",
+					pr_debug("diag: find equip id = %x at %p\n",
 						 equip_id, log_mask_ptr);
 					break;
 				} else {
-					pr_info("diag: did not find equip id = %x at %p\n",
+					pr_debug("diag: did not find equip id = %x at %p\n",
 						 equip_id, log_mask_ptr);
 					log_mask_ptr += 514;
 				}
@@ -583,9 +581,11 @@
 	uint8_t *update_ptr = dci_cumulative_event_mask;
 	uint8_t *event_mask_ptr;
 
+	mutex_lock(&dci_event_mask_mutex);
 	event_mask_ptr = driver->dci_client_tbl[client_index].dci_event_mask;
 	for (i = 0; i < DCI_EVENT_MASK_SIZE; i++)
 		*(update_ptr+i) |= *(event_mask_ptr+i);
+	mutex_unlock(&dci_event_mask_mutex);
 }
 
 void diag_send_dci_event_mask(smd_channel_t *ch)
@@ -631,6 +631,7 @@
 	uint8_t *log_mask_ptr =
 	driver->dci_client_tbl[client_index].dci_log_mask;
 
+	mutex_lock(&dci_log_mask_mutex);
 	*update_ptr = 0; /* add first equip id */
 	/* skip the first equip id */
 	update_ptr++; log_mask_ptr++;
@@ -644,6 +645,7 @@
 		update_ptr++;
 		log_mask_ptr++;
 	}
+	mutex_unlock(&dci_log_mask_mutex);
 }
 
 void diag_send_dci_log_mask(smd_channel_t *ch)
@@ -743,6 +745,8 @@
 	driver->num_dci_client = 0;
 	driver->in_busy_dci = 0;
 	mutex_init(&driver->dci_mutex);
+	mutex_init(&dci_log_mask_mutex);
+	mutex_init(&dci_event_mask_mutex);
 	if (driver->buf_in_dci == NULL) {
 		driver->buf_in_dci = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
 		if (driver->buf_in_dci == NULL)
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 97a285c..afcabcc 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -53,6 +53,17 @@
 	int total_capacity;
 	int dropped_logs;
 	int dropped_events;
+	int received_logs;
+	int received_events;
+};
+
+/* This is used for DCI health stats */
+struct diag_dci_health_stats {
+	int dropped_logs;
+	int dropped_events;
+	int received_logs;
+	int received_events;
+	int reset_status;
 };
 
 enum {
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 8a7ae9f..fe61d2d 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -246,17 +246,23 @@
 	int i = 0;
 	struct diagchar_priv *diagpriv_data = file->private_data;
 
+	pr_debug("diag: process exit %s\n", current->comm);
 	if (!(file->private_data)) {
 		pr_alert("diag: Invalid file pointer");
 		return -ENOMEM;
 	}
-
-	/* clean up any DCI registrations for this client
+	/* clean up any DCI registrations, if this is a DCI client
 	* This will specially help in case of ungraceful exit of any DCI client
 	* This call will remove any pending registrations of such client
 	*/
-	diagchar_ioctl(NULL, DIAG_IOCTL_DCI_DEINIT, 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) {
+			diagchar_ioctl(NULL, DIAG_IOCTL_DCI_DEINIT, 0);
+			break;
+		}
+	}
 	/* If the exiting process is the socket process */
 	if (driver->socket_process &&
 		(driver->socket_process->tgid == current->tgid)) {
@@ -381,7 +387,9 @@
 	int success = -1;
 	void *temp_buf;
 	uint16_t support_list = 0;
-	struct diag_dci_client_tbl *notify_params;
+	struct diag_dci_client_tbl *params =
+		kzalloc(sizeof(struct diag_dci_client_tbl), GFP_KERNEL);
+	struct diag_dci_health_stats stats;
 	int status;
 
 	if (iocmd == DIAG_IOCTL_COMMAND_REG) {
@@ -455,8 +463,12 @@
 			return DIAG_DCI_NO_REG;
 		if (driver->num_dci_client >= MAX_DCI_CLIENTS)
 			return DIAG_DCI_NO_REG;
-		notify_params = (struct diag_dci_client_tbl *) ioarg;
+		if (copy_from_user(params, (void *)ioarg,
+				 sizeof(struct diag_dci_client_tbl)))
+			return -EFAULT;
 		mutex_lock(&driver->dci_mutex);
+		if (!(driver->num_dci_client))
+			driver->in_busy_dci = 0;
 		driver->num_dci_client++;
 		pr_debug("diag: id = %d\n", driver->dci_client_id);
 		driver->dci_client_id++;
@@ -464,9 +476,9 @@
 			if (driver->dci_client_tbl[i].client == NULL) {
 				driver->dci_client_tbl[i].client = current;
 				driver->dci_client_tbl[i].list =
-							 notify_params->list;
+							 params->list;
 				driver->dci_client_tbl[i].signal_type =
-					 notify_params->signal_type;
+					 params->signal_type;
 				create_dci_log_mask_tbl(driver->
 					dci_client_tbl[i].dci_log_mask);
 				create_dci_event_mask_tbl(driver->
@@ -478,6 +490,8 @@
 								 IN_BUF_SIZE;
 				driver->dci_client_tbl[i].dropped_logs = 0;
 				driver->dci_client_tbl[i].dropped_events = 0;
+				driver->dci_client_tbl[i].received_logs = 0;
+				driver->dci_client_tbl[i].received_events = 0;
 				break;
 			}
 		}
@@ -487,32 +501,52 @@
 		success = -1;
 		/* Delete this process from DCI table */
 		mutex_lock(&driver->dci_mutex);
-		for (i = 0; i < dci_max_reg; i++) {
-			if (driver->req_tracking_tbl[i].pid == current->tgid) {
-				pr_debug("diag: delete %d\n", current->tgid);
+		for (i = 0; i < dci_max_reg; i++)
+			if (driver->req_tracking_tbl[i].pid == current->tgid)
 				driver->req_tracking_tbl[i].pid = 0;
-				success = i;
-			}
-		}
 		for (i = 0; i < MAX_DCI_CLIENTS; i++) {
-			if (driver->dci_client_tbl[i].client == current) {
+			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 any registrations were deleted successfully OR a valid
-		   client_id was sent in DEINIT call , then its DCI client */
-		if (success >= 0 || ioarg)
+		if (success >= 0)
 			driver->num_dci_client--;
-		driver->num_dci_client--;
 		mutex_unlock(&driver->dci_mutex);
-		pr_debug("diag: complete deleting registrations\n");
 		return success;
 	} else if (iocmd == DIAG_IOCTL_DCI_SUPPORT) {
 		if (driver->ch_dci)
 			support_list = support_list | DIAG_CON_MPSS;
 		*(uint16_t *)ioarg = support_list;
 		return DIAG_DCI_NO_ERROR;
+	} else if (iocmd == DIAG_IOCTL_DCI_HEALTH_STATS) {
+		if (copy_from_user(&stats, (void *)ioarg,
+				 sizeof(struct diag_dci_health_stats)))
+			return -EFAULT;
+		for (i = 0; i < MAX_DCI_CLIENTS; i++) {
+			params = &(driver->dci_client_tbl[i]);
+			if (params->client &&
+				params->client->tgid == current->tgid) {
+				stats.dropped_logs = params->dropped_logs;
+				stats.dropped_events = params->dropped_events;
+				stats.received_logs = params->received_logs;
+				stats.received_events = params->received_events;
+				if (stats.reset_status) {
+					params->dropped_logs = 0;
+					params->dropped_events = 0;
+					params->received_logs = 0;
+					params->received_events = 0;
+				}
+				break;
+			}
+		}
+		if (copy_to_user((void *)ioarg, &stats,
+				   sizeof(struct diag_dci_health_stats)))
+			return -EFAULT;
+		return DIAG_DCI_NO_ERROR;
 	} else if (iocmd == DIAG_IOCTL_LSM_DEINIT) {
 		for (i = 0; i < driver->num_clients; i++)
 			if (driver->client_map[i].pid == current->tgid)
@@ -1003,8 +1037,8 @@
 static int diagchar_write(struct file *file, const char __user *buf,
 				size_t count, loff_t *ppos)
 {
-	int err, ret = 0, pkt_type;
-	bool mdm_mask = false;
+	int err, ret = 0, pkt_type, token_offset = 0;
+	bool remote_data = false;
 #ifdef DIAG_DEBUG
 	int length = 0, i;
 #endif
@@ -1038,14 +1072,16 @@
 	if (pkt_type == USER_SPACE_DATA_TYPE) {
 		err = copy_from_user(driver->user_space_data, buf + 4,
 							 payload_size);
+		/* Check for proc_type */
+		if (*(int *)driver->user_space_data == MDM_TOKEN) {
+			remote_data = true;
+			token_offset = 4;
+			payload_size -= 4;
+			buf += 4;
+		}
+
 		/* Check masks for On-Device logging */
 		if (driver->mask_check) {
-			/* Check if mask is for MDM or MSM */
-			if (*(int *)driver->user_space_data == MDM_TOKEN) {
-				mdm_mask = true;
-				driver->user_space_data += 4;
-				buf += 4;
-			}
 			if (!mask_request_validate(driver->user_space_data)) {
 				pr_alert("diag: mask request Invalid\n");
 				return -EFAULT;
@@ -1055,31 +1091,34 @@
 #ifdef DIAG_DEBUG
 		pr_debug("diag: user space data %d\n", payload_size);
 		for (i = 0; i < payload_size; i++)
-			pr_debug("\t %x", *((driver->user_space_data)+i));
+			pr_debug("\t %x", *((driver->user_space_data
+						+ token_offset)+i));
 #endif
 #ifdef CONFIG_DIAG_SDIO_PIPE
 		/* send masks to 9k too */
-		if (driver->sdio_ch && mdm_mask) {
+		if (driver->sdio_ch && remote_data) {
 			wait_event_interruptible(driver->wait_q,
 				 (sdio_write_avail(driver->sdio_ch) >=
 					 payload_size));
 			if (driver->sdio_ch && (payload_size > 0)) {
 				sdio_write(driver->sdio_ch, (void *)
-				   (driver->user_space_data), payload_size);
+				   (driver->user_space_data + token_offset),
+				   payload_size);
 			}
 		}
 #endif
 #ifdef CONFIG_DIAG_BRIDGE_CODE
 		/* send masks to 9k too */
-		if (driver->hsic_ch && (payload_size > 0) && mdm_mask) {
+		if (driver->hsic_ch && (payload_size > 0) && remote_data) {
 			/* wait sending mask updates if HSIC ch not ready */
 			if (driver->in_busy_hsic_write)
 				wait_event_interruptible(driver->wait_q,
 					(driver->in_busy_hsic_write != 1));
 			driver->in_busy_hsic_write = 1;
 			driver->in_busy_hsic_read_on_device = 0;
-			err = diag_bridge_write(driver->user_space_data,
-							 payload_size);
+			err = diag_bridge_write(
+					driver->user_space_data + token_offset,
+					payload_size);
 			if (err) {
 				pr_err("diag: err sending mask to MDM: %d\n",
 									 err);
@@ -1093,11 +1132,12 @@
 					driver->in_busy_hsic_write = 0;
 			}
 		}
-		if (driver->diag_smux_enabled && mdm_mask && driver->lcid) {
+		if (driver->diag_smux_enabled && remote_data
+						&& driver->lcid) {
 			if (payload_size > 0) {
 				err = msm_smux_write(driver->lcid, NULL,
-						driver->user_space_data,
-						payload_size);
+					driver->user_space_data + token_offset,
+					payload_size);
 				if (err) {
 					pr_err("diag:send mask to MDM err %d",
 							err);
@@ -1107,9 +1147,10 @@
 		}
 #endif
 		/* send masks to 8k now */
-		if (!mdm_mask)
-			diag_process_hdlc((void *)(driver->user_space_data),
-							 payload_size);
+		if (!remote_data)
+			diag_process_hdlc((void *)
+				(driver->user_space_data + token_offset),
+				 payload_size);
 		return 0;
 	}
 
diff --git a/drivers/coresight/coresight-csr.c b/drivers/coresight/coresight-csr.c
index e9ac904..1f6bd1d 100644
--- a/drivers/coresight/coresight-csr.c
+++ b/drivers/coresight/coresight-csr.c
@@ -86,7 +86,7 @@
 	CSR_UNLOCK(drvdata);
 
 	usbbamctrl = csr_readl(drvdata, CSR_USBBAMCTRL);
-	usbbamctrl = (usbbamctrl & ~0x3) | BLKSIZE_256;
+	usbbamctrl = (usbbamctrl & ~0x3) | BLKSIZE_2048;
 	csr_writel(drvdata, usbbamctrl, CSR_USBBAMCTRL);
 
 	usbflshctrl = csr_readl(drvdata, CSR_USBFLSHCTRL);
diff --git a/drivers/coresight/coresight-etm.c b/drivers/coresight/coresight-etm.c
index 50bae55..f3fe70f 100644
--- a/drivers/coresight/coresight-etm.c
+++ b/drivers/coresight/coresight-etm.c
@@ -25,8 +25,9 @@
 #include <linux/wakelock.h>
 #include <linux/sysfs.h>
 #include <linux/stat.h>
-#include <linux/mutex.h>
+#include <linux/spinlock.h>
 #include <linux/clk.h>
+#include <linux/cpu.h>
 #include <linux/of_coresight.h>
 #include <linux/coresight.h>
 #include <asm/sections.h>
@@ -191,10 +192,12 @@
 	struct device			*dev;
 	struct coresight_device		*csdev;
 	struct clk			*clk;
-	struct mutex			mutex;
+	spinlock_t			spinlock;
 	struct wake_lock		wake_lock;
 	int				cpu;
 	uint8_t				arch;
+	bool				enable;
+	bool				os_unlock;
 	uint8_t				nr_addr_cmp;
 	uint8_t				nr_cntr;
 	uint8_t				nr_ext_inp;
@@ -203,7 +206,6 @@
 	uint8_t				reset;
 	uint32_t			mode;
 	uint32_t			ctrl;
-	uint8_t				ctrl_pwrdwn;
 	uint32_t			trigger_event;
 	uint32_t			startstop_ctrl;
 	uint32_t			enable_event;
@@ -230,12 +232,22 @@
 	uint32_t			ctxid_mask;
 	uint32_t			sync_freq;
 	uint32_t			timestamp_event;
-	uint8_t				pdcr_pwrup;
 	bool				pcsave_impl;
 	bool				pcsave_enable;
 };
 
-static struct etm_drvdata *etm0drvdata;
+static struct etm_drvdata *etmdrvdata[NR_CPUS];
+
+/*
+ * Memory mapped writes to clear os lock are not supported on Krait v1, v2
+ * and OS lock must be unlocked before any memory mapped access, otherwise
+ * memory mapped reads/writes will be invalid.
+ */
+static void etm_os_unlock(void *info)
+{
+	etm_writel_cp14(0x0, ETMOSLAR);
+	isb();
+}
 
 /*
  * ETM clock is derived from the processor clock and gets enabled on a
@@ -339,48 +351,19 @@
 	     etm_readl(drvdata, ETMSR));
 }
 
-static void etm_save_pwrdwn(struct etm_drvdata *drvdata)
-{
-	drvdata->ctrl_pwrdwn = BVAL(etm_readl(drvdata, ETMCR), 0);
-}
-
-static void etm_restore_pwrdwn(struct etm_drvdata *drvdata)
-{
-	uint32_t etmcr;
-
-	etmcr = etm_readl(drvdata, ETMCR);
-	etmcr = (etmcr & ~BIT(0)) | drvdata->ctrl_pwrdwn;
-	etm_writel(drvdata, etmcr, ETMCR);
-}
-
-static void etm_save_pwrup(struct etm_drvdata *drvdata)
-{
-	drvdata->pdcr_pwrup = BVAL(etm_readl_mm(drvdata, ETMPDCR), 3);
-}
-
-static void etm_restore_pwrup(struct etm_drvdata *drvdata)
-{
-	uint32_t etmpdcr;
-
-	etmpdcr = etm_readl_mm(drvdata, ETMPDCR);
-	etmpdcr = (etmpdcr & ~BIT(3)) | (drvdata->pdcr_pwrup << 3);
-	etm_writel_mm(drvdata, etmpdcr, ETMPDCR);
-}
-
 static void etm_enable_pcsave(void *info)
 {
 	struct etm_drvdata *drvdata = info;
 
 	ETM_UNLOCK(drvdata);
 
-	etm_save_pwrup(drvdata);
 	/*
 	 * ETMPDCR is only accessible via memory mapped interface and so use
 	 * it first to enable power/clock to allow subsequent cp14 accesses.
 	 */
 	etm_set_pwrup(drvdata);
 	etm_clr_pwrdwn(drvdata);
-	etm_restore_pwrup(drvdata);
+	etm_clr_pwrup(drvdata);
 
 	ETM_LOCK(drvdata);
 }
@@ -391,14 +374,8 @@
 
 	ETM_UNLOCK(drvdata);
 
-	etm_save_pwrup(drvdata);
-	/*
-	 * ETMPDCR is only accessible via memory mapped interface and so use
-	 * it first to enable power/clock to allow subsequent cp14 accesses.
-	 */
-	etm_set_pwrup(drvdata);
-	etm_set_pwrdwn(drvdata);
-	etm_restore_pwrup(drvdata);
+	if (!drvdata->enable)
+		etm_set_pwrdwn(drvdata);
 
 	ETM_LOCK(drvdata);
 }
@@ -416,12 +393,13 @@
 	 * to allow subsequent cp14 accesses.
 	 */
 	etm_set_pwrup(drvdata);
-	etm_save_pwrdwn(drvdata);
 	/*
 	 * Clear power down bit since when this bit is set writes to
-	 * certain registers might be ignored.
+	 * certain registers might be ignored. This is also a pre-requisite
+	 * for trace enable.
 	 */
 	etm_clr_pwrdwn(drvdata);
+	etm_clr_pwrup(drvdata);
 	etm_set_prog(drvdata);
 
 	etmcr = etm_readl(drvdata, ETMCR);
@@ -463,7 +441,6 @@
 	etm_writel(drvdata, 0x00000000, ETMVMIDCVR);
 
 	etm_clr_prog(drvdata);
-	etm_restore_pwrdwn(drvdata);
 	ETM_LOCK(drvdata);
 
 	dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu);
@@ -480,17 +457,29 @@
 	if (ret)
 		goto err_clk;
 
-	mutex_lock(&drvdata->mutex);
-	/* executing __etm_enable on the cpu whose ETM is being enabled
+	get_online_cpus();
+	spin_lock(&drvdata->spinlock);
+
+	/*
+	 * Executing __etm_enable on the cpu whose ETM is being enabled
 	 * ensures that register writes occur when cpu is powered.
 	 */
-	smp_call_function_single(drvdata->cpu, __etm_enable, drvdata, 1);
-	mutex_unlock(&drvdata->mutex);
+	ret = smp_call_function_single(drvdata->cpu, __etm_enable, drvdata, 1);
+	if (ret)
+		goto err;
+	drvdata->enable = true;
+
+	spin_unlock(&drvdata->spinlock);
+	put_online_cpus();
 
 	wake_unlock(&drvdata->wake_lock);
 
 	dev_info(drvdata->dev, "ETM tracing enabled\n");
 	return 0;
+err:
+	spin_unlock(&drvdata->spinlock);
+	put_online_cpus();
+	clk_disable_unprepare(drvdata->clk);
 err_clk:
 	wake_unlock(&drvdata->wake_lock);
 	return ret;
@@ -501,20 +490,13 @@
 	struct etm_drvdata *drvdata = info;
 
 	ETM_UNLOCK(drvdata);
-	etm_save_pwrdwn(drvdata);
-	/*
-	 * Clear power down bit since when this bit is set writes to
-	 * certain registers might be ignored.
-	 */
-	etm_clr_pwrdwn(drvdata);
 	etm_set_prog(drvdata);
 
 	/* program trace enable to low by using always false event */
 	etm_writel(drvdata, 0x6F | BIT(14), ETMTEEVR);
 
-	etm_restore_pwrdwn(drvdata);
-	/* Vote for ETM power/clock disable */
-	etm_clr_pwrup(drvdata);
+	if (!drvdata->pcsave_enable)
+		etm_set_pwrdwn(drvdata);
 	ETM_LOCK(drvdata);
 
 	dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu);
@@ -526,12 +508,18 @@
 
 	wake_lock(&drvdata->wake_lock);
 
-	mutex_lock(&drvdata->mutex);
-	/* executing __etm_disable on the cpu whose ETM is being disabled
+	get_online_cpus();
+	spin_lock(&drvdata->spinlock);
+
+	/*
+	 * Executing __etm_disable on the cpu whose ETM is being disabled
 	 * ensures that register writes occur when cpu is powered.
 	 */
 	smp_call_function_single(drvdata->cpu, __etm_disable, drvdata, 1);
-	mutex_unlock(&drvdata->mutex);
+	drvdata->enable = false;
+
+	spin_unlock(&drvdata->spinlock);
+	put_online_cpus();
 
 	clk_disable_unprepare(drvdata->clk);
 
@@ -600,7 +588,7 @@
 	if (sscanf(buf, "%lx", &val) != 1)
 		return -EINVAL;
 
-	mutex_lock(&drvdata->mutex);
+	spin_lock(&drvdata->spinlock);
 	if (val) {
 		drvdata->mode = ETM_MODE_EXCLUDE;
 		drvdata->ctrl = 0x0;
@@ -644,7 +632,7 @@
 			drvdata->sync_freq = 0x80;
 		drvdata->timestamp_event = 0x406F;
 	}
-	mutex_unlock(&drvdata->mutex);
+	spin_unlock(&drvdata->spinlock);
 	return size;
 }
 static DEVICE_ATTR(reset, S_IRUGO | S_IWUSR, etm_show_reset, etm_store_reset);
@@ -667,7 +655,7 @@
 	if (sscanf(buf, "%lx", &val) != 1)
 		return -EINVAL;
 
-	mutex_lock(&drvdata->mutex);
+	spin_lock(&drvdata->spinlock);
 	drvdata->mode = val & ETM_MODE_ALL;
 
 	if (drvdata->mode & ETM_MODE_EXCLUDE)
@@ -694,7 +682,7 @@
 		drvdata->ctrl |= (BIT(14) | BIT(15));
 	else
 		drvdata->ctrl &= ~(BIT(14) | BIT(15));
-	mutex_unlock(&drvdata->mutex);
+	spin_unlock(&drvdata->spinlock);
 
 	return size;
 }
@@ -796,12 +784,13 @@
 	if (val >= drvdata->nr_addr_cmp)
 		return -EINVAL;
 
-	/* Use mutex to ensure index doesn't change while it gets dereferenced
-	 * multiple times within a mutex block elsewhere.
+	/*
+	 * Use spinlock to ensure index doesn't change while it gets
+	 * dereferenced multiple times within a spinlock block elsewhere.
 	 */
-	mutex_lock(&drvdata->mutex);
+	spin_lock(&drvdata->spinlock);
 	drvdata->addr_idx = val;
-	mutex_unlock(&drvdata->mutex);
+	spin_unlock(&drvdata->spinlock);
 	return size;
 }
 static DEVICE_ATTR(addr_idx, S_IRUGO | S_IWUSR, etm_show_addr_idx,
@@ -814,16 +803,16 @@
 	unsigned long val;
 	uint8_t idx;
 
-	mutex_lock(&drvdata->mutex);
+	spin_lock(&drvdata->spinlock);
 	idx = drvdata->addr_idx;
 	if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
 	      drvdata->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
-		mutex_unlock(&drvdata->mutex);
+		spin_unlock(&drvdata->spinlock);
 		return -EPERM;
 	}
 
 	val = drvdata->addr_val[idx];
-	mutex_unlock(&drvdata->mutex);
+	spin_unlock(&drvdata->spinlock);
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -838,17 +827,17 @@
 	if (sscanf(buf, "%lx", &val) != 1)
 		return -EINVAL;
 
-	mutex_lock(&drvdata->mutex);
+	spin_lock(&drvdata->spinlock);
 	idx = drvdata->addr_idx;
 	if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
 	      drvdata->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
-		mutex_unlock(&drvdata->mutex);
+		spin_unlock(&drvdata->spinlock);
 		return -EPERM;
 	}
 
 	drvdata->addr_val[idx] = val;
 	drvdata->addr_type[idx] = ETM_ADDR_TYPE_SINGLE;
-	mutex_unlock(&drvdata->mutex);
+	spin_unlock(&drvdata->spinlock);
 	return size;
 }
 static DEVICE_ATTR(addr_single, S_IRUGO | S_IWUSR, etm_show_addr_single,
@@ -861,23 +850,23 @@
 	unsigned long val1, val2;
 	uint8_t idx;
 
-	mutex_lock(&drvdata->mutex);
+	spin_lock(&drvdata->spinlock);
 	idx = drvdata->addr_idx;
 	if (idx % 2 != 0) {
-		mutex_unlock(&drvdata->mutex);
+		spin_unlock(&drvdata->spinlock);
 		return -EPERM;
 	}
 	if (!((drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE &&
 	       drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
 	      (drvdata->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
 	       drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
-		mutex_unlock(&drvdata->mutex);
+		spin_unlock(&drvdata->spinlock);
 		return -EPERM;
 	}
 
 	val1 = drvdata->addr_val[idx];
 	val2 = drvdata->addr_val[idx + 1];
-	mutex_unlock(&drvdata->mutex);
+	spin_unlock(&drvdata->spinlock);
 	return scnprintf(buf, PAGE_SIZE, "%#lx %#lx\n", val1, val2);
 }
 
@@ -895,17 +884,17 @@
 	if (val1 > val2)
 		return -EINVAL;
 
-	mutex_lock(&drvdata->mutex);
+	spin_lock(&drvdata->spinlock);
 	idx = drvdata->addr_idx;
 	if (idx % 2 != 0) {
-		mutex_unlock(&drvdata->mutex);
+		spin_unlock(&drvdata->spinlock);
 		return -EPERM;
 	}
 	if (!((drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE &&
 	       drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
 	      (drvdata->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
 	       drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
-		mutex_unlock(&drvdata->mutex);
+		spin_unlock(&drvdata->spinlock);
 		return -EPERM;
 	}
 
@@ -914,7 +903,7 @@
 	drvdata->addr_val[idx + 1] = val2;
 	drvdata->addr_type[idx + 1] = ETM_ADDR_TYPE_RANGE;
 	drvdata->enable_ctrl1 |= (1 << (idx/2));
-	mutex_unlock(&drvdata->mutex);
+	spin_unlock(&drvdata->spinlock);
 	return size;
 }
 static DEVICE_ATTR(addr_range, S_IRUGO | S_IWUSR, etm_show_addr_range,
@@ -927,16 +916,16 @@
 	unsigned long val;
 	uint8_t idx;
 
-	mutex_lock(&drvdata->mutex);
+	spin_lock(&drvdata->spinlock);
 	idx = drvdata->addr_idx;
 	if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
 	      drvdata->addr_type[idx] == ETM_ADDR_TYPE_START)) {
-		mutex_unlock(&drvdata->mutex);
+		spin_unlock(&drvdata->spinlock);
 		return -EPERM;
 	}
 
 	val = drvdata->addr_val[idx];
-	mutex_unlock(&drvdata->mutex);
+	spin_unlock(&drvdata->spinlock);
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -951,11 +940,11 @@
 	if (sscanf(buf, "%lx", &val) != 1)
 		return -EINVAL;
 
-	mutex_lock(&drvdata->mutex);
+	spin_lock(&drvdata->spinlock);
 	idx = drvdata->addr_idx;
 	if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
 	      drvdata->addr_type[idx] == ETM_ADDR_TYPE_START)) {
-		mutex_unlock(&drvdata->mutex);
+		spin_unlock(&drvdata->spinlock);
 		return -EPERM;
 	}
 
@@ -963,7 +952,7 @@
 	drvdata->addr_type[idx] = ETM_ADDR_TYPE_START;
 	drvdata->startstop_ctrl |= (1 << idx);
 	drvdata->enable_ctrl1 |= BIT(25);
-	mutex_unlock(&drvdata->mutex);
+	spin_unlock(&drvdata->spinlock);
 	return size;
 }
 static DEVICE_ATTR(addr_start, S_IRUGO | S_IWUSR, etm_show_addr_start,
@@ -976,16 +965,16 @@
 	unsigned long val;
 	uint8_t idx;
 
-	mutex_lock(&drvdata->mutex);
+	spin_lock(&drvdata->spinlock);
 	idx = drvdata->addr_idx;
 	if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
 	      drvdata->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
-		mutex_unlock(&drvdata->mutex);
+		spin_unlock(&drvdata->spinlock);
 		return -EPERM;
 	}
 
 	val = drvdata->addr_val[idx];
-	mutex_unlock(&drvdata->mutex);
+	spin_unlock(&drvdata->spinlock);
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -1000,11 +989,11 @@
 	if (sscanf(buf, "%lx", &val) != 1)
 		return -EINVAL;
 
-	mutex_lock(&drvdata->mutex);
+	spin_lock(&drvdata->spinlock);
 	idx = drvdata->addr_idx;
 	if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
 	      drvdata->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
-		mutex_unlock(&drvdata->mutex);
+		spin_unlock(&drvdata->spinlock);
 		return -EPERM;
 	}
 
@@ -1012,7 +1001,7 @@
 	drvdata->addr_type[idx] = ETM_ADDR_TYPE_STOP;
 	drvdata->startstop_ctrl |= (1 << (idx + 16));
 	drvdata->enable_ctrl1 |= BIT(25);
-	mutex_unlock(&drvdata->mutex);
+	spin_unlock(&drvdata->spinlock);
 	return size;
 }
 static DEVICE_ATTR(addr_stop, S_IRUGO | S_IWUSR, etm_show_addr_stop,
@@ -1024,9 +1013,9 @@
 	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
-	mutex_lock(&drvdata->mutex);
+	spin_lock(&drvdata->spinlock);
 	val = drvdata->addr_acctype[drvdata->addr_idx];
-	mutex_unlock(&drvdata->mutex);
+	spin_unlock(&drvdata->spinlock);
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -1040,9 +1029,9 @@
 	if (sscanf(buf, "%lx", &val) != 1)
 		return -EINVAL;
 
-	mutex_lock(&drvdata->mutex);
+	spin_lock(&drvdata->spinlock);
 	drvdata->addr_acctype[drvdata->addr_idx] = val;
-	mutex_unlock(&drvdata->mutex);
+	spin_unlock(&drvdata->spinlock);
 	return size;
 }
 static DEVICE_ATTR(addr_acctype, S_IRUGO | S_IWUSR, etm_show_addr_acctype,
@@ -1069,12 +1058,13 @@
 	if (val >= drvdata->nr_cntr)
 		return -EINVAL;
 
-	/* Use mutex to ensure index doesn't change while it gets dereferenced
-	 * multiple times within a mutex block elsewhere.
+	/*
+	 * Use spinlock to ensure index doesn't change while it gets
+	 * dereferenced multiple times within a spinlock block elsewhere.
 	 */
-	mutex_lock(&drvdata->mutex);
+	spin_lock(&drvdata->spinlock);
 	drvdata->cntr_idx = val;
-	mutex_unlock(&drvdata->mutex);
+	spin_unlock(&drvdata->spinlock);
 	return size;
 }
 static DEVICE_ATTR(cntr_idx, S_IRUGO | S_IWUSR, etm_show_cntr_idx,
@@ -1086,9 +1076,9 @@
 	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
-	mutex_lock(&drvdata->mutex);
+	spin_lock(&drvdata->spinlock);
 	val = drvdata->cntr_rld_val[drvdata->cntr_idx];
-	mutex_unlock(&drvdata->mutex);
+	spin_unlock(&drvdata->spinlock);
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -1102,9 +1092,9 @@
 	if (sscanf(buf, "%lx", &val) != 1)
 		return -EINVAL;
 
-	mutex_lock(&drvdata->mutex);
+	spin_lock(&drvdata->spinlock);
 	drvdata->cntr_rld_val[drvdata->cntr_idx] = val;
-	mutex_unlock(&drvdata->mutex);
+	spin_unlock(&drvdata->spinlock);
 	return size;
 }
 static DEVICE_ATTR(cntr_rld_val, S_IRUGO | S_IWUSR, etm_show_cntr_rld_val,
@@ -1116,9 +1106,9 @@
 	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
-	mutex_lock(&drvdata->mutex);
+	spin_lock(&drvdata->spinlock);
 	val = drvdata->cntr_event[drvdata->cntr_idx];
-	mutex_unlock(&drvdata->mutex);
+	spin_unlock(&drvdata->spinlock);
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -1132,9 +1122,9 @@
 	if (sscanf(buf, "%lx", &val) != 1)
 		return -EINVAL;
 
-	mutex_lock(&drvdata->mutex);
+	spin_lock(&drvdata->spinlock);
 	drvdata->cntr_event[drvdata->cntr_idx] = val & ETM_EVENT_MASK;
-	mutex_unlock(&drvdata->mutex);
+	spin_unlock(&drvdata->spinlock);
 	return size;
 }
 static DEVICE_ATTR(cntr_event, S_IRUGO | S_IWUSR, etm_show_cntr_event,
@@ -1146,9 +1136,9 @@
 	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
-	mutex_lock(&drvdata->mutex);
+	spin_lock(&drvdata->spinlock);
 	val = drvdata->cntr_rld_event[drvdata->cntr_idx];
-	mutex_unlock(&drvdata->mutex);
+	spin_unlock(&drvdata->spinlock);
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -1162,9 +1152,9 @@
 	if (sscanf(buf, "%lx", &val) != 1)
 		return -EINVAL;
 
-	mutex_lock(&drvdata->mutex);
+	spin_lock(&drvdata->spinlock);
 	drvdata->cntr_rld_event[drvdata->cntr_idx] = val & ETM_EVENT_MASK;
-	mutex_unlock(&drvdata->mutex);
+	spin_unlock(&drvdata->spinlock);
 	return size;
 }
 static DEVICE_ATTR(cntr_rld_event, S_IRUGO | S_IWUSR, etm_show_cntr_rld_event,
@@ -1176,9 +1166,9 @@
 	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
-	mutex_lock(&drvdata->mutex);
+	spin_lock(&drvdata->spinlock);
 	val = drvdata->cntr_val[drvdata->cntr_idx];
-	mutex_unlock(&drvdata->mutex);
+	spin_unlock(&drvdata->spinlock);
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -1192,9 +1182,9 @@
 	if (sscanf(buf, "%lx", &val) != 1)
 		return -EINVAL;
 
-	mutex_lock(&drvdata->mutex);
+	spin_lock(&drvdata->spinlock);
 	drvdata->cntr_val[drvdata->cntr_idx] = val;
-	mutex_unlock(&drvdata->mutex);
+	spin_unlock(&drvdata->spinlock);
 	return size;
 }
 static DEVICE_ATTR(cntr_val, S_IRUGO | S_IWUSR, etm_show_cntr_val,
@@ -1398,12 +1388,13 @@
 	if (val >= drvdata->nr_ctxid_cmp)
 		return -EINVAL;
 
-	/* Use mutex to ensure index doesn't change while it gets dereferenced
-	 * multiple times within a mutex block elsewhere.
+	/*
+	 * Use spinlock to ensure index doesn't change while it gets
+	 * dereferenced multiple times within a spinlock block elsewhere.
 	 */
-	mutex_lock(&drvdata->mutex);
+	spin_lock(&drvdata->spinlock);
 	drvdata->ctxid_idx = val;
-	mutex_unlock(&drvdata->mutex);
+	spin_unlock(&drvdata->spinlock);
 	return size;
 }
 static DEVICE_ATTR(ctxid_idx, S_IRUGO | S_IWUSR, etm_show_ctxid_idx,
@@ -1415,9 +1406,9 @@
 	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
-	mutex_lock(&drvdata->mutex);
+	spin_lock(&drvdata->spinlock);
 	val = drvdata->ctxid_val[drvdata->ctxid_idx];
-	mutex_unlock(&drvdata->mutex);
+	spin_unlock(&drvdata->spinlock);
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -1431,9 +1422,9 @@
 	if (sscanf(buf, "%lx", &val) != 1)
 		return -EINVAL;
 
-	mutex_lock(&drvdata->mutex);
+	spin_lock(&drvdata->spinlock);
 	drvdata->ctxid_val[drvdata->ctxid_idx] = val;
-	mutex_unlock(&drvdata->mutex);
+	spin_unlock(&drvdata->spinlock);
 	return size;
 }
 static DEVICE_ATTR(ctxid_val, S_IRUGO | S_IWUSR, etm_show_ctxid_val,
@@ -1527,26 +1518,43 @@
 
 static int __etm_store_pcsave(struct etm_drvdata *drvdata, unsigned long val)
 {
-	int ret;
+	int ret = 0;
 
 	ret = clk_prepare_enable(drvdata->clk);
 	if (ret)
 		return ret;
 
-	mutex_lock(&drvdata->mutex);
+	get_online_cpus();
+	spin_lock(&drvdata->spinlock);
 	if (val) {
-		smp_call_function_single(drvdata->cpu, etm_enable_pcsave,
-					 drvdata, 1);
+		if (drvdata->pcsave_enable)
+			goto out;
+
+		ret = smp_call_function_single(drvdata->cpu, etm_enable_pcsave,
+					       drvdata, 1);
+		if (ret)
+			goto out;
 		drvdata->pcsave_enable = true;
+
+		dev_info(drvdata->dev, "PC save enabled\n");
 	} else {
-		smp_call_function_single(drvdata->cpu, etm_disable_pcsave,
-					 drvdata, 1);
+		if (!drvdata->pcsave_enable)
+			goto out;
+
+		ret = smp_call_function_single(drvdata->cpu, etm_disable_pcsave,
+					       drvdata, 1);
+		if (ret)
+			goto out;
 		drvdata->pcsave_enable = false;
+
+		dev_info(drvdata->dev, "PC save disabled\n");
 	}
-	mutex_unlock(&drvdata->mutex);
+out:
+	spin_unlock(&drvdata->spinlock);
+	put_online_cpus();
 
 	clk_disable_unprepare(drvdata->clk);
-	return 0;
+	return ret;
 }
 
 static ssize_t etm_store_pcsave(struct device *dev,
@@ -1613,15 +1621,42 @@
 	NULL,
 };
 
-/* Memory mapped writes to clear os lock not supported */
-static void etm_os_unlock(void *unused)
+static int etm_cpu_callback(struct notifier_block *nfb, unsigned long action,
+			    void *hcpu)
 {
-	unsigned long value = 0x0;
+	unsigned int cpu = (unsigned long)hcpu;
 
-	asm("mcr p14, 1, %0, c1, c0, 4\n\t" : : "r" (value));
-	asm("isb\n\t");
+	switch (action & (~CPU_TASKS_FROZEN)) {
+	case CPU_STARTING:
+		if (etmdrvdata[cpu] && !etmdrvdata[cpu]->os_unlock) {
+			spin_lock(&etmdrvdata[cpu]->spinlock);
+			etm_os_unlock(etmdrvdata[cpu]);
+			etmdrvdata[cpu]->os_unlock = true;
+			spin_unlock(&etmdrvdata[cpu]->spinlock);
+		}
+
+		if (etmdrvdata[cpu] && etmdrvdata[cpu]->enable) {
+			spin_lock(&etmdrvdata[cpu]->spinlock);
+			__etm_enable(etmdrvdata[cpu]);
+			spin_unlock(&etmdrvdata[cpu]->spinlock);
+		}
+		break;
+
+	case CPU_DYING:
+		if (etmdrvdata[cpu] && etmdrvdata[cpu]->enable) {
+			spin_lock(&etmdrvdata[cpu]->spinlock);
+			__etm_disable(etmdrvdata[cpu]);
+			spin_unlock(&etmdrvdata[cpu]->spinlock);
+		}
+		break;
+	}
+	return NOTIFY_OK;
 }
 
+static struct notifier_block etm_cpu_notifier = {
+	.notifier_call = etm_cpu_callback,
+};
+
 static bool __devinit etm_arch_supported(uint8_t arch)
 {
 	switch (arch) {
@@ -1633,15 +1668,6 @@
 	return true;
 }
 
-static void __devinit etm_prepare_arch(struct etm_drvdata *drvdata)
-{
-	/* Unlock OS lock first to allow memory mapped reads and writes. This
-	 * is required for Krait pass1
-	 * */
-	etm_os_unlock(NULL);
-	smp_call_function(etm_os_unlock, NULL, 1);
-}
-
 static void __devinit etm_init_arch_data(void *info)
 {
 	uint32_t etmidr;
@@ -1660,6 +1686,7 @@
 	 * certain registers might be ignored.
 	 */
 	etm_clr_pwrdwn(drvdata);
+	etm_clr_pwrup(drvdata);
 	/* Set prog bit. It will be set from reset but this is included to
 	 * ensure it is set
 	 */
@@ -1677,19 +1704,17 @@
 	drvdata->nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
 
 	etm_set_pwrdwn(drvdata);
-	/* Vote for ETM power/clock disable */
-	etm_clr_pwrup(drvdata);
 	ETM_LOCK(drvdata);
 }
 
 static void __devinit etm_copy_arch_data(struct etm_drvdata *drvdata)
 {
-	drvdata->arch = etm0drvdata->arch;
-	drvdata->nr_addr_cmp = etm0drvdata->nr_addr_cmp;
-	drvdata->nr_cntr = etm0drvdata->nr_cntr;
-	drvdata->nr_ext_inp = etm0drvdata->nr_ext_inp;
-	drvdata->nr_ext_out = etm0drvdata->nr_ext_out;
-	drvdata->nr_ctxid_cmp = etm0drvdata->nr_ctxid_cmp;
+	drvdata->arch = etmdrvdata[0]->arch;
+	drvdata->nr_addr_cmp = etmdrvdata[0]->nr_addr_cmp;
+	drvdata->nr_cntr = etmdrvdata[0]->nr_cntr;
+	drvdata->nr_ext_inp = etmdrvdata[0]->nr_ext_inp;
+	drvdata->nr_ext_out = etmdrvdata[0]->nr_ext_out;
+	drvdata->nr_ctxid_cmp = etmdrvdata[0]->nr_ctxid_cmp;
 }
 
 static void __devinit etm_init_default_data(struct etm_drvdata *drvdata)
@@ -1774,7 +1799,7 @@
 	if (!drvdata->base)
 		return -ENOMEM;
 
-	mutex_init(&drvdata->mutex);
+	spin_lock_init(&drvdata->spinlock);
 	wake_lock_init(&drvdata->wake_lock, WAKE_LOCK_SUSPEND, "coresight-etm");
 
 	drvdata->clk = devm_clk_get(dev, "core_clk");
@@ -1787,23 +1812,32 @@
 	if (ret)
 		goto err0;
 
-	drvdata->cpu = count++;
-
 	ret = clk_prepare_enable(drvdata->clk);
 	if (ret)
 		goto err0;
 
-	/* Use CPU0 to populate read-only configuration data for ETM0. For other
-	 * ETMs copy it over from ETM0.
+	drvdata->cpu = count++;
+
+	get_online_cpus();
+	etmdrvdata[drvdata->cpu] = drvdata;
+
+	if (!smp_call_function_single(drvdata->cpu, etm_os_unlock, NULL, 1))
+		drvdata->os_unlock = true;
+	/*
+	 * Use CPU0 to populate read-only configuration data for ETM0. For
+	 * other ETMs copy it over from ETM0.
 	 */
 	if (drvdata->cpu == 0) {
-		etm_prepare_arch(drvdata);
-		smp_call_function_single(drvdata->cpu, etm_init_arch_data,
-					 drvdata, 1);
-		etm0drvdata = drvdata;
+		register_hotcpu_notifier(&etm_cpu_notifier);
+		if (smp_call_function_single(drvdata->cpu, etm_init_arch_data,
+					     drvdata, 1))
+			dev_err(dev, "ETM arch init failed\n");
 	} else {
 		etm_copy_arch_data(drvdata);
 	}
+
+	put_online_cpus();
+
 	if (etm_arch_supported(drvdata->arch) == false) {
 		ret = -EINVAL;
 		goto err1;
@@ -1821,7 +1855,7 @@
 		ret = msm_dump_table_register(&dump);
 		if (ret) {
 			devm_kfree(dev, baddr);
-			dev_err(dev, "ETM REG dump setup failed\n");
+			dev_err(dev, "ETM REG dump setup failed/unsupported\n");
 		}
 	} else {
 		dev_err(dev, "ETM REG dump space allocation failed\n");
@@ -1830,7 +1864,7 @@
 	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
 	if (!desc) {
 		ret = -ENOMEM;
-		goto err0;
+		goto err2;
 	}
 	desc->type = CORESIGHT_DEV_TYPE_SOURCE;
 	desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
@@ -1842,7 +1876,7 @@
 	drvdata->csdev = coresight_register(desc);
 	if (IS_ERR(drvdata->csdev)) {
 		ret = PTR_ERR(drvdata->csdev);
-		goto err0;
+		goto err2;
 	}
 
 	if (pdev->dev.of_node)
@@ -1864,11 +1898,17 @@
 		__etm_store_pcsave(drvdata, true);
 
 	return 0;
+err2:
+	if (drvdata->cpu == 0)
+		unregister_hotcpu_notifier(&etm_cpu_notifier);
+	wake_lock_destroy(&drvdata->wake_lock);
+	return ret;
 err1:
+	if (drvdata->cpu == 0)
+		unregister_hotcpu_notifier(&etm_cpu_notifier);
 	clk_disable_unprepare(drvdata->clk);
 err0:
 	wake_lock_destroy(&drvdata->wake_lock);
-	mutex_destroy(&drvdata->mutex);
 	return ret;
 }
 
@@ -1878,8 +1918,9 @@
 
 	device_remove_file(&drvdata->csdev->dev, &dev_attr_pcsave);
 	coresight_unregister(drvdata->csdev);
+	if (drvdata->cpu == 0)
+		unregister_hotcpu_notifier(&etm_cpu_notifier);
 	wake_lock_destroy(&drvdata->wake_lock);
-	mutex_destroy(&drvdata->mutex);
 	return 0;
 }
 
diff --git a/drivers/coresight/coresight-stm.c b/drivers/coresight/coresight-stm.c
index f6a948b..1379c55 100644
--- a/drivers/coresight/coresight-stm.c
+++ b/drivers/coresight/coresight-stm.c
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
+#include <linux/bitmap.h>
 #include <linux/of_coresight.h>
 #include <linux/coresight.h>
 #include <linux/coresight-stm.h>
@@ -45,44 +46,47 @@
 	mb();								\
 } while (0)
 
-#define STMDMASTARTR		(0xC04)
-#define STMDMASTOPR		(0xC08)
-#define STMDMASTATR		(0xC0C)
-#define STMDMACTLR		(0xC10)
-#define STMDMAIDR		(0xCFC)
-#define STMHEER			(0xD00)
-#define STMHETER		(0xD20)
-#define STMHEMCR		(0xD64)
-#define STMHEMASTR		(0xDF4)
-#define STMHEFEAT1R		(0xDF8)
-#define STMHEIDR		(0xDFC)
-#define STMSPER			(0xE00)
-#define STMSPTER		(0xE20)
-#define STMSPSCR		(0xE60)
-#define STMSPMSCR		(0xE64)
-#define STMSPOVERRIDER		(0xE68)
-#define STMSPMOVERRIDER		(0xE6C)
-#define STMSPTRIGCSR		(0xE70)
-#define STMTCSR			(0xE80)
-#define STMTSSTIMR		(0xE84)
-#define STMTSFREQR		(0xE8C)
-#define STMSYNCR		(0xE90)
-#define STMAUXCR		(0xE94)
-#define STMSPFEAT1R		(0xEA0)
-#define STMSPFEAT2R		(0xEA4)
-#define STMSPFEAT3R		(0xEA8)
-#define STMITTRIGGER		(0xEE8)
-#define STMITATBDATA0		(0xEEC)
-#define STMITATBCTR2		(0xEF0)
-#define STMITATBID		(0xEF4)
-#define STMITATBCTR0		(0xEF8)
+#define STMDMASTARTR			(0xC04)
+#define STMDMASTOPR			(0xC08)
+#define STMDMASTATR			(0xC0C)
+#define STMDMACTLR			(0xC10)
+#define STMDMAIDR			(0xCFC)
+#define STMHEER				(0xD00)
+#define STMHETER			(0xD20)
+#define STMHEMCR			(0xD64)
+#define STMHEMASTR			(0xDF4)
+#define STMHEFEAT1R			(0xDF8)
+#define STMHEIDR			(0xDFC)
+#define STMSPER				(0xE00)
+#define STMSPTER			(0xE20)
+#define STMSPSCR			(0xE60)
+#define STMSPMSCR			(0xE64)
+#define STMSPOVERRIDER			(0xE68)
+#define STMSPMOVERRIDER			(0xE6C)
+#define STMSPTRIGCSR			(0xE70)
+#define STMTCSR				(0xE80)
+#define STMTSSTIMR			(0xE84)
+#define STMTSFREQR			(0xE8C)
+#define STMSYNCR			(0xE90)
+#define STMAUXCR			(0xE94)
+#define STMSPFEAT1R			(0xEA0)
+#define STMSPFEAT2R			(0xEA4)
+#define STMSPFEAT3R			(0xEA8)
+#define STMITTRIGGER			(0xEE8)
+#define STMITATBDATA0			(0xEEC)
+#define STMITATBCTR2			(0xEF0)
+#define STMITATBID			(0xEF4)
+#define STMITATBCTR0			(0xEF8)
 
-#define NR_STM_CHANNEL		(32)
-#define BYTES_PER_CHANNEL	(256)
-#define STM_TRACE_BUF_SIZE	(1024)
+#define NR_STM_CHANNEL			(32)
+#define BYTES_PER_CHANNEL		(256)
+#define STM_TRACE_BUF_SIZE		(4096)
+#define STM_USERSPACE_HEADER_SIZE	(8)
+#define STM_USERSPACE_MAGIC1_VAL	(0xf0)
+#define STM_USERSPACE_MAGIC2_VAL	(0xf1)
 
-#define OST_START_TOKEN		(0x30)
-#define OST_VERSION		(0x1)
+#define OST_START_TOKEN			(0x30)
+#define OST_VERSION			(0x1)
 
 enum stm_pkt_type {
 	STM_PKT_TYPE_DATA	= 0x98,
@@ -128,7 +132,7 @@
 	spinlock_t		spinlock;
 	struct channel_space	chs;
 	bool			enable;
-	uint32_t		entity;
+	DECLARE_BITMAP(entities, OST_ENTITY_MAX);
 };
 
 static struct stm_drvdata *stmdrvdata;
@@ -482,7 +486,8 @@
 	struct stm_drvdata *drvdata = stmdrvdata;
 
 	/* we don't support sizes more than 24bits (0 to 23) */
-	if (!(drvdata && drvdata->enable && (drvdata->entity & entity_id) &&
+	if (!(drvdata && drvdata->enable &&
+	      test_bit(entity_id, drvdata->entities) && size &&
 	      (size < 0x1000000)))
 		return 0;
 
@@ -496,13 +501,12 @@
 	struct stm_drvdata *drvdata = container_of(file->private_data,
 						   struct stm_drvdata, miscdev);
 	char *buf;
+	uint8_t entity_id, proto_id;
+	uint32_t options;
 
-	if (!drvdata->enable)
+	if (!drvdata->enable || !size)
 		return -EINVAL;
 
-	if (!(drvdata->entity & OST_ENTITY_DEV_NODE))
-		return size;
-
 	if (size > STM_TRACE_BUF_SIZE)
 		size = STM_TRACE_BUF_SIZE;
 
@@ -516,7 +520,32 @@
 		return -EFAULT;
 	}
 
-	__stm_trace(STM_OPTION_TIMESTAMPED, OST_ENTITY_DEV_NODE, 0, buf, size);
+	if (size >= STM_USERSPACE_HEADER_SIZE &&
+	    buf[0] == STM_USERSPACE_MAGIC1_VAL &&
+	    buf[1] == STM_USERSPACE_MAGIC2_VAL) {
+
+		entity_id = buf[2];
+		proto_id = buf[3];
+		options = *(uint32_t *)(buf + 4);
+
+		if (!test_bit(entity_id, drvdata->entities) ||
+		    !(size - STM_USERSPACE_HEADER_SIZE)) {
+			kfree(buf);
+			return size;
+		}
+
+		__stm_trace(options, entity_id, proto_id,
+			    buf + STM_USERSPACE_HEADER_SIZE,
+			    size - STM_USERSPACE_HEADER_SIZE);
+	} else {
+		if (!test_bit(OST_ENTITY_DEV_NODE, drvdata->entities)) {
+			kfree(buf);
+			return size;
+		}
+
+		__stm_trace(STM_OPTION_TIMESTAMPED, OST_ENTITY_DEV_NODE, 0,
+			    buf, size);
+	}
 
 	kfree(buf);
 
@@ -594,35 +623,50 @@
 static DEVICE_ATTR(port_enable, S_IRUGO | S_IWUSR, stm_show_port_enable,
 		   stm_store_port_enable);
 
-static ssize_t stm_show_entity(struct device *dev,
+static ssize_t stm_show_entities(struct device *dev,
 			       struct device_attribute *attr, char *buf)
 {
 	struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-	unsigned long val = drvdata->entity;
+	ssize_t len;
 
-	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	len = bitmap_scnprintf(buf, PAGE_SIZE, drvdata->entities,
+			       OST_ENTITY_MAX);
+
+	if (PAGE_SIZE - len < 2)
+		len = -EINVAL;
+	else
+		len += scnprintf(buf + len, 2, "\n");
+
+	return len;
 }
 
-static ssize_t stm_store_entity(struct device *dev,
+static ssize_t stm_store_entities(struct device *dev,
 				struct device_attribute *attr,
 				const char *buf, size_t size)
 {
 	struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-	unsigned long val;
+	unsigned long val1, val2;
 
-	if (sscanf(buf, "%lx", &val) != 1)
+	if (sscanf(buf, "%lx %lx", &val1, &val2) != 2)
 		return -EINVAL;
 
-	drvdata->entity = val;
+	if (val1 >= OST_ENTITY_MAX)
+		return -EINVAL;
+
+	if (val2)
+		__set_bit(val1, drvdata->entities);
+	else
+		__clear_bit(val1, drvdata->entities);
+
 	return size;
 }
-static DEVICE_ATTR(entity, S_IRUGO | S_IWUSR, stm_show_entity,
-		   stm_store_entity);
+static DEVICE_ATTR(entities, S_IRUGO | S_IWUSR, stm_show_entities,
+		   stm_store_entities);
 
 static struct attribute *stm_attrs[] = {
 	&dev_attr_hwevent_enable.attr,
 	&dev_attr_port_enable.attr,
-	&dev_attr_entity.attr,
+	&dev_attr_entities.attr,
 	NULL,
 };
 
@@ -698,7 +742,7 @@
 	if (ret)
 		return ret;
 
-	drvdata->entity = OST_ENTITY_ALL;
+	bitmap_fill(drvdata->entities, OST_ENTITY_MAX);
 
 	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
 	if (!desc)
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index 13f69cd..3bb9ec7 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -1043,8 +1043,7 @@
 	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
 		drvdata->size = SZ_1M;
 	else
-		drvdata->size = (tmc_readl(drvdata, TMC_RSZ) * BYTES_PER_WORD)
-				+ PAGE_SIZE;
+		drvdata->size = tmc_readl(drvdata, TMC_RSZ) * BYTES_PER_WORD;
 
 	clk_disable_unprepare(drvdata->clk);
 
@@ -1067,7 +1066,8 @@
 		if (ret)
 			goto err0;
 	} else {
-		baddr = devm_kzalloc(dev, drvdata->size, GFP_KERNEL);
+		baddr = devm_kzalloc(dev, PAGE_SIZE + drvdata->size,
+				     GFP_KERNEL);
 		if (!baddr)
 			return -ENOMEM;
 		drvdata->buf = baddr + PAGE_SIZE;
@@ -1075,7 +1075,7 @@
 							TMC_ETFETB_DUMP_VER;
 		dump.id = MSM_TMC_ETFETB + etfetb_count;
 		dump.start_addr = virt_to_phys(baddr);
-		dump.end_addr = dump.start_addr + drvdata->size;
+		dump.end_addr = dump.start_addr + PAGE_SIZE + drvdata->size;
 		ret = msm_dump_table_register(&dump);
 		/* Don't free the buffer in case of error since it can still
 		 * be used to provide dump collection via the device node
diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c
index f834ea8..63cdc68 100644
--- a/drivers/cpufreq/cpufreq_interactive.c
+++ b/drivers/cpufreq/cpufreq_interactive.c
@@ -972,6 +972,9 @@
 	spin_lock_init(&down_cpumask_lock);
 	mutex_init(&set_speed_lock);
 
+	/* Kick the kthread to idle */
+	wake_up_process(up_task);
+
 	idle_notifier_register(&cpufreq_interactive_idle_nb);
 	INIT_WORK(&inputopen.inputopen_work, cpufreq_interactive_input_open);
 	return cpufreq_register_governor(&cpufreq_gov_interactive);
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 785ba6c..4b03cfd 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -115,7 +115,12 @@
 
 static struct workqueue_struct *input_wq;
 
-static DEFINE_PER_CPU(struct work_struct, dbs_refresh_work);
+struct dbs_work_struct {
+	struct work_struct work;
+	unsigned int cpu;
+};
+
+static DEFINE_PER_CPU(struct dbs_work_struct, dbs_refresh_work);
 
 static struct dbs_tuners {
 	unsigned int sampling_rate;
@@ -831,11 +836,15 @@
 	return 0;
 }
 
-static void dbs_refresh_callback(struct work_struct *unused)
+static void dbs_refresh_callback(struct work_struct *work)
 {
 	struct cpufreq_policy *policy;
 	struct cpu_dbs_info_s *this_dbs_info;
-	unsigned int cpu = smp_processor_id();
+	struct dbs_work_struct *dbs_work;
+	unsigned int cpu;
+
+	dbs_work = container_of(work, struct dbs_work_struct, work);
+	cpu = dbs_work->cpu;
 
 	get_online_cpus();
 
@@ -877,9 +886,8 @@
 		return;
 	}
 
-	for_each_online_cpu(i) {
-		queue_work_on(i, input_wq, &per_cpu(dbs_refresh_work, i));
-	}
+	for_each_online_cpu(i)
+		queue_work_on(i, input_wq, &per_cpu(dbs_refresh_work, i).work);
 }
 
 static int dbs_input_connect(struct input_handler *handler,
@@ -1072,8 +1080,12 @@
 	for_each_possible_cpu(i) {
 		struct cpu_dbs_info_s *this_dbs_info =
 			&per_cpu(od_cpu_dbs_info, i);
+		struct dbs_work_struct *dbs_work =
+			&per_cpu(dbs_refresh_work, i);
+
 		mutex_init(&this_dbs_info->timer_mutex);
-		INIT_WORK(&per_cpu(dbs_refresh_work, i), dbs_refresh_callback);
+		INIT_WORK(&dbs_work->work, dbs_refresh_callback);
+		dbs_work->cpu = i;
 	}
 
 	return cpufreq_register_governor(&cpufreq_gov_ondemand);
diff --git a/drivers/crypto/msm/qce40.c b/drivers/crypto/msm/qce40.c
index 7a229a5..de060cc 100644
--- a/drivers/crypto/msm/qce40.c
+++ b/drivers/crypto/msm/qce40.c
@@ -1844,6 +1844,8 @@
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_status_wait);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_status_wait);
+	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_status_wait);
+	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_status_wait);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_auth_byte_count);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_auth_result_20);
 	*cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_status_ocu);
@@ -1860,6 +1862,8 @@
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_status_wait);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_status_wait);
+	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_status_wait);
+	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_status_wait);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_auth_byte_count);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_auth_result_32);
 	*cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_status_ocu);
@@ -1877,6 +1881,8 @@
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_status_wait);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_status_wait);
+	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_status_wait);
+	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_status_wait);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_auth_byte_count);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_auth_result_20);
 	*cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_status_ocu);
@@ -1894,6 +1900,8 @@
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->ce_data_in);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_status_wait);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_status_wait);
+	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_status_wait);
+	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_status_wait);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_auth_byte_count);
 	*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->get_auth_result_32);
 	*cmd_ptr_vaddr++ = QCE_SET_LAST_CMD_PTR(cmdlist->get_status_ocu);
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 1312448..4361263 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -487,7 +487,10 @@
 		pce->data = auth_cfg;
 
 		pce = cmdlistinfo->auth_seg_size;
-		pce->data = totallen_in;
+		if (creq->dir == QCE_ENCRYPT)
+			pce->data = totallen_in;
+		else
+			pce->data = totallen_in - creq->authsize;
 		pce = cmdlistinfo->auth_seg_start;
 		pce->data = 0;
 	}
@@ -503,7 +506,8 @@
 		encr_cfg |= (CRYPTO_ENCR_MODE_XTS << CRYPTO_ENCR_MODE);
 		break;
 	case QCE_MODE_CCM:
-		encr_cfg |= (CRYPTO_ENCR_MODE_CCM << CRYPTO_ENCR_MODE);
+		encr_cfg |= (CRYPTO_ENCR_MODE_CCM << CRYPTO_ENCR_MODE) |
+				(CRYPTO_LAST_CCM_XFR << CRYPTO_LAST_CCM);
 		break;
 	case QCE_MODE_CTR:
 	default:
@@ -1930,7 +1934,9 @@
 		auth_cfg &= ~(1 << CRYPTO_USE_HW_KEY_AUTH);
 		encr_cfg = (CRYPTO_ENCR_KEY_SZ_AES256 << CRYPTO_ENCR_KEY_SZ) |
 			(CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG) |
-			((CRYPTO_ENCR_MODE_CCM << CRYPTO_ENCR_MODE));
+			(CRYPTO_ENCR_MODE_CCM << CRYPTO_ENCR_MODE) |
+			(CRYPTO_LAST_CCM_XFR << CRYPTO_LAST_CCM);
+
 		key_reg = 8;
 	}
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
@@ -2161,8 +2167,10 @@
 	struct qce_cmdlist_info *cmdlistinfo = NULL;
 	struct qce_cmdlist_info *auth_cmdlistinfo = NULL;
 
-	if (q_req->mode != QCE_MODE_CCM)
+	if (q_req->mode != QCE_MODE_CCM) {
 		ivsize = crypto_aead_ivsize(aead);
+		auth_cmdlistinfo = &pce_dev->ce_sps.cmdlistptr.aead_sha1_hmac;
+	}
 
 	ce_burst_size = pce_dev->ce_sps.ce_burst_size;
 	if (q_req->dir == QCE_ENCRYPT) {
@@ -2770,13 +2778,11 @@
 	ce_support->aes_xts = true;
 	ce_support->ota = false;
 	ce_support->bam = true;
-	if (pce_dev->ce_sps.minor_version) {
+	ce_support->aes_ccm = true;
+	if (pce_dev->ce_sps.minor_version)
 		ce_support->aligned_only = false;
-		ce_support->aes_ccm = true;
-	} else {
+	else
 		ce_support->aligned_only = true;
-		ce_support->aes_ccm = false;
-	}
 	return 0;
 }
 EXPORT_SYMBOL(qce_hw_support);
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index 7fc5cab..10f83f3 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -919,7 +919,7 @@
 
 			for (sg = areq->dst; bytes != nbytes; sg++) {
 				memcpy(sg_virt(sg),
-				((char *)rctx->data + rctx->assoclen + bytes),
+				((char *)rctx->data + areq->assoclen + bytes),
 								sg->length);
 				bytes += sg->length;
 			}
diff --git a/drivers/gpio/qpnp-pin.c b/drivers/gpio/qpnp-pin.c
index 67a2e6b..527fd1b 100644
--- a/drivers/gpio/qpnp-pin.c
+++ b/drivers/gpio/qpnp-pin.c
@@ -128,7 +128,7 @@
 	Q_PIN_CFG_PULL,
 	Q_PIN_CFG_VIN_SEL,
 	Q_PIN_CFG_OUT_STRENGTH,
-	Q_PIN_CFG_SELECT,
+	Q_PIN_CFG_SRC_SEL,
 	Q_PIN_CFG_MASTER_EN,
 	Q_PIN_CFG_AOUT_REF,
 	Q_PIN_CFG_AIN_ROUTE,
@@ -289,7 +289,7 @@
 		    val == 0)
 			return -EINVAL;
 		break;
-	case Q_PIN_CFG_SELECT:
+	case Q_PIN_CFG_SRC_SEL:
 		if (q_spec->type == Q_MPP_TYPE &&
 		    (val == QPNP_PIN_SEL_FUNC_1 ||
 		     val == QPNP_PIN_SEL_FUNC_2))
@@ -348,9 +348,9 @@
 	else if (Q_CHK_INVALID(Q_PIN_CFG_INVERT, q_spec, param->invert))
 		pr_err("invalid invert polarity value %d for %s %d\n",
 						param->invert,  name, pin);
-	else if (Q_CHK_INVALID(Q_PIN_CFG_SELECT, q_spec, param->select))
+	else if (Q_CHK_INVALID(Q_PIN_CFG_SRC_SEL, q_spec, param->src_sel))
 		pr_err("invalid source select value %d for %s %d\n",
-						param->select, name, pin);
+						param->src_sel, name, pin);
 	else if (Q_CHK_INVALID(Q_PIN_CFG_OUT_STRENGTH,
 						q_spec, param->out_strength))
 		pr_err("invalid out strength value %d for %s %d\n",
@@ -506,10 +506,10 @@
 		q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
 			  Q_REG_OUT_INVERT_SHIFT, Q_REG_OUT_INVERT_MASK,
 			  param->invert);
-	if (Q_HAVE_HW_SP(Q_PIN_CFG_SELECT, q_spec, param->select))
+	if (Q_HAVE_HW_SP(Q_PIN_CFG_SRC_SEL, q_spec, param->src_sel))
 		q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
 			  Q_REG_SRC_SEL_SHIFT, Q_REG_SRC_SEL_MASK,
-			  param->select);
+			  param->src_sel);
 	if (Q_HAVE_HW_SP(Q_PIN_CFG_OUT_STRENGTH, q_spec, param->out_strength))
 		q_reg_clr_set(&q_spec->regs[Q_REG_I_DIG_OUT_CTL],
 			  Q_REG_OUT_STRENGTH_SHIFT, Q_REG_OUT_STRENGTH_MASK,
@@ -828,7 +828,7 @@
 	param.out_strength = q_reg_get(&q_spec->regs[Q_REG_I_DIG_OUT_CTL],
 				       Q_REG_OUT_STRENGTH_SHIFT,
 				       Q_REG_OUT_STRENGTH_MASK);
-	param.select   = q_reg_get(&q_spec->regs[Q_REG_I_MODE_CTL],
+	param.src_sel   = q_reg_get(&q_spec->regs[Q_REG_I_MODE_CTL],
 				       Q_REG_SRC_SEL_SHIFT, Q_REG_SRC_SEL_MASK);
 	param.master_en    = q_reg_get(&q_spec->regs[Q_REG_I_EN_CTL],
 				       Q_REG_MASTER_EN_SHIFT,
@@ -855,8 +855,8 @@
 		&param.vin_sel);
 	of_property_read_u32(node, "qcom,out-strength",
 		&param.out_strength);
-	of_property_read_u32(node, "qcom,src-select",
-		&param.select);
+	of_property_read_u32(node, "qcom,src-sel",
+		&param.src_sel);
 	of_property_read_u32(node, "qcom,master-en",
 		&param.master_en);
 	of_property_read_u32(node, "qcom,aout-ref",
@@ -942,7 +942,7 @@
 		cfg->shift = Q_REG_OUT_STRENGTH_SHIFT;
 		cfg->mask = Q_REG_OUT_STRENGTH_MASK;
 		break;
-	case Q_PIN_CFG_SELECT:
+	case Q_PIN_CFG_SRC_SEL:
 		cfg->addr = Q_REG_MODE_CTL;
 		cfg->idx = Q_REG_I_MODE_CTL;
 		cfg->shift = Q_REG_SRC_SEL_SHIFT;
@@ -1036,7 +1036,7 @@
 	{ Q_PIN_CFG_PULL, "pull" },
 	{ Q_PIN_CFG_VIN_SEL, "vin_sel" },
 	{ Q_PIN_CFG_OUT_STRENGTH, "out_strength" },
-	{ Q_PIN_CFG_SELECT, "select" },
+	{ Q_PIN_CFG_SRC_SEL, "src_sel" },
 	{ Q_PIN_CFG_MASTER_EN, "master_en" },
 	{ Q_PIN_CFG_AOUT_REF, "aout_ref" },
 	{ Q_PIN_CFG_AIN_ROUTE, "ain_route" },
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index f9a9212..aa3469c 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -399,14 +399,16 @@
 		return ION_CP_ALLOCATE_FAIL;
 	}
 
-	if (secure_allocation &&
-	    (cp_heap->umap_count > 0 || cp_heap->kmap_cached_count > 0)) {
-		mutex_unlock(&cp_heap->lock);
-		pr_err("ION cannot allocate secure memory from heap with "
-			"outstanding mappings: User space: %lu, kernel space "
-			"(cached): %lu\n", cp_heap->umap_count,
-					   cp_heap->kmap_cached_count);
-		return ION_CP_ALLOCATE_FAIL;
+	/*
+	 * The check above already checked for non-secure allocations when the
+	 * heap is protected. HEAP_PROTECTED implies that this must be a secure
+	 * allocation. If the heap is protected and there are userspace or
+	 * cached kernel mappings, something has gone wrong in the security
+	 * model.
+	 */
+	if (cp_heap->heap_protected == HEAP_PROTECTED) {
+		BUG_ON(cp_heap->umap_count != 0);
+		BUG_ON(cp_heap->kmap_cached_count != 0);
 	}
 
 	/*
@@ -569,18 +571,11 @@
 	if (!table)
 		return ERR_PTR(-ENOMEM);
 
-	if (buf->is_secure) {
+	if (buf->is_secure && IS_ALIGNED(buffer->size, SZ_1M)) {
 		int n_chunks;
 		int i;
 		struct scatterlist *sg;
 
-		if (!IS_ALIGNED(buffer->size, SZ_1M)) {
-			pr_err("%s: buffer is marked as secure but buffer size %x is not aligned to 1MB\n",
-				__func__, buffer->size);
-
-			return ERR_PTR(-EINVAL);
-		}
-
 		/* Count number of 1MB chunks. Alignment is already checked. */
 		n_chunks = buffer->size >> 20;
 
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 7fe47ee..20f84d6 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -24,6 +24,7 @@
 #include <linux/sched.h>
 #include <linux/rwsem.h>
 #include <linux/uaccess.h>
+#include <linux/memblock.h>
 #include <mach/ion.h>
 #include <mach/msm_memtypes.h>
 #include "../ion_priv.h"
@@ -88,6 +89,16 @@
 		.name	= ION_AUDIO_HEAP_NAME,
 	},
 	{
+		.id	= ION_PIL1_HEAP_ID,
+		.type	= ION_HEAP_TYPE_CARVEOUT,
+		.name	= ION_PIL1_HEAP_NAME,
+	},
+	{
+		.id	= ION_PIL2_HEAP_ID,
+		.type	= ION_HEAP_TYPE_CARVEOUT,
+		.name	= ION_PIL2_HEAP_NAME,
+	},
+	{
 		.id	= ION_CP_WB_HEAP_ID,
 		.type	= ION_HEAP_TYPE_CP,
 		.name	= ION_WB_HEAP_NAME,
@@ -458,6 +469,7 @@
 {
 	unsigned int val;
 	int ret = 0;
+	u32 out_values[2];
 	const char *memory_name_prop;
 
 	ret = of_property_read_u32(node, "qcom,memory-reservation-size", &val);
@@ -481,12 +493,29 @@
 			ret = -EINVAL;
 		}
 	} else {
-		ret = 0;
+		ret = of_property_read_u32_array(node, "qcom,memory-fixed",
+								out_values, 2);
+		if (!ret)
+			heap->size = out_values[1];
+		else
+			ret = 0;
 	}
 out:
 	return ret;
 }
 
+static void msm_ion_get_heap_base(struct device_node *node,
+				 struct ion_platform_heap *heap)
+{
+	u32 out_values[2];
+	int ret = 0;
+
+	ret = of_property_read_u32_array(node, "qcom,memory-fixed",
+							out_values, 2);
+	if (!ret)
+		heap->base = out_values[0];
+	return;
+}
 
 static void msm_ion_get_heap_adjacent(struct device_node *node,
 				      struct ion_platform_heap *heap)
@@ -560,6 +589,7 @@
 		if (ret)
 			goto free_heaps;
 
+		msm_ion_get_heap_base(node, &pdata->heaps[idx]);
 		msm_ion_get_heap_align(node, &pdata->heaps[idx]);
 
 		ret = msm_ion_get_heap_size(node, &pdata->heaps[idx]);
@@ -734,6 +764,19 @@
 	if (pdata_needs_to_be_freed)
 		free_pdata(pdata);
 
+	/* Check if each heap has been removed from the memblock */
+	for (i = 0; i < num_heaps; i++) {
+		struct ion_platform_heap *heap_data = &pdata->heaps[i];
+		if (!heap_data->base)
+			continue;
+		err = memblock_overlaps_memory(heap_data->base,
+						heap_data->size);
+		if (err) {
+			panic("ION heap %s not removed from memblock\n",
+							heap_data->name);
+		}
+	}
+
 	check_for_heap_overlap(pdata->heaps, num_heaps);
 	platform_set_drvdata(pdev, idev);
 	return 0;
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index bec19e2..f9d0316 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -38,6 +38,7 @@
 /* Command identifiers */
 #define KGSL_CONTEXT_TO_MEM_IDENTIFIER	0x2EADBEEF
 #define KGSL_CMD_IDENTIFIER		0x2EEDFACE
+#define KGSL_CMD_INTERNAL_IDENTIFIER	0x2EEDD00D
 #define KGSL_START_OF_IB_IDENTIFIER	0x2EADEABE
 #define KGSL_END_OF_IB_IDENTIFIER	0x2ABEDEAD
 
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index 8de2c70..4e4843b 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1718,9 +1718,15 @@
 					eoptimestamp));
 
 		if (context_id < KGSL_MEMSTORE_MAX) {
-			kgsl_sharedmem_writel(&rb->device->memstore,
+			/* reset per context ts_cmp_enable */
+			kgsl_sharedmem_writel(&device->memstore,
 					KGSL_MEMSTORE_OFFSET(context_id,
 						ts_cmp_enable), 0);
+			/* Always reset global timestamp ts_cmp_enable */
+			kgsl_sharedmem_writel(&device->memstore,
+					KGSL_MEMSTORE_OFFSET(
+						KGSL_MEMSTORE_GLOBAL,
+						ts_cmp_enable), 0);
 			wmb();
 		}
 
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 4c7534c..feced43 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2586,9 +2586,15 @@
 					eoptimestamp));
 
 		if (context_id < KGSL_MEMSTORE_MAX) {
+			/* reset per context ts_cmp_enable */
 			kgsl_sharedmem_writel(&device->memstore,
 					KGSL_MEMSTORE_OFFSET(context_id,
 						ts_cmp_enable), 0);
+			/* Always reset global timestamp ts_cmp_enable */
+			kgsl_sharedmem_writel(&device->memstore,
+					KGSL_MEMSTORE_OFFSET(
+						KGSL_MEMSTORE_GLOBAL,
+						ts_cmp_enable), 0);
 			wmb();
 		}
 
@@ -2766,12 +2772,12 @@
 static struct a3xx_vbif_data a330_vbif[] = {
 	/* Set up 16 deep read/write request queues */
 	{ A3XX_VBIF_IN_RD_LIM_CONF0, 0x18181818 },
-	{ A3XX_VBIF_IN_RD_LIM_CONF1, 0x18181818 },
-	{ A3XX_VBIF_OUT_RD_LIM_CONF0, 0x18181818 },
-	{ A3XX_VBIF_OUT_WR_LIM_CONF0, 0x18181818 },
+	{ A3XX_VBIF_IN_RD_LIM_CONF1, 0x00001818 },
+	{ A3XX_VBIF_OUT_RD_LIM_CONF0, 0x00001818 },
+	{ A3XX_VBIF_OUT_WR_LIM_CONF0, 0x00001818 },
 	{ A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303 },
 	{ A3XX_VBIF_IN_WR_LIM_CONF0, 0x18181818 },
-	{ A3XX_VBIF_IN_WR_LIM_CONF1, 0x18181818 },
+	{ A3XX_VBIF_IN_WR_LIM_CONF1, 0x00001818 },
 	/* Enable WR-REQ */
 	{ A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003F },
 	/* Set up round robin arbitration between both AXI ports */
@@ -2779,10 +2785,10 @@
 	/* Set up VBIF_ROUND_ROBIN_QOS_ARB */
 	{ A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0001 },
 	/* Set up AOOO */
-	{ A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000FFFF },
-	{ A3XX_VBIF_OUT_AXI_AOOO, 0xFFFFFFFF },
+	{ A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003F },
+	{ A3XX_VBIF_OUT_AXI_AOOO, 0x003F003F },
 	/* Enable 1K sort */
-	{ A3XX_VBIF_ABIT_SORT, 0x1FFFF },
+	{ A3XX_VBIF_ABIT_SORT, 0x0001003F },
 	{ A3XX_VBIF_ABIT_SORT_CONF, 0x000000A4 },
 	/* Disable VBIF clock gating. This is to enable AXI running
 	 * higher frequency than GPU.
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index daa78ed..e069fa5 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -70,6 +70,14 @@
 	{CP_WAIT_FOR_IDLE,		"WAIT4IDL"},
 };
 
+static const struct pm_id_name pm3_nop_values[] = {
+	{KGSL_CONTEXT_TO_MEM_IDENTIFIER,	"CTX_SWCH"},
+	{KGSL_CMD_IDENTIFIER,			"CMD__EXT"},
+	{KGSL_CMD_INTERNAL_IDENTIFIER,		"CMD__INT"},
+	{KGSL_START_OF_IB_IDENTIFIER,		"IB_START"},
+	{KGSL_END_OF_IB_IDENTIFIER,		"IB___END"},
+};
+
 static uint32_t adreno_is_pm4_len(uint32_t word)
 {
 	if (word == INVALID_RB_CMD)
@@ -129,6 +137,28 @@
 	return "????????";
 }
 
+static bool adreno_is_pm3_nop_value(uint32_t word)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pm3_nop_values); ++i) {
+		if (word == pm3_nop_values[i].id)
+			return 1;
+	}
+	return 0;
+}
+
+static const char *adreno_pm3_nop_name(uint32_t word)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pm3_nop_values); ++i) {
+		if (word == pm3_nop_values[i].id)
+			return pm3_nop_values[i].name;
+	}
+	return "????????";
+}
+
 static void adreno_dump_regs(struct kgsl_device *device,
 			   const int *registers, int size)
 {
@@ -245,8 +275,13 @@
 				"%s", adreno_pm4_name(ptr4[j]));
 			*argp = -(adreno_is_pm4_len(ptr4[j])+1);
 		} else {
-			lx += scnprintf(linebuf + lx, linebuflen - lx,
-				"%8.8X", ptr4[j]);
+			if (adreno_is_pm3_nop_value(ptr4[j]))
+				lx += scnprintf(linebuf + lx, linebuflen - lx,
+					"%s", adreno_pm3_nop_name(ptr4[j]));
+			else
+				lx += scnprintf(linebuf + lx, linebuflen - lx,
+					"%8.8X", ptr4[j]);
+
 			if (*argp > 1)
 				--*argp;
 			else if (*argp == 1) {
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index da9daf7..9648f27 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -28,6 +28,14 @@
 
 #define GSL_RB_NOP_SIZEDWORDS				2
 
+/*
+ * CP DEBUG settings for all cores:
+ * DYNAMIC_CLK_DISABLE [27] - turn off the dynamic clock control
+ * PROG_END_PTR_ENABLE [25] - Allow 128 bit writes to the VBIF
+ */
+
+#define CP_DEBUG_DEFAULT ((1 << 27) | (1 << 25))
+
 void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb)
 {
 	BUG_ON(rb->wptr == 0);
@@ -231,7 +239,7 @@
 	KGSL_DRV_INFO(device, "loading pm4 ucode version: %d\n",
 		adreno_dev->pm4_fw[0]);
 
-	adreno_regwrite(device, REG_CP_DEBUG, 0x02000000);
+	adreno_regwrite(device, REG_CP_DEBUG, CP_DEBUG_DEFAULT);
 	adreno_regwrite(device, REG_CP_ME_RAM_WADDR, 0);
 	for (i = 1; i < adreno_dev->pm4_fw_size; i++)
 		adreno_regwrite(device, REG_CP_ME_RAM_DATA,
@@ -524,16 +532,18 @@
 	total_sizedwords += flags & KGSL_CMD_FLAGS_PMODE ? 4 : 0;
 	/* 2 dwords to store the start of command sequence */
 	total_sizedwords += 2;
-	/*
-	 * Add CP_COND_EXEC commands to generate CP_INTERRUPT only
-	 * for submissions from userspace.
-	 */
-	total_sizedwords += (context &&
-			!(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) ? 7 : 0;
+	/* internal ib command identifier for the ringbuffer */
+	total_sizedwords += (flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE) ? 2 : 0;
+
+	/* Add CP_COND_EXEC commands to generate CP_INTERRUPT */
+	total_sizedwords += context ? 7 : 0;
 
 	if (adreno_is_a3xx(adreno_dev))
 		total_sizedwords += 7;
 
+	if (adreno_is_a2xx(adreno_dev))
+		total_sizedwords += 2; /* CP_WAIT_FOR_IDLE */
+
 	total_sizedwords += 2; /* scratchpad ts for recovery */
 	if (context && context->flags & CTXT_FLAGS_PER_CONTEXT_TS &&
 			!(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) {
@@ -560,6 +570,11 @@
 	GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_nop_packet(1));
 	GSL_RB_WRITE(ringcmds, rcmd_gpu, KGSL_CMD_IDENTIFIER);
 
+	if (flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE) {
+		GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_nop_packet(1));
+		GSL_RB_WRITE(ringcmds, rcmd_gpu, KGSL_CMD_INTERNAL_IDENTIFIER);
+	}
+
 	if (flags & KGSL_CMD_FLAGS_PMODE) {
 		/* disable protected mode error checking */
 		GSL_RB_WRITE(ringcmds, rcmd_gpu,
@@ -594,6 +609,16 @@
 	}
 	timestamp = rb->timestamp[context_id];
 
+	/* HW Workaround for MMU Page fault
+	* due to memory getting free early before
+	* GPU completes it.
+	*/
+	if (adreno_is_a2xx(adreno_dev)) {
+		GSL_RB_WRITE(ringcmds, rcmd_gpu,
+			cp_type3_packet(CP_WAIT_FOR_IDLE, 1));
+		GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x00);
+	}
+
 	/* scratchpad ts for recovery */
 	GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type0_packet(REG_CP_TIMESTAMP, 1));
 	GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
@@ -647,7 +672,7 @@
 				rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
 	}
 
-	if (context && !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) {
+	if (context) {
 		/* Conditional execution based on memory values */
 		GSL_RB_WRITE(ringcmds, rcmd_gpu,
 			cp_type3_packet(CP_COND_EXEC, 4));
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 1b1f0ac..b8adbe67 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -333,14 +333,19 @@
 
 	context = kzalloc(sizeof(*context), GFP_KERNEL);
 
-	if (context == NULL)
-		return NULL;
+	if (context == NULL) {
+		KGSL_DRV_INFO(dev_priv->device, "kzalloc(%d) failed\n",
+				sizeof(*context));
+		return ERR_PTR(-ENOMEM);
+	}
 
 	while (1) {
 		if (idr_pre_get(&dev_priv->device->context_idr,
 				GFP_KERNEL) == 0) {
-			kfree(context);
-			return NULL;
+			KGSL_DRV_INFO(dev_priv->device,
+					"idr_pre_get: ENOMEM\n");
+			ret = -ENOMEM;
+			goto func_end;
 		}
 
 		ret = idr_get_new_above(&dev_priv->device->context_idr,
@@ -350,10 +355,8 @@
 			break;
 	}
 
-	if (ret) {
-		kfree(context);
-		return NULL;
-	}
+	if (ret)
+		goto func_end;
 
 	/* MAX - 1, there is one memdesc in memstore for device info */
 	if (id >= KGSL_MEMSTORE_MAX) {
@@ -361,18 +364,24 @@
 				"ctxts due to memstore limitation\n",
 				KGSL_MEMSTORE_MAX);
 		idr_remove(&dev_priv->device->context_idr, id);
-		kfree(context);
-		return NULL;
+		ret = -ENOSPC;
+		goto func_end;
 	}
 
 	kref_init(&context->refcount);
 	context->id = id;
 	context->dev_priv = dev_priv;
 
-	if (kgsl_sync_timeline_create(context)) {
+	ret = kgsl_sync_timeline_create(context);
+	if (ret) {
 		idr_remove(&dev_priv->device->context_idr, id);
+		goto func_end;
+	}
+
+func_end:
+	if (ret) {
 		kfree(context);
-		return NULL;
+		return ERR_PTR(ret);
 	}
 
 	return context;
@@ -1283,8 +1292,8 @@
 
 	context = kgsl_create_context(dev_priv);
 
-	if (context == NULL) {
-		result = -ENOMEM;
+	if (IS_ERR(context)) {
+		result = PTR_ERR(context);
 		goto done;
 	}
 
@@ -1298,7 +1307,7 @@
 	trace_kgsl_context_create(dev_priv->device, context, param->flags);
 	param->drawctxt_id = context->id;
 done:
-	if (result && context)
+	if (result && !IS_ERR(context))
 		kgsl_context_detach(context);
 
 	return result;
diff --git a/drivers/gpu/msm/kgsl_drm.c b/drivers/gpu/msm/kgsl_drm.c
index 2003098..98c7434 100644
--- a/drivers/gpu/msm/kgsl_drm.c
+++ b/drivers/gpu/msm/kgsl_drm.c
@@ -17,6 +17,7 @@
 #include "drmP.h"
 #include "drm.h"
 #include <linux/android_pmem.h>
+#include <linux/msm_ion.h>
 
 #include "kgsl.h"
 #include "kgsl_device.h"
@@ -27,7 +28,7 @@
 #define DRIVER_AUTHOR           "Qualcomm"
 #define DRIVER_NAME             "kgsl"
 #define DRIVER_DESC             "KGSL DRM"
-#define DRIVER_DATE             "20100127"
+#define DRIVER_DATE             "20121107"
 
 #define DRIVER_MAJOR            2
 #define DRIVER_MINOR            1
@@ -106,6 +107,7 @@
 	uint32_t type;
 	struct kgsl_memdesc memdesc;
 	struct kgsl_pagetable *pagetable;
+	struct ion_handle *ion_handle;
 	uint64_t mmap_offset;
 	int bufcount;
 	int flags;
@@ -129,6 +131,8 @@
 	struct list_head wait_list;
 };
 
+static struct ion_client *kgsl_drm_ion_phys_client;
+
 static int kgsl_drm_inited = DRM_KGSL_NOT_INITED;
 
 /* This is a global list of all the memory currently mapped in the MMU */
@@ -243,15 +247,50 @@
 	if (TYPE_IS_PMEM(priv->type)) {
 		if (priv->type == DRM_KGSL_GEM_TYPE_EBI ||
 		    priv->type & DRM_KGSL_GEM_PMEM_EBI) {
-				result = kgsl_sharedmem_ebimem_user(
-						&priv->memdesc,
-						priv->pagetable,
-						obj->size * priv->bufcount);
-				if (result) {
-					DRM_ERROR(
-					"Unable to allocate PMEM memory\n");
-					return result;
-				}
+			priv->ion_handle = ion_alloc(kgsl_drm_ion_phys_client,
+				obj->size * priv->bufcount, PAGE_SIZE,
+				ION_HEAP(ION_SF_HEAP_ID), 0);
+			if (IS_ERR_OR_NULL(priv->ion_handle)) {
+				DRM_ERROR(
+				"Unable to allocate ION Phys memory handle\n");
+				return -ENOMEM;
+			}
+
+			priv->memdesc.pagetable = priv->pagetable;
+
+			result = ion_phys(kgsl_drm_ion_phys_client,
+				priv->ion_handle, (ion_phys_addr_t *)
+				&priv->memdesc.physaddr, &priv->memdesc.size);
+			if (result) {
+				DRM_ERROR(
+				"Unable to get ION Physical memory address\n");
+				ion_free(kgsl_drm_ion_phys_client,
+					priv->ion_handle);
+				priv->ion_handle = NULL;
+				return result;
+			}
+
+			result = memdesc_sg_phys(&priv->memdesc,
+				priv->memdesc.physaddr, priv->memdesc.size);
+			if (result) {
+				DRM_ERROR(
+				"Unable to get sg list\n");
+				ion_free(kgsl_drm_ion_phys_client,
+					priv->ion_handle);
+				priv->ion_handle = NULL;
+				return result;
+			}
+
+			result = kgsl_mmu_map(priv->pagetable, &priv->memdesc,
+					GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+			if (result) {
+				DRM_ERROR(
+				"Unable to map GPU\n");
+				ion_free(kgsl_drm_ion_phys_client,
+					priv->ion_handle);
+				priv->ion_handle = NULL;
+				return result;
+			}
 		}
 		else
 			return -EINVAL;
@@ -296,7 +335,16 @@
 	kgsl_gem_mem_flush(&priv->memdesc,  priv->type,
 			   DRM_KGSL_GEM_CACHE_OP_FROM_DEV);
 
-	kgsl_sharedmem_free(&priv->memdesc);
+	if (priv->memdesc.gpuaddr)
+		kgsl_mmu_unmap(priv->memdesc.pagetable, &priv->memdesc);
+
+	kgsl_sg_free(priv->memdesc.sg, priv->memdesc.sglen);
+
+	if (priv->ion_handle)
+		ion_free(kgsl_drm_ion_phys_client, priv->ion_handle);
+	priv->ion_handle = NULL;
+
+	memset(&priv->memdesc, 0, sizeof(priv->memdesc));
 
 	kgsl_mmu_putpagetable(priv->pagetable);
 	priv->pagetable = NULL;
@@ -587,6 +635,43 @@
 }
 
 int
+kgsl_gem_get_ion_fd_ioctl(struct drm_device *dev, void *data,
+			struct drm_file *file_priv)
+{
+	struct drm_kgsl_gem_get_ion_fd *args = data;
+	struct drm_gem_object *obj;
+	struct drm_kgsl_gem_object *priv;
+	int ret = 0;
+
+	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+
+	if (obj == NULL) {
+		DRM_ERROR("Invalid GEM handle %x\n", args->handle);
+		return -EBADF;
+	}
+
+	mutex_lock(&dev->struct_mutex);
+	priv = obj->driver_private;
+
+	if (TYPE_IS_FD(priv->type))
+		ret = -EINVAL;
+	else {
+		if (priv->ion_handle) {
+			args->ion_fd = ion_share_dma_buf(
+			kgsl_drm_ion_phys_client, priv->ion_handle);
+		} else {
+			DRM_ERROR("GEM object has no ion memory allocated.\n");
+			ret = -EINVAL;
+		}
+	}
+
+	drm_gem_object_unreference(obj);
+	mutex_unlock(&dev->struct_mutex);
+
+	return ret;
+}
+
+int
 kgsl_gem_setmemtype_ioctl(struct drm_device *dev, void *data,
 			struct drm_file *file_priv)
 {
@@ -1434,6 +1519,7 @@
 	DRM_IOCTL_DEF_DRV(KGSL_GEM_ALLOC, kgsl_gem_alloc_ioctl, 0),
 	DRM_IOCTL_DEF_DRV(KGSL_GEM_MMAP, kgsl_gem_mmap_ioctl, 0),
 	DRM_IOCTL_DEF_DRV(KGSL_GEM_GET_BUFINFO, kgsl_gem_get_bufinfo_ioctl, 0),
+	DRM_IOCTL_DEF_DRV(KGSL_GEM_GET_ION_FD, kgsl_gem_get_ion_fd_ioctl, 0),
 	DRM_IOCTL_DEF_DRV(KGSL_GEM_SET_BUFCOUNT,
 		      kgsl_gem_set_bufcount_ioctl, 0),
 	DRM_IOCTL_DEF_DRV(KGSL_GEM_SET_ACTIVE, kgsl_gem_set_active_ioctl, 0),
@@ -1447,6 +1533,16 @@
 		      DRM_MASTER),
 };
 
+static const struct file_operations kgsl_drm_driver_fops = {
+	.owner = THIS_MODULE,
+	.open = drm_open,
+	.release = drm_release,
+	.unlocked_ioctl = drm_ioctl,
+	.mmap = msm_drm_gem_mmap,
+	.poll = drm_poll,
+	.fasync = drm_fasync,
+};
+
 static struct drm_driver driver = {
 	.driver_features = DRIVER_GEM,
 	.load = kgsl_drm_load,
@@ -1458,17 +1554,7 @@
 	.gem_init_object = kgsl_gem_init_object,
 	.gem_free_object = kgsl_gem_free_object,
 	.ioctls = kgsl_drm_ioctls,
-
-	.fops = {
-		 .owner = THIS_MODULE,
-		 .open = drm_open,
-		 .release = drm_release,
-		 .unlocked_ioctl = drm_ioctl,
-		 .mmap = msm_drm_gem_mmap,
-		 .poll = drm_poll,
-		 .fasync = drm_fasync,
-		 },
-
+	.fops = &kgsl_drm_driver_fops,
 	.name = DRIVER_NAME,
 	.desc = DRIVER_DESC,
 	.date = DRIVER_DATE,
@@ -1497,11 +1583,24 @@
 		gem_buf_fence[i].fence_id = ENTRY_EMPTY;
 	}
 
+	/* Create ION Client */
+	kgsl_drm_ion_phys_client = msm_ion_client_create(
+			ION_HEAP_CARVEOUT_MASK, "kgsl_drm");
+	if (!kgsl_drm_ion_phys_client) {
+		DRM_ERROR("Unable to create ION client\n");
+		return -ENOMEM;
+	}
+
 	return drm_platform_init(&driver, dev);
 }
 
 void kgsl_drm_exit(void)
 {
 	kgsl_drm_inited = DRM_KGSL_NOT_INITED;
+
+	if (kgsl_drm_ion_phys_client)
+		ion_client_destroy(kgsl_drm_ion_phys_client);
+	kgsl_drm_ion_phys_client = NULL;
+
 	drm_platform_exit(&driver, driver.kdriver.platform_device);
 }
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 422bd55..7a7a8dc 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -169,7 +169,7 @@
 	if (pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq >
 	    pwr->pwrlevels[pwr->thermal_pwrlevel].gpu_freq)
 		kgsl_pwrctrl_pwrlevel_change(device, pwr->thermal_pwrlevel);
-	else if (!max)
+	else if (!max || (NULL == device->pwrscale.policy))
 		kgsl_pwrctrl_pwrlevel_change(device, i);
 
 done:
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index a70647a..be51c11 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -541,27 +541,8 @@
 	struct page **pages = NULL;
 	pgprot_t page_prot = pgprot_writecombine(PAGE_KERNEL);
 	void *ptr;
-	struct sysinfo si;
 	unsigned int align;
 
-	/*
-	 * Get the current memory information to be used in deciding if we
-	 * should go ahead with this allocation
-	 */
-
-	si_meminfo(&si);
-
-	/*
-	 * Limit the size of the allocation to the amount of free memory minus
-	 * 32MB. Why 32MB?  Because thats the buffer that page_alloc uses and
-	 * it just seems like a reasonable limit that won't make the OOM killer
-	 * go all serial on us.  Of course, if we are down this low all bets
-	 * are off but above all do no harm.
-	 */
-
-	if (size >= ((si.freeram << PAGE_SHIFT) - SZ_32M))
-		return -ENOMEM;
-
 	align = (memdesc->flags & KGSL_MEMALIGN_MASK) >> KGSL_MEMALIGN_SHIFT;
 
 	page_size = (align >= ilog2(SZ_64K) && size >= SZ_64K)
@@ -623,7 +604,7 @@
 	while (len > 0) {
 		struct page *page;
 		unsigned int gfp_mask = GFP_KERNEL | __GFP_HIGHMEM |
-			__GFP_NOWARN;
+			__GFP_NOWARN | __GFP_NORETRY;
 		int j;
 
 		/* don't waste space at the end of the allocation*/
@@ -640,6 +621,13 @@
 				page_size = PAGE_SIZE;
 				continue;
 			}
+
+			KGSL_CORE_ERR(
+				"Out of memory: only allocated %dKB of %dKB requested\n",
+				(size - len) >> 10, size >> 10);
+
+			ret = -ENOMEM;
+			goto done;
 		}
 
 		for (j = 0; j < page_size >> PAGE_SHIFT; j++)
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index 0a85b93..0e82cf7 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -54,28 +54,6 @@
 #define QPNP_STATUS2_CONV_SEQ_TIMEOUT_STS		BIT(0)
 #define QPNP_CONV_TIMEOUT_ERR				2
 
-#define QPNP_INT_RT_ST					0x10
-#define QPNP_INT_SET_TYPE				0x11
-#define QPNP_INT_SET_TYPE_LOW_THR_INT_SET		BIT(4)
-#define QPNP_INT_SET_TYPE_HIGH_THR_INT_SET		BIT(3)
-#define QPNP_INT_SET_TYPE_CONV_SEQ_TIMEOUT_INT_SET	BIT(2)
-#define QPNP_INT_SET_TYPE_FIFO_NOT_EMPTY_INT_SET	BIT(1)
-#define QPNP_INT_SET_TYPE_EOC_SET_INT_TYPE		BIT(0)
-#define QPNP_INT_POLARITY_HIGH				0x12
-#define QPNP_INT_POLARITY_LOW				0x13
-#define QPNP_INT_EN_SET					0x15
-#define QPNP_INT_EN_SET_LOW_THR_INT_EN_SET		BIT(4)
-#define QPNP_INT_EN_SET_HIGH_THR_INT_EN_SET		BIT(3)
-#define QPNP_INT_EN_SET_CONV_SEQ_TIMEOUT_INT_EN		BIT(2)
-#define QPNP_INT_EN_SET_FIFO_NOT_EMPTY_INT_EN		BIT(1)
-#define QPNP_INT_EN_SET_EOC_INT_EN_SET			BIT(0)
-#define QPNP_INT_CLR					0x16
-#define QPNP_INT_CLR_LOW_THR_INT_EN_CLR			BIT(4)
-#define QPNP_INT_CLR_HIGH_THR_INT_EN_CLKR		BIT(3)
-#define QPNP_INT_CLR_CONV_SEQ_TIMEOUT_INT_EN		BIT(2)
-#define QPNP_INT_CLR_FIFO_NOT_EMPTY_INT_EN		BIT(1)
-#define QPNP_INT_CLR_EOC_INT_EN_CLR			BIT(0)
-#define QPNP_INT_CLR_MASK				0x1f
 #define QPNP_IADC_MODE_CTL				0x40
 #define QPNP_OP_MODE_SHIFT				4
 #define QPNP_USE_BMS_DATA				BIT(4)
@@ -146,6 +124,7 @@
 #define QPNP_RAW_CODE_16_BIT_LSB_MASK			0xff
 #define QPNP_BIT_SHIFT_8				8
 #define QPNP_RSENSE_MSB_SIGN_CHECK			0x80
+#define QPNP_ADC_COMPLETION_TIMEOUT			HZ
 
 struct qpnp_iadc_drv {
 	struct qpnp_adc_drv			*adc;
@@ -192,47 +171,9 @@
 	return 0;
 }
 
-static int32_t qpnp_iadc_configure_interrupt(void)
-{
-	int rc = 0;
-	u8 data = 0;
-
-	/* Configure interrupt as an Edge trigger */
-	rc = qpnp_iadc_write_reg(QPNP_INT_SET_TYPE,
-					QPNP_INT_CLR_MASK);
-	if (rc < 0) {
-		pr_err("%s Interrupt configure failed\n", __func__);
-		return rc;
-	}
-
-	/* Configure interrupt for rising edge trigger */
-	rc = qpnp_iadc_write_reg(QPNP_INT_POLARITY_HIGH,
-					QPNP_INT_CLR_MASK);
-	if (rc < 0) {
-		pr_err("%s Rising edge trigger configure failed\n", __func__);
-		return rc;
-	}
-
-	/* Disable low level interrupt triggering */
-	data = QPNP_INT_CLR_MASK;
-	rc = qpnp_iadc_write_reg(QPNP_INT_POLARITY_LOW,
-					(~data & QPNP_INT_CLR_MASK));
-	if (rc < 0) {
-		pr_err("%s Setting level low to disable failed\n", __func__);
-		return rc;
-	}
-
-	return 0;
-}
-
 static void trigger_iadc_completion(struct work_struct *work)
 {
 	struct qpnp_iadc_drv *iadc = qpnp_iadc;
-	int rc;
-
-	rc = qpnp_iadc_write_reg(QPNP_INT_CLR, QPNP_INT_CLR_MASK);
-	if (rc < 0)
-		pr_err("qpnp iadc interrupt mask failed with %d\n", rc);
 
 	complete(&iadc->adc->adc_rslt_completion);
 
@@ -315,13 +256,6 @@
 
 	qpnp_iadc_conv_req = QPNP_IADC_CONV_REQ;
 
-	rc = qpnp_iadc_write_reg(QPNP_INT_EN_SET,
-					QPNP_INT_EN_SET_EOC_INT_EN_SET);
-	if (rc < 0) {
-		pr_err("qpnp adc configure error for interrupt setup\n");
-		return rc;
-	}
-
 	rc = qpnp_iadc_write_reg(QPNP_IADC_MODE_CTL, qpnp_iadc_mode_reg);
 	if (rc) {
 		pr_err("qpnp adc read adc failed with %d\n", rc);
@@ -366,7 +300,22 @@
 		return rc;
 	}
 
-	wait_for_completion(&iadc->adc->adc_rslt_completion);
+	rc = wait_for_completion_timeout(&iadc->adc->adc_rslt_completion,
+				QPNP_ADC_COMPLETION_TIMEOUT);
+	if (!rc) {
+		u8 status1 = 0;
+		rc = qpnp_iadc_read_reg(QPNP_STATUS1, &status1);
+		if (rc < 0)
+			return rc;
+		status1 &= (QPNP_STATUS1_REQ_STS | QPNP_STATUS1_EOC);
+		if (status1 == QPNP_STATUS1_EOC)
+			pr_debug("End of conversion status set\n");
+		else {
+			pr_err("EOC interrupt not received\n");
+			return -EINVAL;
+		}
+	}
+
 
 	rc = qpnp_iadc_read_conversion_result(raw_code);
 	if (rc) {
@@ -672,9 +621,9 @@
 		qpnp_adc_attr.index = iadc->adc->adc_channels[i].channel_num;
 		qpnp_adc_attr.dev_attr.attr.name =
 						iadc->adc->adc_channels[i].name;
-		sysfs_attr_init(&iadc->sens_attr[i].dev_attr.attr);
 		memcpy(&iadc->sens_attr[i], &qpnp_adc_attr,
 						sizeof(qpnp_adc_attr));
+		sysfs_attr_init(&iadc->sens_attr[i].dev_attr.attr);
 		rc = device_create_file(&spmi->dev,
 				&iadc->sens_attr[i].dev_attr);
 		if (rc) {
@@ -766,12 +715,6 @@
 	}
 	iadc->iadc_hwmon = hwmon_device_register(&iadc->adc->spmi->dev);
 
-	rc = qpnp_iadc_configure_interrupt();
-	if (rc) {
-		dev_err(&spmi->dev, "failed to configure interrupt\n");
-		return rc;
-	}
-
 	rc = qpnp_iadc_version_check();
 	if (rc) {
 		dev_err(&spmi->dev, "IADC version not supported\n");
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index 5690c88..c59aa5b 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -54,18 +54,6 @@
 #define QPNP_VADC_STATUS2_CONV_SEQ_STATE_SHIFT			4
 #define QPNP_VADC_CONV_TIMEOUT_ERR				2
 
-#define QPNP_VADC_INT_SET_TYPE					0x11
-#define QPNP_VADC_INT_POLARITY_HIGH				0x12
-#define QPNP_VADC_INT_POLARITY_LOW				0x13
-#define QPNP_VADC_INT_LATCHED_CLR				0x14
-#define QPNP_VADC_INT_EN_SET					0x15
-#define QPNP_VADC_INT_CLR					0x16
-#define QPNP_VADC_INT_LOW_THR_BIT				BIT(4)
-#define QPNP_VADC_INT_HIGH_THR_BIT				BIT(3)
-#define QPNP_VADC_INT_CONV_SEQ_TIMEOUT_BIT			BIT(2)
-#define QPNP_VADC_INT_FIFO_NOT_EMPTY_BIT			BIT(1)
-#define QPNP_VADC_INT_EOC_BIT					BIT(0)
-#define QPNP_VADC_INT_CLR_MASK					0x1f
 #define QPNP_VADC_MODE_CTL					0x40
 #define QPNP_VADC_OP_MODE_SHIFT					4
 #define QPNP_VADC_VREF_XO_THM_FORCE				BIT(2)
@@ -101,6 +89,7 @@
 #define QPNP_VADC_CONV_TIMEOUT_ERR				2
 #define QPNP_VADC_CONV_TIME_MIN					2000
 #define QPNP_VADC_CONV_TIME_MAX					2100
+#define QPNP_ADC_COMPLETION_TIMEOUT				HZ
 
 struct qpnp_vadc_drv {
 	struct qpnp_adc_drv		*adc;
@@ -156,39 +145,6 @@
 	return 0;
 }
 
-static int32_t qpnp_vadc_configure_interrupt(void)
-{
-	int rc = 0;
-	u8 data = 0;
-
-	/* Configure interrupt as an Edge trigger */
-	rc = qpnp_vadc_write_reg(QPNP_VADC_INT_SET_TYPE,
-					QPNP_VADC_INT_CLR_MASK);
-	if (rc < 0) {
-		pr_err("%s Interrupt configure failed\n", __func__);
-		return rc;
-	}
-
-	/* Configure interrupt for rising edge trigger */
-	rc = qpnp_vadc_write_reg(QPNP_VADC_INT_POLARITY_HIGH,
-					QPNP_VADC_INT_CLR_MASK);
-	if (rc < 0) {
-		pr_err("%s Rising edge trigger configure failed\n", __func__);
-		return rc;
-	}
-
-	/* Disable low level interrupt triggering */
-	data = QPNP_VADC_INT_CLR_MASK;
-	rc = qpnp_vadc_write_reg(QPNP_VADC_INT_POLARITY_LOW,
-					(~data & QPNP_VADC_INT_CLR_MASK));
-	if (rc < 0) {
-		pr_err("%s Setting level low to disable failed\n", __func__);
-		return rc;
-	}
-
-	return 0;
-}
-
 static int32_t qpnp_vadc_enable(bool state)
 {
 	int rc = 0;
@@ -222,13 +178,6 @@
 	u8 mode_ctrl = 0;
 	int rc = 0;
 
-	rc = qpnp_vadc_write_reg(QPNP_VADC_INT_EN_SET,
-			QPNP_VADC_INT_EOC_BIT);
-	if (rc < 0) {
-		pr_err("Configure error for interrupt setup\n");
-		return rc;
-	}
-
 	/* Mode selection */
 	mode_ctrl = chan_prop->mode_sel << QPNP_VADC_OP_MODE_SHIFT;
 	rc = qpnp_vadc_write_reg(QPNP_VADC_MODE_CTL, mode_ctrl);
@@ -389,11 +338,6 @@
 static void qpnp_vadc_work(struct work_struct *work)
 {
 	struct qpnp_vadc_drv *vadc = qpnp_vadc;
-	int rc;
-
-	rc = qpnp_vadc_write_reg(QPNP_VADC_INT_CLR, QPNP_VADC_INT_EOC_BIT);
-	if (rc)
-		pr_err("qpnp_vadc clear mask interrupt failed with %d\n", rc);
 
 	complete(&vadc->adc->adc_rslt_completion);
 
@@ -606,8 +550,11 @@
 			!= channel || dt_index > vadc->max_channels_available)
 		dt_index++;
 
-	if (dt_index > vadc->max_channels_available)
+	if (dt_index > vadc->max_channels_available) {
+		pr_err("not a valid VADC channel\n");
+		rc = -EINVAL;
 		goto fail_unlock;
+	}
 
 	vadc->adc->amux_prop->decimation =
 			vadc->adc->adc_channels[dt_index].adc_decimation;
@@ -635,7 +582,22 @@
 		goto fail_unlock;
 	}
 
-	wait_for_completion(&vadc->adc->adc_rslt_completion);
+	rc = wait_for_completion_timeout(&vadc->adc->adc_rslt_completion,
+					QPNP_ADC_COMPLETION_TIMEOUT);
+	if (!rc) {
+		u8 status1 = 0;
+		rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
+		if (rc < 0)
+			goto fail_unlock;
+		status1 &= (QPNP_VADC_STATUS1_REQ_STS | QPNP_VADC_STATUS1_EOC);
+		if (status1 == QPNP_VADC_STATUS1_EOC)
+			pr_debug("End of conversion status set\n");
+		else {
+			pr_err("EOC interrupt not received\n");
+			rc = -EINVAL;
+			goto fail_unlock;
+		}
+	}
 
 	if (trigger_channel < ADC_SEQ_NONE) {
 		rc = qpnp_vadc_read_status(vadc->adc->amux_prop->mode_sel);
@@ -714,9 +676,9 @@
 		qpnp_adc_attr.index = vadc->adc->adc_channels[i].channel_num;
 		qpnp_adc_attr.dev_attr.attr.name =
 						vadc->adc->adc_channels[i].name;
-		sysfs_attr_init(&vadc->sens_attr[i].dev_attr.attr);
 		memcpy(&vadc->sens_attr[i], &qpnp_adc_attr,
 						sizeof(qpnp_adc_attr));
+		sysfs_attr_init(&vadc->sens_attr[i].dev_attr.attr);
 		rc = device_create_file(&spmi->dev,
 				&vadc->sens_attr[i].dev_attr);
 		if (rc) {
@@ -797,25 +759,14 @@
 	rc = qpnp_vadc_init_hwmon(spmi);
 	if (rc) {
 		dev_err(&spmi->dev, "failed to initialize qpnp hwmon adc\n");
-		goto fail_free_irq;
+		return rc;
 	}
 	vadc->vadc_hwmon = hwmon_device_register(&vadc->adc->spmi->dev);
 	vadc->vadc_init_calib = false;
-	vadc->vadc_initialized = true;
 	vadc->max_channels_available = count_adc_channel_list;
-
-	rc = qpnp_vadc_configure_interrupt();
-	if (rc) {
-		dev_err(&spmi->dev, "failed to configure interrupt");
-		goto fail_free_irq;
-	}
+	vadc->vadc_initialized = true;
 
 	return 0;
-
-fail_free_irq:
-	free_irq(vadc->adc->adc_irq, vadc);
-
-	return rc;
 }
 
 static int __devexit qpnp_vadc_remove(struct spmi_device *spmi)
@@ -830,7 +781,6 @@
 			&vadc->sens_attr[i].dev_attr);
 		i++;
 	}
-	free_irq(vadc->adc->adc_irq, vadc);
 	vadc->vadc_initialized = false;
 	dev_set_drvdata(&spmi->dev, NULL);
 
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index f671806..b3bd8a0 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -363,6 +363,7 @@
 	int t38_start_addr;
 	bool update_cfg;
 	const char *fw_name;
+	bool no_force_update;
 };
 
 static struct dentry *debug_base;
@@ -984,9 +985,9 @@
 			continue;
 		}
 
-		/* check whether report id is part of T9 or T15 */
 		id = reportid - data->t9_min_reportid;
 
+		 /* check whether report id is part of T9,T15 or T42*/
 		if (reportid >= data->t9_min_reportid &&
 					reportid <= data->t9_max_reportid)
 			mxt_input_touchevent(data, &message, id);
@@ -1273,25 +1274,18 @@
 			data->cfg_version[0], data->cfg_version[1],
 			data->cfg_version[2]);
 
-	/* It is possible that the config data on the controller is not
-	 * versioned and the version number returns 0. In this case,
-	 * find a match without the config version checking.
-	 */
-	error = mxt_search_config_array(data,
-				data->cfg_version[0] != 0 ? true : false);
+	/* configuration update requires major match */
+	error = mxt_search_config_array(data, true);
+
+	/* if no_force_update is false , try again with false
+	as the second parameter to mxt_search_config_array */
+	if (error && (data->no_force_update == false))
+		error = mxt_search_config_array(data, false);
+
 	if (error) {
-		/* If a match wasn't found for a non-zero config version,
-		 * it means the controller has the wrong config data. Search
-		 * for a best match based on controller and firmware version,
-		 * but not config version.
-		 */
-		if (data->cfg_version[0])
-			error = mxt_search_config_array(data, false);
-		if (error) {
-			dev_err(dev,
-				"Unable to find matching config in pdata\n");
-			return error;
-		}
+		dev_err(dev,
+			"Unable to find matching config in pdata\n");
+		return error;
 	}
 
 	return 0;
@@ -1418,13 +1412,62 @@
 	return 0;
 }
 
+static int mxt_update_cfg(struct mxt_data *data)
+{
+	int error;
+	const u8 *cfg_ver;
+
+	/* Get config data from platform data */
+	error = mxt_get_config(data);
+	if (error)
+		dev_dbg(&data->client->dev, "Config info not found.\n");
+
+	/* Check register init values */
+	if (data->config_info && data->config_info->config) {
+		if (data->update_cfg) {
+			error = mxt_check_reg_init(data);
+			if (error) {
+				dev_err(&data->client->dev,
+					"Failed to check reg init value\n");
+				return error;
+			}
+
+			error = mxt_backup_nv(data);
+			if (error) {
+				dev_err(&data->client->dev, "Failed to back up NV\n");
+				return error;
+			}
+
+			cfg_ver = data->config_info->config +
+						data->cfg_version_idx;
+			dev_info(&data->client->dev,
+				"Config updated from %d.%d.%d to %d.%d.%d\n",
+				data->cfg_version[0], data->cfg_version[1],
+				data->cfg_version[2],
+				cfg_ver[0], cfg_ver[1], cfg_ver[2]);
+
+			memcpy(data->cfg_version, cfg_ver, MXT_CFG_VERSION_LEN);
+		}
+	} else {
+		dev_info(&data->client->dev,
+			"No cfg data defined, skipping check reg init\n");
+	}
+
+	error = mxt_save_objects(data);
+	if (error)
+		return error;
+
+	return 0;
+}
+
+
+
 static int mxt_initialize(struct mxt_data *data)
 {
 	struct i2c_client *client = data->client;
 	struct mxt_info *info = &data->info;
 	int error;
 	u8 val;
-	const u8 *cfg_ver;
 
 	error = mxt_get_info(data);
 	if (error) {
@@ -1465,46 +1508,9 @@
 	if (error)
 		goto free_object_table;
 
-	/* Get config data from platform data */
-	error = mxt_get_config(data);
-	if (error)
-		dev_dbg(&client->dev, "Config info not found.\n");
-
-	/* Check register init values */
-	if (data->config_info && data->config_info->config) {
-		if (data->update_cfg) {
-			error = mxt_check_reg_init(data);
-			if (error) {
-				dev_err(&client->dev,
-					"Failed to check reg init value\n");
-				goto free_object_table;
-			}
-
-			error = mxt_backup_nv(data);
-			if (error) {
-				dev_err(&client->dev, "Failed to back up NV\n");
-				goto free_object_table;
-			}
-
-			cfg_ver = data->config_info->config +
-							data->cfg_version_idx;
-			dev_info(&client->dev,
-				"Config updated from %d.%d.%d to %d.%d.%d\n",
-				data->cfg_version[0], data->cfg_version[1],
-				data->cfg_version[2],
-				cfg_ver[0], cfg_ver[1], cfg_ver[2]);
-
-			memcpy(data->cfg_version, cfg_ver, MXT_CFG_VERSION_LEN);
-		}
-	} else {
-		dev_info(&client->dev,
-			"No cfg data defined, skipping check reg init\n");
-	}
-
-	error = mxt_save_objects(data);
+	error = mxt_update_cfg(data);
 	if (error)
 		goto free_object_table;
-
 	/* Update matrix size at info struct */
 	error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, &val);
 	if (error)
@@ -1732,6 +1738,30 @@
 	return fw_name;
 }
 
+static ssize_t mxt_force_cfg_update_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct mxt_data *data = dev_get_drvdata(dev);
+	int flag = buf[0]-'0';
+	int error;
+	data->no_force_update = !flag;
+
+	if (data->state == APPMODE) {
+		disable_irq(data->irq);
+		error = mxt_update_cfg(data);
+		enable_irq(data->irq);
+		if (error)
+			return error;
+	} else {
+		dev_err(dev,
+		"Not in APPMODE, Unable to force cfg update\n");
+		return -EINVAL;
+	}
+
+	return count;
+}
+
 static ssize_t mxt_update_fw_store(struct device *dev,
 					struct device_attribute *attr,
 					const char *buf, size_t count)
@@ -1742,7 +1772,7 @@
 	u8 bootldr_id;
 	u8 cfg_version[MXT_CFG_VERSION_LEN] = {0};
 
-
+	data->no_force_update = false;
 	/* If fw_name is set, then the existing firmware has an upgrade */
 	if (!data->fw_name) {
 		/*
@@ -1824,10 +1854,12 @@
 
 static DEVICE_ATTR(object, 0444, mxt_object_show, NULL);
 static DEVICE_ATTR(update_fw, 0664, NULL, mxt_update_fw_store);
+static DEVICE_ATTR(force_cfg_update, 0664, NULL, mxt_force_cfg_update_store);
 
 static struct attribute *mxt_attrs[] = {
 	&dev_attr_object.attr,
 	&dev_attr_update_fw.attr,
+	&dev_attr_force_cfg_update.attr,
 	NULL
 };
 
@@ -2433,6 +2465,10 @@
 	pdata->i2c_pull_up = of_property_read_bool(np, "atmel,i2c-pull-up");
 	pdata->digital_pwr_regulator = of_property_read_bool(np,
 						"atmel,dig-reg-support");
+
+	pdata->no_force_update = of_property_read_bool(np,
+						"atmel,no-force-update");
+
 	/* reset, irq gpio info */
 	pdata->reset_gpio = of_get_named_gpio_flags(np, "atmel,reset-gpio",
 				0, &pdata->reset_gpio_flags);
@@ -2583,6 +2619,7 @@
 	data->client = client;
 	data->input_dev = input_dev;
 	data->pdata = pdata;
+	data->no_force_update = pdata->no_force_update;
 
 	__set_bit(EV_ABS, input_dev->evbit);
 	__set_bit(EV_KEY, input_dev->evbit);
diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c
index bf173b3..f8c9809 100644
--- a/drivers/iommu/msm_iommu.c
+++ b/drivers/iommu/msm_iommu.c
@@ -772,6 +772,55 @@
 		&& (len >= align);
 }
 
+static int check_range(unsigned long *fl_table, unsigned int va,
+				 unsigned int len)
+{
+	unsigned int offset = 0;
+	unsigned long *fl_pte;
+	unsigned long fl_offset;
+	unsigned long *sl_table;
+	unsigned long sl_start, sl_end;
+	int i;
+
+	fl_offset = FL_OFFSET(va);	/* Upper 12 bits */
+	fl_pte = fl_table + fl_offset;	/* int pointers, 4 bytes */
+
+	while (offset < len) {
+		if (*fl_pte & FL_TYPE_TABLE) {
+			sl_start = SL_OFFSET(va);
+			sl_table =  __va(((*fl_pte) & FL_BASE_MASK));
+			sl_end = ((len - offset) / SZ_4K) + sl_start;
+
+			if (sl_end > NUM_SL_PTE)
+				sl_end = NUM_SL_PTE;
+
+			for (i = sl_start; i < sl_end; i++) {
+				if (sl_table[i] != 0) {
+					pr_err("%08x - %08x already mapped\n",
+						va, va + SZ_4K);
+					return -EBUSY;
+				}
+				offset += SZ_4K;
+				va += SZ_4K;
+			}
+
+
+			sl_start = 0;
+		} else {
+			if (*fl_pte != 0) {
+				pr_err("%08x - %08x already mapped\n",
+				       va, va + SZ_1M);
+				return -EBUSY;
+			}
+			va += SZ_1M;
+			offset += SZ_1M;
+			sl_start = 0;
+		}
+		fl_pte++;
+	}
+	return 0;
+}
+
 static int msm_iommu_map_range(struct iommu_domain *domain, unsigned int va,
 			       struct scatterlist *sg, unsigned int len,
 			       int prot)
@@ -804,6 +853,9 @@
 		ret = -EINVAL;
 		goto fail;
 	}
+	ret = check_range(fl_table, va, len);
+	if (ret)
+		goto fail;
 
 	fl_offset = FL_OFFSET(va);	/* Upper 12 bits */
 	fl_pte = fl_table + fl_offset;	/* int pointers, 4 bytes */
diff --git a/drivers/iommu/msm_iommu_dev-v2.c b/drivers/iommu/msm_iommu_dev-v2.c
index ea6c87c..5a0b593 100644
--- a/drivers/iommu/msm_iommu_dev-v2.c
+++ b/drivers/iommu/msm_iommu_dev-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -21,7 +21,6 @@
 #include <linux/interrupt.h>
 #include <linux/err.h>
 #include <linux/slab.h>
-#include <linux/atomic.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
@@ -95,9 +94,8 @@
 	struct device_node *child;
 	int ret = 0;
 
-	ret = device_move(&pdev->dev, &msm_iommu_root_dev->dev, DPM_ORDER_NONE);
-	if (ret)
-		goto fail;
+	drvdata->dev = &pdev->dev;
+	msm_iommu_add_drv(drvdata);
 
 	ret = msm_iommu_parse_bfb_settings(pdev, drvdata);
 	if (ret)
@@ -118,20 +116,12 @@
 	return ret;
 }
 
-static atomic_t msm_iommu_next_id = ATOMIC_INIT(-1);
-
 static int __devinit msm_iommu_probe(struct platform_device *pdev)
 {
 	struct msm_iommu_drvdata *drvdata;
 	struct resource *r;
 	int ret, needs_alt_core_clk;
 
-	if (msm_iommu_root_dev == pdev)
-		return 0;
-
-	if (pdev->id == -1)
-		pdev->id = atomic_inc_return(&msm_iommu_next_id) - 1;
-
 	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
 	if (!drvdata)
 		return -ENOMEM;
@@ -192,6 +182,7 @@
 
 	drv = platform_get_drvdata(pdev);
 	if (drv) {
+		msm_iommu_remove_drv(drv);
 		if (drv->clk)
 			clk_put(drv->clk);
 		clk_put(drv->pclk);
@@ -315,25 +306,8 @@
 
 static int __init msm_iommu_driver_init(void)
 {
-	struct device_node *node;
 	int ret;
 
-	node = of_find_compatible_node(NULL, NULL, "qcom,msm-smmu-v2");
-	if (!node)
-		return -ENODEV;
-
-	of_node_put(node);
-
-	msm_iommu_root_dev = platform_device_register_simple(
-						"msm_iommu", -1, 0, 0);
-	if (!msm_iommu_root_dev) {
-		pr_err("Failed to create root IOMMU device\n");
-		ret = -ENODEV;
-		goto error;
-	}
-
-	atomic_inc(&msm_iommu_next_id);
-
 	ret = platform_driver_register(&msm_iommu_driver);
 	if (ret != 0) {
 		pr_err("Failed to register IOMMU driver\n");
@@ -354,7 +328,6 @@
 {
 	platform_driver_unregister(&msm_iommu_ctx_driver);
 	platform_driver_unregister(&msm_iommu_driver);
-	platform_device_unregister(msm_iommu_root_dev);
 }
 
 subsys_initcall(msm_iommu_driver_init);
diff --git a/drivers/iommu/msm_iommu_dev.c b/drivers/iommu/msm_iommu_dev.c
index 967283d..d9eddcd 100644
--- a/drivers/iommu/msm_iommu_dev.c
+++ b/drivers/iommu/msm_iommu_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -21,62 +21,63 @@
 #include <linux/interrupt.h>
 #include <linux/err.h>
 #include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
 
 #include <mach/iommu_hw-8xxx.h>
 #include <mach/iommu.h>
 
-struct iommu_ctx_iter_data {
-	/* input */
-	const char *name;
+static DEFINE_MUTEX(iommu_list_lock);
+static LIST_HEAD(iommu_list);
 
-	/* output */
-	struct device *dev;
-};
-
-struct platform_device *msm_iommu_root_dev;
-
-static int each_iommu_ctx(struct device *dev, void *data)
+void msm_iommu_add_drv(struct msm_iommu_drvdata *drv)
 {
-	struct iommu_ctx_iter_data *res = data;
+	mutex_lock(&iommu_list_lock);
+	list_add(&drv->list, &iommu_list);
+	mutex_unlock(&iommu_list_lock);
+}
+
+void msm_iommu_remove_drv(struct msm_iommu_drvdata *drv)
+{
+	mutex_lock(&iommu_list_lock);
+	list_del(&drv->list);
+	mutex_unlock(&iommu_list_lock);
+}
+
+static int find_iommu_ctx(struct device *dev, void *data)
+{
 	struct msm_iommu_ctx_drvdata *c;
 
 	c = dev_get_drvdata(dev);
-	if (!res || !c || !c->name || !res->name)
-		return -EINVAL;
+	if (!c || !c->name)
+		return 0;
 
-	if (!strcmp(res->name, c->name)) {
-		res->dev = dev;
-		return 1;
-	}
-	return 0;
+	return !strcmp(data, c->name);
 }
 
-static int each_iommu(struct device *dev, void *data)
+static struct device *find_context(struct device *dev, const char *name)
 {
-	return device_for_each_child(dev, data, each_iommu_ctx);
+	return device_find_child(dev, (void *)name, find_iommu_ctx);
 }
 
 struct device *msm_iommu_get_ctx(const char *ctx_name)
 {
-	struct iommu_ctx_iter_data r;
-	int found;
+	struct msm_iommu_drvdata *drv;
+	struct device *dev = NULL;
 
-	if (!msm_iommu_root_dev) {
-		pr_err("No root IOMMU device.\n");
-		goto fail;
+	mutex_lock(&iommu_list_lock);
+	list_for_each_entry(drv, &iommu_list, list) {
+		dev = find_context(drv->dev, ctx_name);
+		if (dev)
+			break;
 	}
+	mutex_unlock(&iommu_list_lock);
 
-	r.name = ctx_name;
-	found = device_for_each_child(&msm_iommu_root_dev->dev, &r, each_iommu);
-
-	if (found <= 0 || !dev_get_drvdata(r.dev)) {
+	if (!dev || !dev_get_drvdata(dev))
 		pr_err("Could not find context <%s>\n", ctx_name);
-		goto fail;
-	}
+	put_device(dev);
 
-	return r.dev;
-fail:
-	return NULL;
+	return dev;
 }
 EXPORT_SYMBOL(msm_iommu_get_ctx);
 
@@ -134,11 +135,6 @@
 	resource_size_t	len;
 	int ret, par;
 
-	if (pdev->id == -1) {
-		msm_iommu_root_dev = pdev;
-		return 0;
-	}
-
 	drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
 
 	if (!drvdata) {
@@ -227,6 +223,9 @@
 	drvdata->ncb = iommu_dev->ncb;
 	drvdata->ttbr_split = iommu_dev->ttbr_split;
 	drvdata->name = iommu_dev->name;
+	drvdata->dev = &pdev->dev;
+
+	msm_iommu_add_drv(drvdata);
 
 	pr_info("device %s mapped at %p, with %d ctx banks\n",
 		iommu_dev->name, regs_base, iommu_dev->ncb);
@@ -263,6 +262,7 @@
 
 	drv = platform_get_drvdata(pdev);
 	if (drv) {
+		msm_iommu_remove_drv(drv);
 		if (drv->clk)
 			clk_put(drv->clk);
 		clk_put(drv->pclk);
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 696c9f9..d658217 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -21,6 +21,7 @@
 #include <linux/of_platform.h>
 #include <linux/of_device.h>
 #include <linux/spmi.h>
+#include <linux/qpnp/pwm.h>
 
 #define WLED_MOD_EN_REG(base, n)	(base + 0x60 + n*0x10)
 #define WLED_IDAC_DLY_REG(base, n)	(WLED_MOD_EN_REG(base, n) + 0x01)
@@ -75,14 +76,85 @@
 #define WLED_CTRL_DLY_DEFAULT		0x00
 #define WLED_SWITCH_FREQ_DEFAULT	0x02
 
+#define FLASH_SAFETY_TIMER(base)	(base + 0x40)
+#define FLASH_MAX_CURR(base)		(base + 0x41)
+#define FLASH_LED_0_CURR(base)		(base + 0x42)
+#define FLASH_LED_1_CURR(base)		(base + 0x43)
+#define FLASH_CLAMP_CURR(base)		(base + 0x44)
+#define FLASH_LED_TMR_CTRL(base)	(base + 0x48)
+#define FLASH_HEADROOM(base)		(base + 0x49)
+#define FLASH_STARTUP_DELAY(base)	(base + 0x4B)
+#define FLASH_MASK_ENABLE(base)		(base + 0x4C)
+#define FLASH_VREG_OK_FORCE(base)	(base + 0x4F)
+#define FLASH_ENABLE_CONTROL(base)	(base + 0x46)
+#define FLASH_LED_STROBE_CTRL(base)	(base + 0x47)
+
+#define FLASH_MAX_LEVEL			0x4F
+#define	FLASH_NO_MASK			0x00
+
+#define FLASH_MASK_1			0x20
+#define FLASH_MASK_REG_MASK		0xE0
+#define FLASH_HEADROOM_MASK		0x03
+#define FLASH_SAFETY_TIMER_MASK		0x7F
+#define FLASH_CURRENT_MASK		0xFF
+#define FLASH_TMR_MASK			0x03
+#define FLASH_TMR_WATCHDOG		0x03
+#define FLASH_TMR_SAFETY		0x00
+
+#define FLASH_HW_VREG_OK		0x80
+#define FLASH_VREG_MASK			0xC0
+
+#define FLASH_STARTUP_DLY_MASK		0x02
+
+#define FLASH_ENABLE_ALL		0xE0
+#define FLASH_ENABLE_MODULE		0x80
+#define FLASH_ENABLE_MODULE_MASK	0x80
+#define FLASH_DISABLE_ALL		0x00
+#define FLASH_ENABLE_MASK		0x60
+#define FLASH_ENABLE_LED_0		0x40
+#define FLASH_ENABLE_LED_1		0x20
+#define FLASH_INIT_MASK			0xE0
+
+#define FLASH_STROBE_ALL		0xC0
+#define FLASH_STROBE_MASK		0xC0
+#define FLASH_LED_0_OUTPUT		0x80
+#define FLASH_LED_1_OUTPUT		0x40
+
+#define FLASH_CURRENT_PRGM_MIN		1
+#define FLASH_CURRENT_PRGM_SHIFT	1
+
+#define FLASH_DURATION_200ms		0x13
+#define FLASH_CLAMP_200mA		0x0F
+
 #define LED_TRIGGER_DEFAULT		"none"
 
+#define RGB_LED_SRC_SEL(base)		(base + 0x45)
+#define RGB_LED_EN_CTL(base)		(base + 0x46)
+#define RGB_LED_ATC_CTL(base)		(base + 0x47)
+
+#define RGB_MAX_LEVEL			LED_FULL
+#define RGB_LED_ENABLE_RED		0x80
+#define RGB_LED_ENABLE_GREEN		0x40
+#define RGB_LED_ENABLE_BLUE		0x20
+#define RGB_LED_SOURCE_VPH_PWR		0x01
+#define RGB_LED_ENABLE_MASK		0xE0
+#define RGB_LED_SRC_MASK		0x03
+#define QPNP_LED_PWM_FLAGS	(PM_PWM_LUT_LOOP | PM_PWM_LUT_RAMP_UP)
+#define	PWM_LUT_MAX_SIZE		63
+#define RGB_LED_DISABLE			0x00
+
 /**
  * enum qpnp_leds - QPNP supported led ids
  * @QPNP_ID_WLED - White led backlight
  */
 enum qpnp_leds {
-	QPNP_ID_WLED,
+	QPNP_ID_WLED = 0,
+	QPNP_ID_FLASH1_LED0,
+	QPNP_ID_FLASH1_LED1,
+	QPNP_ID_RGB_RED,
+	QPNP_ID_RGB_GREEN,
+	QPNP_ID_RGB_BLUE,
+	QPNP_ID_MAX,
 };
 
 /* current boost limit */
@@ -113,6 +185,25 @@
 	WLED_3200kHz,
 };
 
+enum flash_headroom {
+	HEADROOM_250mV = 0,
+	HEADROOM_300mV,
+	HEADROOM_400mV,
+	HEADROOM_500mV,
+};
+
+enum flash_startup_dly {
+	DELAY_10us = 0,
+	DELAY_32us,
+	DELAY_64us,
+	DELAY_128us,
+};
+
+enum rgb_mode {
+	RGB_MODE_PWM = 0,
+	RGB_MODE_LPG,
+};
+
 static u8 wled_debug_regs[] = {
 	/* common registers */
 	0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4d, 0x4e, 0x4f,
@@ -125,6 +216,14 @@
 	0x80, 0x81, 0x82, 0x83, 0x86,
 };
 
+static u8 flash_debug_regs[] = {
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x48, 0x49, 0x4b, 0x4c,
+	0x4f, 0x46, 0x47,
+};
+
+static u8 rgb_pwm_debug_regs[] = {
+	0x45, 0x46, 0x47,
+};
 /**
  *  wled_config_data - wled configuration data
  *  @num_strings - number of wled strings supported
@@ -149,6 +248,50 @@
 };
 
 /**
+ *  flash_config_data - flash configuration data
+ *  @current_prgm - current to be programmed, scaled by max level
+ *  @clamp_curr - clamp current to use
+ *  @headroom - headroom value to use
+ *  @duration - duration of the flash
+ *  @enable_module - enable address for particular flash
+ *  @trigger_flash - trigger flash
+ *  @startup_dly - startup delay for flash
+ *  @current_addr - address to write for current
+ *  @second_addr - address of secondary flash to be written
+ *  @safety_timer - enable safety timer or watchdog timer
+ */
+struct flash_config_data {
+	u8	current_prgm;
+	u8	clamp_curr;
+	u8	headroom;
+	u8	duration;
+	u8	enable_module;
+	u8	trigger_flash;
+	u8	startup_dly;
+	u16	current_addr;
+	u16	second_addr;
+	bool	safety_timer;
+};
+
+/**
+ *  rgb_config_data - rgb configuration data
+ *  @lut_params - lut parameters to be used by pwm driver
+ *  @pwm_device - pwm device
+ *  @pwm_channel - pwm channel to be configured for led
+ *  @pwm_period_us - period for pwm, in us
+ *  @mode - mode the led operates in
+ */
+struct rgb_config_data {
+	struct lut_params	lut_params;
+	struct pwm_device	*pwm_dev;
+	int			pwm_channel;
+	u32			pwm_period_us;
+	struct pwm_duty_cycles	*duty_cycles;
+	u8	mode;
+	u8	enable;
+};
+
+/**
  * struct qpnp_led_data - internal led data structure
  * @led_classdev - led class device
  * @id - led index
@@ -168,6 +311,8 @@
 	u8			num_leds;
 	spinlock_t		lock;
 	struct wled_config_data *wled_cfg;
+	struct flash_config_data	*flash_cfg;
+	struct rgb_config_data	*rgb_cfg;
 	int			max_current;
 	bool			default_on;
 };
@@ -289,6 +434,123 @@
 	return 0;
 }
 
+static int qpnp_flash_set(struct qpnp_led_data *led)
+{
+	int rc;
+	int val = led->cdev.brightness;
+
+	led->flash_cfg->current_prgm = (val * FLASH_MAX_LEVEL /
+						led->max_current);
+
+	led->flash_cfg->current_prgm =
+		led->flash_cfg->current_prgm >> FLASH_CURRENT_PRGM_SHIFT;
+	if (!led->flash_cfg->current_prgm)
+		led->flash_cfg->current_prgm = FLASH_CURRENT_PRGM_MIN;
+
+	/* Set led current */
+	if (val > 0) {
+		rc = qpnp_led_masked_write(led, led->flash_cfg->current_addr,
+			FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"Current reg write failed(%d)\n", rc);
+			return rc;
+		}
+
+		rc = qpnp_led_masked_write(led, led->flash_cfg->second_addr,
+			FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"Current reg write failed(%d)\n", rc);
+			return rc;
+		}
+
+		rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
+			FLASH_ENABLE_MASK,
+			FLASH_ENABLE_ALL);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"Enable reg write failed(%d)\n", rc);
+			return rc;
+		}
+		rc = qpnp_led_masked_write(led,
+			FLASH_LED_STROBE_CTRL(led->base),
+			FLASH_STROBE_MASK, FLASH_STROBE_ALL);
+
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"LED %d flash write failed(%d)\n", led->id, rc);
+			return rc;
+		}
+	} else {
+		rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
+			FLASH_ENABLE_MASK,
+			FLASH_DISABLE_ALL);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"Enable reg write failed(%d)\n", rc);
+			return rc;
+		}
+
+		rc = qpnp_led_masked_write(led,
+			FLASH_LED_STROBE_CTRL(led->base),
+			FLASH_STROBE_MASK,
+			FLASH_DISABLE_ALL);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"LED %d flash write failed(%d)\n", led->id, rc);
+			return rc;
+		}
+	}
+
+	qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
+
+	return 0;
+}
+
+static int qpnp_rgb_set(struct qpnp_led_data *led)
+{
+	int duty_us;
+	int rc;
+
+	if (led->cdev.brightness) {
+		if (led->rgb_cfg->mode == RGB_MODE_PWM) {
+			duty_us = (led->rgb_cfg->pwm_period_us *
+				led->cdev.brightness) / LED_FULL;
+			rc = pwm_config(led->rgb_cfg->pwm_dev, duty_us,
+					led->rgb_cfg->pwm_period_us);
+			if (rc < 0) {
+				dev_err(&led->spmi_dev->dev, "Failed to " \
+					"configure pwm for new values\n");
+				return rc;
+			}
+		}
+		rc = qpnp_led_masked_write(led,
+			RGB_LED_EN_CTL(led->base),
+			led->rgb_cfg->enable, led->rgb_cfg->enable);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"Failed to write led enable reg\n");
+			return rc;
+		}
+		rc = pwm_enable(led->rgb_cfg->pwm_dev);
+	} else {
+		pwm_disable(led->rgb_cfg->pwm_dev);
+		rc = qpnp_led_masked_write(led,
+			RGB_LED_EN_CTL(led->base),
+			led->rgb_cfg->enable, RGB_LED_DISABLE);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"Failed to write led enable reg\n");
+			return rc;
+		}
+	}
+
+	qpnp_dump_regs(led, rgb_pwm_debug_regs, ARRAY_SIZE(rgb_pwm_debug_regs));
+
+	return 0;
+}
+
 static void qpnp_led_set(struct led_classdev *led_cdev,
 				enum led_brightness value)
 {
@@ -311,6 +573,21 @@
 			dev_err(&led->spmi_dev->dev,
 				"WLED set brightness failed (%d)\n", rc);
 		break;
+	case QPNP_ID_FLASH1_LED0:
+	case QPNP_ID_FLASH1_LED1:
+		rc = qpnp_flash_set(led);
+		if (rc < 0)
+			dev_err(&led->spmi_dev->dev,
+				"FLASH set brightness failed (%d)\n", rc);
+		break;
+	case QPNP_ID_RGB_RED:
+	case QPNP_ID_RGB_GREEN:
+	case QPNP_ID_RGB_BLUE:
+		rc = qpnp_rgb_set(led);
+		if (rc < 0)
+			dev_err(&led->spmi_dev->dev,
+				"RGB set brightness failed (%d)\n", rc);
+		break;
 	default:
 		dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
 		break;
@@ -324,6 +601,15 @@
 	case QPNP_ID_WLED:
 		led->cdev.max_brightness = WLED_MAX_LEVEL;
 		break;
+	case QPNP_ID_FLASH1_LED0:
+	case QPNP_ID_FLASH1_LED1:
+		led->cdev.max_brightness = led->max_current;
+		break;
+	case QPNP_ID_RGB_RED:
+	case QPNP_ID_RGB_GREEN:
+	case QPNP_ID_RGB_BLUE:
+		led->cdev.max_brightness = RGB_MAX_LEVEL;
+		break;
 	default:
 		dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
 		return -EINVAL;
@@ -471,6 +757,189 @@
 	return 0;
 }
 
+static int __devinit qpnp_flash_init(struct qpnp_led_data *led)
+{
+	int rc;
+
+	rc = qpnp_led_masked_write(led,
+		FLASH_LED_STROBE_CTRL(led->base),
+		FLASH_STROBE_MASK, FLASH_DISABLE_ALL);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"LED %d flash write failed(%d)\n", led->id, rc);
+		return rc;
+	}
+	rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
+		FLASH_INIT_MASK, FLASH_ENABLE_MODULE);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Enable reg write failed(%d)\n", rc);
+		return rc;
+	}
+
+	/* Set flash safety timer */
+	rc = qpnp_led_masked_write(led, FLASH_SAFETY_TIMER(led->base),
+		FLASH_SAFETY_TIMER_MASK, led->flash_cfg->duration);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Safety timer reg write failed(%d)\n", rc);
+		return rc;
+	}
+
+	/* Set max current */
+	rc = qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
+		FLASH_CURRENT_MASK, FLASH_MAX_LEVEL);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Max current reg write failed(%d)\n", rc);
+		return rc;
+	}
+	/* Set clamp current */
+	rc = qpnp_led_masked_write(led, FLASH_CLAMP_CURR(led->base),
+		FLASH_CURRENT_MASK, led->flash_cfg->clamp_curr);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Clamp current reg write failed(%d)\n", rc);
+		return rc;
+	}
+
+	/* Set timer control - safety or watchdog */
+	if (led->flash_cfg->safety_timer)
+		rc = qpnp_led_masked_write(led, FLASH_LED_TMR_CTRL(led->base),
+			FLASH_TMR_MASK, FLASH_TMR_SAFETY);
+	else
+		rc = qpnp_led_masked_write(led, FLASH_LED_TMR_CTRL(led->base),
+			FLASH_TMR_MASK, FLASH_TMR_WATCHDOG);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"LED timer ctrl reg write failed(%d)\n", rc);
+		return rc;
+	}
+	/* Set headroom */
+	rc = qpnp_led_masked_write(led, FLASH_HEADROOM(led->base),
+		FLASH_HEADROOM_MASK, led->flash_cfg->headroom);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Headroom reg write failed(%d)\n", rc);
+		return rc;
+	}
+
+	/* Set mask enable */
+	rc = qpnp_led_masked_write(led, FLASH_MASK_ENABLE(led->base),
+		FLASH_MASK_REG_MASK, FLASH_MASK_1);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Mask enable reg write failed(%d)\n", rc);
+		return rc;
+	}
+
+	/* Set startup delay */
+	rc = qpnp_led_masked_write(led, FLASH_STARTUP_DELAY(led->base),
+		FLASH_STARTUP_DLY_MASK, led->flash_cfg->startup_dly);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Startup delay reg write failed(%d)\n", rc);
+		return rc;
+	}
+
+	rc = qpnp_led_masked_write(led, FLASH_VREG_OK_FORCE(led->base),
+		FLASH_VREG_MASK, FLASH_HW_VREG_OK);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Vreg OK reg write failed(%d)\n", rc);
+		return rc;
+	}
+
+	/* Set led current and enable module */
+	rc = qpnp_led_masked_write(led, led->flash_cfg->current_addr,
+		FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Current reg write failed(%d)\n", rc);
+		return rc;
+	}
+
+	rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
+		FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Enable reg write failed(%d)\n", rc);
+		return rc;
+	}
+	/* dump flash registers */
+	qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
+
+	return 0;
+}
+
+static int __devinit qpnp_rgb_init(struct qpnp_led_data *led)
+{
+	int rc, start_idx, idx_len;
+
+	rc = qpnp_led_masked_write(led, RGB_LED_SRC_SEL(led->base),
+		RGB_LED_SRC_MASK, RGB_LED_SOURCE_VPH_PWR);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Failed to write led source select register\n");
+		return rc;
+	}
+
+	if (led->rgb_cfg->pwm_channel != -1) {
+		led->rgb_cfg->pwm_dev =
+			pwm_request(led->rgb_cfg->pwm_channel,
+						led->cdev.name);
+
+		if (IS_ERR_OR_NULL(led->rgb_cfg->pwm_dev)) {
+			dev_err(&led->spmi_dev->dev,
+				"could not acquire PWM Channel %d, " \
+				"error %ld\n",
+				led->rgb_cfg->pwm_channel,
+				PTR_ERR(led->rgb_cfg->pwm_dev));
+			led->rgb_cfg->pwm_dev = NULL;
+			return -ENODEV;
+		}
+
+		if (led->rgb_cfg->mode == RGB_MODE_LPG) {
+			start_idx =
+			led->rgb_cfg->duty_cycles->start_idx;
+			idx_len =
+			led->rgb_cfg->duty_cycles->num_duty_pcts;
+
+			if (idx_len >= PWM_LUT_MAX_SIZE &&
+					start_idx) {
+				dev_err(&led->spmi_dev->dev,
+					"Wrong LUT size or index\n");
+				return -EINVAL;
+			}
+			if ((start_idx + idx_len) >
+					PWM_LUT_MAX_SIZE) {
+				dev_err(&led->spmi_dev->dev,
+					"Exceed LUT limit\n");
+				return -EINVAL;
+			}
+			rc = pwm_lut_config(led->rgb_cfg->pwm_dev,
+				led->rgb_cfg->pwm_period_us,
+				led->rgb_cfg->duty_cycles->duty_pcts,
+				led->rgb_cfg->lut_params);
+			if (rc < 0) {
+				dev_err(&led->spmi_dev->dev, "Failed to " \
+					"configure pwm LUT\n");
+				return rc;
+			}
+		}
+	} else {
+		dev_err(&led->spmi_dev->dev,
+			"Invalid PWM channel\n");
+		return -EINVAL;
+	}
+
+	/* Initialize led for use in auto trickle charging mode */
+	rc = qpnp_led_masked_write(led, RGB_LED_ATC_CTL(led->base),
+		led->rgb_cfg->enable, led->rgb_cfg->enable);
+
+	return 0;
+}
+
 static int __devinit qpnp_led_initialize(struct qpnp_led_data *led)
 {
 	int rc;
@@ -482,12 +951,27 @@
 			dev_err(&led->spmi_dev->dev,
 				"WLED initialize failed(%d)\n", rc);
 		break;
+	case QPNP_ID_FLASH1_LED0:
+	case QPNP_ID_FLASH1_LED1:
+		rc = qpnp_flash_init(led);
+		if (rc)
+			dev_err(&led->spmi_dev->dev,
+				"FLASH initialize failed(%d)\n", rc);
+		break;
+	case QPNP_ID_RGB_RED:
+	case QPNP_ID_RGB_GREEN:
+	case QPNP_ID_RGB_BLUE:
+		rc = qpnp_rgb_init(led);
+		if (rc)
+			dev_err(&led->spmi_dev->dev,
+				"RGB initialize failed(%d)\n", rc);
+		break;
 	default:
 		dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
-		rc = -EINVAL;
+		return -EINVAL;
 	}
 
-	return rc;
+	return 0;
 }
 
 static int __devinit qpnp_get_common_configs(struct qpnp_led_data *led,
@@ -586,6 +1070,194 @@
 	return 0;
 }
 
+static int __devinit qpnp_get_config_flash(struct qpnp_led_data *led,
+				struct device_node *node)
+{
+	int rc;
+	u32 val;
+
+	led->flash_cfg = devm_kzalloc(&led->spmi_dev->dev,
+				sizeof(struct flash_config_data), GFP_KERNEL);
+	if (!led->flash_cfg) {
+		dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	if (led->id == QPNP_ID_FLASH1_LED0) {
+		led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
+		led->flash_cfg->current_addr = FLASH_LED_0_CURR(led->base);
+		led->flash_cfg->second_addr = FLASH_LED_1_CURR(led->base);
+		led->flash_cfg->trigger_flash = FLASH_LED_0_OUTPUT;
+	} else if (led->id == QPNP_ID_FLASH1_LED1) {
+		led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
+		led->flash_cfg->current_addr = FLASH_LED_1_CURR(led->base);
+		led->flash_cfg->second_addr = FLASH_LED_0_CURR(led->base);
+		led->flash_cfg->trigger_flash = FLASH_LED_1_OUTPUT;
+	} else {
+		dev_err(&led->spmi_dev->dev, "Unknown flash LED name given\n");
+		return -EINVAL;
+	}
+
+	rc = of_property_read_u32(node, "qcom,current", &val);
+	if (!rc)
+		led->flash_cfg->current_prgm = (val *
+				FLASH_MAX_LEVEL / led->max_current);
+	else
+		return -EINVAL;
+
+	rc = of_property_read_u32(node, "qcom,headroom", &val);
+	if (!rc)
+		led->flash_cfg->headroom = (u8) val;
+	else if (rc == -EINVAL)
+		led->flash_cfg->headroom = HEADROOM_300mV;
+	else
+		return rc;
+
+	rc = of_property_read_u32(node, "qcom,duration", &val);
+	if (!rc)
+		led->flash_cfg->duration = (((u8) val) - 10) / 10;
+	else if (rc == -EINVAL)
+		led->flash_cfg->duration = FLASH_DURATION_200ms;
+	else
+		return rc;
+
+	rc = of_property_read_u32(node, "qcom,clamp-curr", &val);
+	if (!rc)
+		led->flash_cfg->clamp_curr = (val *
+				FLASH_MAX_LEVEL / led->max_current);
+	else if (rc == -EINVAL)
+		led->flash_cfg->clamp_curr = FLASH_CLAMP_200mA;
+	else
+		return rc;
+
+	rc = of_property_read_u32(node, "qcom,startup-dly", &val);
+	if (!rc)
+		led->flash_cfg->startup_dly = (u8) val;
+	else if (rc == -EINVAL)
+		led->flash_cfg->startup_dly = DELAY_32us;
+	else
+		return rc;
+
+	led->flash_cfg->safety_timer =
+		of_property_read_bool(node, "qcom,safety-timer");
+
+	return 0;
+}
+
+static int __devinit qpnp_get_config_rgb(struct qpnp_led_data *led,
+				struct device_node *node)
+{
+	struct property *prop;
+	int rc, i;
+	u32 val;
+	u8 *temp_cfg;
+
+	led->rgb_cfg = devm_kzalloc(&led->spmi_dev->dev,
+				sizeof(struct rgb_config_data), GFP_KERNEL);
+	if (!led->rgb_cfg) {
+		dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	if (led->id == QPNP_ID_RGB_RED)
+		led->rgb_cfg->enable = RGB_LED_ENABLE_RED;
+	else if (led->id == QPNP_ID_RGB_GREEN)
+		led->rgb_cfg->enable = RGB_LED_ENABLE_GREEN;
+	else if (led->id == QPNP_ID_RGB_BLUE)
+		led->rgb_cfg->enable = RGB_LED_ENABLE_BLUE;
+	else
+		return -EINVAL;
+
+	rc = of_property_read_u32(node, "qcom,mode", &val);
+	if (!rc)
+		led->rgb_cfg->mode = (u8) val;
+	else
+		return rc;
+
+	rc = of_property_read_u32(node, "qcom,pwm-channel", &val);
+	if (!rc)
+		led->rgb_cfg->pwm_channel = (u8) val;
+	else
+		return rc;
+
+	rc = of_property_read_u32(node, "qcom,pwm-us", &val);
+	if (!rc)
+		led->rgb_cfg->pwm_period_us = val;
+	else
+		return rc;
+
+	if (led->rgb_cfg->mode == RGB_MODE_LPG) {
+		led->rgb_cfg->duty_cycles =
+			devm_kzalloc(&led->spmi_dev->dev,
+			sizeof(struct pwm_duty_cycles), GFP_KERNEL);
+		if (!led->rgb_cfg->duty_cycles) {
+			dev_err(&led->spmi_dev->dev,
+				"Unable to allocate memory\n");
+			return -ENOMEM;
+		}
+
+		rc = of_property_read_u32(node, "qcom,duty-ms", &val);
+		if (!rc)
+			led->rgb_cfg->duty_cycles->duty_ms = (u8) val;
+		else
+			return rc;
+
+		prop = of_find_property(node, "qcom,duty-pcts",
+			&led->rgb_cfg->duty_cycles->num_duty_pcts);
+		if (!prop) {
+			dev_err(&led->spmi_dev->dev, "Looking up property " \
+				"node qcom,duty-pcts failed\n");
+			return -ENODEV;
+		} else if (!led->rgb_cfg->duty_cycles->num_duty_pcts) {
+			dev_err(&led->spmi_dev->dev, "Invalid length of " \
+				"duty pcts\n");
+			return -EINVAL;
+		}
+
+		led->rgb_cfg->duty_cycles->duty_pcts =
+			devm_kzalloc(&led->spmi_dev->dev,
+			sizeof(int) * led->rgb_cfg->duty_cycles->num_duty_pcts,
+			GFP_KERNEL);
+		if (!led->rgb_cfg->duty_cycles->duty_pcts) {
+			dev_err(&led->spmi_dev->dev,
+				"Unable to allocate memory\n");
+			return -ENOMEM;
+		}
+
+		temp_cfg = devm_kzalloc(&led->spmi_dev->dev,
+				led->rgb_cfg->duty_cycles->num_duty_pcts *
+				sizeof(u8), GFP_KERNEL);
+		if (!temp_cfg) {
+			dev_err(&led->spmi_dev->dev, "Failed to allocate " \
+				"memory for duty pcts\n");
+			return -ENOMEM;
+		}
+
+		memcpy(temp_cfg, prop->value,
+			led->rgb_cfg->duty_cycles->num_duty_pcts);
+
+		for (i = 0; i < led->rgb_cfg->duty_cycles->num_duty_pcts; i++)
+			led->rgb_cfg->duty_cycles->duty_pcts[i] =
+				(int) temp_cfg[i];
+
+		rc = of_property_read_u32(node, "qcom,start-idx", &val);
+		if (!rc) {
+			led->rgb_cfg->lut_params.start_idx = (u8) val;
+			led->rgb_cfg->duty_cycles->start_idx = (u8) val;
+		} else
+			return rc;
+
+		led->rgb_cfg->lut_params.idx_len =
+			led->rgb_cfg->duty_cycles->num_duty_pcts;
+		led->rgb_cfg->lut_params.lut_pause_hi = 0;
+		led->rgb_cfg->lut_params.lut_pause_lo = 0;
+		led->rgb_cfg->lut_params.ramp_step_ms = 255;
+		led->rgb_cfg->lut_params.flags = QPNP_LED_PWM_FLAGS;
+	}
+
+	return 0;
+}
+
 static int __devinit qpnp_leds_probe(struct spmi_device *spmi)
 {
 	struct qpnp_led_data *led;
@@ -673,6 +1345,21 @@
 					"Unable to read wled config data\n");
 				return rc;
 			}
+		} else if (strncmp(led_label, "flash", sizeof("flash"))
+				== 0) {
+			rc = qpnp_get_config_flash(led, temp);
+			if (rc < 0) {
+				dev_err(&led->spmi_dev->dev,
+					"Unable to read flash config data\n");
+				return rc;
+			}
+		} else if (strncmp(led_label, "rgb", sizeof("rgb")) == 0) {
+			rc = qpnp_get_config_rgb(led, temp);
+			if (rc < 0) {
+				dev_err(&led->spmi_dev->dev,
+					"Unable to read rgb config data\n");
+				return rc;
+			}
 		} else {
 			dev_err(&led->spmi_dev->dev, "No LED matching label\n");
 			return -EINVAL;
@@ -751,3 +1438,4 @@
 MODULE_DESCRIPTION("QPNP LEDs driver");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("leds:leds-qpnp");
+
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index cbd3b38..625eb78 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -617,7 +617,8 @@
 			dmxdev->dvr_input_buffer.data = NULL;
 			spin_unlock_irq(&dmxdev->dvr_in_lock);
 
-			if (dmxdev->dvr_buffer_mode == DMX_BUFFER_MODE_INTERNAL)
+			if (dmxdev->dvr_input_buffer_mode ==
+				DMX_BUFFER_MODE_INTERNAL)
 				vfree(mem);
 		}
 
@@ -963,6 +964,12 @@
 static int dvb_dvr_set_buffer_mode(struct dmxdev *dmxdev,
 			unsigned int f_flags, enum dmx_buffer_mode mode)
 {
+	struct dvb_ringbuffer *buf;
+	spinlock_t *lock;
+	enum dmx_buffer_mode *buffer_mode;
+	void **buff_handle;
+	void *oldmem;
+
 	if ((mode != DMX_BUFFER_MODE_INTERNAL) &&
 		(mode != DMX_BUFFER_MODE_EXTERNAL))
 		return -EINVAL;
@@ -975,10 +982,42 @@
 		(!dmxdev->demux->map_buffer || !dmxdev->demux->unmap_buffer))
 		return -EINVAL;
 
-	if ((f_flags & O_ACCMODE) == O_RDONLY)
-		dmxdev->dvr_buffer_mode = mode;
-	else
-		dmxdev->dvr_input_buffer_mode = mode;
+	if ((f_flags & O_ACCMODE) == O_RDONLY) {
+		buf = &dmxdev->dvr_buffer;
+		lock = &dmxdev->lock;
+		buffer_mode = &dmxdev->dvr_buffer_mode;
+		buff_handle = &dmxdev->dvr_priv_buff_handle;
+	} else {
+		buf = &dmxdev->dvr_input_buffer;
+		lock = &dmxdev->dvr_in_lock;
+		buffer_mode = &dmxdev->dvr_input_buffer_mode;
+		buff_handle = &dmxdev->demux->dvr_input.priv_handle;
+	}
+
+	if (mode == *buffer_mode)
+		return 0;
+
+	oldmem = buf->data;
+	spin_lock_irq(lock);
+	buf->data = NULL;
+	spin_unlock_irq(lock);
+
+	*buffer_mode = mode;
+
+	if (mode == DMX_BUFFER_MODE_INTERNAL) {
+		/* switched from external to internal */
+		if (*buff_handle) {
+			dmxdev->demux->unmap_buffer(dmxdev->demux,
+				*buff_handle);
+			*buff_handle = NULL;
+		}
+
+		/* set default internal buffer */
+		dvb_dvr_set_buffer_size(dmxdev, f_flags, DVR_BUFFER_SIZE);
+	} else if (oldmem) {
+		/* switched from internal to external */
+		vfree(oldmem);
+	}
 
 	return 0;
 }
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
index 191a0c4..360d96a 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
@@ -18,15 +18,15 @@
 #include "mpq_dmx_plugin_common.h"
 
 
-#define TSIF_COUNT					2
+#define TSIF_COUNT			2
 
 #define TSPP_MAX_PID_FILTER_NUM		16
 
 /* Max number of section filters */
-#define TSPP_MAX_SECTION_FILTER_NUM		64
+#define TSPP_MAX_SECTION_FILTER_NUM	64
 
 /* For each TSIF we allocate two pipes, one for PES and one for sections */
-#define TSPP_PES_CHANNEL				0
+#define TSPP_PES_CHANNEL			0
 #define TSPP_SECTION_CHANNEL			1
 
 /* the channel_id set to TSPP driver based on TSIF number and channel type */
@@ -35,7 +35,7 @@
 #define TSPP_GET_TSIF_NUM(ch_id)		(ch_id >> 1)
 
 /* mask that set to care for all bits in pid filter */
-#define TSPP_PID_MASK					0x1FFF
+#define TSPP_PID_MASK				0x1FFF
 
 /* dvb-demux defines pid 0x2000 as full capture pid */
 #define TSPP_PASS_THROUGH_PID			0x2000
@@ -47,15 +47,25 @@
 
 #define TSPP_RAW_TTS_SIZE				192
 
-/* Size of single descriptor. Using max descriptor size (170 packets).
+#define MAX_BAM_DESCRIPTOR_SIZE		(32*1024 - 1)
+
+/* Size of single descriptor for PES/rec pipe.
+ * Using max descriptor size (170 packets).
  * Assuming 20MBit/sec stream, with 170 packets
  * per descriptor there would be about 82 descriptors,
  * Meanning about 82 notifications per second.
  */
-#define MAX_BAM_DESCRIPTOR_SIZE		(32*1024 - 1)
-#define TSPP_BUFFER_SIZE			\
+#define TSPP_PES_BUFFER_SIZE			\
 	((MAX_BAM_DESCRIPTOR_SIZE / TSPP_RAW_TTS_SIZE) * TSPP_RAW_TTS_SIZE)
 
+/* Size of single descriptor for section pipe.
+ * Assuming 8MBit/sec section rate, with 65 packets
+ * per descriptor there would be about 85 descriptors,
+ * Meanning about 85 notifications per second.
+ */
+#define TSPP_SECTION_BUFFER_SIZE			\
+	(65 * TSPP_RAW_TTS_SIZE)
+
 /* Number of descriptors, total size: TSPP_BUFFER_SIZE*TSPP_BUFFER_COUNT */
 #define TSPP_BUFFER_COUNT				(32)
 
@@ -65,11 +75,18 @@
 /* Channel timeout in msec */
 #define TSPP_CHANNEL_TIMEOUT			16
 
+enum mem_buffer_allocation_mode {
+	MPQ_DMX_TSPP_INTERNAL_ALLOC = 0,
+	MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC = 1
+};
+
 /* module parameters for load time configuration */
 static int clock_inv;
 static int tsif_mode = 2;
+static int allocation_mode = MPQ_DMX_TSPP_INTERNAL_ALLOC;
 module_param(tsif_mode, int, S_IRUGO);
 module_param(clock_inv, int, S_IRUGO);
+module_param(allocation_mode, int, S_IRUGO);
 
 /*
  * Work scheduled each time TSPP notifies dmx
@@ -97,6 +114,15 @@
 		/* work used to submit to workqueue to process pes channel */
 		struct tspp_work pes_work;
 
+		/* ION handle used for TSPP data buffer allocation */
+		struct ion_handle *pes_mem_heap_handle;
+		/* TSPP data buffer heap virtual base address */
+		void *pes_mem_heap_virt_base;
+		/* TSPP data buffer heap physical base address */
+		ion_phys_addr_t pes_mem_heap_phys_base;
+		/* buffer allocation index */
+		int pes_index;
+
 		/*
 		 * TSPP pipe holding all TS packets with section data.
 		 * The following is reference count for number of feeds
@@ -107,6 +133,15 @@
 		/* work used to submit to workqueue to process pes channel */
 		struct tspp_work section_work;
 
+		/* ION handle used for TSPP data buffer allocation */
+		struct ion_handle *section_mem_heap_handle;
+		/* TSPP data buffer heap virtual base address */
+		void *section_mem_heap_virt_base;
+		/* TSPP data buffer heap physical base address */
+		ion_phys_addr_t section_mem_heap_phys_base;
+		/* buffer allocation index */
+		int section_index;
+
 		/*
 		 * Holds PIDs of allocated TSPP filters along with
 		 * how many feeds are opened on same PID.
@@ -128,8 +163,65 @@
 		/* mutex protecting the data-structure */
 		struct mutex mutex;
 	} tsif[TSIF_COUNT];
+
+	/* ION client used for TSPP data buffer allocation */
+	struct ion_client *ion_client;
 } mpq_dmx_tspp_info;
 
+static void *tspp_mem_allocator(int channel_id, u32 size,
+				u32 *phys_base, void *user)
+{
+	void *virt_addr = NULL;
+	int i = TSPP_GET_TSIF_NUM(channel_id);
+
+	if (TSPP_IS_PES_CHANNEL(channel_id)) {
+		if (mpq_dmx_tspp_info.tsif[i].pes_index == TSPP_BUFFER_COUNT)
+			return NULL;
+		virt_addr =
+			(mpq_dmx_tspp_info.tsif[i].pes_mem_heap_virt_base +
+			(mpq_dmx_tspp_info.tsif[i].pes_index * size));
+		*phys_base =
+			(mpq_dmx_tspp_info.tsif[i].pes_mem_heap_phys_base +
+			(mpq_dmx_tspp_info.tsif[i].pes_index * size));
+		mpq_dmx_tspp_info.tsif[i].pes_index++;
+	} else {
+		if (mpq_dmx_tspp_info.tsif[i].section_index ==
+						TSPP_BUFFER_COUNT)
+			return NULL;
+		virt_addr =
+			(mpq_dmx_tspp_info.tsif[i].section_mem_heap_virt_base +
+			(mpq_dmx_tspp_info.tsif[i].section_index * size));
+		*phys_base =
+			(mpq_dmx_tspp_info.tsif[i].section_mem_heap_phys_base +
+			(mpq_dmx_tspp_info.tsif[i].section_index * size));
+		mpq_dmx_tspp_info.tsif[i].section_index++;
+	}
+
+	return virt_addr;
+}
+
+static void tspp_mem_free(int channel_id, u32 size,
+			void *virt_base, u32 phys_base, void *user)
+{
+	int i = TSPP_GET_TSIF_NUM(channel_id);
+
+	/*
+	 * actual buffer heap free is done in mpq_dmx_tspp_plugin_exit().
+	 * we update index here, so if this function is called repetitively
+	 * for all the buffers, then afterwards tspp_mem_allocator()
+	 * can be called again.
+	 * Note: it would be incorrect to call tspp_mem_allocator()
+	 * a few times, then call tspp_mem_free(), then call
+	 * tspp_mem_allocator() again.
+	 */
+	if (TSPP_IS_PES_CHANNEL(channel_id)) {
+		if (mpq_dmx_tspp_info.tsif[i].pes_index > 0)
+			mpq_dmx_tspp_info.tsif[i].pes_index--;
+	} else {
+		if (mpq_dmx_tspp_info.tsif[i].section_index > 0)
+			mpq_dmx_tspp_info.tsif[i].section_index--;
+	}
+}
 
 /**
  * Returns a free filter slot that can be used.
@@ -278,6 +370,7 @@
 	int ret;
 	int channel_id;
 	int *channel_ref_count;
+	u32 buffer_size;
 
 	tspp_source.clk_inverse = clock_inv;
 	tspp_source.data_inverse = 0;
@@ -334,10 +427,12 @@
 		channel_id = TSPP_CHANNEL_ID(tsif, TSPP_PES_CHANNEL);
 		channel_ref_count =
 			&mpq_dmx_tspp_info.tsif[tsif].pes_channel_ref;
+		buffer_size = TSPP_PES_BUFFER_SIZE;
 	} else {
 		channel_id = TSPP_CHANNEL_ID(tsif, TSPP_SECTION_CHANNEL);
 		channel_ref_count =
 			&mpq_dmx_tspp_info.tsif[tsif].section_channel_ref;
+		buffer_size = TSPP_SECTION_BUFFER_SIZE;
 	}
 
 	/* check if required TSPP pipe is already allocated or not */
@@ -374,20 +469,34 @@
 					   (void *)tsif,
 					   TSPP_CHANNEL_TIMEOUT);
 
-		/* TODO: register allocater and provide allocation function
-		 * that allocate from continous memory so that we can have
+		/* register allocater and provide allocation function
+		 * that allocates from continous memory so that we can have
 		 * big notification size, smallest descriptor, and still provide
 		 * TZ with single big buffer based on notification size.
 		 */
 
-		/* set buffer/descriptor size and count */
-		ret = tspp_allocate_buffers(0,
-					    channel_id,
-					    TSPP_BUFFER_COUNT,
-					    TSPP_BUFFER_SIZE,
-					    TSPP_NOTIFICATION_SIZE,
-					    NULL,
-					    NULL);
+		/* set buffer/descriptor size and count,
+		 * allocate TSPP data buffers
+		 */
+		if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) {
+			ret = tspp_allocate_buffers(0,
+						    channel_id,
+						    TSPP_BUFFER_COUNT,
+						    buffer_size,
+						    TSPP_NOTIFICATION_SIZE,
+						    tspp_mem_allocator,
+						    tspp_mem_free,
+						    NULL);
+		} else {
+			ret = tspp_allocate_buffers(0,
+						    channel_id,
+						    TSPP_BUFFER_COUNT,
+						    buffer_size,
+						    TSPP_NOTIFICATION_SIZE,
+						    NULL,
+						    NULL,
+						    NULL);
+		}
 		if (ret < 0) {
 			MPQ_DVB_ERR_PRINT(
 				"%s: tspp_allocate_buffers(%d) failed (%d)\n",
@@ -745,20 +854,154 @@
 	return 0;
 }
 
+static void mpq_dmx_tsif_ion_cleanup(int i)
+{
+	mpq_dmx_tspp_info.tsif[i].pes_mem_heap_phys_base = 0;
+	mpq_dmx_tspp_info.tsif[i].section_mem_heap_phys_base = 0;
+
+	if (!IS_ERR_OR_NULL(mpq_dmx_tspp_info.tsif[i].pes_mem_heap_handle)) {
+		if (!IS_ERR_OR_NULL(mpq_dmx_tspp_info.tsif[i].
+				pes_mem_heap_virt_base))
+			ion_unmap_kernel(mpq_dmx_tspp_info.ion_client,
+				mpq_dmx_tspp_info.tsif[i].pes_mem_heap_handle);
+
+		ion_free(mpq_dmx_tspp_info.ion_client,
+			mpq_dmx_tspp_info.tsif[i].pes_mem_heap_handle);
+	}
+
+	if (!IS_ERR_OR_NULL(mpq_dmx_tspp_info.tsif[i].
+			section_mem_heap_handle)) {
+		if (!IS_ERR_OR_NULL(mpq_dmx_tspp_info.tsif[i].
+					section_mem_heap_virt_base))
+			ion_unmap_kernel(mpq_dmx_tspp_info.ion_client,
+					mpq_dmx_tspp_info.tsif[i].
+						section_mem_heap_handle);
+
+		ion_free(mpq_dmx_tspp_info.ion_client,
+			mpq_dmx_tspp_info.tsif[i].section_mem_heap_handle);
+	}
+
+	mpq_dmx_tspp_info.tsif[i].pes_mem_heap_virt_base = NULL;
+	mpq_dmx_tspp_info.tsif[i].section_mem_heap_virt_base = NULL;
+	mpq_dmx_tspp_info.tsif[i].pes_mem_heap_handle = NULL;
+	mpq_dmx_tspp_info.tsif[i].section_mem_heap_handle = NULL;
+}
+
+static void mpq_dmx_tspp_ion_cleanup(void)
+{
+	int i;
+
+	for (i = 0; i < TSIF_COUNT; i++)
+		mpq_dmx_tsif_ion_cleanup(i);
+}
+
 static int mpq_tspp_dmx_init(
 			struct dvb_adapter *mpq_adapter,
 			struct mpq_demux *mpq_demux)
 {
-	int result;
+	int i, result;
+	size_t len;
 
 	MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
 
+	if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) {
+		/*
+		 * Save ION client, used to allocate memory
+		 * for TSPP's buffers.
+		 */
+		mpq_dmx_tspp_info.ion_client = mpq_demux->ion_client;
+
+		if (IS_ERR_OR_NULL(mpq_dmx_tspp_info.ion_client))
+			return -EINVAL;
+
+		for (i = 0; i < TSIF_COUNT; i++) {
+			mpq_dmx_tspp_info.tsif[i].pes_mem_heap_handle =
+				ion_alloc(mpq_dmx_tspp_info.ion_client,
+					(TSPP_BUFFER_COUNT *
+					 TSPP_PES_BUFFER_SIZE),
+					TSPP_RAW_TTS_SIZE,
+					ION_HEAP(ION_CP_MM_HEAP_ID),
+					0); /* non-cached */
+			if (IS_ERR_OR_NULL(mpq_dmx_tspp_info.tsif[i].
+						pes_mem_heap_handle)) {
+				MPQ_DVB_ERR_PRINT("%s: ion_alloc() failed\n",
+						__func__);
+				mpq_dmx_tspp_ion_cleanup();
+				return -ENOMEM;
+			}
+			/* save virtual base address of heap */
+			mpq_dmx_tspp_info.tsif[i].pes_mem_heap_virt_base =
+				ion_map_kernel(mpq_dmx_tspp_info.ion_client,
+					mpq_dmx_tspp_info.tsif[i].
+						pes_mem_heap_handle);
+			if (IS_ERR_OR_NULL(mpq_dmx_tspp_info.tsif[i].
+						pes_mem_heap_virt_base)) {
+				MPQ_DVB_ERR_PRINT(
+					"%s: ion_map_kernel() failed\n",
+					__func__);
+				mpq_dmx_tspp_ion_cleanup();
+				return -ENOMEM;
+			}
+			/* save physical base address of heap */
+			result = ion_phys(mpq_dmx_tspp_info.ion_client,
+				mpq_dmx_tspp_info.tsif[i].pes_mem_heap_handle,
+				&(mpq_dmx_tspp_info.tsif[i].
+					pes_mem_heap_phys_base), &len);
+			if (result < 0) {
+				MPQ_DVB_ERR_PRINT("%s: ion_phys() failed\n",
+						__func__);
+				mpq_dmx_tspp_ion_cleanup();
+				return -ENOMEM;
+			}
+
+			mpq_dmx_tspp_info.tsif[i].section_mem_heap_handle =
+				ion_alloc(mpq_dmx_tspp_info.ion_client,
+					(TSPP_BUFFER_COUNT *
+					 TSPP_SECTION_BUFFER_SIZE),
+					TSPP_RAW_TTS_SIZE,
+					ION_HEAP(ION_CP_MM_HEAP_ID),
+					0); /* non-cached */
+			if (IS_ERR_OR_NULL(mpq_dmx_tspp_info.tsif[i].
+						section_mem_heap_handle)) {
+				MPQ_DVB_ERR_PRINT("%s: ion_alloc() failed\n",
+						__func__);
+				mpq_dmx_tspp_ion_cleanup();
+				return -ENOMEM;
+			}
+			/* save virtual base address of heap */
+			mpq_dmx_tspp_info.tsif[i].section_mem_heap_virt_base =
+				ion_map_kernel(mpq_dmx_tspp_info.ion_client,
+				mpq_dmx_tspp_info.tsif[i].
+					section_mem_heap_handle);
+			if (IS_ERR_OR_NULL(mpq_dmx_tspp_info.tsif[i].
+					section_mem_heap_virt_base)) {
+				MPQ_DVB_ERR_PRINT(
+					"%s: ion_map_kernel() failed\n",
+					__func__);
+				mpq_dmx_tspp_ion_cleanup();
+				return -ENOMEM;
+			}
+			/* save physical base address of heap */
+			result = ion_phys(mpq_dmx_tspp_info.ion_client,
+				mpq_dmx_tspp_info.tsif[i].
+					section_mem_heap_handle,
+				&(mpq_dmx_tspp_info.tsif[i].
+					section_mem_heap_phys_base), &len);
+			if (result < 0) {
+				MPQ_DVB_ERR_PRINT("%s: ion_phys() failed\n",
+						__func__);
+				mpq_dmx_tspp_ion_cleanup();
+				return -ENOMEM;
+			}
+		}
+	}
+
 	/* Set the kernel-demux object capabilities */
 	mpq_demux->demux.dmx.capabilities =
 		DMX_TS_FILTERING			|
 		DMX_PES_FILTERING			|
-		DMX_SECTION_FILTERING		|
-		DMX_MEMORY_BASED_FILTERING	|
+		DMX_SECTION_FILTERING			|
+		DMX_MEMORY_BASED_FILTERING		|
 		DMX_CRC_CHECKING			|
 		DMX_TS_DESCRAMBLING;
 
@@ -818,6 +1061,7 @@
 init_failed_dmx_release:
 	dvb_dmx_release(&mpq_demux->demux);
 init_failed:
+	mpq_dmx_tspp_ion_cleanup();
 	return result;
 }
 
@@ -831,6 +1075,10 @@
 
 	for (i = 0; i < TSIF_COUNT; i++) {
 		mpq_dmx_tspp_info.tsif[i].pes_channel_ref = 0;
+		mpq_dmx_tspp_info.tsif[i].pes_index = 0;
+		mpq_dmx_tspp_info.tsif[i].pes_mem_heap_handle = NULL;
+		mpq_dmx_tspp_info.tsif[i].pes_mem_heap_virt_base = NULL;
+		mpq_dmx_tspp_info.tsif[i].pes_mem_heap_phys_base = 0;
 
 		mpq_dmx_tspp_info.tsif[i].pes_work.channel_id =
 			TSPP_CHANNEL_ID(i, TSPP_PES_CHANNEL);
@@ -839,6 +1087,10 @@
 				  mpq_dmx_tspp_work);
 
 		mpq_dmx_tspp_info.tsif[i].section_channel_ref = 0;
+		mpq_dmx_tspp_info.tsif[i].section_index = 0;
+		mpq_dmx_tspp_info.tsif[i].section_mem_heap_handle = NULL;
+		mpq_dmx_tspp_info.tsif[i].section_mem_heap_virt_base = NULL;
+		mpq_dmx_tspp_info.tsif[i].section_mem_heap_phys_base = 0;
 
 		mpq_dmx_tspp_info.tsif[i].section_work.channel_id =
 			TSPP_CHANNEL_ID(i, TSPP_SECTION_CHANNEL);
@@ -861,14 +1113,12 @@
 				mpq_dmx_tspp_info.tsif[i].name);
 
 		if (mpq_dmx_tspp_info.tsif[i].workqueue == NULL) {
-
 			for (j = 0; j < i; j++) {
 				destroy_workqueue(
 					mpq_dmx_tspp_info.tsif[j].workqueue);
 
 				mutex_destroy(&mpq_dmx_tspp_info.tsif[j].mutex);
 			}
-
 			MPQ_DVB_ERR_PRINT(
 				"%s: create_singlethread_workqueue failed\n",
 				__func__);
@@ -905,6 +1155,11 @@
 	for (i = 0; i < TSIF_COUNT; i++) {
 		mutex_lock(&mpq_dmx_tspp_info.tsif[i].mutex);
 
+		/*
+		 * Note: tspp_close_channel will also free the TSPP buffers
+		 * even if we allocated them ourselves,
+		 * using our free function.
+		 */
 		if (mpq_dmx_tspp_info.tsif[i].pes_channel_ref) {
 			tspp_unregister_notification(0, TSPP_PES_CHANNEL);
 			tspp_close_channel(0,
@@ -917,9 +1172,11 @@
 				TSPP_CHANNEL_ID(i, TSPP_SECTION_CHANNEL));
 		}
 
-		/* TODO: if we allocate buffer
-		 * to TSPP ourself, need to free those as well
+		/* if we allocated buffer pools
+		 * to TSPP, need to free those as well
 		 */
+		if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC)
+			mpq_dmx_tsif_ion_cleanup(i);
 
 		mutex_unlock(&mpq_dmx_tspp_info.tsif[i].mutex);
 		flush_workqueue(mpq_dmx_tspp_info.tsif[i].workqueue);
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index ac143b1..fde7cb7 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -39,6 +39,17 @@
 #include <asm/unaligned.h>
 
 static unsigned int rds_buf = 100;
+static int oda_agt;
+static int grp_mask;
+static int rt_plus_carrier = -1;
+static int ert_carrier = -1;
+static unsigned char ert_buf[256];
+static unsigned char ert_len;
+static unsigned char c_byt_pair_index;
+static char utf_8_flag;
+static char rt_ert_flag;
+static char formatting_dir;
+
 module_param(rds_buf, uint, 0);
 MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
 
@@ -108,7 +119,11 @@
 
 static struct video_device *priv_videodev;
 static int iris_do_calibration(struct iris_device *radio);
-
+static void hci_buff_ert(struct iris_device *radio,
+		struct rds_grp_data *rds_buf);
+static void hci_ev_rt_plus(struct iris_device *radio,
+		struct rds_grp_data rds_buf);
+static void hci_ev_ert(struct iris_device *radio);
 static int update_spur_table(struct iris_device *radio);
 static struct v4l2_queryctrl iris_v4l2_queryctrl[] = {
 	{
@@ -921,6 +936,20 @@
 	return radio_hci_send_cmd(hdev, opcode, 0, NULL);
 }
 
+static int hci_fm_rds_grp_mask_req(struct radio_hci_dev *hdev,
+		unsigned long param)
+{
+	 __u16 opcode = 0;
+
+	struct hci_fm_rds_grp_req *fm_grp_mask =
+		(struct hci_fm_rds_grp_req *)param;
+
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+		HCI_OCF_FM_RDS_GRP);
+	return radio_hci_send_cmd(hdev, opcode, sizeof(*fm_grp_mask),
+		fm_grp_mask);
+}
+
 static int hci_fm_rds_grp_process_req(struct radio_hci_dev *hdev,
 		unsigned long param)
 {
@@ -1313,7 +1342,13 @@
 static int hci_fm_rds_grp(struct hci_fm_rds_grp_req *arg,
 	struct radio_hci_dev *hdev)
 {
-	return 0;
+	int ret = 0;
+	struct hci_fm_rds_grp_req *fm_grp_mask = arg;
+
+	ret = radio_hci_request(hdev, hci_fm_rds_grp_mask_req, (unsigned
+		long)fm_grp_mask, RADIO_HCI_TIMEOUT);
+
+	return ret;
 }
 
 static int hci_fm_rds_grps_process(__u32 *arg, struct radio_hci_dev *hdev)
@@ -2078,6 +2113,234 @@
 		iris_q_event(radio, IRIS_EVT_MONO);
 }
 
+static void hci_ev_raw_rds_group_data(struct radio_hci_dev *hdev,
+		struct sk_buff *skb)
+{
+	struct iris_device *radio;
+	unsigned char blocknum, index;
+	struct rds_grp_data temp;
+	unsigned int mask_bit;
+	unsigned short int aid, agt, gtc;
+	unsigned short int carrier;
+
+	radio = video_get_drvdata(video_get_dev());
+	index = RDSGRP_DATA_OFFSET;
+
+	for (blocknum = 0; blocknum < RDS_BLOCKS_NUM; blocknum++) {
+		temp.rdsBlk[blocknum].rdsLsb =
+			(skb->data[index]);
+		temp.rdsBlk[blocknum].rdsMsb =
+			(skb->data[index+1]);
+		index = index + 2;
+	}
+
+	aid = AID(temp.rdsBlk[3].rdsLsb, temp.rdsBlk[3].rdsMsb);
+	gtc = GTC(temp.rdsBlk[1].rdsMsb);
+	agt = AGT(temp.rdsBlk[1].rdsLsb);
+
+	if (gtc == GRP_3A) {
+		switch (aid) {
+		case ERT_AID:
+			/* calculate the grp mask for RDS grp
+			 * which will contain actual eRT text
+			 *
+			 * Bit Pos  0  1  2  3  4   5  6   7
+			 * Grp Type 0A 0B 1A 1B 2A  2B 3A  3B
+			 *
+			 * similary for rest grps
+			 */
+			mask_bit = (((agt >> 1) << 1) + (agt & 1));
+			oda_agt = (1 << mask_bit);
+			utf_8_flag = (temp.rdsBlk[2].rdsLsb & 1);
+			formatting_dir = EXTRACT_BIT(temp.rdsBlk[2].rdsLsb,
+							ERT_FORMAT_DIR_BIT);
+			if (ert_carrier != agt)
+				iris_q_event(radio, IRIS_EVT_NEW_ODA);
+			ert_carrier = agt;
+			break;
+		case RT_PLUS_AID:
+			/* calculate the grp mask for RDS grp
+			 * which will contain actual eRT text
+			 *
+			 * Bit Pos  0  1  2  3  4   5  6   7
+			 * Grp Type 0A 0B 1A 1B 2A  2B 3A  3B
+			 *
+			 * similary for rest grps
+			 */
+			mask_bit = (((agt >> 1) << 1) + (agt & 1));
+			oda_agt =  (1 << mask_bit);
+			/*Extract 5th bit of MSB (b7b6b5b4b3b2b1b0)*/
+			rt_ert_flag = EXTRACT_BIT(temp.rdsBlk[2].rdsMsb,
+					 RT_ERT_FLAG_BIT);
+			if (rt_plus_carrier != agt)
+				iris_q_event(radio, IRIS_EVT_NEW_ODA);
+			rt_plus_carrier = agt;
+			break;
+		default:
+			oda_agt = 0;
+			break;
+		}
+	} else {
+		carrier = gtc;
+		if ((carrier == rt_plus_carrier))
+			hci_ev_rt_plus(radio, temp);
+		else if (carrier == ert_carrier)
+			hci_buff_ert(radio, &temp);
+	}
+}
+
+static void hci_buff_ert(struct iris_device *radio,
+	struct rds_grp_data *rds_buf)
+{
+	int i;
+	unsigned short int info_byte = 0;
+	unsigned short int byte_pair_index;
+
+	byte_pair_index = AGT(rds_buf->rdsBlk[1].rdsLsb);
+	if (byte_pair_index == 0) {
+		c_byt_pair_index = 0;
+		ert_len = 0;
+	}
+	if (c_byt_pair_index == byte_pair_index) {
+		c_byt_pair_index++;
+		for (i = 2; i <= 3; i++) {
+			info_byte = rds_buf->rdsBlk[i].rdsLsb;
+			info_byte |= (rds_buf->rdsBlk[i].rdsMsb << 8);
+			ert_buf[ert_len++] = rds_buf->rdsBlk[i].rdsMsb;
+			ert_buf[ert_len++] = rds_buf->rdsBlk[i].rdsLsb;
+			if ((utf_8_flag == 0)
+				 && (info_byte == CARRIAGE_RETURN)) {
+				ert_len -= 2;
+				break;
+			} else if ((utf_8_flag == 1)
+					&&
+					(rds_buf->rdsBlk[i].rdsMsb
+						 == CARRIAGE_RETURN)) {
+				info_byte = CARRIAGE_RETURN;
+				ert_len -= 2;
+				break;
+			} else if ((utf_8_flag == 1)
+					&&
+					(rds_buf->rdsBlk[i].rdsLsb
+						 == CARRIAGE_RETURN)) {
+				info_byte = CARRIAGE_RETURN;
+				ert_len--;
+				break;
+			}
+		}
+		if ((byte_pair_index == MAX_ERT_SEGMENT) ||
+			(info_byte == CARRIAGE_RETURN)) {
+			hci_ev_ert(radio);
+			c_byt_pair_index = 0;
+			ert_len = 0;
+		}
+	} else {
+		ert_len = 0;
+		c_byt_pair_index = 0;
+	}
+}
+static void hci_ev_ert(struct iris_device *radio)
+
+{
+	char *data = NULL;
+
+	if (ert_len <= 0)
+		return;
+	data = kmalloc((ert_len + 3), GFP_ATOMIC);
+	if (data != NULL) {
+		data[0] = ert_len;
+		data[1] = utf_8_flag;
+		data[2] = formatting_dir;
+		memcpy((data + 3), ert_buf, ert_len);
+		iris_q_evt_data(radio, data, (ert_len + 3), IRIS_BUF_ERT);
+		iris_q_event(radio, IRIS_EVT_NEW_ERT);
+		kfree(data);
+	}
+}
+
+static void hci_ev_rt_plus(struct iris_device *radio,
+		 struct rds_grp_data rds_buf)
+{
+	char tag_type1, tag_type2;
+	char *data = NULL;
+	int len = 0;
+	unsigned short int agt;
+
+	agt = AGT(rds_buf.rdsBlk[1].rdsLsb);
+	/*right most 3 bits of Lsb of block 2
+	 * and left most 3 bits of Msb of block 3
+	 */
+	tag_type1 = (((agt & TAG1_MSB_MASK) << TAG1_MSB_OFFSET) |
+			 (rds_buf.rdsBlk[2].rdsMsb >> TAG1_LSB_OFFSET));
+
+	/*right most 1 bit of lsb of 3rd block
+	 * and left most 5 bits of Msb of 4th block
+	*/
+	tag_type2 = (((rds_buf.rdsBlk[2].rdsLsb & TAG2_MSB_MASK)
+			 << TAG2_MSB_OFFSET) |
+			 (rds_buf.rdsBlk[3].rdsMsb >> TAG2_LSB_OFFSET));
+
+	if (tag_type1 != DUMMY_CLASS)
+		len += RT_PLUS_LEN_1_TAG;
+	if (tag_type2 != DUMMY_CLASS)
+		len += RT_PLUS_LEN_1_TAG;
+
+	if (len != 0) {
+		len += 2;
+		data = kmalloc(len, GFP_ATOMIC);
+	} else {
+		FMDERR("Len is zero\n");
+		return ;
+	}
+	if (data != NULL) {
+		data[0] = len;
+		len = 1;
+		data[len++] = rt_ert_flag;
+		if (tag_type1 != DUMMY_CLASS) {
+			data[len++] = tag_type1;
+			/*start position of tag1
+			 *right most 5 bits of msb of 3rd block
+			 *and left most bit of lsb of 3rd block
+			 */
+			data[len++] = (((rds_buf.rdsBlk[2].rdsMsb &
+						 TAG1_POS_MSB_MASK)
+						<< TAG1_POS_MSB_OFFSET)
+						|
+					(rds_buf.rdsBlk[2].rdsLsb >>
+						TAG1_POS_LSB_OFFSET));
+			/*length of tag1
+			 *left most 6 bits of lsb of 3rd block
+			 */
+			data[len++] = ((rds_buf.rdsBlk[2].rdsLsb
+						>> TAG1_LEN_OFFSET)
+							 &
+						TAG1_LEN_MASK) + 1;
+		}
+		if (tag_type2 != DUMMY_CLASS) {
+			data[len++] = tag_type2;
+			/*start position of tag2
+			 *right most 3 bit of msb of 4th block
+			 *and left most 3 bits of lsb of 4th block
+			 */
+			data[len++] = (((rds_buf.rdsBlk[3].rdsMsb
+						& TAG2_POS_MSB_MASK)
+						<< TAG2_POS_MSB_OFFSET)
+						|
+					(rds_buf.rdsBlk[3].rdsLsb
+						>> TAG2_POS_LSB_OFFSET));
+			/*length of tag2
+			 *right most 5 bits of lsb of 4th block
+			 */
+			data[len++] = (rds_buf.rdsBlk[3].rdsLsb
+						& TAG2_LEN_MASK) + 1;
+		}
+		iris_q_evt_data(radio, data, len, IRIS_BUF_RT_PLUS);
+		iris_q_event(radio,  IRIS_EVT_NEW_RT_PLUS);
+		kfree(data);
+	} else {
+		FMDERR("memory allocation failed\n");
+	}
+}
 
 static inline void hci_ev_program_service(struct radio_hci_dev *hdev,
 		struct sk_buff *skb)
@@ -2217,6 +2480,7 @@
 		hci_ev_service_available(hdev, skb);
 		break;
 	case HCI_EV_RDS_RX_DATA:
+		hci_ev_raw_rds_group_data(hdev, skb);
 		break;
 	case HCI_EV_PROGRAM_SERVICE:
 		hci_ev_program_service(hdev, skb);
@@ -2984,8 +3248,13 @@
 		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
-		radio->rds_grp.rds_grp_enable_mask = ctrl->value;
+		grp_mask = (grp_mask | oda_agt | ctrl->value);
+		radio->rds_grp.rds_grp_enable_mask = grp_mask;
+		radio->rds_grp.rds_buf_size = 1;
+		radio->rds_grp.en_rds_change_filter = 0;
 		retval = hci_fm_rds_grp(&radio->rds_grp, radio->fm_hdev);
+		if (retval < 0)
+			FMDERR("error in setting group mask\n");
 		break;
 	case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
 		rds_grps_proc = radio->g_rds_grp_proc_ps | ctrl->value;
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 5921632..56d3e0c 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -10,18 +10,19 @@
   EXTRA_CFLAGS += -Idrivers/media/video/msm/sensors
   EXTRA_CFLAGS += -Idrivers/media/video/msm/actuators
   EXTRA_CFLAGS += -Idrivers/media/video/msm/server
+  EXTRA_CFLAGS += -Idrivers/media/video/msm/flash
   obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o
   obj-$(CONFIG_MSM_CAMERA) += server/
   obj-$(CONFIG_MSM_CAM_IRQ_ROUTER) += msm_camirq_router.o
   obj-$(CONFIG_MSM_CAMERA) += cci/ eeprom/ sensors/ actuators/ csi/
   obj-$(CONFIG_MSM_CPP) += cpp/
   obj-$(CONFIG_MSM_CAMERA) += msm_gesture.o
+  obj-$(CONFIG_MSM_CAMERA) += flash/
 else
   obj-$(CONFIG_MSM_CAMERA) += msm_camera.o
 endif
 obj-$(CONFIG_MSM_CAMERA) += vfe/
 obj-$(CONFIG_MSM_CAMERA) += msm_axi_qos.o gemini/ mercury/ jpeg_10/
-obj-$(CONFIG_MSM_CAMERA_FLASH) += flash.o
 ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
   obj-$(CONFIG_ARCH_MSM8X60) += msm_vpe.o
   obj-$(CONFIG_ARCH_MSM7X30) += msm_vpe.o msm_axi_qos.o
diff --git a/drivers/media/video/msm/flash.c b/drivers/media/video/msm/flash.c
deleted file mode 100644
index 54c59f8..0000000
--- a/drivers/media/video/msm/flash.c
+++ /dev/null
@@ -1,763 +0,0 @@
-
-/* Copyright (c) 2009-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
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/leds-pmic8058.h>
-#include <linux/pwm.h>
-#include <linux/pmic8058-pwm.h>
-#include <linux/hrtimer.h>
-#include <linux/export.h>
-#include <mach/pmic.h>
-#include <mach/camera.h>
-#include <mach/gpio.h>
-#include "msm_camera_i2c.h"
-
-struct i2c_client *sx150x_client;
-struct timer_list timer_flash;
-static struct msm_camera_sensor_info *sensor_data;
-static struct msm_camera_i2c_client i2c_client;
-enum msm_cam_flash_stat{
-	MSM_CAM_FLASH_OFF,
-	MSM_CAM_FLASH_ON,
-};
-
-static struct i2c_client *sc628a_client;
-
-static const struct i2c_device_id sc628a_i2c_id[] = {
-	{"sc628a", 0},
-	{ }
-};
-
-static int sc628a_i2c_probe(struct i2c_client *client,
-		const struct i2c_device_id *id)
-{
-	int rc = 0;
-	CDBG("sc628a_probe called!\n");
-
-	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
-		pr_err("i2c_check_functionality failed\n");
-		goto probe_failure;
-	}
-
-	sc628a_client = client;
-
-	CDBG("sc628a_probe success rc = %d\n", rc);
-	return 0;
-
-probe_failure:
-	pr_err("sc628a_probe failed! rc = %d\n", rc);
-	return rc;
-}
-
-static struct i2c_driver sc628a_i2c_driver = {
-	.id_table = sc628a_i2c_id,
-	.probe  = sc628a_i2c_probe,
-	.remove = __exit_p(sc628a_i2c_remove),
-	.driver = {
-		.name = "sc628a",
-	},
-};
-
-static struct i2c_client *tps61310_client;
-
-static const struct i2c_device_id tps61310_i2c_id[] = {
-	{"tps61310", 0},
-	{ }
-};
-
-static int tps61310_i2c_probe(struct i2c_client *client,
-		const struct i2c_device_id *id)
-{
-	int rc = 0;
-	CDBG("%s enter\n", __func__);
-
-	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
-		pr_err("i2c_check_functionality failed\n");
-		goto probe_failure;
-	}
-
-	tps61310_client = client;
-	i2c_client.client = tps61310_client;
-	i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
-	rc = msm_camera_i2c_write(&i2c_client, 0x01, 0x00,
-		MSM_CAMERA_I2C_BYTE_DATA);
-	if (rc < 0) {
-		tps61310_client = NULL;
-		goto probe_failure;
-	}
-
-	CDBG("%s success! rc = %d\n", __func__, rc);
-	return 0;
-
-probe_failure:
-	pr_err("%s failed! rc = %d\n", __func__, rc);
-	return rc;
-}
-
-static struct i2c_driver tps61310_i2c_driver = {
-	.id_table = tps61310_i2c_id,
-	.probe  = tps61310_i2c_probe,
-	.remove = __exit_p(tps61310_i2c_remove),
-	.driver = {
-		.name = "tps61310",
-	},
-};
-
-static int config_flash_gpio_table(enum msm_cam_flash_stat stat,
-			struct msm_camera_sensor_strobe_flash_data *sfdata)
-{
-	int rc = 0, i = 0;
-	int msm_cam_flash_gpio_tbl[][2] = {
-		{sfdata->flash_trigger, 1},
-		{sfdata->flash_charge, 1},
-		{sfdata->flash_charge_done, 0}
-	};
-
-	if (stat == MSM_CAM_FLASH_ON) {
-		for (i = 0; i < ARRAY_SIZE(msm_cam_flash_gpio_tbl); i++) {
-			rc = gpio_request(msm_cam_flash_gpio_tbl[i][0],
-							  "CAM_FLASH_GPIO");
-			if (unlikely(rc < 0)) {
-				pr_err("%s not able to get gpio\n", __func__);
-				for (i--; i >= 0; i--)
-					gpio_free(msm_cam_flash_gpio_tbl[i][0]);
-				break;
-			}
-			if (msm_cam_flash_gpio_tbl[i][1])
-				gpio_direction_output(
-					msm_cam_flash_gpio_tbl[i][0], 0);
-			else
-				gpio_direction_input(
-					msm_cam_flash_gpio_tbl[i][0]);
-		}
-	} else {
-		for (i = 0; i < ARRAY_SIZE(msm_cam_flash_gpio_tbl); i++) {
-			gpio_direction_input(msm_cam_flash_gpio_tbl[i][0]);
-			gpio_free(msm_cam_flash_gpio_tbl[i][0]);
-		}
-	}
-	return rc;
-}
-
-int msm_camera_flash_current_driver(
-	struct msm_camera_sensor_flash_current_driver *current_driver,
-	unsigned led_state)
-{
-	int rc = 0;
-#if defined CONFIG_LEDS_PMIC8058
-	int idx;
-	const struct pmic8058_leds_platform_data *driver_channel =
-		current_driver->driver_channel;
-	int num_leds = driver_channel->num_leds;
-
-	CDBG("%s: led_state = %d\n", __func__, led_state);
-
-	/* Evenly distribute current across all channels */
-	switch (led_state) {
-	case MSM_CAMERA_LED_OFF:
-		for (idx = 0; idx < num_leds; ++idx) {
-			rc = pm8058_set_led_current(
-				driver_channel->leds[idx].id, 0);
-			if (rc < 0)
-				pr_err(
-					"%s: FAIL name = %s, rc = %d\n",
-					__func__,
-					driver_channel->leds[idx].name,
-					rc);
-		}
-		break;
-
-	case MSM_CAMERA_LED_LOW:
-		for (idx = 0; idx < num_leds; ++idx) {
-			rc = pm8058_set_led_current(
-				driver_channel->leds[idx].id,
-				current_driver->low_current/num_leds);
-			if (rc < 0)
-				pr_err(
-					"%s: FAIL name = %s, rc = %d\n",
-					__func__,
-					driver_channel->leds[idx].name,
-					rc);
-		}
-		break;
-
-	case MSM_CAMERA_LED_HIGH:
-		for (idx = 0; idx < num_leds; ++idx) {
-			rc = pm8058_set_led_current(
-				driver_channel->leds[idx].id,
-				current_driver->high_current/num_leds);
-			if (rc < 0)
-				pr_err(
-					"%s: FAIL name = %s, rc = %d\n",
-					__func__,
-					driver_channel->leds[idx].name,
-					rc);
-		}
-		break;
-	case MSM_CAMERA_LED_INIT:
-	case MSM_CAMERA_LED_RELEASE:
-		break;
-
-	default:
-		rc = -EFAULT;
-		break;
-	}
-	CDBG("msm_camera_flash_led_pmic8058: return %d\n", rc);
-#endif /* CONFIG_LEDS_PMIC8058 */
-	return rc;
-}
-
-int msm_camera_flash_led(
-		struct msm_camera_sensor_flash_external *external,
-		unsigned led_state)
-{
-	int rc = 0;
-
-	CDBG("msm_camera_flash_led: %d\n", led_state);
-	switch (led_state) {
-	case MSM_CAMERA_LED_INIT:
-		rc = gpio_request(external->led_en, "sgm3141");
-		CDBG("MSM_CAMERA_LED_INIT: gpio_req: %d %d\n",
-				external->led_en, rc);
-		if (!rc)
-			gpio_direction_output(external->led_en, 0);
-		else
-			return 0;
-
-		rc = gpio_request(external->led_flash_en, "sgm3141");
-		CDBG("MSM_CAMERA_LED_INIT: gpio_req: %d %d\n",
-				external->led_flash_en, rc);
-		if (!rc)
-			gpio_direction_output(external->led_flash_en, 0);
-
-			break;
-
-	case MSM_CAMERA_LED_RELEASE:
-		CDBG("MSM_CAMERA_LED_RELEASE\n");
-		gpio_set_value_cansleep(external->led_en, 0);
-		gpio_free(external->led_en);
-		gpio_set_value_cansleep(external->led_flash_en, 0);
-		gpio_free(external->led_flash_en);
-		break;
-
-	case MSM_CAMERA_LED_OFF:
-		CDBG("MSM_CAMERA_LED_OFF\n");
-		gpio_set_value_cansleep(external->led_en, 0);
-		gpio_set_value_cansleep(external->led_flash_en, 0);
-		break;
-
-	case MSM_CAMERA_LED_LOW:
-		CDBG("MSM_CAMERA_LED_LOW\n");
-		gpio_set_value_cansleep(external->led_en, 1);
-		gpio_set_value_cansleep(external->led_flash_en, 1);
-		break;
-
-	case MSM_CAMERA_LED_HIGH:
-		CDBG("MSM_CAMERA_LED_HIGH\n");
-		gpio_set_value_cansleep(external->led_en, 1);
-		gpio_set_value_cansleep(external->led_flash_en, 1);
-		break;
-
-	default:
-		rc = -EFAULT;
-		break;
-	}
-
-	return rc;
-}
-
-int msm_camera_flash_external(
-	struct msm_camera_sensor_flash_external *external,
-	unsigned led_state)
-{
-	int rc = 0;
-
-	switch (led_state) {
-
-	case MSM_CAMERA_LED_INIT:
-		if (external->flash_id == MAM_CAMERA_EXT_LED_FLASH_SC628A) {
-			if (!sc628a_client) {
-				rc = i2c_add_driver(&sc628a_i2c_driver);
-				if (rc < 0 || sc628a_client == NULL) {
-					pr_err("sc628a_i2c_driver add failed\n");
-					rc = -ENOTSUPP;
-					return rc;
-				}
-			}
-		} else if (external->flash_id ==
-			MAM_CAMERA_EXT_LED_FLASH_TPS61310) {
-			if (!tps61310_client) {
-				rc = i2c_add_driver(&tps61310_i2c_driver);
-				if (rc < 0 || tps61310_client == NULL) {
-					pr_err("tps61310_i2c_driver add failed\n");
-					rc = -ENOTSUPP;
-					return rc;
-				}
-			}
-		} else {
-			pr_err("Flash id not supported\n");
-			rc = -ENOTSUPP;
-			return rc;
-		}
-
-#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
-		if (external->expander_info && !sx150x_client) {
-			struct i2c_adapter *adapter =
-			i2c_get_adapter(external->expander_info->bus_id);
-			if (adapter)
-				sx150x_client = i2c_new_device(adapter,
-					external->expander_info->board_info);
-			if (!sx150x_client || !adapter) {
-				pr_err("sx150x_client is not available\n");
-				rc = -ENOTSUPP;
-				if (sc628a_client) {
-					i2c_del_driver(&sc628a_i2c_driver);
-					sc628a_client = NULL;
-				}
-				if (tps61310_client) {
-					i2c_del_driver(&tps61310_i2c_driver);
-					tps61310_client = NULL;
-				}
-				return rc;
-			}
-			i2c_put_adapter(adapter);
-		}
-#endif
-		if (sc628a_client)
-			rc = gpio_request(external->led_en, "sc628a");
-		if (tps61310_client)
-			rc = gpio_request(external->led_en, "tps61310");
-
-		if (!rc) {
-			gpio_direction_output(external->led_en, 0);
-		} else {
-			goto error;
-		}
-
-		if (sc628a_client)
-			rc = gpio_request(external->led_flash_en, "sc628a");
-		if (tps61310_client)
-			rc = gpio_request(external->led_flash_en, "tps61310");
-
-		if (!rc) {
-			gpio_direction_output(external->led_flash_en, 0);
-			break;
-		}
-
-		gpio_set_value_cansleep(external->led_en, 0);
-		gpio_free(external->led_en);
-error:
-		pr_err("%s gpio request failed\n", __func__);
-		if (sc628a_client) {
-			i2c_del_driver(&sc628a_i2c_driver);
-			sc628a_client = NULL;
-		}
-		if (tps61310_client) {
-			i2c_del_driver(&tps61310_i2c_driver);
-			tps61310_client = NULL;
-		}
-		break;
-
-	case MSM_CAMERA_LED_RELEASE:
-		if (sc628a_client || tps61310_client) {
-			gpio_set_value_cansleep(external->led_en, 0);
-			gpio_free(external->led_en);
-			gpio_set_value_cansleep(external->led_flash_en, 0);
-			gpio_free(external->led_flash_en);
-			if (sc628a_client) {
-				i2c_del_driver(&sc628a_i2c_driver);
-				sc628a_client = NULL;
-			}
-			if (tps61310_client) {
-				i2c_del_driver(&tps61310_i2c_driver);
-				tps61310_client = NULL;
-			}
-		}
-#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
-		if (external->expander_info && sx150x_client) {
-			i2c_unregister_device(sx150x_client);
-			sx150x_client = NULL;
-		}
-#endif
-		break;
-
-	case MSM_CAMERA_LED_OFF:
-		if (sc628a_client) {
-			i2c_client.client = sc628a_client;
-			i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
-			rc = msm_camera_i2c_write(&i2c_client, 0x02, 0x00,
-				MSM_CAMERA_I2C_BYTE_DATA);
-		}
-		if (tps61310_client) {
-			i2c_client.client = tps61310_client;
-			i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
-			rc = msm_camera_i2c_write(&i2c_client, 0x01, 0x00,
-				MSM_CAMERA_I2C_BYTE_DATA);
-		}
-		gpio_set_value_cansleep(external->led_en, 0);
-		gpio_set_value_cansleep(external->led_flash_en, 0);
-		break;
-
-	case MSM_CAMERA_LED_LOW:
-		gpio_set_value_cansleep(external->led_en, 1);
-		gpio_set_value_cansleep(external->led_flash_en, 1);
-		usleep_range(2000, 3000);
-		if (sc628a_client) {
-			i2c_client.client = sc628a_client;
-			i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
-			rc = msm_camera_i2c_write(&i2c_client, 0x02, 0x06,
-				MSM_CAMERA_I2C_BYTE_DATA);
-		}
-		if (tps61310_client) {
-			i2c_client.client = tps61310_client;
-			i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
-			rc = msm_camera_i2c_write(&i2c_client, 0x01, 0x86,
-				MSM_CAMERA_I2C_BYTE_DATA);
-		}
-		break;
-
-	case MSM_CAMERA_LED_HIGH:
-		gpio_set_value_cansleep(external->led_en, 1);
-		gpio_set_value_cansleep(external->led_flash_en, 1);
-		usleep_range(2000, 3000);
-		if (sc628a_client) {
-			i2c_client.client = sc628a_client;
-			i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
-			rc = msm_camera_i2c_write(&i2c_client, 0x02, 0x49,
-				MSM_CAMERA_I2C_BYTE_DATA);
-		}
-		if (tps61310_client) {
-			i2c_client.client = tps61310_client;
-			i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
-			rc = msm_camera_i2c_write(&i2c_client, 0x01, 0x8B,
-				MSM_CAMERA_I2C_BYTE_DATA);
-		}
-		break;
-
-	default:
-		rc = -EFAULT;
-		break;
-	}
-	return rc;
-}
-
-static int msm_camera_flash_pwm(
-	struct msm_camera_sensor_flash_pwm *pwm,
-	unsigned led_state)
-{
-	int rc = 0;
-	int PWM_PERIOD = USEC_PER_SEC / pwm->freq;
-
-	static struct pwm_device *flash_pwm;
-
-	if (!flash_pwm) {
-		flash_pwm = pwm_request(pwm->channel, "camera-flash");
-		if (flash_pwm == NULL || IS_ERR(flash_pwm)) {
-			pr_err("%s: FAIL pwm_request(): flash_pwm=%p\n",
-			       __func__, flash_pwm);
-			flash_pwm = NULL;
-			return -ENXIO;
-		}
-	}
-
-	switch (led_state) {
-	case MSM_CAMERA_LED_LOW:
-		rc = pwm_config(flash_pwm,
-			(PWM_PERIOD/pwm->max_load)*pwm->low_load,
-			PWM_PERIOD);
-		if (rc >= 0)
-			rc = pwm_enable(flash_pwm);
-		break;
-
-	case MSM_CAMERA_LED_HIGH:
-		rc = pwm_config(flash_pwm,
-			(PWM_PERIOD/pwm->max_load)*pwm->high_load,
-			PWM_PERIOD);
-		if (rc >= 0)
-			rc = pwm_enable(flash_pwm);
-		break;
-
-	case MSM_CAMERA_LED_OFF:
-		pwm_disable(flash_pwm);
-		break;
-	case MSM_CAMERA_LED_INIT:
-	case MSM_CAMERA_LED_RELEASE:
-		break;
-
-	default:
-		rc = -EFAULT;
-		break;
-	}
-	return rc;
-}
-
-int msm_camera_flash_pmic(
-	struct msm_camera_sensor_flash_pmic *pmic,
-	unsigned led_state)
-{
-	int rc = 0;
-
-	switch (led_state) {
-	case MSM_CAMERA_LED_OFF:
-		rc = pmic->pmic_set_current(pmic->led_src_1, 0);
-		if (pmic->num_of_src > 1)
-			rc = pmic->pmic_set_current(pmic->led_src_2, 0);
-		break;
-
-	case MSM_CAMERA_LED_LOW:
-		rc = pmic->pmic_set_current(pmic->led_src_1,
-				pmic->low_current);
-		if (pmic->num_of_src > 1)
-			rc = pmic->pmic_set_current(pmic->led_src_2, 0);
-		break;
-
-	case MSM_CAMERA_LED_HIGH:
-		rc = pmic->pmic_set_current(pmic->led_src_1,
-			pmic->high_current);
-		if (pmic->num_of_src > 1)
-			rc = pmic->pmic_set_current(pmic->led_src_2,
-				pmic->high_current);
-		break;
-
-	case MSM_CAMERA_LED_INIT:
-	case MSM_CAMERA_LED_RELEASE:
-		 break;
-
-	default:
-		rc = -EFAULT;
-		break;
-	}
-	CDBG("flash_set_led_state: return %d\n", rc);
-
-	return rc;
-}
-
-int32_t msm_camera_flash_set_led_state(
-	struct msm_camera_sensor_flash_data *fdata, unsigned led_state)
-{
-	int32_t rc;
-
-	if (fdata->flash_type != MSM_CAMERA_FLASH_LED ||
-		fdata->flash_src == NULL)
-		return -ENODEV;
-
-	switch (fdata->flash_src->flash_sr_type) {
-	case MSM_CAMERA_FLASH_SRC_PMIC:
-		rc = msm_camera_flash_pmic(&fdata->flash_src->_fsrc.pmic_src,
-			led_state);
-		break;
-
-	case MSM_CAMERA_FLASH_SRC_PWM:
-		rc = msm_camera_flash_pwm(&fdata->flash_src->_fsrc.pwm_src,
-			led_state);
-		break;
-
-	case MSM_CAMERA_FLASH_SRC_CURRENT_DRIVER:
-		rc = msm_camera_flash_current_driver(
-			&fdata->flash_src->_fsrc.current_driver_src,
-			led_state);
-		break;
-
-	case MSM_CAMERA_FLASH_SRC_EXT:
-		rc = msm_camera_flash_external(
-			&fdata->flash_src->_fsrc.ext_driver_src,
-			led_state);
-		break;
-
-	case MSM_CAMERA_FLASH_SRC_LED1:
-		rc = msm_camera_flash_led(
-				&fdata->flash_src->_fsrc.ext_driver_src,
-				led_state);
-		break;
-
-	default:
-		rc = -ENODEV;
-		break;
-	}
-
-	return rc;
-}
-
-static int msm_strobe_flash_xenon_charge(int32_t flash_charge,
-		int32_t charge_enable, uint32_t flash_recharge_duration)
-{
-	gpio_set_value_cansleep(flash_charge, charge_enable);
-	if (charge_enable) {
-		timer_flash.expires = jiffies +
-			msecs_to_jiffies(flash_recharge_duration);
-		/* add timer for the recharge */
-		if (!timer_pending(&timer_flash))
-			add_timer(&timer_flash);
-	} else
-		del_timer_sync(&timer_flash);
-	return 0;
-}
-
-static void strobe_flash_xenon_recharge_handler(unsigned long data)
-{
-	unsigned long flags;
-	struct msm_camera_sensor_strobe_flash_data *sfdata =
-		(struct msm_camera_sensor_strobe_flash_data *)data;
-
-	spin_lock_irqsave(&sfdata->timer_lock, flags);
-	msm_strobe_flash_xenon_charge(sfdata->flash_charge, 1,
-		sfdata->flash_recharge_duration);
-	spin_unlock_irqrestore(&sfdata->timer_lock, flags);
-
-	return;
-}
-
-static irqreturn_t strobe_flash_charge_ready_irq(int irq_num, void *data)
-{
-	struct msm_camera_sensor_strobe_flash_data *sfdata =
-		(struct msm_camera_sensor_strobe_flash_data *)data;
-
-	/* put the charge signal to low */
-	gpio_set_value_cansleep(sfdata->flash_charge, 0);
-
-	return IRQ_HANDLED;
-}
-
-static int msm_strobe_flash_xenon_init(
-	struct msm_camera_sensor_strobe_flash_data *sfdata)
-{
-	unsigned long flags;
-	int rc = 0;
-
-	spin_lock_irqsave(&sfdata->spin_lock, flags);
-	if (!sfdata->state) {
-
-		rc = config_flash_gpio_table(MSM_CAM_FLASH_ON, sfdata);
-		if (rc < 0) {
-			pr_err("%s: gpio_request failed\n", __func__);
-			goto go_out;
-		}
-		rc = request_irq(sfdata->irq, strobe_flash_charge_ready_irq,
-			IRQF_TRIGGER_RISING, "charge_ready", sfdata);
-		if (rc < 0) {
-			pr_err("%s: request_irq failed %d\n", __func__, rc);
-			goto go_out;
-		}
-
-		spin_lock_init(&sfdata->timer_lock);
-		/* setup timer */
-		init_timer(&timer_flash);
-		timer_flash.function = strobe_flash_xenon_recharge_handler;
-		timer_flash.data = (unsigned long)sfdata;
-	}
-	sfdata->state++;
-go_out:
-	spin_unlock_irqrestore(&sfdata->spin_lock, flags);
-
-	return rc;
-}
-
-static int msm_strobe_flash_xenon_release
-(struct msm_camera_sensor_strobe_flash_data *sfdata, int32_t final_release)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&sfdata->spin_lock, flags);
-	if (sfdata->state > 0) {
-		if (final_release)
-			sfdata->state = 0;
-		else
-			sfdata->state--;
-
-		if (!sfdata->state) {
-			free_irq(sfdata->irq, sfdata);
-			config_flash_gpio_table(MSM_CAM_FLASH_OFF, sfdata);
-			if (timer_pending(&timer_flash))
-				del_timer_sync(&timer_flash);
-		}
-	}
-	spin_unlock_irqrestore(&sfdata->spin_lock, flags);
-	return 0;
-}
-
-static void msm_strobe_flash_xenon_fn_init
-	(struct msm_strobe_flash_ctrl *strobe_flash_ptr)
-{
-	strobe_flash_ptr->strobe_flash_init =
-				msm_strobe_flash_xenon_init;
-	strobe_flash_ptr->strobe_flash_charge =
-				msm_strobe_flash_xenon_charge;
-	strobe_flash_ptr->strobe_flash_release =
-				msm_strobe_flash_xenon_release;
-}
-
-int msm_strobe_flash_init(struct msm_sync *sync, uint32_t sftype)
-{
-	int rc = 0;
-	switch (sftype) {
-	case MSM_CAMERA_STROBE_FLASH_XENON:
-		if (sync->sdata->strobe_flash_data) {
-			msm_strobe_flash_xenon_fn_init(&sync->sfctrl);
-			rc = sync->sfctrl.strobe_flash_init(
-			sync->sdata->strobe_flash_data);
-		} else
-			return -ENODEV;
-		break;
-	default:
-		rc = -ENODEV;
-	}
-	return rc;
-}
-
-int msm_strobe_flash_ctrl(struct msm_camera_sensor_strobe_flash_data *sfdata,
-	struct strobe_flash_ctrl_data *strobe_ctrl)
-{
-	int rc = 0;
-	switch (strobe_ctrl->type) {
-	case STROBE_FLASH_CTRL_INIT:
-		if (!sfdata)
-			return -ENODEV;
-		rc = msm_strobe_flash_xenon_init(sfdata);
-		break;
-	case STROBE_FLASH_CTRL_CHARGE:
-		rc = msm_strobe_flash_xenon_charge(sfdata->flash_charge,
-			strobe_ctrl->charge_en,
-			sfdata->flash_recharge_duration);
-		break;
-	case STROBE_FLASH_CTRL_RELEASE:
-		if (sfdata)
-			rc = msm_strobe_flash_xenon_release(sfdata, 0);
-		break;
-	default:
-		pr_err("Invalid Strobe Flash State\n");
-		rc = -EINVAL;
-	}
-	return rc;
-}
-
-int msm_flash_ctrl(struct msm_camera_sensor_info *sdata,
-	struct flash_ctrl_data *flash_info)
-{
-	int rc = 0;
-	sensor_data = sdata;
-	switch (flash_info->flashtype) {
-	case LED_FLASH:
-		rc = msm_camera_flash_set_led_state(sdata->flash_data,
-			flash_info->ctrl_data.led_state);
-			break;
-	case STROBE_FLASH:
-		rc = msm_strobe_flash_ctrl(sdata->strobe_flash_data,
-			&(flash_info->ctrl_data.strobe_ctrl));
-		break;
-	default:
-		pr_err("Invalid Flash MODE\n");
-		rc = -EINVAL;
-	}
-	return rc;
-}
diff --git a/drivers/media/video/msm/flash/Makefile b/drivers/media/video/msm/flash/Makefile
new file mode 100644
index 0000000..e83f052
--- /dev/null
+++ b/drivers/media/video/msm/flash/Makefile
@@ -0,0 +1,9 @@
+GCC_VERSION      := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
+ccflags-y += -Idrivers/media/video/msm
+ccflags-y += -Idrivers/media/video/msm/io
+obj-$(CONFIG_MSM_CAMERA_FLASH) += msm_flash.o
+obj-$(CONFIG_MSM_CAMERA_FLASH_SC628A) += sc628a.o
+obj-$(CONFIG_MSM_CAMERA_FLASH_TPS61310) += tps61310.o
+obj-$(CONFIG_MSM_CAMERA_FLASH_PMIC_FLASH) += pmic8058_flash.o
+obj-$(CONFIG_MSM_CAMERA_FLASH_SGM3141) += sgm3141.o
+obj-$(CONFIG_MSM_CAMERA_FLASH_PMIC8058_PWM) += pmic8058_pwm.o
diff --git a/drivers/media/video/msm/flash/msm_flash.c b/drivers/media/video/msm/flash/msm_flash.c
new file mode 100644
index 0000000..6639a4b
--- /dev/null
+++ b/drivers/media/video/msm/flash/msm_flash.c
@@ -0,0 +1,514 @@
+/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/hrtimer.h>
+#include <linux/export.h>
+#include <linux/of.h>
+#include <mach/pmic.h>
+#include <mach/camera.h>
+#include <mach/gpio.h>
+#include "msm_flash.h"
+#include "msm.h"
+
+static struct timer_list timer_flash;
+
+enum msm_cam_flash_stat {
+	MSM_CAM_FLASH_OFF,
+	MSM_CAM_FLASH_ON,
+};
+
+static int config_flash_gpio_table(enum msm_cam_flash_stat stat,
+			struct msm_camera_sensor_strobe_flash_data *sfdata)
+{
+	int rc = 0, i = 0;
+	int msm_cam_flash_gpio_tbl[][2] = {
+		{sfdata->flash_trigger, 1},
+		{sfdata->flash_charge, 1},
+		{sfdata->flash_charge_done, 0}
+	};
+
+	if (stat == MSM_CAM_FLASH_ON) {
+		for (i = 0; i < ARRAY_SIZE(msm_cam_flash_gpio_tbl); i++) {
+			rc = gpio_request(msm_cam_flash_gpio_tbl[i][0],
+							  "CAM_FLASH_GPIO");
+			if (unlikely(rc < 0)) {
+				pr_err("%s not able to get gpio\n", __func__);
+				for (i--; i >= 0; i--)
+					gpio_free(msm_cam_flash_gpio_tbl[i][0]);
+				break;
+			}
+			if (msm_cam_flash_gpio_tbl[i][1])
+				gpio_direction_output(
+					msm_cam_flash_gpio_tbl[i][0], 0);
+			else
+				gpio_direction_input(
+					msm_cam_flash_gpio_tbl[i][0]);
+		}
+	} else {
+		for (i = 0; i < ARRAY_SIZE(msm_cam_flash_gpio_tbl); i++) {
+			gpio_direction_input(msm_cam_flash_gpio_tbl[i][0]);
+			gpio_free(msm_cam_flash_gpio_tbl[i][0]);
+		}
+	}
+	return rc;
+}
+
+static int msm_strobe_flash_xenon_charge(int32_t flash_charge,
+		int32_t charge_enable, uint32_t flash_recharge_duration)
+{
+	gpio_set_value_cansleep(flash_charge, charge_enable);
+	if (charge_enable) {
+		timer_flash.expires = jiffies +
+			msecs_to_jiffies(flash_recharge_duration);
+		/* add timer for the recharge */
+		if (!timer_pending(&timer_flash))
+			add_timer(&timer_flash);
+	} else
+		del_timer_sync(&timer_flash);
+	return 0;
+}
+
+static void strobe_flash_xenon_recharge_handler(unsigned long data)
+{
+	unsigned long flags;
+	struct msm_camera_sensor_strobe_flash_data *sfdata =
+		(struct msm_camera_sensor_strobe_flash_data *)data;
+
+	spin_lock_irqsave(&sfdata->timer_lock, flags);
+	msm_strobe_flash_xenon_charge(sfdata->flash_charge, 1,
+		sfdata->flash_recharge_duration);
+	spin_unlock_irqrestore(&sfdata->timer_lock, flags);
+
+	return;
+}
+
+static irqreturn_t strobe_flash_charge_ready_irq(int irq_num, void *data)
+{
+	struct msm_camera_sensor_strobe_flash_data *sfdata =
+		(struct msm_camera_sensor_strobe_flash_data *)data;
+
+	/* put the charge signal to low */
+	gpio_set_value_cansleep(sfdata->flash_charge, 0);
+
+	return IRQ_HANDLED;
+}
+
+static int msm_strobe_flash_xenon_init(
+	struct msm_camera_sensor_strobe_flash_data *sfdata)
+{
+	unsigned long flags;
+	int rc = 0;
+
+	spin_lock_irqsave(&sfdata->spin_lock, flags);
+	if (!sfdata->state) {
+
+		rc = config_flash_gpio_table(MSM_CAM_FLASH_ON, sfdata);
+		if (rc < 0) {
+			pr_err("%s: gpio_request failed\n", __func__);
+			goto go_out;
+		}
+		rc = request_irq(sfdata->irq, strobe_flash_charge_ready_irq,
+			IRQF_TRIGGER_RISING, "charge_ready", sfdata);
+		if (rc < 0) {
+			pr_err("%s: request_irq failed %d\n", __func__, rc);
+			goto go_out;
+		}
+
+		spin_lock_init(&sfdata->timer_lock);
+		/* setup timer */
+		init_timer(&timer_flash);
+		timer_flash.function = strobe_flash_xenon_recharge_handler;
+		timer_flash.data = (unsigned long)sfdata;
+	}
+	sfdata->state++;
+go_out:
+	spin_unlock_irqrestore(&sfdata->spin_lock, flags);
+
+	return rc;
+}
+
+static int msm_strobe_flash_xenon_release
+(struct msm_camera_sensor_strobe_flash_data *sfdata, int32_t final_release)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&sfdata->spin_lock, flags);
+	if (sfdata->state > 0) {
+		if (final_release)
+			sfdata->state = 0;
+		else
+			sfdata->state--;
+
+		if (!sfdata->state) {
+			free_irq(sfdata->irq, sfdata);
+			config_flash_gpio_table(MSM_CAM_FLASH_OFF, sfdata);
+			if (timer_pending(&timer_flash))
+				del_timer_sync(&timer_flash);
+		}
+	}
+	spin_unlock_irqrestore(&sfdata->spin_lock, flags);
+	return 0;
+}
+
+static int msm_strobe_flash_ctrl(
+	struct msm_camera_sensor_strobe_flash_data *sfdata,
+	struct strobe_flash_ctrl_data *strobe_ctrl)
+{
+	int rc = 0;
+	switch (strobe_ctrl->type) {
+	case STROBE_FLASH_CTRL_INIT:
+		if (!sfdata)
+			return -ENODEV;
+		rc = msm_strobe_flash_xenon_init(sfdata);
+		break;
+	case STROBE_FLASH_CTRL_CHARGE:
+		rc = msm_strobe_flash_xenon_charge(sfdata->flash_charge,
+			strobe_ctrl->charge_en,
+			sfdata->flash_recharge_duration);
+		break;
+	case STROBE_FLASH_CTRL_RELEASE:
+		if (sfdata)
+			rc = msm_strobe_flash_xenon_release(sfdata, 0);
+		break;
+	default:
+		pr_err("Invalid Strobe Flash State\n");
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+int msm_flash_led_init(struct msm_flash_ctrl_t *fctrl)
+{
+	int rc = 0;
+	struct msm_camera_sensor_flash_external *external = NULL;
+	CDBG("%s:%d called\n", __func__, __LINE__);
+	if (!fctrl) {
+		pr_err("%s:%d fctrl NULL\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+	external = &fctrl->flash_data->flash_src->_fsrc.ext_driver_src;
+	if (external->expander_info && !fctrl->expander_client) {
+		struct i2c_adapter *adapter =
+		i2c_get_adapter(external->expander_info->bus_id);
+		if (adapter)
+			fctrl->expander_client = i2c_new_device(adapter,
+				external->expander_info->board_info);
+		if (!fctrl->expander_client || !adapter) {
+			pr_err("fctrl->expander_client is not available\n");
+			rc = -ENOTSUPP;
+			return rc;
+		}
+		i2c_put_adapter(adapter);
+	}
+	rc = msm_camera_init_gpio_table(
+		fctrl->flash_data->flash_src->init_gpio_tbl,
+		fctrl->flash_data->flash_src->init_gpio_tbl_size, 1);
+	if (rc < 0)
+		pr_err("%s:%d failed\n", __func__, __LINE__);
+	return rc;
+}
+
+int msm_flash_led_release(struct msm_flash_ctrl_t *fctrl)
+{
+	struct msm_camera_sensor_flash_external *external = NULL;
+	CDBG("%s:%d called\n", __func__, __LINE__);
+	if (!fctrl) {
+		pr_err("%s:%d fctrl NULL\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+	external = &fctrl->flash_data->flash_src->_fsrc.ext_driver_src;
+	msm_camera_set_gpio_table(
+		fctrl->flash_data->flash_src->set_gpio_tbl,
+		fctrl->flash_data->flash_src->set_gpio_tbl_size, 0);
+	msm_camera_init_gpio_table(
+		fctrl->flash_data->flash_src->init_gpio_tbl,
+		fctrl->flash_data->flash_src->init_gpio_tbl_size, 0);
+	if (external->expander_info && fctrl->expander_client) {
+		i2c_unregister_device(fctrl->expander_client);
+		fctrl->expander_client = NULL;
+	}
+	return 0;
+}
+
+int msm_flash_led_off(struct msm_flash_ctrl_t *fctrl)
+{
+	int rc = 0;
+	struct msm_camera_sensor_flash_external *external = NULL;
+	CDBG("%s:%d called\n", __func__, __LINE__);
+	if (!fctrl) {
+		pr_err("%s:%d fctrl NULL\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+	external = &fctrl->flash_data->flash_src->_fsrc.ext_driver_src;
+	if (fctrl->flash_i2c_client && fctrl->reg_setting) {
+		rc = msm_camera_i2c_write_tbl(
+			fctrl->flash_i2c_client,
+			fctrl->reg_setting->off_setting,
+			fctrl->reg_setting->off_setting_size,
+			fctrl->reg_setting->default_data_type);
+		if (rc < 0)
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+	}
+	msm_camera_set_gpio_table(
+		fctrl->flash_data->flash_src->set_gpio_tbl,
+		fctrl->flash_data->flash_src->set_gpio_tbl_size, 0);
+
+	return rc;
+}
+
+int msm_flash_led_low(struct msm_flash_ctrl_t *fctrl)
+{
+	int rc = 0;
+	struct msm_camera_sensor_flash_external *external = NULL;
+	CDBG("%s:%d called\n", __func__, __LINE__);
+	if (!fctrl) {
+		pr_err("%s:%d fctrl NULL\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+	external = &fctrl->flash_data->flash_src->_fsrc.ext_driver_src;
+	msm_camera_set_gpio_table(
+		fctrl->flash_data->flash_src->set_gpio_tbl,
+		fctrl->flash_data->flash_src->set_gpio_tbl_size, 1);
+	if (fctrl->flash_i2c_client && fctrl->reg_setting) {
+		rc = msm_camera_i2c_write_tbl(
+			fctrl->flash_i2c_client,
+			fctrl->reg_setting->low_setting,
+			fctrl->reg_setting->low_setting_size,
+			fctrl->reg_setting->default_data_type);
+		if (rc < 0)
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+	}
+	return rc;
+}
+
+int msm_flash_led_high(struct msm_flash_ctrl_t *fctrl)
+{
+	int rc = 0;
+	struct msm_camera_sensor_flash_external *external = NULL;
+	CDBG("%s:%d called\n", __func__, __LINE__);
+	if (!fctrl) {
+		pr_err("%s:%d fctrl NULL\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+	external = &fctrl->flash_data->flash_src->_fsrc.ext_driver_src;
+	msm_camera_set_gpio_table(
+		fctrl->flash_data->flash_src->set_gpio_tbl,
+		fctrl->flash_data->flash_src->set_gpio_tbl_size, 1);
+	if (fctrl->flash_i2c_client && fctrl->reg_setting) {
+		rc = msm_camera_i2c_write_tbl(
+			fctrl->flash_i2c_client,
+			fctrl->reg_setting->high_setting,
+			fctrl->reg_setting->high_setting_size,
+			fctrl->reg_setting->default_data_type);
+		if (rc < 0)
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+	}
+	return rc;
+}
+
+int msm_camera_flash_led_config(struct msm_flash_ctrl_t *fctrl,
+	uint8_t led_state)
+{
+	int rc = 0;
+
+	CDBG("%s:%d called\n", __func__, __LINE__);
+	if (!fctrl->func_tbl) {
+		pr_err("%s flash func tbl NULL\n", __func__);
+		return 0;
+	}
+	switch (led_state) {
+	case MSM_CAMERA_LED_INIT:
+		if (fctrl->func_tbl->flash_led_init)
+			rc = fctrl->func_tbl->flash_led_init(fctrl);
+		break;
+
+	case MSM_CAMERA_LED_RELEASE:
+		if (fctrl->func_tbl->flash_led_release)
+			rc = fctrl->func_tbl->
+				flash_led_release(fctrl);
+		break;
+
+	case MSM_CAMERA_LED_OFF:
+		if (fctrl->func_tbl->flash_led_off)
+			rc = fctrl->func_tbl->flash_led_off(fctrl);
+		break;
+
+	case MSM_CAMERA_LED_LOW:
+		if (fctrl->func_tbl->flash_led_low)
+			rc = fctrl->func_tbl->flash_led_low(fctrl);
+		break;
+
+	case MSM_CAMERA_LED_HIGH:
+		if (fctrl->func_tbl->flash_led_high)
+			rc = fctrl->func_tbl->flash_led_high(fctrl);
+		break;
+
+	default:
+		rc = -EFAULT;
+		break;
+	}
+	return rc;
+}
+
+static struct msm_flash_ctrl_t *get_fctrl(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct msm_flash_ctrl_t, v4l2_sdev);
+}
+
+static long msm_flash_config(struct msm_flash_ctrl_t *fctrl, void __user *argp)
+{
+	long rc = 0;
+	struct flash_ctrl_data flash_info;
+	if (!argp) {
+		pr_err("%s argp NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (copy_from_user(&flash_info, argp, sizeof(flash_info))) {
+		pr_err("%s:%d failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+	switch (flash_info.flashtype) {
+	case LED_FLASH:
+		if (fctrl->func_tbl->flash_led_config)
+			rc = fctrl->func_tbl->flash_led_config(fctrl,
+				flash_info.ctrl_data.led_state);
+		if (rc < 0)
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+		break;
+	case STROBE_FLASH:
+		rc = msm_strobe_flash_ctrl(fctrl->strobe_flash_data,
+			&(flash_info.ctrl_data.strobe_ctrl));
+		break;
+	default:
+		pr_err("Invalid Flash MODE\n");
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static long msm_flash_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int cmd, void *arg)
+{
+	struct msm_flash_ctrl_t *fctrl = NULL;
+	void __user *argp = (void __user *)arg;
+	if (!sd) {
+		pr_err("%s:%d sd NULL\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+	fctrl = get_fctrl(sd);
+	if (!fctrl) {
+		pr_err("%s:%d fctrl NULL\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+	switch (cmd) {
+	case VIDIOC_MSM_FLASH_LED_DATA_CFG:
+		fctrl->flash_data = (struct msm_camera_sensor_flash_data *)argp;
+		return 0;
+	case VIDIOC_MSM_FLASH_STROBE_DATA_CFG:
+		fctrl->strobe_flash_data =
+			(struct msm_camera_sensor_strobe_flash_data *)argp;
+		return 0;
+	case VIDIOC_MSM_FLASH_CFG:
+		return msm_flash_config(fctrl, argp);
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
+static struct v4l2_subdev_core_ops msm_flash_subdev_core_ops = {
+	.ioctl = msm_flash_subdev_ioctl,
+};
+
+static struct v4l2_subdev_ops msm_flash_subdev_ops = {
+	.core = &msm_flash_subdev_core_ops,
+};
+
+int msm_flash_i2c_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	int rc = 0;
+	struct msm_flash_ctrl_t *fctrl = NULL;
+	CDBG("%s:%d called\n", __func__, __LINE__);
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+
+	fctrl = (struct msm_flash_ctrl_t *)(id->driver_data);
+	if (fctrl->flash_i2c_client)
+		fctrl->flash_i2c_client->client = client;
+
+	/* Assign name for sub device */
+	snprintf(fctrl->v4l2_sdev.name, sizeof(fctrl->v4l2_sdev.name),
+		"%s", id->name);
+
+	/* Initialize sub device */
+	v4l2_i2c_subdev_init(&fctrl->v4l2_sdev, client, &msm_flash_subdev_ops);
+
+	CDBG("%s:%d probe success\n", __func__, __LINE__);
+	return 0;
+
+probe_failure:
+	CDBG("%s:%d probe failed\n", __func__, __LINE__);
+	return rc;
+}
+
+int msm_flash_platform_probe(struct platform_device *pdev, void *data)
+{
+	struct msm_flash_ctrl_t *fctrl = (struct msm_flash_ctrl_t *)data;
+	struct msm_cam_subdev_info sd_info;
+	CDBG("%s:%d called\n", __func__, __LINE__);
+
+	if (!fctrl) {
+		pr_err("%s fctrl NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	/* Initialize sub device */
+	v4l2_subdev_init(&fctrl->v4l2_sdev, &msm_flash_subdev_ops);
+
+	/* Assign name for sub device */
+	snprintf(fctrl->v4l2_sdev.name, sizeof(fctrl->v4l2_sdev.name),
+		"%s", "msm_flash");
+
+	fctrl->pdev = pdev;
+	sd_info.sdev_type = FLASH_DEV;
+	sd_info.sd_index = pdev->id;
+	msm_cam_register_subdev_node(&fctrl->v4l2_sdev, &sd_info);
+
+	CDBG("%s:%d probe success\n", __func__, __LINE__);
+	return 0;
+}
+
+int msm_flash_create_v4l2_subdev(void *data, uint8_t sd_index)
+{
+	struct msm_flash_ctrl_t *fctrl = (struct msm_flash_ctrl_t *)data;
+	struct msm_cam_subdev_info sd_info;
+	CDBG("%s:%d called\n", __func__, __LINE__);
+
+	/* Initialize sub device */
+	v4l2_subdev_init(&fctrl->v4l2_sdev, &msm_flash_subdev_ops);
+
+	/* Assign name for sub device */
+	snprintf(fctrl->v4l2_sdev.name, sizeof(fctrl->v4l2_sdev.name),
+		"%s", "msm_flash");
+
+	sd_info.sdev_type = FLASH_DEV;
+	sd_info.sd_index = sd_index;
+	msm_cam_register_subdev_node(&fctrl->v4l2_sdev, &sd_info);
+
+	CDBG("%s:%d probe success\n", __func__, __LINE__);
+	return 0;
+}
diff --git a/drivers/media/video/msm/flash/msm_flash.h b/drivers/media/video/msm/flash/msm_flash.h
new file mode 100644
index 0000000..a7c8846
--- /dev/null
+++ b/drivers/media/video/msm/flash/msm_flash.h
@@ -0,0 +1,91 @@
+/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef MSM_FLASH_H
+#define MSM_FLASH_H
+
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <media/v4l2-subdev.h>
+#include <mach/board.h>
+#include "msm_camera_i2c.h"
+
+#define MAX_LED_TRIGGERS 2
+
+struct msm_flash_ctrl_t;
+
+struct msm_flash_reg_t {
+	enum msm_camera_i2c_data_type default_data_type;
+	struct msm_camera_i2c_reg_conf *init_setting;
+	uint8_t init_setting_size;
+	struct msm_camera_i2c_reg_conf *off_setting;
+	uint8_t off_setting_size;
+	struct msm_camera_i2c_reg_conf *low_setting;
+	uint8_t low_setting_size;
+	struct msm_camera_i2c_reg_conf *high_setting;
+	uint8_t high_setting_size;
+};
+
+struct msm_flash_fn_t {
+	int (*flash_led_config)(struct msm_flash_ctrl_t *, uint8_t);
+	int (*flash_led_init)(struct msm_flash_ctrl_t *);
+	int (*flash_led_release)(struct msm_flash_ctrl_t *);
+	int (*flash_led_off)(struct msm_flash_ctrl_t *);
+	int (*flash_led_low)(struct msm_flash_ctrl_t *);
+	int (*flash_led_high)(struct msm_flash_ctrl_t *);
+};
+
+struct msm_flash_ctrl_t {
+	struct msm_camera_i2c_client *flash_i2c_client;
+	struct platform_device *pdev;
+	struct i2c_client *expander_client;
+	struct v4l2_subdev v4l2_sdev;
+	struct msm_camera_sensor_flash_data *flash_data;
+	struct msm_camera_sensor_strobe_flash_data *strobe_flash_data;
+	struct msm_flash_fn_t *func_tbl;
+	struct msm_flash_reg_t *reg_setting;
+	const char *led_trigger_name[MAX_LED_TRIGGERS];
+	struct led_trigger *led_trigger[MAX_LED_TRIGGERS];
+	uint32_t max_brightness[MAX_LED_TRIGGERS];
+	void *data;
+};
+
+int msm_flash_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id);
+
+int msm_flash_platform_probe(struct platform_device *pdev, void *data);
+
+int msm_flash_create_v4l2_subdev(void *data, uint8_t sd_index);
+
+int msm_camera_flash_led_config(struct msm_flash_ctrl_t *fctrl,
+	uint8_t led_state);
+
+int msm_flash_led_init(struct msm_flash_ctrl_t *fctrl);
+
+int msm_flash_led_release(struct msm_flash_ctrl_t *fctrl);
+
+int msm_flash_led_off(struct msm_flash_ctrl_t *fctrl);
+
+int msm_flash_led_low(struct msm_flash_ctrl_t *fctrl);
+
+int msm_flash_led_high(struct msm_flash_ctrl_t *fctrl);
+
+#define VIDIOC_MSM_FLASH_LED_DATA_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 20, void __user *)
+
+#define VIDIOC_MSM_FLASH_STROBE_DATA_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 21, void __user *)
+
+#define VIDIOC_MSM_FLASH_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 22, void __user *)
+
+#endif
diff --git a/drivers/media/video/msm/flash/pmic8058_flash.c b/drivers/media/video/msm/flash/pmic8058_flash.c
new file mode 100644
index 0000000..2017bcb
--- /dev/null
+++ b/drivers/media/video/msm/flash/pmic8058_flash.c
@@ -0,0 +1,79 @@
+/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/export.h>
+#include "msm_flash.h"
+
+#define SD_INDEX 0
+
+static struct msm_flash_ctrl_t fctrl;
+
+static int msm_camera_pmic_flash(struct msm_flash_ctrl_t *fctrl,
+	uint8_t led_state)
+{
+	int rc = 0;
+	struct msm_camera_sensor_flash_pmic *pmic =
+		&fctrl->flash_data->flash_src->_fsrc.pmic_src;
+
+	switch (led_state) {
+	case MSM_CAMERA_LED_OFF:
+		rc = pmic->pmic_set_current(pmic->led_src_1, 0);
+		if (pmic->num_of_src > 1)
+			rc = pmic->pmic_set_current(pmic->led_src_2, 0);
+		break;
+
+	case MSM_CAMERA_LED_LOW:
+		rc = pmic->pmic_set_current(pmic->led_src_1,
+				pmic->low_current);
+		if (pmic->num_of_src > 1)
+			rc = pmic->pmic_set_current(pmic->led_src_2, 0);
+		break;
+
+	case MSM_CAMERA_LED_HIGH:
+		rc = pmic->pmic_set_current(pmic->led_src_1,
+			pmic->high_current);
+		if (pmic->num_of_src > 1)
+			rc = pmic->pmic_set_current(pmic->led_src_2,
+				pmic->high_current);
+		break;
+
+	case MSM_CAMERA_LED_INIT:
+	case MSM_CAMERA_LED_RELEASE:
+		 break;
+
+	default:
+		rc = -EFAULT;
+		break;
+	}
+	CDBG("flash_set_led_state: return %d\n", rc);
+
+	return rc;
+}
+
+static int __init msm_flash_i2c_add_driver(void)
+{
+	CDBG("%s called\n", __func__);
+	return msm_flash_create_v4l2_subdev(&fctrl, SD_INDEX);
+}
+
+static struct msm_flash_fn_t pmic_flash_func_tbl = {
+	.flash_led_config = msm_camera_pmic_flash,
+};
+
+static struct msm_flash_ctrl_t fctrl = {
+	.func_tbl = &pmic_flash_func_tbl,
+};
+
+module_init(msm_flash_i2c_add_driver);
+MODULE_DESCRIPTION("PMIC FLASH");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/flash/pmic8058_pwm.c b/drivers/media/video/msm/flash/pmic8058_pwm.c
new file mode 100644
index 0000000..2215340
--- /dev/null
+++ b/drivers/media/video/msm/flash/pmic8058_pwm.c
@@ -0,0 +1,89 @@
+/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/pwm.h>
+
+#include "msm_flash.h"
+#define SD_INDEX 0
+
+static struct msm_flash_ctrl_t fctrl;
+
+static int msm_camera_flash_pwm(struct msm_flash_ctrl_t *fctrl,
+	uint8_t led_state)
+{
+	int rc = 0;
+	struct msm_camera_sensor_flash_pwm *pwm =
+		&fctrl->flash_data->flash_src->_fsrc.pwm_src;
+	int PWM_PERIOD = USEC_PER_SEC / pwm->freq;
+
+	struct pwm_device *flash_pwm = (struct pwm_device *)fctrl->data;
+
+	if (!flash_pwm) {
+		flash_pwm = pwm_request(pwm->channel, "camera-flash");
+		if (flash_pwm == NULL || IS_ERR(flash_pwm)) {
+			pr_err("%s: FAIL pwm_request(): flash_pwm=%p\n",
+			       __func__, flash_pwm);
+			flash_pwm = NULL;
+			return -ENXIO;
+		}
+	}
+
+	switch (led_state) {
+	case MSM_CAMERA_LED_LOW:
+		rc = pwm_config(flash_pwm,
+			(PWM_PERIOD/pwm->max_load)*pwm->low_load,
+			PWM_PERIOD);
+		if (rc >= 0)
+			rc = pwm_enable(flash_pwm);
+		break;
+
+	case MSM_CAMERA_LED_HIGH:
+		rc = pwm_config(flash_pwm,
+			(PWM_PERIOD/pwm->max_load)*pwm->high_load,
+			PWM_PERIOD);
+		if (rc >= 0)
+			rc = pwm_enable(flash_pwm);
+		break;
+
+	case MSM_CAMERA_LED_OFF:
+		pwm_disable(flash_pwm);
+		break;
+	case MSM_CAMERA_LED_INIT:
+	case MSM_CAMERA_LED_RELEASE:
+		break;
+
+	default:
+		rc = -EFAULT;
+		break;
+	}
+	return rc;
+}
+
+static int __init msm_flash_i2c_add_driver(void)
+{
+	CDBG("%s called\n", __func__);
+	return msm_flash_create_v4l2_subdev(&fctrl, SD_INDEX);
+}
+
+static struct msm_flash_fn_t pmic8058_pwm_func_tbl = {
+	.flash_led_config = msm_camera_flash_pwm,
+};
+
+static struct msm_flash_ctrl_t fctrl = {
+	.func_tbl = &pmic8058_pwm_func_tbl,
+};
+
+module_init(msm_flash_i2c_add_driver);
+MODULE_DESCRIPTION("PMIC FLASH");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/flash/sc628a.c b/drivers/media/video/msm/flash/sc628a.c
new file mode 100644
index 0000000..58824e1
--- /dev/null
+++ b/drivers/media/video/msm/flash/sc628a.c
@@ -0,0 +1,91 @@
+/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/export.h>
+#include "msm_flash.h"
+
+#define FLASH_NAME "sc628a"
+
+static struct msm_flash_ctrl_t fctrl;
+static struct i2c_driver sc628a_i2c_driver;
+
+static struct msm_camera_i2c_reg_conf sc628a_off_setting[] = {
+	{0x02, 0x00},
+};
+
+static struct msm_camera_i2c_reg_conf sc628a_low_setting[] = {
+	{0x02, 0x06},
+};
+
+static struct msm_camera_i2c_reg_conf sc628a_high_setting[] = {
+	{0x02, 0x49},
+};
+
+static int __exit msm_flash_i2c_remove(struct i2c_client *client)
+{
+	i2c_del_driver(&sc628a_i2c_driver);
+	return 0;
+}
+
+static const struct i2c_device_id sc628a_i2c_id[] = {
+	{FLASH_NAME, (kernel_ulong_t)&fctrl},
+	{ }
+};
+
+static struct i2c_driver sc628a_i2c_driver = {
+	.id_table = sc628a_i2c_id,
+	.probe  = msm_flash_i2c_probe,
+	.remove = __exit_p(msm_flash_i2c_remove),
+	.driver = {
+		.name = FLASH_NAME,
+	},
+};
+
+static int __init msm_flash_i2c_add_driver(void)
+{
+	CDBG("%s called\n", __func__);
+	return i2c_add_driver(&sc628a_i2c_driver);
+}
+
+static struct msm_camera_i2c_client sc628a_i2c_client = {
+	.addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
+};
+
+static struct msm_flash_reg_t sc628a_regs = {
+	.default_data_type = MSM_CAMERA_I2C_BYTE_DATA,
+	.off_setting = sc628a_off_setting,
+	.off_setting_size = ARRAY_SIZE(sc628a_off_setting),
+	.low_setting = sc628a_low_setting,
+	.low_setting_size = ARRAY_SIZE(sc628a_low_setting),
+	.high_setting = sc628a_high_setting,
+	.high_setting_size = ARRAY_SIZE(sc628a_high_setting),
+};
+
+static struct msm_flash_fn_t sc628a_func_tbl = {
+	.flash_led_config = msm_camera_flash_led_config,
+	.flash_led_init = msm_flash_led_init,
+	.flash_led_release = msm_flash_led_release,
+	.flash_led_off = msm_flash_led_off,
+	.flash_led_low = msm_flash_led_low,
+	.flash_led_high = msm_flash_led_high,
+};
+
+static struct msm_flash_ctrl_t fctrl = {
+	.flash_i2c_client = &sc628a_i2c_client,
+	.reg_setting = &sc628a_regs,
+	.func_tbl = &sc628a_func_tbl,
+};
+
+subsys_initcall(msm_flash_i2c_add_driver);
+MODULE_DESCRIPTION("SC628A FLASH");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/flash/sgm3141.c b/drivers/media/video/msm/flash/sgm3141.c
new file mode 100644
index 0000000..a8f8ca0
--- /dev/null
+++ b/drivers/media/video/msm/flash/sgm3141.c
@@ -0,0 +1,98 @@
+/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/export.h>
+#include <mach/gpio.h>
+#include "msm_flash.h"
+
+#define SD_INDEX 0
+
+static struct msm_flash_ctrl_t fctrl;
+
+static int msm_camera_flash_led(struct msm_flash_ctrl_t *fctrl,
+	uint8_t led_state)
+{
+	int rc = 0;
+	struct msm_camera_sensor_flash_external *external =
+		&fctrl->flash_data->flash_src->_fsrc.ext_driver_src;
+
+	CDBG("msm_camera_flash_led: %d\n", led_state);
+	switch (led_state) {
+	case MSM_CAMERA_LED_INIT:
+		rc = gpio_request(external->led_en, "sgm3141");
+		CDBG("MSM_CAMERA_LED_INIT: gpio_req: %d %d\n",
+				external->led_en, rc);
+		if (!rc)
+			gpio_direction_output(external->led_en, 0);
+		else
+			return 0;
+
+		rc = gpio_request(external->led_flash_en, "sgm3141");
+		CDBG("MSM_CAMERA_LED_INIT: gpio_req: %d %d\n",
+				external->led_flash_en, rc);
+		if (!rc)
+			gpio_direction_output(external->led_flash_en, 0);
+
+			break;
+
+	case MSM_CAMERA_LED_RELEASE:
+		CDBG("MSM_CAMERA_LED_RELEASE\n");
+		gpio_set_value_cansleep(external->led_en, 0);
+		gpio_free(external->led_en);
+		gpio_set_value_cansleep(external->led_flash_en, 0);
+		gpio_free(external->led_flash_en);
+		break;
+
+	case MSM_CAMERA_LED_OFF:
+		CDBG("MSM_CAMERA_LED_OFF\n");
+		gpio_set_value_cansleep(external->led_en, 0);
+		gpio_set_value_cansleep(external->led_flash_en, 0);
+		break;
+
+	case MSM_CAMERA_LED_LOW:
+		CDBG("MSM_CAMERA_LED_LOW\n");
+		gpio_set_value_cansleep(external->led_en, 1);
+		gpio_set_value_cansleep(external->led_flash_en, 1);
+		break;
+
+	case MSM_CAMERA_LED_HIGH:
+		CDBG("MSM_CAMERA_LED_HIGH\n");
+		gpio_set_value_cansleep(external->led_en, 1);
+		gpio_set_value_cansleep(external->led_flash_en, 1);
+		break;
+
+	default:
+		rc = -EFAULT;
+		break;
+	}
+
+	return rc;
+}
+
+static int __init msm_flash_i2c_add_driver(void)
+{
+	CDBG("%s called\n", __func__);
+	return msm_flash_create_v4l2_subdev(&fctrl, SD_INDEX);
+}
+
+static struct msm_flash_fn_t sgm3141_func_tbl = {
+	.flash_led_config = msm_camera_flash_led,
+};
+
+static struct msm_flash_ctrl_t fctrl = {
+	.func_tbl = &sgm3141_func_tbl,
+};
+
+module_init(msm_flash_i2c_add_driver);
+MODULE_DESCRIPTION("SGM3141 FLASH");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/flash/tps61310.c b/drivers/media/video/msm/flash/tps61310.c
new file mode 100644
index 0000000..63e6955
--- /dev/null
+++ b/drivers/media/video/msm/flash/tps61310.c
@@ -0,0 +1,97 @@
+/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/export.h>
+#include "msm_flash.h"
+
+#define FLASH_NAME "tps61310"
+
+static struct msm_flash_ctrl_t fctrl;
+static struct i2c_driver tps61310_i2c_driver;
+
+static struct msm_camera_i2c_reg_conf tps61310_init_setting[] = {
+	{0x01, 0x00},
+};
+
+static struct msm_camera_i2c_reg_conf tps61310_off_setting[] = {
+	{0x01, 0x00},
+};
+
+static struct msm_camera_i2c_reg_conf tps61310_low_setting[] = {
+	{0x01, 0x86},
+};
+
+static struct msm_camera_i2c_reg_conf tps61310_high_setting[] = {
+	{0x01, 0x8B},
+};
+
+static int __exit msm_flash_i2c_remove(struct i2c_client *client)
+{
+	i2c_del_driver(&tps61310_i2c_driver);
+	return 0;
+}
+
+static const struct i2c_device_id tps61310_i2c_id[] = {
+	{FLASH_NAME, (kernel_ulong_t)&fctrl},
+	{ }
+};
+
+static struct i2c_driver tps61310_i2c_driver = {
+	.id_table = tps61310_i2c_id,
+	.probe  = msm_flash_i2c_probe,
+	.remove = __exit_p(msm_flash_i2c_remove),
+	.driver = {
+		.name = FLASH_NAME,
+	},
+};
+
+static int __init msm_flash_i2c_add_driver(void)
+{
+	CDBG("%s called\n", __func__);
+	return i2c_add_driver(&tps61310_i2c_driver);
+}
+
+static struct msm_camera_i2c_client tps61310_i2c_client = {
+	.addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
+};
+
+static struct msm_flash_reg_t tps61310_regs = {
+	.default_data_type = MSM_CAMERA_I2C_BYTE_DATA,
+	.init_setting = tps61310_init_setting,
+	.init_setting_size = ARRAY_SIZE(tps61310_init_setting),
+	.off_setting = tps61310_off_setting,
+	.off_setting_size = ARRAY_SIZE(tps61310_off_setting),
+	.low_setting = tps61310_low_setting,
+	.low_setting_size = ARRAY_SIZE(tps61310_low_setting),
+	.high_setting = tps61310_high_setting,
+	.high_setting_size = ARRAY_SIZE(tps61310_high_setting),
+};
+
+static struct msm_flash_fn_t tps61310_func_tbl = {
+	.flash_led_config = msm_camera_flash_led_config,
+	.flash_led_init = msm_flash_led_init,
+	.flash_led_release = msm_flash_led_release,
+	.flash_led_off = msm_flash_led_off,
+	.flash_led_low = msm_flash_led_low,
+	.flash_led_high = msm_flash_led_high,
+};
+
+static struct msm_flash_ctrl_t fctrl = {
+	.flash_i2c_client = &tps61310_i2c_client,
+	.reg_setting = &tps61310_regs,
+	.func_tbl = &tps61310_func_tbl,
+};
+
+subsys_initcall(msm_flash_i2c_add_driver);
+MODULE_DESCRIPTION("TPS61310 FLASH");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/io/msm_camera_io_util.c b/drivers/media/video/msm/io/msm_camera_io_util.c
index 613850b..1e0a013 100644
--- a/drivers/media/video/msm/io/msm_camera_io_util.c
+++ b/drivers/media/video/msm/io/msm_camera_io_util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundataion. 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
@@ -494,3 +494,42 @@
 		pr_warning("%s: INVALID CASE\n", __func__);
 	}
 }
+
+int msm_camera_init_gpio_table(struct gpio *gpio_tbl, uint8_t gpio_tbl_size,
+	int gpio_en)
+{
+	int rc = 0;
+
+	if (gpio_en) {
+		rc = gpio_request_array(gpio_tbl, gpio_tbl_size);
+		if (rc < 0) {
+			pr_err("%s:%d failed\n" , __func__, __LINE__);
+			return rc;
+		}
+	} else {
+		gpio_free_array(gpio_tbl, gpio_tbl_size);
+	}
+	return rc;
+}
+
+int msm_camera_set_gpio_table(struct msm_gpio_set_tbl *gpio_tbl,
+	uint8_t gpio_tbl_size, int gpio_en)
+{
+	int rc = 0, i;
+
+	if (gpio_en) {
+		for (i = 0; i < gpio_tbl_size; i++) {
+			gpio_set_value_cansleep(gpio_tbl[i].gpio,
+				gpio_tbl[i].flags);
+			usleep_range(gpio_tbl[i].delay,
+				gpio_tbl[i].delay + 1000);
+		}
+	} else {
+		for (i = gpio_tbl_size - 1; i >= 0; i--) {
+			if (gpio_tbl[i].flags)
+				gpio_set_value_cansleep(gpio_tbl[i].gpio,
+					GPIOF_OUT_INIT_LOW);
+		}
+	}
+	return rc;
+}
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_dev.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_dev.c
index 0662f54..3e6e0d5 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_dev.c
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_dev.c
@@ -265,6 +265,7 @@
 
 static const struct of_device_id msm_jpeg_dt_match[] = {
 			{.compatible = "qcom,jpeg"},
+			{},
 };
 
 MODULE_DEVICE_TABLE(of, msm_jpeg_dt_match);
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 50a9776..ef1edae 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1396,6 +1396,7 @@
 		}
 	}
 
+	i2c_put_adapter(adapter);
 	return act_sdev;
 
 client_fail:
@@ -1431,6 +1432,7 @@
 	if (eeprom_sdev == NULL)
 		goto client_fail;
 
+	i2c_put_adapter(adapter);
 	return eeprom_sdev;
 client_fail:
 	pr_err("%s client_fail\n", __func__);
@@ -1444,6 +1446,45 @@
 	return NULL;
 }
 
+static struct v4l2_subdev *msm_flash_probe(
+	struct msm_camera_sensor_flash_data *flash_info)
+{
+	struct v4l2_subdev *flash_sdev = NULL;
+	struct i2c_adapter *adapter = NULL;
+	void *flash_client = NULL;
+
+	D("%s called\n", __func__);
+
+	if (!flash_info || !flash_info->board_info)
+		goto probe_fail;
+
+	adapter = i2c_get_adapter(flash_info->bus_id);
+	if (!adapter)
+		goto probe_fail;
+
+	flash_client = i2c_new_device(adapter, flash_info->board_info);
+	if (!flash_client)
+		goto device_fail;
+
+	flash_sdev = (struct v4l2_subdev *)i2c_get_clientdata(flash_client);
+	if (flash_sdev == NULL)
+		goto client_fail;
+
+	i2c_put_adapter(adapter);
+	return flash_sdev;
+
+client_fail:
+	pr_err("%s client_fail\n", __func__);
+	i2c_unregister_device(flash_client);
+device_fail:
+	pr_err("%s device_fail\n", __func__);
+	i2c_put_adapter(adapter);
+	adapter = NULL;
+probe_fail:
+	pr_err("%s probe_fail\n", __func__);
+	return NULL;
+}
+
 /* register a msm sensor into the msm device, which will probe the
  * sensor HW. if the HW exist then create a video device (/dev/videoX/)
  * to represent this sensor */
@@ -1471,6 +1512,7 @@
 
 	pcam->act_sdev = msm_actuator_probe(sdata->actuator_info);
 	pcam->eeprom_sdev = msm_eeprom_probe(sdata->eeprom_info);
+	pcam->flash_sdev = msm_flash_probe(sdata->flash_data);
 
 	D("%s: pcam =0x%p\n", __func__, pcam);
 
@@ -1528,6 +1570,15 @@
 		}
 	}
 
+	if (pcam->flash_sdev) {
+		rc = v4l2_device_register_subdev(&pcam->v4l2_dev,
+			pcam->flash_sdev);
+		if (rc < 0) {
+			D("%s flash sub device register failed\n", __func__);
+			goto failure;
+		}
+	}
+
 	pcam->vnode_id = vnode_count++;
 	return rc;
 
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 17303dd..1198f17 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -75,6 +75,7 @@
 #define MAX_NUM_JPEG_DEV 3
 #define MAX_NUM_CPP_DEV 1
 #define MAX_NUM_CCI_DEV 1
+#define MAX_NUM_FLASH_DEV 4
 
 /* msm queue management APIs*/
 
@@ -293,6 +294,7 @@
 	struct v4l2_subdev *vfe_sdev; /* vfe sub device */
 	struct v4l2_subdev *eeprom_sdev; /* eeprom sub device */
 	struct v4l2_subdev *cpp_sdev;/*cpp sub device*/
+	struct v4l2_subdev *flash_sdev;/*flash sub device*/
 
 	struct msm_cam_config_dev *config_device;
 
@@ -398,6 +400,7 @@
 	struct v4l2_subdev *sensor_sdev; /* sensor sub device */
 	struct v4l2_subdev *act_sdev; /* actuator sub device */
 	struct v4l2_subdev *eeprom_sdev; /* actuator sub device */
+	struct v4l2_subdev *flash_sdev; /* flash sub device */
 	struct msm_camera_sensor_info *sdata;
 
 	struct msm_device_queue eventData_q; /*payload for events sent to app*/
@@ -580,6 +583,7 @@
 	struct v4l2_subdev *cpp_device[MAX_NUM_CPP_DEV];
 	struct v4l2_subdev *irqr_device;
 	struct v4l2_subdev *cci_device;
+	struct v4l2_subdev *flash_device[MAX_NUM_FLASH_DEV];
 
 	spinlock_t  intr_table_lock;
 	struct irqmgr_intr_lkup_table irq_lkup_table;
@@ -723,6 +727,8 @@
 	struct msm_cam_subdev_info *sd_info);
 int msm_mctl_find_sensor_subdevs(struct msm_cam_media_controller *p_mctl,
 	uint8_t csiphy_core_index, uint8_t csid_core_index);
+int msm_mctl_find_flash_subdev(struct msm_cam_media_controller *p_mctl,
+	uint8_t index);
 int msm_server_open_client(int *p_qidx);
 int msm_server_send_ctrl(struct msm_ctrl_cmd *out, int ctrl_id);
 int msm_server_close_client(int idx);
diff --git a/drivers/media/video/msm/msm_camera.c b/drivers/media/video/msm/msm_camera.c
index dce3630..c40711d 100644
--- a/drivers/media/video/msm/msm_camera.c
+++ b/drivers/media/video/msm/msm_camera.c
@@ -2855,61 +2855,6 @@
 		rc = pmsm->sync->sctrl.s_config(argp);
 		break;
 
-	case MSM_CAM_IOCTL_FLASH_LED_CFG: {
-		uint32_t led_state;
-		if (copy_from_user(&led_state, argp, sizeof(led_state))) {
-			ERR_COPY_FROM_USER();
-			rc = -EFAULT;
-		} else
-			rc = msm_camera_flash_set_led_state(pmsm->sync->
-					sdata->flash_data, led_state);
-		break;
-	}
-
-	case MSM_CAM_IOCTL_STROBE_FLASH_CFG: {
-		uint32_t flash_type;
-		if (copy_from_user(&flash_type, argp, sizeof(flash_type))) {
-			pr_err("msm_strobe_flash_init failed");
-			ERR_COPY_FROM_USER();
-			rc = -EFAULT;
-		} else {
-			CDBG("msm_strobe_flash_init enter");
-			rc = msm_strobe_flash_init(pmsm->sync, flash_type);
-		}
-		break;
-	}
-
-	case MSM_CAM_IOCTL_STROBE_FLASH_RELEASE:
-		if (pmsm->sync->sdata->strobe_flash_data) {
-			rc = pmsm->sync->sfctrl.strobe_flash_release(
-				pmsm->sync->sdata->strobe_flash_data, 0);
-		}
-		break;
-
-	case MSM_CAM_IOCTL_STROBE_FLASH_CHARGE: {
-		uint32_t charge_en;
-		if (copy_from_user(&charge_en, argp, sizeof(charge_en))) {
-			ERR_COPY_FROM_USER();
-			rc = -EFAULT;
-		} else
-			rc = pmsm->sync->sfctrl.strobe_flash_charge(
-			pmsm->sync->sdata->strobe_flash_data->flash_charge,
-			charge_en, pmsm->sync->sdata->strobe_flash_data->
-				flash_recharge_duration);
-		break;
-	}
-
-	case MSM_CAM_IOCTL_FLASH_CTRL: {
-		struct flash_ctrl_data flash_info;
-		if (copy_from_user(&flash_info, argp, sizeof(flash_info))) {
-			ERR_COPY_FROM_USER();
-			rc = -EFAULT;
-		} else
-			rc = msm_flash_ctrl(pmsm->sync->sdata, &flash_info);
-
-		break;
-	}
-
 	case MSM_CAM_IOCTL_ERROR_CONFIG:
 		rc = msm_error_config(pmsm->sync, argp);
 		break;
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 36fb849..0210d23 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundataion. 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
@@ -40,6 +40,7 @@
 #include "msm_vfe32.h"
 #include "msm_camera_eeprom.h"
 #include "msm_csi_register.h"
+#include "msm_flash.h"
 
 #ifdef CONFIG_MSM_CAMERA_DEBUG
 #define D(fmt, args...) pr_debug("msm_mctl: " fmt, ##args)
@@ -414,14 +415,9 @@
 	}
 
 	case MSM_CAM_IOCTL_FLASH_CTRL: {
-		struct flash_ctrl_data flash_info;
-		if (copy_from_user(&flash_info, argp, sizeof(flash_info))) {
-			ERR_COPY_FROM_USER();
-			rc = -EFAULT;
-		} else {
-			if (msm_sensor_state_check(p_mctl))
-				rc = msm_flash_ctrl(p_mctl->sdata, &flash_info);
-		}
+		if (p_mctl->flash_sdev && msm_sensor_state_check(p_mctl))
+			rc = v4l2_subdev_call(p_mctl->flash_sdev,
+				core, ioctl, VIDIOC_MSM_FLASH_CFG, argp);
 		break;
 	}
 	case MSM_CAM_IOCTL_PICT_PP:
@@ -520,6 +516,7 @@
 	struct msm_camera_sensor_info *sinfo =
 		(struct msm_camera_sensor_info *) s_ctrl->sensordata;
 	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	struct msm_camera_sensor_flash_data *flash_data = sinfo->flash_data;
 	uint8_t csid_core;
 	D("%s\n", __func__);
 	if (!p_mctl) {
@@ -569,6 +566,35 @@
 			goto msm_csi_version;
 		}
 
+		if (!p_mctl->flash_sdev && flash_data) {
+			if ((flash_data->flash_type == MSM_CAMERA_FLASH_LED) &&
+				(flash_data->flash_src_index >= 0))
+				msm_mctl_find_flash_subdev(p_mctl,
+					flash_data->flash_src_index);
+		}
+
+		if (p_mctl->flash_sdev && p_mctl->sdata->flash_data &&
+			p_mctl->sdata->flash_data->flash_type !=
+			MSM_CAMERA_FLASH_NONE) {
+			rc = v4l2_subdev_call(p_mctl->flash_sdev, core, ioctl,
+					VIDIOC_MSM_FLASH_LED_DATA_CFG,
+					p_mctl->sdata->flash_data);
+			if (rc < 0) {
+				pr_err("%s: set flash led failed %d\n",
+				__func__, rc);
+			}
+		}
+
+		if (p_mctl->flash_sdev && p_mctl->sdata->strobe_flash_data) {
+			rc = v4l2_subdev_call(p_mctl->flash_sdev, core, ioctl,
+					VIDIOC_MSM_FLASH_STROBE_DATA_CFG,
+					p_mctl->sdata->strobe_flash_data);
+			if (rc < 0) {
+				pr_err("%s: set strobe flash led failed %d\n",
+				__func__, rc);
+			}
+		}
+
 		pm_qos_add_request(&p_mctl->pm_qos_req_list,
 			PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
 		pm_qos_update_request(&p_mctl->pm_qos_req_list,
@@ -739,6 +765,7 @@
 	pmctl->vfe_output_mode = 0;
 	spin_lock_init(&pmctl->pp_info.lock);
 
+	pmctl->flash_sdev = pcam->flash_sdev;
 	pmctl->act_sdev = pcam->act_sdev;
 	pmctl->eeprom_sdev = pcam->eeprom_sdev;
 	pmctl->sensor_sdev = pcam->sensor_sdev;
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index b8b1d51..49543a4 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1853,6 +1853,14 @@
 	return rc;
 }
 
+int msm_mctl_find_flash_subdev(struct msm_cam_media_controller *p_mctl,
+	uint8_t index)
+{
+	if (index < MAX_NUM_FLASH_DEV)
+		p_mctl->flash_sdev = g_server_dev.flash_device[index];
+	return 0;
+}
+
 static irqreturn_t msm_camera_server_parse_irq(int irq_num, void *data)
 {
 	unsigned long flags;
@@ -2327,6 +2335,16 @@
 				sd_info->irq_num);
 		}
 		break;
+
+	case FLASH_DEV:
+		if (index >= MAX_NUM_FLASH_DEV) {
+			pr_err("%s Invalid flash idx %d", __func__, index);
+			err = -EINVAL;
+			break;
+		}
+		g_server_dev.flash_device[index] = sd;
+		break;
+
 	default:
 		break;
 	}
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index eb0cd8a..912fad4 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -29,7 +29,6 @@
 #include "msm_vidc_debug.h"
 #include "vidc_hal_api.h"
 #include "msm_smem.h"
-#include "msm_vidc_ssr.h"
 
 #define BASE_DEVICE_NUMBER 32
 #define SHARED_QSIZE 0x1000000
@@ -777,6 +776,11 @@
 		goto exit;
 	}
 	for (i = 0; i < b->length; ++i) {
+		if (EXTRADATA_IDX(b->length) &&
+			(i == EXTRADATA_IDX(b->length)) &&
+			!b->m.planes[i].length) {
+			continue;
+		}
 		temp = get_registered_buf(&v4l2_inst->registered_bufs,
 				b->m.planes[i].reserved[0],
 				b->m.planes[i].reserved[1],
@@ -850,6 +854,12 @@
 	vidc_inst = get_vidc_inst(file, fh);
 	v4l2_inst = get_v4l2_inst(file, fh);
 	for (i = 0; i < b->length; ++i) {
+		if (EXTRADATA_IDX(b->length) &&
+			(i == EXTRADATA_IDX(b->length)) &&
+			!b->m.planes[i].length) {
+			b->m.planes[i].m.userptr = 0;
+			continue;
+		}
 		binfo = get_registered_buf(&v4l2_inst->registered_bufs,
 				b->m.planes[i].reserved[0],
 				b->m.planes[i].reserved[1],
@@ -902,6 +912,11 @@
 		goto fail_dq_buf;
 	}
 	for (i = 0; i < b->length; i++) {
+		if (EXTRADATA_IDX(b->length) &&
+				(i == EXTRADATA_IDX(b->length)) &&
+				!b->m.planes[i].m.userptr) {
+			continue;
+		}
 		b->m.planes[i].m.userptr = device_to_uvaddr(
 				&v4l2_inst->registered_bufs,
 				b->m.planes[i].m.userptr);
@@ -1367,9 +1382,6 @@
 	core->debugfs_root = msm_vidc_debugfs_init_core(
 		core, vidc_driver->debugfs_root);
 	pdev->dev.platform_data = core;
-	rc = msm_vidc_ssr_init(core);
-	if (rc < 0)
-		dprintk(VIDC_ERR, "msm_vidc : Sub Systrem Restart failed\n");
 	return rc;
 
 err_cores_exceeded:
@@ -1398,7 +1410,6 @@
 	vidc_hal_delete_device(core->device);
 	video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev);
 	video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev);
-	rc = msm_vidc_ssr_uninit(core);
 	v4l2_device_unregister(&core->v4l2_dev);
 	if (core->resources.ocmem.handle)
 		ocmem_notifier_unregister(core->resources.ocmem.handle,
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index 3afc496..22063d4 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -167,23 +167,7 @@
 static u32 get_frame_size_nv12(int plane,
 					u32 height, u32 width)
 {
-	int size;
-	int luma_h, luma_w, luma_stride, luma_scanl, luma_size;
-	int chroma_h, chroma_w, chroma_stride, chroma_scanl, chroma_size;
-
-	luma_w = width;
-	luma_h = height;
-
-	chroma_w = luma_w;
-	chroma_h = luma_h/2;
-	NV12_IL_CALC_Y_STRIDE(luma_stride, luma_w, 32);
-	NV12_IL_CALC_Y_BUFHEIGHT(luma_scanl, luma_h, 32);
-	NV12_IL_CALC_UV_STRIDE(chroma_stride, chroma_w, 32);
-	NV12_IL_CALC_UV_BUFHEIGHT(chroma_scanl, luma_h, 32);
-	NV12_IL_CALC_BUF_SIZE(size, luma_size, luma_stride,
-		luma_scanl, chroma_size, chroma_stride, chroma_scanl, 32);
-	size = ALIGN(size, SZ_4K);
-	return size;
+	return VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height);
 }
 
 static u32 get_frame_size_compressed(int plane,
@@ -346,7 +330,8 @@
 			buffer_info.align_device_addr =
 				b->m.planes[0].m.userptr;
 			extra_idx = EXTRADATA_IDX(b->length);
-			if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+			if (extra_idx && (extra_idx < VIDEO_MAX_PLANES) &&
+				b->m.planes[extra_idx].m.userptr) {
 				buffer_info.extradata_addr =
 					b->m.planes[extra_idx].m.userptr;
 				dprintk(VIDC_DBG,
@@ -354,6 +339,9 @@
 				b->m.planes[extra_idx].m.userptr);
 				buffer_info.extradata_size =
 					b->m.planes[extra_idx].length;
+			} else {
+				buffer_info.extradata_addr = 0;
+				buffer_info.extradata_size = 0;
 			}
 			rc = vidc_hal_session_set_buffers((void *)inst->session,
 					&buffer_info);
@@ -409,9 +397,13 @@
 			buffer_info.align_device_addr =
 				 b->m.planes[0].m.userptr;
 			extra_idx = EXTRADATA_IDX(b->length);
-			if (extra_idx && (extra_idx < VIDEO_MAX_PLANES))
+			if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)
+				&& b->m.planes[extra_idx].m.userptr)
 				buffer_info.extradata_addr =
 					b->m.planes[extra_idx].m.userptr;
+			else
+				buffer_info.extradata_addr = 0;
+
 			rc = vidc_hal_session_release_buffers(
 					(void *)inst->session, &buffer_info);
 			if (rc)
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index 3f892b1..d53da9e 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -23,6 +23,7 @@
 #define DEFAULT_WIDTH 1280
 #define MIN_NUM_OUTPUT_BUFFERS 4
 #define MAX_NUM_OUTPUT_BUFFERS 8
+#define MAX_INPUT_BUFFERS 32
 #define MIN_BIT_RATE 64000
 #define MAX_BIT_RATE 160000000
 #define DEFAULT_BIT_RATE 64000
@@ -136,11 +137,11 @@
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME,
 		.name = "Request I Frame",
-		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.type = V4L2_CTRL_TYPE_BUTTON,
 		.minimum = 0,
-		.maximum = 1,
+		.maximum = 0,
 		.default_value = 0,
-		.step = 1,
+		.step = 0,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
 	},
@@ -461,23 +462,7 @@
 
 static u32 get_frame_size_nv12(int plane, u32 height, u32 width)
 {
-	int size;
-	int luma_h, luma_w, luma_stride, luma_scanl, luma_size;
-	int chroma_h, chroma_w, chroma_stride, chroma_scanl, chroma_size;
-
-	luma_w = width;
-	luma_h = height;
-
-	chroma_w = luma_w;
-	chroma_h = luma_h/2;
-	NV12_IL_CALC_Y_STRIDE(luma_stride, luma_w, 32);
-	NV12_IL_CALC_Y_BUFHEIGHT(luma_scanl, luma_h, 32);
-	NV12_IL_CALC_UV_STRIDE(chroma_stride, chroma_w, 32);
-	NV12_IL_CALC_UV_BUFHEIGHT(chroma_scanl, luma_h, 32);
-	NV12_IL_CALC_BUF_SIZE(size, luma_size, luma_stride,
-		luma_scanl, chroma_size, chroma_stride, chroma_scanl, 32);
-	size = ALIGN(size, SZ_4K);
-	return size;
+	return VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height);
 }
 
 static u32 get_frame_size_nv21(int plane, u32 height, u32 width)
@@ -574,6 +559,8 @@
 {
 	int i, rc = 0;
 	struct msm_vidc_inst *inst;
+	struct hal_buffer_count_actual new_buf_count;
+	enum hal_property property_id;
 	unsigned long flags;
 	if (!q || !q->drv_priv) {
 		dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
@@ -609,6 +596,11 @@
 			max(*num_buffers, inst->buff_req.buffer[0].
 			buffer_count_actual);
 		spin_unlock_irqrestore(&inst->lock, flags);
+		property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
+		new_buf_count.buffer_type = HAL_BUFFER_INPUT;
+		new_buf_count.buffer_count_actual = MAX_INPUT_BUFFERS;
+		rc = vidc_hal_session_set_property(inst->session,
+					property_id, &new_buf_count);
 		dprintk(VIDC_DBG, "size = %d, alignment = %d, count = %d\n",
 				inst->buff_req.buffer[0].buffer_size,
 				inst->buff_req.buffer[0].buffer_alignment,
@@ -824,7 +816,7 @@
 	case V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME:
 		property_id =
 			HAL_CONFIG_VENC_REQUEST_IFRAME;
-		request_iframe.enable = control.value;
+		request_iframe.enable = true;
 		pdata = &request_iframe;
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL:
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index 038f03e..02773ff 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -17,7 +17,7 @@
 #include <asm/div64.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/peripheral-loader.h>
+#include <mach/subsystem_restart.h>
 
 #include "msm_vidc_common.h"
 #include "vidc_hal_api.h"
@@ -388,7 +388,9 @@
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
 	struct v4l2_event dqevent;
+	struct v4l2_control control = {0};
 	struct msm_vidc_cb_event *event_notify;
+	int rc = 0;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
 		dqevent.id = 0;
@@ -396,7 +398,16 @@
 		switch (event_notify->hal_event_type) {
 		case HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES:
 			dqevent.type =
-				V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
+				V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+			control.id =
+				V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER;
+			rc = v4l2_g_ctrl(&inst->ctrl_handler, &control);
+			if (rc)
+				dprintk(VIDC_WARN,
+					"Failed to get Smooth streamng flag\n");
+			if (!rc && control.value == true)
+				dqevent.type =
+					V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
 			break;
 		case HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES:
 			dqevent.type =
@@ -509,9 +520,73 @@
 	}
 }
 
+static void handle_session_error(enum command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst = NULL;
+	struct v4l2_event dqevent;
+	if (response) {
+		inst = (struct msm_vidc_inst *)response->session_id;
+		if (inst) {
+			dprintk(VIDC_WARN,
+				"Session error receivd for session %p\n", inst);
+			mutex_lock(&inst->sync_lock);
+			inst->state = MSM_VIDC_CORE_INVALID;
+			mutex_unlock(&inst->sync_lock);
+			dqevent.type = V4L2_EVENT_MSM_VIDC_SYS_ERROR;
+			dqevent.id = 0;
+			v4l2_event_queue_fh(&inst->event_handler, &dqevent);
+			wake_up(&inst->kernel_event_queue);
+		}
+	} else {
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for session error\n");
+	}
+}
+static void handle_sys_error(enum command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst = NULL ;
+	struct msm_vidc_core *core = NULL;
+	struct v4l2_event dqevent;
+	unsigned long flags;
+	if (response) {
+		inst = (struct msm_vidc_inst *)response->session_id;
+		dprintk(VIDC_WARN,
+				"Sys error received for session %p\n", inst);
+		if (inst) {
+			core = inst->core;
+			if (core) {
+				spin_lock_irqsave(&core->lock, flags);
+				core->state = VIDC_CORE_INVALID;
+				spin_unlock_irqrestore(&core->lock, flags);
+				dqevent.type = V4L2_EVENT_MSM_VIDC_SYS_ERROR;
+				dqevent.id = 0;
+				list_for_each_entry(inst, &core->instances,
+					list) {
+					if (inst) {
+						v4l2_event_queue_fh(
+							&inst->event_handler,
+								&dqevent);
+						spin_lock_irqsave(&inst->lock,
+							flags);
+						inst->state =
+							MSM_VIDC_CORE_INVALID;
+						spin_unlock_irqrestore(
+							&inst->lock, flags);
+					}
+				}
+			wake_up(&inst->kernel_event_queue);
+			}
+		}
+	} else {
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for sys error\n");
+	}
+}
+
 static void handle_sys_watchdog_timeout(enum command_response cmd, void *data)
 {
-	subsystem_restart("msm_vidc");
 	dprintk(VIDC_ERR,
 		"msm_vidc: Sub System Restart initiated\n");
 }
@@ -755,6 +830,12 @@
 	case SYS_WATCHDOG_TIMEOUT:
 		handle_sys_watchdog_timeout(cmd, data);
 		break;
+	case SYS_ERROR:
+		handle_sys_error(cmd, data);
+		break;
+	case SESSION_ERROR:
+		handle_session_error(cmd, data);
+		break;
 	default:
 		dprintk(VIDC_ERR, "response unhandled\n");
 		break;
@@ -837,12 +918,12 @@
 	}
 
 	if (!core->resources.fw.cookie)
-		core->resources.fw.cookie = pil_get("venus");
+		core->resources.fw.cookie = subsystem_get("venus");
 
 	if (IS_ERR_OR_NULL(core->resources.fw.cookie)) {
 		dprintk(VIDC_ERR, "Failed to download firmware\n");
 		rc = -ENOMEM;
-		goto fail_pil_get;
+		goto fail_subsystem_get;
 	}
 
 	rc = msm_comm_enable_clks(core);
@@ -860,9 +941,9 @@
 fail_iommu_attach:
 	msm_comm_disable_clks(core);
 fail_enable_clks:
-	pil_put(core->resources.fw.cookie);
+	subsystem_put(core->resources.fw.cookie);
 	core->resources.fw.cookie = NULL;
-fail_pil_get:
+fail_subsystem_get:
 	return rc;
 }
 
@@ -873,7 +954,7 @@
 		return;
 	}
 	if (core->resources.fw.cookie) {
-		pil_put(core->resources.fw.cookie);
+		subsystem_put(core->resources.fw.cookie);
 		core->resources.fw.cookie = NULL;
 		msm_comm_iommu_detach(core);
 		msm_comm_disable_clks(core);
@@ -1551,7 +1632,8 @@
 			frame_data.buffer_type = HAL_BUFFER_OUTPUT;
 			extra_idx =
 			EXTRADATA_IDX(inst->fmts[CAPTURE_PORT]->num_planes);
-			if (extra_idx)
+			if (extra_idx && (extra_idx < VIDEO_MAX_PLANES) &&
+				vb->v4l2_planes[extra_idx].m.userptr)
 				frame_data.extradata_addr =
 					vb->v4l2_planes[extra_idx].m.userptr;
 			dprintk(VIDC_DBG,
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index f288cc6..8e1a99e 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -30,6 +30,7 @@
 #include <media/v4l2-ctrls.h>
 #include <media/videobuf2-core.h>
 #include <media/msm_vidc.h>
+#include <media/msm_media_info.h>
 
 #include "vidc_hal_api.h"
 
@@ -49,33 +50,7 @@
 
 #define MAX_NAME_LENGTH 64
 
-#define NV12_IL_CALC_Y_STRIDE(stride, frame_width, stride_multiple) \
-	{ stride = (frame_width + stride_multiple - 1) & \
-	(0xffffffff - (stride_multiple - 1)); }
-
-#define NV12_IL_CALC_Y_BUFHEIGHT(buf_height, frame_height,\
-	min_buf_height_multiple) \
-	{ buf_height = (frame_height + min_buf_height_multiple - 1) & \
-	(0xffffffff - (min_buf_height_multiple - 1)); }
-
-#define NV12_IL_CALC_UV_STRIDE(stride, frame_width, stride_multiple) \
-	{ stride = ((((frame_width + 1) >> 1) + stride_multiple - 1) & \
-	(0xffffffff - (stride_multiple - 1))) << 1; }
-
-#define NV12_IL_CALC_UV_BUFHEIGHT(buf_height, frame_height,\
-	min_buf_height_multiple) \
-	{ buf_height = ((((frame_height + 1) >> 1) + \
-	min_buf_height_multiple - 1) & (0xffffffff - \
-	(min_buf_height_multiple - 1))); }
-
-#define NV12_IL_CALC_BUF_SIZE(buf_size, y_buf_size, y_stride, \
-	y_buf_height, uv_buf_size, uv_stride, uv_buf_height, uv_alignment) \
-	{ y_buf_size = (y_stride * y_buf_height); \
-	uv_buf_size = (uv_stride * uv_buf_height) + uv_alignment; \
-	buf_size = y_buf_size + uv_buf_size; }
-
 #define EXTRADATA_IDX(__num_planes) (__num_planes - 1)
-
 enum vidc_ports {
 	OUTPUT_PORT,
 	CAPTURE_PORT,
diff --git a/drivers/media/video/msm_vidc/msm_vidc_ssr.c b/drivers/media/video/msm_vidc/msm_vidc_ssr.c
index e8a6745..33464c6f 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_ssr.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_ssr.c
@@ -157,7 +157,8 @@
 		dprintk(VIDC_ERR, "msm_vidc Sub System registration failed\n");
 		rc = -ENODEV;
 	}
-	core->ssr_info.msm_vidc_ramdump_dev = create_ramdump_device("msm_vidc");
+	core->ssr_info.msm_vidc_ramdump_dev = create_ramdump_device("msm_vidc",
+			msm_vidc_subsystem.dev);
 	if (!core->ssr_info.msm_vidc_ramdump_dev) {
 		dprintk(VIDC_ERR, "Unable to create msm_vidc ramdump device\n");
 		rc = -ENODEV;
diff --git a/drivers/media/video/msm_vidc/vidc_hal.c b/drivers/media/video/msm_vidc/vidc_hal.c
index 190e132..2f9d8d4 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.c
+++ b/drivers/media/video/msm_vidc/vidc_hal.c
@@ -613,11 +613,9 @@
 	write_register(device->hal_data->register_base_addr,
 				   VIDC_VENUS_VBIF_CLK_ON, 1, 0);
 	write_register(device->hal_data->register_base_addr,
-			VIDC_VBIF_OUT_AXI_AOOO_EN, 0x00000FFF, 0);
+			VIDC_VBIF_OUT_AXI_AOOO_EN, 0x00001FFF, 0);
 	write_register(device->hal_data->register_base_addr,
-			VIDC_VBIF_OUT_AXI_AOOO, 0x0FFF0FFF, 0);
-	write_register(device->hal_data->register_base_addr,
-			VIDC_VENUS_VBIF_CLK_ON, 1, 0);
+			VIDC_VBIF_OUT_AXI_AOOO, 0x1FFF1FFF, 0);
 	write_register(device->hal_data->register_base_addr,
 			VIDC_VBIF_IN_RD_LIM_CONF0, 0x10101001, 0);
 	write_register(device->hal_data->register_base_addr,
@@ -641,7 +639,15 @@
 	write_register(device->hal_data->register_base_addr,
 			VIDC_VBIF_ARB_CTL, 0x00000030, 0);
 	write_register(device->hal_data->register_base_addr,
+			VIDC_VENUS_VBIF_DDR_OUT_MAX_BURST, 0x00000707, 0);
+	write_register(device->hal_data->register_base_addr,
+			VIDC_VENUS_VBIF_OCMEM_OUT_MAX_BURST, 0x00000707, 0);
+	write_register(device->hal_data->register_base_addr,
+			VIDC_VENUS_VBIF_ROUND_ROBIN_QOS_ARB, 0x00000001, 0);
+	write_register(device->hal_data->register_base_addr,
 			VIDC_VENUS0_WRAPPER_VBIF_REQ_PRIORITY, 0x5555556, 0);
+	write_register(device->hal_data->register_base_addr,
+			VIDC_VENUS0_WRAPPER_VBIF_PRIORITY_LEVEL, 0, 0);
 }
 
 static int vidc_hal_sys_set_debug(struct hal_device *device, int debug)
@@ -2230,7 +2236,7 @@
 		list_for_each_entry(close, &hal_ctxt.dev_head, list) {
 			if (close->hal_data->irq == dev->hal_data->irq) {
 				hal_ctxt.dev_count--;
-				free_irq(dev->hal_data->irq, NULL);
+				free_irq(dev->hal_data->irq, close);
 				list_del(&close->list);
 				destroy_workqueue(close->vidc_workq);
 				kfree(close->hal_data);
diff --git a/drivers/media/video/msm_vidc/vidc_hal_api.h b/drivers/media/video/msm_vidc/vidc_hal_api.h
index d3fa1d0..8aff5af 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_api.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_api.h
@@ -814,6 +814,7 @@
 	SYS_IDLE,
 	SYS_DEBUG,
 	SYS_WATCHDOG_TIMEOUT,
+	SYS_ERROR,
 /* SESSION COMMANDS_DONE */
 	SESSION_LOAD_RESOURCE_DONE,
 	SESSION_INIT_DONE,
@@ -833,6 +834,7 @@
 	SESSION_RELEASE_BUFFER_DONE,
 	SESSION_RELEASE_RESOURCE_DONE,
 	SESSION_PROPERTY_INFO,
+	SESSION_ERROR,
 	RESPONSE_UNUSED = 0x10000000,
 };
 
diff --git a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
index 7eb0ae1..ba599ec 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
+++ b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
@@ -146,6 +146,21 @@
 	cmd_done.device_id = device->device_id;
 	device->callback(SYS_WATCHDOG_TIMEOUT, &cmd_done);
 }
+static void hal_process_sys_error(struct hal_device *device)
+{
+	struct msm_vidc_cb_cmd_done cmd_done;
+	disable_irq_nosync(device->hal_data->irq);
+	memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
+	cmd_done.device_id = device->device_id;
+	device->callback(SYS_ERROR, &cmd_done);
+}
+static void hal_process_session_error(struct hal_device *device)
+{
+	struct msm_vidc_cb_cmd_done cmd_done;
+	memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
+	cmd_done.device_id = device->device_id;
+	device->callback(SESSION_ERROR, &cmd_done);
+}
 static void hal_process_event_notify(struct hal_device *device,
 	struct hfi_msg_event_notify_packet *pkt)
 {
@@ -160,10 +175,11 @@
 	switch (pkt->event_id) {
 	case HFI_EVENT_SYS_ERROR:
 		dprintk(VIDC_INFO, "HFI_EVENT_SYS_ERROR");
-		hal_process_sys_watchdog_timeout(device);
+		hal_process_sys_error(device);
 		break;
 	case HFI_EVENT_SESSION_ERROR:
 		dprintk(VIDC_INFO, "HFI_EVENT_SESSION_ERROR");
+		hal_process_session_error(device);
 		break;
 	case HFI_EVENT_SESSION_SEQUENCE_CHANGED:
 		dprintk(VIDC_INFO, "HFI_EVENT_SESSION_SEQUENCE_CHANGED");
diff --git a/drivers/media/video/msm_vidc/vidc_hal_io.h b/drivers/media/video/msm_vidc/vidc_hal_io.h
index b85e015..6845ac5 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_io.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_io.h
@@ -22,6 +22,12 @@
 
 #define VIDC_VBIF_BASE_OFFS			0x00080000
 #define VIDC_VBIF_VERSION			(VIDC_VBIF_BASE_OFFS + 0x00)
+#define VIDC_VENUS_VBIF_DDR_OUT_MAX_BURST		\
+			(VIDC_VBIF_BASE_OFFS + 0xD8)
+#define VIDC_VENUS_VBIF_OCMEM_OUT_MAX_BURST		\
+			(VIDC_VBIF_BASE_OFFS + 0xDC)
+#define VIDC_VENUS_VBIF_ROUND_ROBIN_QOS_ARB		\
+			(VIDC_VBIF_BASE_OFFS + 0x124)
 
 #define VIDC_CPU_BASE_OFFS			0x000C0000
 #define VIDC_CPU_CS_BASE_OFFS		(VIDC_CPU_BASE_OFFS + 0x00012000)
@@ -128,7 +134,5 @@
 	(VIDC_WRAPPER_BASE_OFFS + 0x20)
 #define VIDC_VENUS0_WRAPPER_VBIF_PRIORITY_LEVEL \
 	(VIDC_WRAPPER_BASE_OFFS + 0x24)
-#define VIDC_VENUS_VBIF_REQ_PRIORITY    (VIDC_WRAPPER_BASE_OFFS + 0x20)
-#define VIDC_VENUS_VBIF_PRIORITY_LEVEL  (VIDC_WRAPPER_BASE_OFFS + 0x24)
 
 #endif
diff --git a/drivers/media/video/msm_wfd/enc-mfc-subdev.c b/drivers/media/video/msm_wfd/enc-mfc-subdev.c
index 09a5e32..d839be3 100644
--- a/drivers/media/video/msm_wfd/enc-mfc-subdev.c
+++ b/drivers/media/video/msm_wfd/enc-mfc-subdev.c
@@ -194,6 +194,9 @@
 			break;
 		}
 
+		if (frame_data->flags & VCD_FRAME_FLAG_CODECCONFIG)
+			vbuf->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_CODECCONFIG;
+
 		vbuf->v4l2_buf.timestamp =
 			ns_to_timeval(frame_data->time_stamp * NSEC_PER_USEC);
 
@@ -1975,6 +1978,7 @@
 	unsigned long phy_addr;
 	int i = 0;
 	int heap_mask = 0;
+	u32 ion_flags = 0;
 	u32 len;
 	control.width = inst->width;
 	control.height = inst->height;
@@ -1988,7 +1992,8 @@
 		goto err;
 	}
 	heap_mask = ION_HEAP(ION_CP_MM_HEAP_ID);
-	heap_mask |= inst->secure ? ION_SECURE : ION_HEAP(ION_IOMMU_HEAP_ID);
+	heap_mask |= inst->secure ? 0 : ION_HEAP(ION_IOMMU_HEAP_ID);
+	ion_flags |= inst->secure ? ION_SECURE : 0;
 
 	if (vcd_get_ion_status()) {
 		for (i = 0; i < 4; ++i) {
@@ -1999,7 +2004,7 @@
 			ctrl->user_virtual_addr = (void *)i;
 			client_ctx->recon_buffer_ion_handle[i]
 				= ion_alloc(client_ctx->user_ion_client,
-			control.size, SZ_8K, heap_mask, 0);
+			control.size, SZ_8K, heap_mask, ion_flags);
 
 			ctrl->kernel_virtual_addr = ion_map_kernel(
 				client_ctx->user_ion_client,
diff --git a/drivers/media/video/msm_wfd/enc-venus-subdev.c b/drivers/media/video/msm_wfd/enc-venus-subdev.c
index 89ad6c7..150c667 100644
--- a/drivers/media/video/msm_wfd/enc-venus-subdev.c
+++ b/drivers/media/video/msm_wfd/enc-venus-subdev.c
@@ -178,7 +178,7 @@
 			rc = msm_vidc_dqbuf(inst->vidc_context, &buffer);
 
 			if (rc) {
-				WFD_MSG_ERR("Error dequeuing buffer" \
+				WFD_MSG_ERR("Error dequeuing buffer " \
 						"from vidc: %d", rc);
 				goto abort_dequeue;
 			}
@@ -1010,7 +1010,8 @@
 	inst = (struct venc_inst *)sd->dev_priv;
 
 	enc_cmd.cmd = V4L2_ENC_QCOM_CMD_FLUSH;
-	enc_cmd.flags = BUF_TYPE_INPUT | BUF_TYPE_OUTPUT;
+	enc_cmd.flags = V4L2_QCOM_CMD_FLUSH_OUTPUT |
+		V4L2_QCOM_CMD_FLUSH_CAPTURE;
 	msm_vidc_encoder_cmd(inst->vidc_context, &enc_cmd);
 
 	wait_for_completion(&inst->cmd_complete);
diff --git a/drivers/media/video/msm_wfd/wfd-ioctl.c b/drivers/media/video/msm_wfd/wfd-ioctl.c
index d8080dd..5f67a96 100644
--- a/drivers/media/video/msm_wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm_wfd/wfd-ioctl.c
@@ -155,13 +155,15 @@
 	struct ion_handle *handle = NULL;
 	void *kvaddr = NULL;
 	unsigned int alloc_regions = 0;
+	unsigned int ion_flags = 0;
 	int rc = 0;
 
 	alloc_regions = ION_HEAP(ION_CP_MM_HEAP_ID);
-	alloc_regions |= secure ? ION_SECURE :
+	alloc_regions |= secure ? 0 :
 				ION_HEAP(ION_IOMMU_HEAP_ID);
+	ion_flags |= secure ? ION_SECURE : 0;
 	handle = ion_alloc(client,
-			mregion->size, SZ_4K, alloc_regions, 0);
+			mregion->size, SZ_4K, alloc_regions, ion_flags);
 
 	if (IS_ERR_OR_NULL(handle)) {
 		WFD_MSG_ERR("Failed to allocate input buffer\n");
@@ -269,8 +271,9 @@
 			goto alloc_fail;
 		}
 
-		WFD_MSG_ERR("NOTE: enc paddr = %p, kvaddr = %p\n",
-				enc_mregion->paddr,
+		WFD_MSG_DBG("NOTE: enc paddr = [%p->%p], kvaddr = %p\n",
+				enc_mregion->paddr, (int8_t *)
+				enc_mregion->paddr + enc_mregion->size,
 				enc_mregion->kvaddr);
 
 		rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
diff --git a/drivers/media/video/msm_wfd/wfd-util.c b/drivers/media/video/msm_wfd/wfd-util.c
index 233668b0..5c00e5c 100644
--- a/drivers/media/video/msm_wfd/wfd-util.c
+++ b/drivers/media/video/msm_wfd/wfd-util.c
@@ -159,10 +159,10 @@
 	}
 	case WFD_STAT_EVENT_MDP_QUEUE:
 		stats->mdp_buf_count++;
-		stats->mdp_updates++;
 		break;
 	case WFD_STAT_EVENT_MDP_DEQUEUE:
 		stats->mdp_buf_count--;
+		stats->mdp_updates++;
 		break;
 	case WFD_STAT_EVENT_ENC_QUEUE: {
 		struct wfd_stats_encode_sample *sample = NULL;
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index 72a3f3b..f009e06 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -82,7 +82,7 @@
 
 static int vcap_reg_powerup(struct vcap_dev *dev)
 {
-	dev->fs_vcap = regulator_get(NULL, "fs_vcap");
+	dev->fs_vcap = regulator_get(dev->ddev, "fs_vcap");
 	if (IS_ERR(dev->fs_vcap)) {
 		pr_err("%s: Regulator FS_VCAP get failed %ld\n", __func__,
 			PTR_ERR(dev->fs_vcap));
@@ -569,6 +569,17 @@
 }
 
 /* VC Videobuf operations */
+static void wait_prepare(struct vb2_queue *q)
+{
+	struct vcap_client_data *c_data = vb2_get_drv_priv(q);
+	mutex_unlock(&c_data->mutex);
+}
+
+static void wait_finish(struct vb2_queue *q)
+{
+	struct vcap_client_data *c_data = vb2_get_drv_priv(q);
+	mutex_lock(&c_data->mutex);
+}
 
 static int capture_queue_setup(struct vb2_queue *vq,
 			       const struct v4l2_format *fmt,
@@ -651,6 +662,8 @@
 
 static struct vb2_ops capture_video_qops = {
 	.queue_setup		= capture_queue_setup,
+	.wait_finish		= wait_finish,
+	.wait_prepare		= wait_prepare,
 	.buf_init			= capture_buffer_init,
 	.buf_prepare		= capture_buffer_prepare,
 	.buf_queue			= capture_buffer_queue,
@@ -749,6 +762,8 @@
 
 static struct vb2_ops vp_in_video_qops = {
 	.queue_setup		= vp_in_queue_setup,
+	.wait_finish		= wait_finish,
+	.wait_prepare		= wait_prepare,
 	.buf_init			= vp_in_buffer_init,
 	.buf_prepare		= vp_in_buffer_prepare,
 	.buf_queue			= vp_in_buffer_queue,
@@ -847,6 +862,8 @@
 
 static struct vb2_ops vp_out_video_qops = {
 	.queue_setup		= vp_out_queue_setup,
+	.wait_finish		= wait_finish,
+	.wait_prepare		= wait_prepare,
 	.buf_init			= vp_out_buffer_init,
 	.buf_prepare		= vp_out_buffer_prepare,
 	.buf_queue			= vp_out_buffer_queue,
@@ -905,10 +922,15 @@
 	case VC_TYPE:
 		vc_format = (struct v4l2_format_vc_ext *) &priv_fmt->u.timing;
 		c_data->vc_format = *vc_format;
+		c_data->stride = priv_fmt->stride;
 
 		size = (c_data->vc_format.hactive_end -
 			c_data->vc_format.hactive_start);
-		size = VCAP_STRIDE_CALC(size);
+		if (c_data->stride == VC_STRIDE_32)
+			size = VCAP_STRIDE_CALC(size, VCAP_STRIDE_ALIGN_32);
+		else
+			size = VCAP_STRIDE_CALC(size, VCAP_STRIDE_ALIGN_16);
+
 
 		if (c_data->vc_format.color_space)
 			size *= 3;
@@ -1072,7 +1094,9 @@
 		rc = get_phys_addr(c_data->dev, &c_data->vc_vidq, p);
 		if (rc < 0)
 			return rc;
+		mutex_lock(&c_data->mutex);
 		rc = vb2_qbuf(&c_data->vc_vidq, p);
+		mutex_unlock(&c_data->mutex);
 		if (rc < 0)
 			free_ion_handle(c_data, &c_data->vc_vidq, p);
 		return rc;
@@ -1082,7 +1106,9 @@
 		rc = get_phys_addr(c_data->dev, &c_data->vp_in_vidq, p);
 		if (rc < 0)
 			return rc;
+		mutex_lock(&c_data->mutex);
 		rc = vb2_qbuf(&c_data->vp_in_vidq, p);
+		mutex_unlock(&c_data->mutex);
 		if (rc < 0)
 			free_ion_handle(c_data, &c_data->vp_in_vidq, p);
 		return rc;
@@ -1090,7 +1116,9 @@
 		rc = get_phys_addr(c_data->dev, &c_data->vp_out_vidq, p);
 		if (rc < 0)
 			return rc;
+		mutex_lock(&c_data->mutex);
 		rc = vb2_qbuf(&c_data->vp_out_vidq, p);
+		mutex_unlock(&c_data->mutex);
 		if (rc < 0)
 			free_ion_handle(c_data, &c_data->vp_out_vidq, p);
 		return rc;
@@ -1114,21 +1142,27 @@
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 		if (c_data->op_mode == VC_AND_VP_VCAP_OP)
 			return -EINVAL;
+		mutex_lock(&c_data->mutex);
 		rc = vb2_dqbuf(&c_data->vc_vidq, p, file->f_flags & O_NONBLOCK);
+		mutex_unlock(&c_data->mutex);
 		if (rc < 0)
 			return rc;
 		return free_ion_handle(c_data, &c_data->vc_vidq, p);
 	case V4L2_BUF_TYPE_INTERLACED_IN_DECODER:
 		if (c_data->op_mode == VC_AND_VP_VCAP_OP)
 			return -EINVAL;
+		mutex_lock(&c_data->mutex);
 		rc = vb2_dqbuf(&c_data->vp_in_vidq, p, file->f_flags &
 				O_NONBLOCK);
+		mutex_unlock(&c_data->mutex);
 		if (rc < 0)
 			return rc;
 		return free_ion_handle(c_data, &c_data->vp_in_vidq, p);
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		mutex_lock(&c_data->mutex);
 		rc = vb2_dqbuf(&c_data->vp_out_vidq, p, file->f_flags &
 				O_NONBLOCK);
+		mutex_unlock(&c_data->mutex);
 		if (rc < 0)
 			return rc;
 		return free_ion_handle(c_data, &c_data->vp_out_vidq, p);
@@ -1488,8 +1522,10 @@
 		dev->vc_resource = 0;
 		mutex_unlock(&dev->dev_mutex);
 		c_data->streaming = 0;
+		mutex_lock(&c_data->mutex);
 		rc = vb2_streamoff(&c_data->vc_vidq,
 				V4L2_BUF_TYPE_VIDEO_CAPTURE);
+		mutex_unlock(&c_data->mutex);
 		if (rc >= 0)
 			atomic_set(&c_data->dev->vc_enabled, 0);
 		return rc;
@@ -1515,14 +1551,18 @@
 			return rc;
 		c_data->streaming = 0;
 
+		mutex_unlock(&dev->dev_mutex);
 		/* These stream on calls should not fail */
 		rc = vb2_streamoff(&c_data->vp_in_vidq,
 				V4L2_BUF_TYPE_INTERLACED_IN_DECODER);
-		if (rc < 0)
+		if (rc < 0) {
+			mutex_unlock(&c_data->mutex);
 			return rc;
+		}
 
 		rc = vb2_streamoff(&c_data->vp_out_vidq,
 				V4L2_BUF_TYPE_VIDEO_OUTPUT);
+		mutex_unlock(&c_data->mutex);
 		if (rc < 0)
 			return rc;
 
@@ -1557,20 +1597,26 @@
 		if (rc < 0)
 			return rc;
 
-		/* These stream on calls should not fail */
 		c_data->streaming = 0;
+		mutex_lock(&c_data->mutex);
+		/* These stream on calls should not fail */
 		rc = vb2_streamoff(&c_data->vc_vidq,
 				V4L2_BUF_TYPE_VIDEO_CAPTURE);
-		if (rc < 0)
+		if (rc < 0) {
+			mutex_unlock(&c_data->mutex);
 			return rc;
+		}
 
 		rc = vb2_streamoff(&c_data->vp_in_vidq,
 				V4L2_BUF_TYPE_INTERLACED_IN_DECODER);
-		if (rc < 0)
+		if (rc < 0) {
+			mutex_unlock(&c_data->mutex);
 			return rc;
+		}
 
 		rc = vb2_streamoff(&c_data->vp_out_vidq,
 				V4L2_BUF_TYPE_VIDEO_OUTPUT);
+		mutex_unlock(&c_data->mutex);
 		if (rc < 0)
 			return rc;
 
@@ -1716,6 +1762,7 @@
 	c_data->dev = dev;
 
 	spin_lock_init(&c_data->cap_slock);
+	mutex_init(&c_data->mutex);
 
 	/* initialize vc queue */
 	q = &c_data->vc_vidq;
@@ -1799,6 +1846,7 @@
 vp_in_q_failed:
 	vb2_queue_release(&c_data->vc_vidq);
 vc_q_failed:
+	mutex_destroy(&c_data->mutex);
 	kfree(c_data);
 	return ret;
 }
@@ -1833,6 +1881,7 @@
 		c_data->dev->vc_client = NULL;
 	if (c_data->dev->vp_client == c_data)
 		c_data->dev->vp_client = NULL;
+	mutex_destroy(&c_data->mutex);
 	kfree(c_data);
 	return 0;
 }
@@ -2267,7 +2316,7 @@
 
 
 	ret = request_irq(dev->vcirq->start, vcap_vc_handler,
-		IRQF_TRIGGER_RISING, "vc_irq", 0);
+		IRQF_TRIGGER_HIGH, "vc_irq", 0);
 	if (ret < 0) {
 		pr_err("%s: vc irq request fail\n", __func__);
 		ret = -EBUSY;
diff --git a/drivers/media/video/vcap_vc.c b/drivers/media/video/vcap_vc.c
index f3c9362..642074f 100644
--- a/drivers/media/video/vcap_vc.c
+++ b/drivers/media/video/vcap_vc.c
@@ -37,7 +37,10 @@
 	} else {
 		int size = (c_data->vc_format.hactive_end -
 				c_data->vc_format.hactive_start);
-		size = VCAP_STRIDE_CALC(size);
+		if (c_data->stride == VC_STRIDE_32)
+			size = VCAP_STRIDE_CALC(size, VCAP_STRIDE_ALIGN_32);
+		else
+			size = VCAP_STRIDE_CALC(size, VCAP_STRIDE_ALIGN_16);
 		size *= (c_data->vc_format.vactive_end -
 				c_data->vc_format.vactive_start);
 		writel_relaxed(buf->paddr, y_addr);
@@ -126,28 +129,9 @@
 	return tv;
 }
 
-irqreturn_t vc_handler(struct vcap_dev *dev)
+inline void vc_isr_error_checking(struct vcap_dev *dev,
+		struct v4l2_event v4l2_evt, uint32_t irq)
 {
-	uint32_t irq, timestamp;
-	struct vcap_buffer *buf;
-	struct vb2_buffer *vb = NULL;
-	struct vcap_client_data *c_data;
-	struct v4l2_event v4l2_evt;
-	uint8_t i, idx, buf_num, tot, done_count = 0;
-	bool work_todo = false;
-
-	irq = readl_relaxed(VCAP_VC_INT_STATUS);
-
-	pr_debug("%s: irq=0x%08x\n", __func__, irq);
-
-	c_data = dev->vc_client;
-	if (!c_data->streaming) {
-		writel_iowmb(irq, VCAP_VC_INT_CLEAR);
-		pr_err("VC no longer streaming\n");
-		return IRQ_HANDLED;
-	}
-
-	v4l2_evt.id = 0;
 	if (irq & 0x8000200) {
 		writel_iowmb(0x00000102, VCAP_VC_NPL_CTRL);
 		v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
@@ -166,6 +150,12 @@
 			VCAP_VC_VSYNC_ERR_EVENT;
 		v4l2_event_queue(dev->vfd, &v4l2_evt);
 	}
+	if (irq & 0x00001000) {
+		writel_iowmb(0x00000102, VCAP_VC_NPL_CTRL);
+		v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
+			VCAP_VC_VSYNC_SEQ_ERR;
+		v4l2_event_queue(dev->vfd, &v4l2_evt);
+	}
 	if (irq & 0x00000800) {
 		writel_iowmb(0x00000102, VCAP_VC_NPL_CTRL);
 		v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
@@ -178,33 +168,26 @@
 			VCAP_VC_LBUF_OFLOW_ERR_EVENT;
 		v4l2_event_queue(dev->vfd, &v4l2_evt);
 	}
+}
 
-	if (!(irq & VC_BUFFER_MASK)) {
-		writel_relaxed(irq, VCAP_VC_INT_CLEAR);
-		pr_err("VC IRQ shows some error\n");
-		return IRQ_HANDLED;
-	}
-
-	if (dev->vc_client == NULL) {
-		/* This should never happen */
-		writel_relaxed(irq, VCAP_VC_INT_CLEAR);
-		pr_err("VC: There is no active vc client\n");
-		return IRQ_HANDLED;
-	}
-	c_data = dev->vc_client;
-
+inline uint8_t vc_isr_buffer_done_count(struct vcap_dev *dev,
+		struct vcap_client_data *c_data, uint32_t irq)
+{
+	int i;
+	uint8_t done_count = 0;
 	for (i = 0; i < VCAP_VC_MAX_BUF; i++) {
 		if (0x2 & (irq >> i))
 			done_count++;
 	}
+	return done_count;
+}
 
-	/* Assign field value in case somehow got out of sync */
-	if (c_data->vc_format.mode == HAL_VCAP_MODE_INT && done_count == 1)
-		c_data->vc_action.top_field = !(irq & 0x1);
-
+inline bool vc_isr_verify_expect_buf_rdy(struct vcap_dev *dev,
+		struct vcap_client_data *c_data, struct v4l2_event v4l2_evt,
+		uint32_t irq, uint8_t done_count, uint8_t tot, uint8_t buf_num)
+{
+	int i;
 	/* Double check expected buffers are done */
-	buf_num = c_data->vc_action.buf_num;
-	tot = c_data->vc_action.tot_buf;
 	for (i = 0; i < done_count; i++) {
 		if (!(irq & (0x1 << (((buf_num + i) % tot) + 1)))) {
 			v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
@@ -213,12 +196,17 @@
 			pr_debug("Unexpected buffer done\n");
 			c_data->vc_action.buf_num =
 				correct_buf_num(irq) % tot;
-			writel_relaxed(irq, VCAP_VC_INT_CLEAR);
-			return IRQ_HANDLED;
+			return true;
 		}
 	}
+	return false;
+}
 
-	/* If here we know which buffers are done */
+inline void vc_isr_update_timestamp(struct vcap_dev *dev,
+		struct vcap_client_data *c_data)
+{
+	uint32_t timestamp;
+
 	timestamp = readl_relaxed(VCAP_VC_TIMESTAMP);
 	if (timestamp < c_data->vc_action.last_ts) {
 		c_data->vc_action.vc_ts.tv_usec +=
@@ -234,65 +222,142 @@
 	c_data->vc_action.vc_ts.tv_usec =
 		c_data->vc_action.vc_ts.tv_usec % VCAP_USEC;
 	c_data->vc_action.last_ts = timestamp;
+}
 
-	c_data->vc_action.buf_num = (buf_num + done_count) % tot;
+inline void vc_isr_no_new_buffer(struct vcap_dev *dev,
+		struct vcap_client_data *c_data, struct v4l2_event v4l2_evt)
+{
+	v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
+		VCAP_VC_BUF_OVERWRITE_EVENT;
+	v4l2_event_queue(dev->vfd, &v4l2_evt);
+
+	c_data->vc_action.field_dropped =
+		!c_data->vc_action.field_dropped;
+
+	c_data->vc_action.field1 =
+		!c_data->vc_action.field1;
+	atomic_inc(&dev->dbg_p.vc_drop_count);
+}
+
+inline void vc_isr_switch_buffers(struct vcap_dev *dev,
+		struct vcap_client_data *c_data, struct vcap_buffer *buf,
+		struct vb2_buffer *vb, uint8_t idx, int done_count, int i)
+{
+	/* Config vc with this new buffer */
+	config_buffer(c_data, buf, VCAP_VC_Y_ADDR_1 + 0x8 * idx,
+			VCAP_VC_C_ADDR_1 + 0x8 * idx);
+	vb->v4l2_buf.timestamp = interpolate_ts(
+		c_data->vc_action.vc_ts,
+		1000000 / c_data->vc_format.frame_rate *
+		(done_count - 1 - i));
+	if (c_data->vc_format.mode == HAL_VCAP_MODE_INT) {
+		if (c_data->vc_action.field1)
+			vb->v4l2_buf.field = V4L2_FIELD_TOP;
+		else
+			vb->v4l2_buf.field = V4L2_FIELD_BOTTOM;
+
+		c_data->vc_action.field1 =
+			!c_data->vc_action.field1;
+	}
+	vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+	c_data->vc_action.buf[idx] = buf;
+}
+
+inline bool vc_isr_change_buffers(struct vcap_dev *dev,
+		struct vcap_client_data *c_data, struct v4l2_event v4l2_evt,
+		int done_count, uint8_t tot, uint8_t buf_num)
+{
+	struct vb2_buffer *vb = NULL;
+	struct vcap_buffer *buf;
+	bool schedule_work = false;
+	uint8_t idx;
+	int i;
+
 	for (i = 0; i < done_count; i++) {
 		idx = (buf_num + i) % tot;
 		vb = &c_data->vc_action.buf[idx]->vb;
 		spin_lock(&c_data->cap_slock);
 		if (list_empty(&c_data->vc_action.active)) {
 			spin_unlock(&c_data->cap_slock);
-			v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
-				VCAP_VC_BUF_OVERWRITE_EVENT;
-			v4l2_event_queue(dev->vfd, &v4l2_evt);
-			c_data->vc_action.top_field =
-				!c_data->vc_action.top_field;
-
-			if (c_data->vc_format.mode == HAL_VCAP_MODE_INT)
-				c_data->vc_action.field_dropped =
-					!c_data->vc_action.field_dropped;
-
-			atomic_inc(&dev->dbg_p.vc_drop_count);
+			vc_isr_no_new_buffer(dev, c_data, v4l2_evt);
 			continue;
 		}
 		if (c_data->vc_format.mode == HAL_VCAP_MODE_INT &&
 				c_data->vc_action.field_dropped) {
 			spin_unlock(&c_data->cap_slock);
-			c_data->vc_action.field_dropped =
-				!c_data->vc_action.field_dropped;
-			c_data->vc_action.top_field =
-				!c_data->vc_action.top_field;
-			atomic_inc(&dev->dbg_p.vc_drop_count);
+			vc_isr_no_new_buffer(dev, c_data, v4l2_evt);
 			continue;
 		}
 		buf = list_entry(c_data->vc_action.active.next,
 				struct vcap_buffer, list);
 		list_del(&buf->list);
 		spin_unlock(&c_data->cap_slock);
-		/* Config vc with this new buffer */
-		config_buffer(c_data, buf, VCAP_VC_Y_ADDR_1 + 0x8 * idx,
-				VCAP_VC_C_ADDR_1 + 0x8 * idx);
-		vb->v4l2_buf.timestamp = interpolate_ts(
-			c_data->vc_action.vc_ts,
-			1000000 / c_data->vc_format.frame_rate *
-			(done_count - 1 - i));
-		if (c_data->vc_format.mode == HAL_VCAP_MODE_INT) {
-			if (c_data->vc_action.top_field)
-				vb->v4l2_buf.field = V4L2_FIELD_TOP;
-			else
-				vb->v4l2_buf.field = V4L2_FIELD_BOTTOM;
-			c_data->vc_action.top_field =
-				!c_data->vc_action.top_field;
-		}
-		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
-		work_todo = true;
-		c_data->vc_action.buf[idx] = buf;
+		vc_isr_switch_buffers(dev, c_data, buf, vb, idx, done_count, i);
+		schedule_work = true;
+	}
+	return schedule_work;
+}
+
+irqreturn_t vc_handler(struct vcap_dev *dev)
+{
+	uint32_t irq;
+	struct vcap_client_data *c_data;
+	struct v4l2_event v4l2_evt;
+	uint8_t done_count = 0, buf_num, tot;
+	bool schedule_work = false;
+
+	v4l2_evt.id = 0;
+	irq = readl_relaxed(VCAP_VC_INT_STATUS);
+	writel_relaxed(irq, VCAP_VC_INT_CLEAR);
+
+	pr_debug("%s: irq=0x%08x\n", __func__, irq);
+
+	if (dev->vc_client == NULL) {
+		/* This should never happen */
+		pr_err("VC: There is no active vc client\n");
+		return IRQ_HANDLED;
 	}
 
-	if (work_todo && c_data->op_mode == VC_AND_VP_VCAP_OP)
+	c_data = dev->vc_client;
+	if (!c_data->streaming) {
+		pr_err("VC no longer streaming\n");
+		return IRQ_HANDLED;
+	}
+
+	if (irq == VC_VSYNC_MASK) {
+		if (c_data->vc_format.mode == HAL_VCAP_MODE_INT)
+			c_data->vc_action.field1 = irq & 0x1;
+		return IRQ_HANDLED;
+	}
+
+	if (irq & VC_ERR_MASK) {
+		vc_isr_error_checking(dev, v4l2_evt, irq);
+		return IRQ_HANDLED;
+	}
+
+	if (!(irq & VC_BUFFER_MASK)) {
+		pr_debug("No frames done\n");
+		return IRQ_HANDLED;
+	}
+
+	done_count = vc_isr_buffer_done_count(dev, c_data, irq);
+	buf_num = c_data->vc_action.buf_num;
+	tot = c_data->vc_action.tot_buf;
+
+	if (vc_isr_verify_expect_buf_rdy(dev, c_data,
+			v4l2_evt, irq, done_count, tot, buf_num))
+		return IRQ_HANDLED;
+
+	vc_isr_update_timestamp(dev, c_data);
+
+	c_data->vc_action.buf_num = (buf_num + done_count) % tot;
+
+	schedule_work = vc_isr_change_buffers(dev, c_data, v4l2_evt,
+		done_count, tot, buf_num);
+
+	if (schedule_work && c_data->op_mode == VC_AND_VP_VCAP_OP)
 		queue_work(dev->vcap_wq, &dev->vc_to_vp_work.work);
 
-	writel_relaxed(irq, VCAP_VC_INT_CLEAR);
 	return IRQ_HANDLED;
 }
 
@@ -362,6 +427,8 @@
 	rc = 0;
 	for (i = 0; i < c_data->vc_action.tot_buf; i++)
 		rc = rc << 1 | 0x2;
+	rc |= VC_ERR_MASK;
+	rc |= VC_VSYNC_MASK;
 	writel_relaxed(rc, VCAP_VC_INT_MASK);
 
 	enable_irq(dev->vcirq->start);
@@ -463,7 +530,10 @@
 	writel_iowmb(0x000033FF, VCAP_VC_BUF_CTRL);
 
 	rc = vc_format->hactive_end - vc_format->hactive_start;
-	rc = VCAP_STRIDE_CALC(rc);
+	if (c_data->stride == VC_STRIDE_32)
+		rc = VCAP_STRIDE_CALC(rc, VCAP_STRIDE_ALIGN_32);
+	else
+		rc = VCAP_STRIDE_CALC(rc, VCAP_STRIDE_ALIGN_16);
 	if (vc_format->color_space)
 		rc *= 3;
 
diff --git a/drivers/media/video/vcap_vc.h b/drivers/media/video/vcap_vc.h
index 7f42c7f..9c3f5a7 100644
--- a/drivers/media/video/vcap_vc.h
+++ b/drivers/media/video/vcap_vc.h
@@ -63,6 +63,8 @@
 
 #define VC_BUFFER_WRITTEN (0x3 << 1)
 #define VC_BUFFER_MASK 0x7E
+#define VC_ERR_MASK 0xE0001E00
+#define VC_VSYNC_MASK 0x1
 
 int vc_start_capture(struct vcap_client_data *c_data);
 int vc_hw_kick_off(struct vcap_client_data *c_data);
diff --git a/drivers/media/video/vcap_vp.c b/drivers/media/video/vcap_vp.c
index 57813f5..82f9e58 100644
--- a/drivers/media/video/vcap_vp.c
+++ b/drivers/media/video/vcap_vp.c
@@ -267,7 +267,7 @@
 	}
 
 	/* Config VP */
-	if (vp_act->bufT2->vb.v4l2_buf.field == V4L2_FIELD_TOP)
+	if (vp_act->bufT2->vb.v4l2_buf.field == V4L2_FIELD_BOTTOM)
 		top_field = 1;
 
 	writel_iowmb(0x00000000 | top_field, VCAP_VP_CTRL);
@@ -832,7 +832,7 @@
 			chroma_fmt << 11 | 0x1 << 4, VCAP_VP_OUT_CONFIG);
 
 	/* Enable Interrupt */
-	if (vp_act->bufT2->vb.v4l2_buf.field == V4L2_FIELD_TOP)
+	if (vp_act->bufT2->vb.v4l2_buf.field == V4L2_FIELD_BOTTOM)
 		top_field = 1;
 	vp_act->vp_state = VP_FRAME2;
 	writel_relaxed(0x01100001, VCAP_VP_INTERRUPT_ENABLE);
@@ -875,7 +875,7 @@
 	if (rc < 0)
 		return rc;
 
-	if (vp_act->bufT2->vb.v4l2_buf.field == V4L2_FIELD_TOP)
+	if (vp_act->bufT2->vb.v4l2_buf.field == V4L2_FIELD_BOTTOM)
 		top_field = 1;
 
 	/* Config VP & Enable Interrupt */
diff --git a/drivers/mfd/marimba-core.c b/drivers/mfd/marimba-core.c
index 6a8ea6e..26f3ece 100644
--- a/drivers/mfd/marimba-core.c
+++ b/drivers/mfd/marimba-core.c
@@ -173,13 +173,14 @@
 	u8 data[num_bytes + 1];
 	u8 mask_value[num_bytes];
 
+	memset(mask_value, 0, sizeof(mask_value));
+
 	marimba = &marimba_modules[marimba->mod_id];
 	if (marimba == NULL) {
 		pr_err("%s: Unable to access Marimba core\n", __func__);
 		return -ENODEV;
 	}
 
-
 	mutex_lock(&marimba->xfer_lock);
 
 	for (i = 0; i < num_bytes; i++)
@@ -619,7 +620,7 @@
 static int __devinit marimba_dbg_init(int adie_type)
 {
 	struct adie_dbg_device *dbgdev;
-	struct dentry *dent;
+	struct dentry *dent = NULL;
 	struct dentry *temp;
 
 	dbgdev = kzalloc(sizeof *dbgdev, GFP_KERNEL);
@@ -856,8 +857,7 @@
 			ssbi_adap = NULL;
 
 		if (!marimba->client) {
-			dev_err(&marimba->client->dev,
-				"can't attach client %d\n", i);
+			pr_err("can't attach client %d\n", i);
 			status = -ENOMEM;
 			goto fail;
 		}
diff --git a/drivers/mfd/pm8038-core.c b/drivers/mfd/pm8038-core.c
index 48bc92d..4996279 100644
--- a/drivers/mfd/pm8038-core.c
+++ b/drivers/mfd/pm8038-core.c
@@ -373,6 +373,11 @@
 	.num_resources	= ARRAY_SIZE(ccadc_cell_resources),
 };
 
+static struct mfd_cell vibrator_cell __devinitdata = {
+	.name           = PM8XXX_VIBRATOR_DEV_NAME,
+	.id             = -1,
+};
+
 static struct pm8xxx_vreg regulator_data[] = {
 	/*   name	     pc_name	    ctrl   test   hpm_min */
 	NLDO1200("8038_l1",		    0x0AE, 0x0AF, LDO_1200),
@@ -609,6 +614,17 @@
 		}
 	}
 
+	if (pdata->vibrator_pdata) {
+		vibrator_cell.platform_data = pdata->vibrator_pdata;
+		vibrator_cell.pdata_size =
+			sizeof(struct pm8xxx_vibrator_platform_data);
+		ret = mfd_add_devices(pmic->dev, 0, &vibrator_cell, 1, NULL, 0);
+		if (ret) {
+			pr_err("Failed to add vibrator ret=%d\n", ret);
+			goto bail;
+		}
+	}
+
 	if (pdata->spk_pdata) {
 		spk_cell.platform_data = pdata->spk_pdata;
 		spk_cell.pdata_size = sizeof(struct pm8xxx_spk_platform_data);
diff --git a/drivers/mfd/pm8xxx-spk.c b/drivers/mfd/pm8xxx-spk.c
index 8ba7372..4366717 100644
--- a/drivers/mfd/pm8xxx-spk.c
+++ b/drivers/mfd/pm8xxx-spk.c
@@ -118,8 +118,6 @@
 	}
 
 	val = pm8xxx_spk_read(PM8XXX_SPK_CTL1_REG_OFF);
-	if (val < 0)
-		return val;
 	val |= mute << 2;
 	ret = pm8xxx_spk_write(PM8XXX_SPK_CTL1_REG_OFF, val);
 	return ret;
@@ -137,8 +135,6 @@
 	}
 
 	val = pm8xxx_spk_read(PM8XXX_SPK_CTL1_REG_OFF);
-	if (val < 0)
-		return val;
 	val = (gain << 4) | (val & 0xF);
 	ret = pm8xxx_spk_write(PM8XXX_SPK_CTL1_REG_OFF, val);
 	if (!ret) {
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index a8e40f7..1f7b67a 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -550,6 +550,13 @@
 	}
 
 	wcd9xxx->num_of_supplies = 0;
+
+	if (ARRAY_SIZE(pdata->regulator) > MAX_REGULATOR) {
+		pr_err("%s: Array Size out of bound\n", __func__);
+		ret = -EINVAL;
+		goto err;
+	}
+
 	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
 		if (pdata->regulator[i].name) {
 			wcd9xxx->supplies[i].supply = pdata->regulator[i].name;
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index 7d1fdf0..23e0fcc 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -56,6 +56,12 @@
 	struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
 	int i;
 
+	if (ARRAY_SIZE(wcd9xxx->irq_masks_cur) > WCD9XXX_NUM_IRQ_REGS ||
+		ARRAY_SIZE(wcd9xxx->irq_masks_cache) > WCD9XXX_NUM_IRQ_REGS) {
+			pr_err("%s: Array Size out of bound\n", __func__);
+			 return;
+	}
+
 	for (i = 0; i < ARRAY_SIZE(wcd9xxx->irq_masks_cur); i++) {
 		/* If there's been a change in the mask write it back
 		 * to the hardware.
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 12f896e..1972845 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1,6 +1,6 @@
 
 
-/* Qualcomm Secure Execution Environment Communicator (QSEECOM) driver
+/*Qualcomm Secure Execution Environment Communicator (QSEECOM) driver
  *
  * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
  *
@@ -32,19 +32,27 @@
 #include <linux/types.h>
 #include <linux/clk.h>
 #include <linux/qseecom.h>
+#include <linux/elf.h>
+#include <linux/firmware.h>
 #include <linux/freezer.h>
 #include <mach/board.h>
 #include <mach/msm_bus.h>
 #include <mach/msm_bus_board.h>
 #include <mach/scm.h>
-#include <mach/peripheral-loader.h>
+#include <mach/subsystem_restart.h>
 #include <mach/socinfo.h>
 #include "qseecom_legacy.h"
+#include "qseecom_kernel.h"
 
 #define QSEECOM_DEV			"qseecom"
 #define QSEOS_VERSION_13		0x13
 #define QSEOS_VERSION_14		0x14
-#define QSEOS_CHECK_VERSION_CMD		0x00001803;
+#define QSEEE_VERSION_00		0x400000
+
+#define QSEOS_CHECK_VERSION_CMD		0x00001803
+
+#define QSEE_CE_CLK_100MHZ		100000000
+#define QSEE_CE_CLK_50MHZ		50000000
 
 enum qseecom_command_scm_resp_type {
 	QSEOS_APP_ID = 0xEE01,
@@ -61,6 +69,9 @@
 	QSEOS_LISTENER_DATA_RSP_COMMAND,
 	QSEOS_LOAD_EXTERNAL_ELF_COMMAND,
 	QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND,
+	QSEOS_GET_APP_STATE_COMMAND,
+	QSEOS_LOAD_SERV_IMAGE_COMMAND,
+	QSEOS_UNLOAD_SERV_IMAGE_COMMAND,
 	QSEOS_CMD_MAX     = 0xEFFFFFFF
 };
 
@@ -93,6 +104,17 @@
 	uint32_t  app_id;
 };
 
+__packed struct qseecom_load_lib_image_ireq {
+	uint32_t qsee_cmd_id;
+	uint32_t mdt_len;
+	uint32_t img_len;
+	uint32_t phy_addr;
+};
+
+__packed struct qseecom_unload_lib_image_ireq {
+	uint32_t qsee_cmd_id;
+};
+
 __packed struct qseecom_register_listener_ireq {
 	uint32_t qsee_cmd_id;
 	uint32_t listener_id;
@@ -168,6 +190,11 @@
 	u32  ref_cnt;
 };
 
+struct qseecom_registered_kclient_list {
+	struct list_head list;
+	struct qseecom_handle *handle;
+};
+
 struct qseecom_control {
 	struct ion_client *ion_clnt;		/* Ion client */
 	struct list_head  registered_listener_list_head;
@@ -176,11 +203,16 @@
 	struct list_head  registered_app_list_head;
 	spinlock_t        registered_app_list_lock;
 
+	struct list_head   registered_kclient_list_head;
+	spinlock_t        registered_kclient_list_lock;
+
 	wait_queue_head_t send_resp_wq;
 	int               send_resp_flag;
 
 	uint32_t          qseos_version;
+	uint32_t          qsee_version;
 	struct device *pdev;
+	bool  commonlib_loaded;
 };
 
 struct qseecom_client_handle {
@@ -218,8 +250,6 @@
 /* Function proto types */
 static int qsee_vote_for_clock(int32_t);
 static void qsee_disable_clock_vote(int32_t);
-static int __qseecom_init_clk(void);
-static void __qseecom_disable_clk(void);
 
 static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data,
 		struct qseecom_register_listener_req *svc)
@@ -642,7 +672,6 @@
 	ion_phys_addr_t pa = 0;
 	uint32_t len;
 	struct qseecom_command_scm_resp resp;
-	struct qseecom_check_app_ireq req;
 	struct qseecom_load_app_ireq load_req;
 
 	/* Copy the relevant information needed for loading the image */
@@ -657,11 +686,8 @@
 	if (ret)
 		pr_warning("Unable to vote for SFPB clock");
 
-	req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
-	memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
-
 	pr_warn("App (%s) does not exist, loading apps for first time\n",
-			(char *)(req.app_name));
+			(char *)(load_img_req.img_name));
 	/* Get the handle of the shared fd */
 	ihandle = ion_import_dma_buf(qseecom.ion_clnt,
 					load_img_req.ifd_data_fd);
@@ -675,6 +701,7 @@
 	ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &len);
 
 	/* Populate the structure for sending scm call to load image */
+	memcpy(load_req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
 	load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
 	load_req.mdt_len = load_img_req.mdt_len;
 	load_req.img_len = load_img_req.img_len;
@@ -738,7 +765,7 @@
 	spin_unlock_irqrestore(&qseecom.registered_app_list_lock, flags);
 
 	pr_warn("App with id %d (%s) now loaded\n", app_id,
-		(char *)(req.app_name));
+		(char *)(load_img_req.img_name));
 
 	data->client.app_id = app_id;
 	load_img_req.app_id = app_id;
@@ -1171,6 +1198,503 @@
 	return ret;
 }
 
+static bool __qseecom_is_fw_image_valid(const struct firmware *fw_entry)
+{
+	struct elf32_hdr *ehdr;
+
+	if (fw_entry->size < sizeof(*ehdr)) {
+		pr_err("%s: Not big enough to be an elf header\n",
+				 qseecom.pdev->init_name);
+		return false;
+	}
+	ehdr = (struct elf32_hdr *)fw_entry->data;
+	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
+		pr_err("%s: Not an elf header\n",
+				 qseecom.pdev->init_name);
+		return false;
+	}
+
+	if (ehdr->e_phnum == 0) {
+		pr_err("%s: No loadable segments\n",
+				 qseecom.pdev->init_name);
+		return false;
+	}
+	if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
+	    sizeof(struct elf32_hdr) > fw_entry->size) {
+		pr_err("%s: Program headers not within mdt\n",
+				 qseecom.pdev->init_name);
+		return false;
+	}
+	return true;
+}
+
+static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size)
+{
+	int ret = -1;
+	int i = 0, rc = 0;
+	const struct firmware *fw_entry = NULL;
+	struct elf32_phdr *phdr;
+	char fw_name[MAX_APP_NAME_SIZE];
+	struct elf32_hdr *ehdr;
+	int num_images = 0;
+
+	snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
+	rc = request_firmware(&fw_entry, fw_name,  qseecom.pdev);
+	if (rc) {
+		pr_err("error with request_firmware\n");
+		ret = -EIO;
+		goto err;
+	}
+	if (!__qseecom_is_fw_image_valid(fw_entry)) {
+		ret = -EIO;
+		goto err;
+	}
+	*fw_size = fw_entry->size;
+	phdr = (struct elf32_phdr *)(fw_entry->data + sizeof(struct elf32_hdr));
+	ehdr = (struct elf32_hdr *)fw_entry->data;
+	num_images = ehdr->e_phnum;
+	release_firmware(fw_entry);
+	for (i = 0; i < num_images; i++, phdr++) {
+		memset(fw_name, 0, sizeof(fw_name));
+		snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
+		ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
+		if (ret)
+			goto err;
+		*fw_size += fw_entry->size;
+		release_firmware(fw_entry);
+	}
+	return ret;
+err:
+	if (fw_entry)
+		release_firmware(fw_entry);
+	*fw_size = 0;
+	return ret;
+}
+
+static int __qseecom_get_fw_data(char *appname, u8 *img_data,
+					struct qseecom_load_app_ireq *load_req)
+{
+	int ret = -1;
+	int i = 0, rc = 0;
+	const struct firmware *fw_entry = NULL;
+	char fw_name[MAX_APP_NAME_SIZE];
+	u8 *img_data_ptr = img_data;
+	struct elf32_hdr *ehdr;
+	int num_images = 0;
+
+	snprintf(fw_name, sizeof(fw_name), "%s.mdt", appname);
+	rc = request_firmware(&fw_entry, fw_name,  qseecom.pdev);
+	if (rc) {
+		ret = -EIO;
+		goto err;
+	}
+	load_req->img_len = fw_entry->size;
+	memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
+	img_data_ptr = img_data_ptr + fw_entry->size;
+	load_req->mdt_len = fw_entry->size; /*Get MDT LEN*/
+	ehdr = (struct elf32_hdr *)fw_entry->data;
+	num_images = ehdr->e_phnum;
+	release_firmware(fw_entry);
+	for (i = 0; i < num_images; i++) {
+		snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
+		ret = request_firmware(&fw_entry, fw_name,  qseecom.pdev);
+		if (ret) {
+			pr_err("Failed to locate blob %s\n", fw_name);
+			goto err;
+		}
+		memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
+		img_data_ptr = img_data_ptr + fw_entry->size;
+		load_req->img_len += fw_entry->size;
+		release_firmware(fw_entry);
+	}
+	load_req->phy_addr = virt_to_phys(img_data);
+	return ret;
+err:
+	release_firmware(fw_entry);
+	return ret;
+}
+
+static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname)
+{
+	int ret = -1;
+	uint32_t fw_size = 0;
+	struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
+	struct qseecom_command_scm_resp resp;
+	u8 *img_data = NULL;
+
+	if (__qseecom_get_fw_size(appname, &fw_size))
+		return -EIO;
+
+	img_data = kzalloc(fw_size, GFP_KERNEL);
+	if (!img_data) {
+		pr_err("Failied to allocate memory for copying image data\n");
+		return -ENOMEM;
+	}
+	ret = __qseecom_get_fw_data(appname, img_data, &load_req);
+	if (ret) {
+		kzfree(img_data);
+		return -EIO;
+	}
+
+	/* Populate the remaining parameters */
+	load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
+	memcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
+	mutex_lock(&app_access_lock);
+	ret = qsee_vote_for_clock(CLK_SFPB);
+	if (ret) {
+		kzfree(img_data);
+		pr_warning("Unable to vote for SFPB clock");
+		mutex_unlock(&app_access_lock);
+		return -EIO;
+	}
+
+	/* SCM_CALL to load the image */
+	ret = scm_call(SCM_SVC_TZSCHEDULER, 1,	&load_req,
+			sizeof(struct qseecom_load_app_ireq),
+			&resp, sizeof(resp));
+	kzfree(img_data);
+	if (ret) {
+		pr_err("scm_call to load failed : ret %d\n", ret);
+		qsee_disable_clock_vote(CLK_SFPB);
+		mutex_unlock(&app_access_lock);
+		return -EIO;
+	}
+
+	switch (resp.result) {
+	case QSEOS_RESULT_SUCCESS:
+		ret = resp.data;
+		break;
+	case QSEOS_RESULT_INCOMPLETE:
+		ret = __qseecom_process_incomplete_cmd(data, &resp);
+		if (ret)
+			pr_err("process_incomplete_cmd FAILED\n");
+		else
+			ret = resp.data;
+		break;
+	case QSEOS_RESULT_FAILURE:
+		pr_err("scm call failed with response QSEOS_RESULT FAILURE\n");
+		break;
+	default:
+		pr_err("scm call return unknown response %d\n", resp.result);
+		ret = -EINVAL;
+		break;
+	}
+	qsee_disable_clock_vote(CLK_SFPB);
+	mutex_unlock(&app_access_lock);
+
+	return ret;
+}
+
+static int qseecom_load_commonlib_image(void)
+{
+	int32_t ret = 0;
+	uint32_t fw_size = 0;
+	struct qseecom_load_app_ireq load_req = {0, 0, 0, 0};
+	struct qseecom_command_scm_resp resp;
+	u8 *img_data = NULL;
+
+	if (__qseecom_get_fw_size("commonlib", &fw_size))
+		return -EIO;
+
+	img_data = kzalloc(fw_size, GFP_KERNEL);
+	if (!img_data) {
+		pr_err("Mem allocation for lib image data failed\n");
+		return -ENOMEM;
+	}
+	ret = __qseecom_get_fw_data("commonlib", img_data, &load_req);
+	if (ret) {
+		kzfree(img_data);
+		return -EIO;
+	}
+	/* Populate the remaining parameters */
+	load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
+	/* SCM_CALL to load the image */
+	ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
+				sizeof(struct qseecom_load_lib_image_ireq),
+							&resp, sizeof(resp));
+	kzfree(img_data);
+	if (ret) {
+		pr_err("scm_call to load failed : ret %d\n", ret);
+		ret = -EIO;
+	} else {
+		switch (resp.result) {
+		case QSEOS_RESULT_SUCCESS:
+			break;
+		case QSEOS_RESULT_FAILURE:
+			pr_err("scm call failed w/response result%d\n",
+						resp.result);
+			ret = -EINVAL;
+			break;
+		default:
+			pr_err("scm call return unknown response %d\n",
+						resp.result);
+			ret = -EINVAL;
+			break;
+		}
+	}
+	return ret;
+}
+
+static int qseecom_unload_commonlib_image(void)
+{
+	int ret = -EINVAL;
+	struct qseecom_unload_lib_image_ireq unload_req = {0};
+	struct qseecom_command_scm_resp resp;
+
+	/* Populate the remaining parameters */
+	unload_req.qsee_cmd_id = QSEOS_UNLOAD_SERV_IMAGE_COMMAND;
+	/* SCM_CALL to load the image */
+	ret = scm_call(SCM_SVC_TZSCHEDULER, 1,	&unload_req,
+			sizeof(struct qseecom_unload_lib_image_ireq),
+						&resp, sizeof(resp));
+	if (ret) {
+		pr_err("scm_call to unload lib failed : ret %d\n", ret);
+		ret = -EIO;
+	} else {
+		switch (resp.result) {
+		case QSEOS_RESULT_SUCCESS:
+			break;
+		case QSEOS_RESULT_FAILURE:
+			pr_err("scm fail resp.result QSEOS_RESULT FAILURE\n");
+			break;
+		default:
+			pr_err("scm call return unknown response %d\n",
+					resp.result);
+			ret = -EINVAL;
+			break;
+		}
+	}
+	return ret;
+}
+
+int qseecom_start_app(struct qseecom_handle **handle,
+						char *app_name, uint32_t size)
+{
+	int32_t ret = 0;
+	unsigned long flags = 0;
+	struct qseecom_dev_handle *data = NULL;
+	struct qseecom_check_app_ireq app_ireq;
+	struct qseecom_registered_app_list *entry = NULL;
+	struct qseecom_registered_kclient_list *kclient_entry = NULL;
+	bool found_app = false;
+	uint32_t len;
+	ion_phys_addr_t pa;
+
+	if (qseecom.qseos_version == QSEOS_VERSION_13) {
+		pr_err("This functionality is UNSUPPORTED in version 1.3\n");
+		return -EINVAL;
+	}
+
+	if (qseecom.qsee_version > QSEEE_VERSION_00) {
+		mutex_lock(&app_access_lock);
+		if (qseecom.commonlib_loaded == false) {
+			ret = qseecom_load_commonlib_image();
+			if (ret == 0)
+				qseecom.commonlib_loaded = true;
+		}
+		mutex_unlock(&app_access_lock);
+	}
+
+	if (ret)
+		return -EIO;
+
+	*handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
+	if (!(*handle)) {
+		pr_err("failed to allocate memory for kernel client handle\n");
+		return -ENOMEM;
+	}
+
+	app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
+	memcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE);
+	ret = __qseecom_check_app_exists(app_ireq);
+	if (ret < 0)
+		return -EINVAL;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		pr_err("kmalloc failed\n");
+		if (ret == 0) {
+			kfree(*handle);
+			*handle = NULL;
+		}
+		return -ENOMEM;
+	}
+	data->abort = 0;
+	data->service = false;
+	data->released = false;
+	data->client.app_id = ret;
+	data->client.sb_length = size;
+	data->client.user_virt_sb_base = 0;
+	data->client.ihandle = NULL;
+
+	init_waitqueue_head(&data->abort_wq);
+	atomic_set(&data->ioctl_count, 0);
+
+	data->client.ihandle = ion_alloc(qseecom.ion_clnt, size, 4096,
+				ION_HEAP(ION_QSECOM_HEAP_ID), 0);
+	if (IS_ERR_OR_NULL(data->client.ihandle)) {
+		pr_err("Ion client could not retrieve the handle\n");
+		kfree(data);
+		kfree(*handle);
+		*handle = NULL;
+		return -EINVAL;
+	}
+
+	if (ret > 0) {
+		pr_warn("App id %d for [%s] app exists\n", ret,
+			(char *)app_ireq.app_name);
+		spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
+		list_for_each_entry(entry,
+				&qseecom.registered_app_list_head, list){
+			if (entry->app_id == ret) {
+				entry->ref_cnt++;
+				found_app = true;
+				break;
+			}
+		}
+		spin_unlock_irqrestore(
+				&qseecom.registered_app_list_lock, flags);
+		if (!found_app)
+			pr_warn("App_id %d [%s] was loaded but not registered\n",
+					ret, (char *)app_ireq.app_name);
+	} else {
+		/* load the app and get the app_id  */
+		pr_debug("%s: Loading app for the first time'\n",
+				qseecom.pdev->init_name);
+		mutex_lock(&app_access_lock);
+		ret = __qseecom_load_fw(data, app_name);
+		mutex_unlock(&app_access_lock);
+
+		if (ret < 0) {
+			kfree(*handle);
+			*handle = NULL;
+			return ret;
+		}
+		data->client.app_id = ret;
+	}
+	if (!found_app) {
+		entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+		if (!entry) {
+			pr_err("kmalloc failed\n");
+			return -ENOMEM;
+		}
+		entry->app_id = ret;
+		entry->ref_cnt = 1;
+
+		spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
+		list_add_tail(&entry->list, &qseecom.registered_app_list_head);
+		spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
+									flags);
+	}
+
+	/* Get the physical address of the ION BUF */
+	ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
+	/* Populate the structure for sending scm call to load image */
+	data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
+							data->client.ihandle);
+	data->client.sb_phys = pa;
+	(*handle)->dev = (void *)data;
+	(*handle)->sbuf = (unsigned char *)data->client.sb_virt;
+	(*handle)->sbuf_len = data->client.sb_length;
+
+	kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL);
+	if (!kclient_entry) {
+		pr_err("kmalloc failed\n");
+		return -ENOMEM;
+	}
+	kclient_entry->handle = *handle;
+
+	spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
+	list_add_tail(&kclient_entry->list,
+			&qseecom.registered_kclient_list_head);
+	spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(qseecom_start_app);
+
+int qseecom_shutdown_app(struct qseecom_handle **handle)
+{
+	int ret = -EINVAL;
+	struct qseecom_dev_handle *data =
+			(struct qseecom_dev_handle *) ((*handle)->dev);
+	struct qseecom_registered_kclient_list *kclient = NULL;
+	unsigned long flags = 0;
+	bool found_handle = false;
+
+	if (qseecom.qseos_version == QSEOS_VERSION_13) {
+		pr_err("This functionality is UNSUPPORTED in version 1.3\n");
+		return -EINVAL;
+	}
+	if (*handle == NULL) {
+		pr_err("Handle is not initialized\n");
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
+	list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
+				list) {
+		if (kclient->handle == (*handle)) {
+			list_del(&kclient->list);
+			found_handle = true;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
+	if (!found_handle)
+		pr_err("Unable to find the handle, exiting\n");
+	else
+		ret = qseecom_unload_app(data);
+	if (ret == 0) {
+		kzfree(data);
+		kzfree(*handle);
+		kzfree(kclient);
+		*handle = NULL;
+	}
+	return ret;
+}
+EXPORT_SYMBOL(qseecom_shutdown_app);
+
+int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
+			uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len)
+{
+	int ret = 0;
+	struct qseecom_send_cmd_req req = {0, 0, 0, 0};
+	struct qseecom_dev_handle *data;
+
+	if (qseecom.qseos_version == QSEOS_VERSION_13) {
+		pr_err("This functionality is UNSUPPORTED in version 1.3\n");
+		return -EINVAL;
+	}
+
+	if (handle == NULL) {
+		pr_err("Handle is not initialized\n");
+		return -EINVAL;
+	}
+	data = handle->dev;
+
+	req.cmd_req_len = sbuf_len;
+	req.resp_len = rbuf_len;
+	req.cmd_req_buf = send_buf;
+	req.resp_buf = resp_buf;
+
+	mutex_lock(&app_access_lock);
+	atomic_inc(&data->ioctl_count);
+
+	ret = __qseecom_send_cmd(data, &req);
+
+	atomic_dec(&data->ioctl_count);
+	mutex_unlock(&app_access_lock);
+
+	if (ret)
+		return ret;
+
+	pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
+			req.resp_len, req.resp_buf);
+	return ret;
+}
+EXPORT_SYMBOL(qseecom_send_command);
+
 static int qseecom_send_resp(void)
 {
 	qseecom.send_resp_flag = 1;
@@ -1209,9 +1733,13 @@
 			if (qsee_sfpb_bw_count > 0)
 				ret = msm_bus_scale_client_update_request(
 						qsee_perf_client, 3);
-			else
+			else {
+				if (ce_core_src_clk != NULL)
+					clk_set_rate(ce_core_src_clk,
+							QSEE_CE_CLK_100MHZ);
 				ret = msm_bus_scale_client_update_request(
 						qsee_perf_client, 1);
+			}
 			if (ret)
 				pr_err("DFAB Bandwidth req failed (%d)\n",
 								ret);
@@ -1228,9 +1756,13 @@
 			if (qsee_bw_count > 0)
 				ret = msm_bus_scale_client_update_request(
 						qsee_perf_client, 3);
-			else
+			else {
+				if (ce_core_src_clk != NULL)
+					clk_set_rate(ce_core_src_clk,
+							QSEE_CE_CLK_100MHZ);
 				ret = msm_bus_scale_client_update_request(
 						qsee_perf_client, 2);
+			}
 
 			if (ret)
 				pr_err("SFPB Bandwidth req failed (%d)\n",
@@ -1269,9 +1801,13 @@
 			if (qsee_sfpb_bw_count > 0)
 				ret = msm_bus_scale_client_update_request(
 						qsee_perf_client, 2);
-			else
+			else {
 				ret = msm_bus_scale_client_update_request(
 						qsee_perf_client, 0);
+				if (ce_core_src_clk != NULL)
+					clk_set_rate(ce_core_src_clk,
+							QSEE_CE_CLK_50MHZ);
+			}
 			if (ret)
 				pr_err("SFPB Bandwidth req fail (%d)\n",
 								ret);
@@ -1289,9 +1825,13 @@
 			if (qsee_bw_count > 0)
 				ret = msm_bus_scale_client_update_request(
 						qsee_perf_client, 1);
-			else
+			else {
 				ret = msm_bus_scale_client_update_request(
 						qsee_perf_client, 0);
+				if (ce_core_src_clk != NULL)
+					clk_set_rate(ce_core_src_clk,
+							QSEE_CE_CLK_50MHZ);
+			}
 			if (ret)
 				pr_err("SFPB Bandwidth req fail (%d)\n",
 								ret);
@@ -1588,7 +2128,15 @@
 	case QSEECOM_IOCTL_LOAD_APP_REQ: {
 		mutex_lock(&app_access_lock);
 		atomic_inc(&data->ioctl_count);
-		ret = qseecom_load_app(data, argp);
+		if (qseecom.qsee_version > QSEEE_VERSION_00) {
+			if (qseecom.commonlib_loaded == false) {
+				ret = qseecom_load_commonlib_image();
+				if (ret == 0)
+					qseecom.commonlib_loaded = true;
+			}
+		}
+		if (ret == 0)
+			ret = qseecom_load_app(data, argp);
 		atomic_dec(&data->ioctl_count);
 		mutex_unlock(&app_access_lock);
 		if (ret)
@@ -1693,7 +2241,7 @@
 		int pil_error;
 		mutex_lock(&pil_access_lock);
 		if (pil_ref_cnt == 0) {
-			pil = pil_get("tzapps");
+			pil = subsystem_get("tzapps");
 			if (IS_ERR(pil)) {
 				pr_err("Playready PIL image load failed\n");
 				pil_error = PTR_ERR(pil);
@@ -1728,7 +2276,7 @@
 	if (qseecom.qseos_version == QSEOS_VERSION_13) {
 		mutex_lock(&pil_access_lock);
 		if (pil_ref_cnt == 1)
-			pil_put(pil);
+			subsystem_put(pil);
 		pil_ref_cnt--;
 		mutex_unlock(&pil_access_lock);
 	}
@@ -1744,7 +2292,47 @@
 		.release = qseecom_release
 };
 
-static int __qseecom_init_clk()
+static int __qseecom_enable_clk(void)
+{
+	int rc = 0;
+
+	/* Enable CE core clk */
+	rc = clk_prepare_enable(ce_core_clk);
+	if (rc) {
+		pr_err("Unable to enable/prepare CE core clk\n");
+		return -EIO;
+	} else {
+		/* Enable CE clk */
+		rc = clk_prepare_enable(ce_clk);
+		if (rc) {
+			pr_err("Unable to enable/prepare CE iface clk\n");
+			clk_disable_unprepare(ce_core_clk);
+			return -EIO;
+		} else {
+			/* Enable AXI clk */
+			rc = clk_prepare_enable(ce_bus_clk);
+			if (rc) {
+				pr_err("Unable to enable/prepare CE iface clk\n");
+				clk_disable_unprepare(ce_core_clk);
+				clk_disable_unprepare(ce_clk);
+				return -EIO;
+			}
+		}
+	}
+	return rc;
+}
+
+static void __qseecom_disable_clk(void)
+{
+	if (ce_clk != NULL)
+		clk_disable_unprepare(ce_clk);
+	if (ce_core_clk != NULL)
+		clk_disable_unprepare(ce_core_clk);
+	if (ce_bus_clk != NULL)
+		clk_disable_unprepare(ce_bus_clk);
+}
+
+static int __qseecom_init_clk(void)
 {
 	int rc = 0;
 	struct device *pdev;
@@ -1753,14 +2341,12 @@
 	/* Get CE3 src core clk. */
 	ce_core_src_clk = clk_get(pdev, "core_clk_src");
 	if (!IS_ERR(ce_core_src_clk)) {
-		ce_core_src_clk = ce_core_src_clk;
-
-		/* Set the core src clk @100Mhz */
-		rc = clk_set_rate(ce_core_src_clk, 100000000);
+		/* Set the core src clk @50Mhz */
+		rc = clk_set_rate(ce_core_src_clk, QSEE_CE_CLK_50MHZ);
 		if (rc) {
 			clk_put(ce_core_src_clk);
 			pr_err("Unable to set the core src clk @100Mhz.\n");
-			goto err_clk;
+			return -EIO;
 		}
 	} else {
 		pr_warn("Unable to get CE core src clk, set to NULL\n");
@@ -1774,7 +2360,7 @@
 		pr_err("Unable to get CE core clk\n");
 		if (ce_core_src_clk != NULL)
 			clk_put(ce_core_src_clk);
-		goto err_clk;
+		return -EIO;
 	}
 
 	/* Get CE Interface clk */
@@ -1785,7 +2371,7 @@
 		if (ce_core_src_clk != NULL)
 			clk_put(ce_core_src_clk);
 		clk_put(ce_core_clk);
-		goto err_clk;
+		return -EIO;
 	}
 
 	/* Get CE AXI clk */
@@ -1797,85 +2383,48 @@
 			clk_put(ce_core_src_clk);
 		clk_put(ce_core_clk);
 		clk_put(ce_clk);
-		goto err_clk;
+		return -EIO;
 	}
-
-	/* Enable CE core clk */
-	rc = clk_prepare_enable(ce_core_clk);
-	if (rc) {
-		pr_err("Unable to enable/prepare CE core clk\n");
-		if (ce_core_src_clk != NULL)
-			clk_put(ce_core_src_clk);
-		clk_put(ce_core_clk);
-		clk_put(ce_clk);
-		goto err_clk;
-	} else {
-		/* Enable CE clk */
-		rc = clk_prepare_enable(ce_clk);
-		if (rc) {
-			pr_err("Unable to enable/prepare CE iface clk\n");
-			clk_disable_unprepare(ce_core_clk);
-			if (ce_core_src_clk != NULL)
-				clk_put(ce_core_src_clk);
-			clk_put(ce_core_clk);
-			clk_put(ce_clk);
-			goto err_clk;
-		} else {
-			/* Enable AXI clk */
-			rc = clk_prepare_enable(ce_bus_clk);
-			if (rc) {
-				pr_err("Unable to enable/prepare CE iface clk\n");
-				clk_disable_unprepare(ce_core_clk);
-				clk_disable_unprepare(ce_clk);
-				if (ce_core_src_clk != NULL)
-					clk_put(ce_core_src_clk);
-				clk_put(ce_core_clk);
-				clk_put(ce_clk);
-				goto err_clk;
-			}
-		}
-	}
-	return rc;
-
-err_clk:
-	if (rc)
-		pr_err("Unable to init CE clks, rc = %d\n", rc);
-	clk_disable_unprepare(ce_clk);
-	clk_disable_unprepare(ce_core_clk);
-	clk_disable_unprepare(ce_bus_clk);
-	if (ce_core_src_clk != NULL)
-		clk_put(ce_core_src_clk);
-	clk_put(ce_clk);
-	clk_put(ce_core_clk);
-	clk_put(ce_bus_clk);
 	return rc;
 }
 
-
-
-static void __qseecom_disable_clk()
+static void __qseecom_deinit_clk(void)
 {
-	clk_disable_unprepare(ce_clk);
-	clk_disable_unprepare(ce_core_clk);
-	clk_disable_unprepare(ce_bus_clk);
-	if (ce_core_src_clk != NULL)
+	if (ce_clk != NULL) {
+		clk_put(ce_clk);
+		ce_clk = NULL;
+	}
+	if (ce_core_clk != NULL) {
+		clk_put(ce_core_clk);
+		ce_clk = NULL;
+	}
+	if (ce_bus_clk != NULL) {
+		clk_put(ce_bus_clk);
+		ce_clk = NULL;
+	}
+	if (ce_core_src_clk != NULL) {
 		clk_put(ce_core_src_clk);
-	clk_put(ce_clk);
-	clk_put(ce_core_clk);
-	clk_put(ce_bus_clk);
+		ce_core_src_clk = NULL;
+	}
 }
 
 static int __devinit qseecom_probe(struct platform_device *pdev)
 {
 	int rc;
-	int ret;
+	int ret = 0;
 	struct device *class_dev;
 	char qsee_not_legacy = 0;
-	struct msm_bus_scale_pdata *qseecom_platform_support;
+	struct msm_bus_scale_pdata *qseecom_platform_support = NULL;
 	uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
 
 	qsee_bw_count = 0;
 	qsee_perf_client = 0;
+	qsee_sfpb_bw_count = 0;
+
+	ce_core_clk = NULL;
+	ce_clk = NULL;
+	ce_core_src_clk = NULL;
+	ce_bus_clk = NULL;
 
 	rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
 	if (rc < 0) {
@@ -1911,26 +2460,38 @@
 	spin_lock_init(&qseecom.registered_listener_list_lock);
 	INIT_LIST_HEAD(&qseecom.registered_app_list_head);
 	spin_lock_init(&qseecom.registered_app_list_lock);
+	INIT_LIST_HEAD(&qseecom.registered_kclient_list_head);
+	spin_lock_init(&qseecom.registered_kclient_list_lock);
 	init_waitqueue_head(&qseecom.send_resp_wq);
 	qseecom.send_resp_flag = 0;
 
 	rc = scm_call(6, 1, &system_call_id, sizeof(system_call_id),
 				&qsee_not_legacy, sizeof(qsee_not_legacy));
 	if (rc) {
-		pr_err("Failed to retrieve QSEE version information %d\n", rc);
+		pr_err("Failed to retrieve QSEOS version information %d\n", rc);
 		goto err;
 	}
-	if (qsee_not_legacy)
+	if (qsee_not_legacy) {
+		uint32_t feature = 10;
+
+		qseecom.qsee_version = QSEEE_VERSION_00;
+		rc = scm_call(6, 3, &feature, sizeof(feature),
+			&qseecom.qsee_version, sizeof(qseecom.qsee_version));
+		if (rc) {
+			pr_err("Failed to get QSEE version info %d\n", rc);
+			goto err;
+		}
 		qseecom.qseos_version = QSEOS_VERSION_14;
-	else {
+	} else {
 		qseecom.qseos_version = QSEOS_VERSION_13;
+		qseecom.qsee_version = 0;
 		pil = NULL;
 		pil_ref_cnt = 0;
 	}
-
+	qseecom.commonlib_loaded = false;
 	qseecom.pdev = class_dev;
 	/* Create ION msm client */
-	qseecom.ion_clnt = msm_ion_client_create(0x03, "qseecom-kernel");
+	qseecom.ion_clnt = msm_ion_client_create(-1, "qseecom-kernel");
 	if (qseecom.ion_clnt == NULL) {
 		pr_err("Ion client cannot be created\n");
 		rc = -ENOMEM;
@@ -1942,6 +2503,11 @@
 		ret = __qseecom_init_clk();
 		if (ret)
 			goto err;
+		ret = __qseecom_enable_clk();
+		if (ret) {
+			__qseecom_deinit_clk();
+			goto err;
+		}
 		qseecom_platform_support = (struct msm_bus_scale_pdata *)
 						msm_bus_cl_get_pdata(pdev);
 	} else {
@@ -1966,9 +2532,70 @@
 
 static int __devinit qseecom_remove(struct platform_device *pdev)
 {
+	struct qseecom_registered_kclient_list *kclient = NULL;
+	unsigned long flags = 0;
+	int ret = 0;
+
 	if (pdev->dev.platform_data != NULL)
 		msm_bus_scale_unregister_client(qsee_perf_client);
-	return 0;
+
+	spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
+	kclient = list_entry((&qseecom.registered_kclient_list_head)->next,
+		struct qseecom_registered_kclient_list, list);
+	if (list_empty(&kclient->list)) {
+		spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock,
+			flags);
+		return 0;
+	}
+	list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
+				list) {
+			if (kclient)
+				list_del(&kclient->list);
+			break;
+	}
+	spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
+
+
+	while (kclient->handle != NULL) {
+		ret = qseecom_unload_app(kclient->handle->dev);
+		if (ret == 0) {
+			kzfree(kclient->handle->dev);
+			kzfree(kclient->handle);
+			kzfree(kclient);
+		}
+		spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
+		kclient = list_entry(
+				(&qseecom.registered_kclient_list_head)->next,
+				struct qseecom_registered_kclient_list, list);
+		if (list_empty(&kclient->list)) {
+			spin_unlock_irqrestore(
+				&qseecom.registered_kclient_list_lock, flags);
+			return 0;
+		}
+		list_for_each_entry(kclient,
+				&qseecom.registered_kclient_list_head, list) {
+			if (kclient)
+				list_del(&kclient->list);
+			break;
+		}
+		spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock,
+				flags);
+		if (!kclient) {
+			ret = 0;
+			break;
+		}
+	}
+	if (qseecom.qseos_version  > QSEEE_VERSION_00)
+		qseecom_unload_commonlib_image();
+
+	if (qsee_perf_client)
+		msm_bus_scale_client_update_request(qsee_perf_client, 0);
+	/* register client for bus scaling */
+	if (pdev->dev.of_node) {
+		__qseecom_disable_clk();
+		__qseecom_deinit_clk();
+	}
+	return ret;
 };
 
 static struct of_device_id qseecom_match[] = {
@@ -1995,9 +2622,6 @@
 
 static void __devexit qseecom_exit(void)
 {
-
-	__qseecom_disable_clk();
-
 	device_destroy(driver_class, qseecom_device_no);
 	class_destroy(driver_class);
 	unregister_chrdev_region(qseecom_device_no, 1);
diff --git a/drivers/misc/qseecom_kernel.h b/drivers/misc/qseecom_kernel.h
new file mode 100644
index 0000000..bfa5709
--- /dev/null
+++ b/drivers/misc/qseecom_kernel.h
@@ -0,0 +1,36 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QSEECOM_KERNEL_H_
+#define __QSEECOM_KERNEL_H_
+
+#include <linux/types.h>
+/*
+ * struct qseecom_handle -
+ *      Handle to the qseecom device for kernel clients
+ * @sbuf - shared buffer pointer
+ * @sbbuf_len - shared buffer size
+ */
+struct qseecom_handle {
+	void *dev; /* in/out */
+	unsigned char *sbuf; /* in/out */
+	uint32_t sbuf_len; /* in/out */
+};
+
+int qseecom_start_app(struct qseecom_handle **handle,
+						char *app_name, uint32_t size);
+int qseecom_shutdown_app(struct qseecom_handle **handle);
+int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
+			uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len);
+
+
+#endif /* __QSEECOM_KERNEL_H_ */
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index 8a1e0da..3b678c5 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -103,29 +103,29 @@
 /*
  * TSPP register offsets
  */
-#define TSPP_RST					0x00
+#define TSPP_RST			0x00
 #define TSPP_CLK_CONTROL		0x04
-#define TSPP_CONFIG				0x08
-#define TSPP_CONTROL				0x0C
+#define TSPP_CONFIG			0x08
+#define TSPP_CONTROL			0x0C
 #define TSPP_PS_DISABLE			0x10
-#define TSPP_MSG_IRQ_STATUS	0x14
+#define TSPP_MSG_IRQ_STATUS		0x14
 #define TSPP_MSG_IRQ_MASK		0x18
 #define TSPP_IRQ_STATUS			0x1C
 #define TSPP_IRQ_MASK			0x20
 #define TSPP_IRQ_CLEAR			0x24
 #define TSPP_PIPE_ERROR_STATUS(_n)	(0x28 + (_n << 2))
-#define TSPP_STATUS				0x68
-#define TSPP_CURR_TSP_HEADER	0x6C
-#define TSPP_CURR_PID_FILTER	0x70
-#define TSPP_SYSTEM_KEY(_n)	(0x74 + (_n << 2))
-#define TSPP_CBC_INIT_VAL(_n)	(0x94 + (_n << 2))
-#define TSPP_DATA_KEY_RESET	0x9C
+#define TSPP_STATUS			0x68
+#define TSPP_CURR_TSP_HEADER		0x6C
+#define TSPP_CURR_PID_FILTER		0x70
+#define TSPP_SYSTEM_KEY(_n)		(0x74 + (_n << 2))
+#define TSPP_CBC_INIT_VAL(_n)		(0x94 + (_n << 2))
+#define TSPP_DATA_KEY_RESET		0x9C
 #define TSPP_KEY_VALID			0xA0
 #define TSPP_KEY_ERROR			0xA4
 #define TSPP_TEST_CTRL			0xA8
-#define TSPP_VERSION				0xAC
+#define TSPP_VERSION			0xAC
 #define TSPP_GENERICS			0xB0
-#define TSPP_NOP					0xB4
+#define TSPP_NOP			0xB4
 
 /*
  * Register bit definitions
@@ -172,30 +172,30 @@
 #define TSPP_MSG_TSIF_0_IRQ               BIT(0)
 
 /* TSPP_IRQ_STATUS + TSPP_IRQ_MASK + TSPP_IRQ_CLEAR */
-#define TSPP_IRQ_STATUS_TSP_RD_CMPL			BIT(19)
-#define TSPP_IRQ_STATUS_KEY_ERROR			BIT(18)
+#define TSPP_IRQ_STATUS_TSP_RD_CMPL		BIT(19)
+#define TSPP_IRQ_STATUS_KEY_ERROR		BIT(18)
 #define TSPP_IRQ_STATUS_KEY_SWITCHED_BAD	BIT(17)
 #define TSPP_IRQ_STATUS_KEY_SWITCHED		BIT(16)
 #define TSPP_IRQ_STATUS_PS_BROKEN(_n)		BIT((_n))
 
 /* TSPP_PIPE_ERROR_STATUS */
-#define TSPP_PIPE_PES_SYNC_ERROR				BIT(3)
-#define TSPP_PIPE_PS_LENGTH_ERROR			BIT(2)
+#define TSPP_PIPE_PES_SYNC_ERROR		BIT(3)
+#define TSPP_PIPE_PS_LENGTH_ERROR		BIT(2)
 #define TSPP_PIPE_PS_CONTINUITY_ERROR		BIT(1)
-#define TSPP_PIP_PS_LOST_START				BIT(0)
+#define TSPP_PIP_PS_LOST_START			BIT(0)
 
 /* TSPP_STATUS			*/
-#define TSPP_STATUS_TSP_PKT_AVAIL			BIT(10)
-#define TSPP_STATUS_TSIF1_DM_REQ				BIT(6)
-#define TSPP_STATUS_TSIF0_DM_REQ				BIT(2)
-#define TSPP_CURR_FILTER_TABLE				BIT(0)
+#define TSPP_STATUS_TSP_PKT_AVAIL		BIT(10)
+#define TSPP_STATUS_TSIF1_DM_REQ		BIT(6)
+#define TSPP_STATUS_TSIF0_DM_REQ		BIT(2)
+#define TSPP_CURR_FILTER_TABLE			BIT(0)
 
 /* TSPP_GENERICS		*/
-#define TSPP_GENERICS_CRYPTO_GEN				BIT(12)
+#define TSPP_GENERICS_CRYPTO_GEN		BIT(12)
 #define TSPP_GENERICS_MAX_CONS_PIPES		BIT(7)
-#define TSPP_GENERICS_MAX_PIPES				BIT(2)
-#define TSPP_GENERICS_TSIF_1_GEN				BIT(1)
-#define TSPP_GENERICS_TSIF_0_GEN				BIT(0)
+#define TSPP_GENERICS_MAX_PIPES			BIT(2)
+#define TSPP_GENERICS_TSIF_1_GEN		BIT(1)
+#define TSPP_GENERICS_TSIF_0_GEN		BIT(0)
 
 /*
  * TSPP memory regions
@@ -375,6 +375,8 @@
 	tspp_notifier *notifier; /* used only with kernel api */
 	void *notify_data;       /* data to be passed with the notifier */
 	u32 notify_timer;        /* notification for partially filled buffers */
+	tspp_memfree *memfree;   /* user defined memory free function */
+	void *user_info; /* user cookie passed to memory alloc/free function */
 };
 
 struct tspp_pid_filter_table {
@@ -584,8 +586,7 @@
 		g = table + i;
 		tmp = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_DISABLE);
 		if (tmp) {
-			pr_err("tspp_gpios_disable(0x%08x, GPIO_CFG_DISABLE)"
-			       " <%s> failed: %d\n",
+			pr_err("tspp_gpios_disable(0x%08x, GPIO_CFG_DISABLE) <%s> failed: %d\n",
 			       g->gpio_cfg, g->label ?: "?", rc);
 			pr_err("tspp: pin %d func %d dir %d pull %d drvstr %d\n",
 			       GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
@@ -608,8 +609,7 @@
 		g = table + i;
 		rc = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_ENABLE);
 		if (rc) {
-			pr_err("tspp: gpio_tlmm_config(0x%08x, GPIO_CFG_ENABLE)"
-			       " <%s> failed: %d\n",
+			pr_err("tspp: gpio_tlmm_config(0x%08x, GPIO_CFG_ENABLE) <%s> failed: %d\n",
 			       g->gpio_cfg, g->label ?: "?", rc);
 			pr_err("tspp: pin %d func %d dir %d pull %d drvstr %d\n",
 			       GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
@@ -820,12 +820,12 @@
 		desc->virt_base = alloc(channel_id, size,
 			&desc->phys_base, user);
 	} else {
-	desc->virt_base = dma_alloc_coherent(NULL, size,
-		&desc->phys_base, GFP_KERNEL);
-	if (desc->virt_base == 0) {
-		pr_err("tspp dma alloc coherent failed %i", size);
-		return -ENOMEM;
-	}
+		desc->virt_base = dma_alloc_coherent(NULL, size,
+			&desc->phys_base, GFP_KERNEL);
+		if (desc->virt_base == 0) {
+			pr_err("tspp dma alloc coherent failed %i", size);
+			return -ENOMEM;
+		}
 	}
 
 	desc->size = size;
@@ -977,9 +977,13 @@
 	channel->buffer_count = 0;
 	channel->filter_count = 0;
 	channel->int_freq = 1;
+	channel->src = TSPP_SOURCE_NONE;
+	channel->mode = TSPP_MODE_DISABLED;
 	channel->notifier = NULL;
 	channel->notify_data = NULL;
 	channel->notify_timer = 0;
+	channel->memfree = NULL;
+	channel->user_info = NULL;
 	init_waitqueue_head(&channel->in_queue);
 
 	if (cdev_add(&channel->cdev, tspp_minor++, 1) != 0) {
@@ -1002,6 +1006,11 @@
 static int tspp_set_buffer_size(struct tspp_channel *channel,
 	struct tspp_buffer *buf)
 {
+	if (channel->buffer_count > 0) {
+		pr_err("tspp: cannot set buffer size - buffers already allocated\n");
+		return -EPERM;
+	}
+
 	if (buf->size < TSPP_MIN_BUFFER_SIZE)
 		channel->buffer_size = TSPP_MIN_BUFFER_SIZE;
 	else if (buf->size > TSPP_MAX_BUFFER_SIZE)
@@ -1033,8 +1042,8 @@
 }
 
 static void tspp_set_signal_inversion(struct tspp_channel *channel,
-	int clock_inverse, int data_inverse,
-	int sync_inverse, int enable_inverse)
+					int clock_inverse, int data_inverse,
+					int sync_inverse, int enable_inverse)
 {
 	int index;
 
@@ -1054,8 +1063,106 @@
 	channel->pdev->tsif[index].enable_inverse = enable_inverse;
 }
 
+static int tspp_is_buffer_size_aligned(u32 size, enum tspp_mode mode)
+{
+	u32 alignment;
+
+	switch (mode) {
+	case TSPP_MODE_RAW:
+		/* must be a multiple of 192 */
+		alignment = (TSPP_PACKET_LENGTH + 4);
+		if (size % alignment)
+			return 0;
+		return 1;
+
+	case TSPP_MODE_RAW_NO_SUFFIX:
+		/* must be a multiple of 188 */
+		alignment = TSPP_PACKET_LENGTH;
+		if (size % alignment)
+			return 0;
+		return 1;
+
+	case TSPP_MODE_DISABLED:
+	case TSPP_MODE_PES:
+	default:
+		/* no alignment requirement */
+		return 1;
+	}
+
+}
+
+static u32 tspp_align_buffer_size_by_mode(u32 size, enum tspp_mode mode)
+{
+	u32 new_size;
+	u32 alignment;
+
+	switch (mode) {
+	case TSPP_MODE_RAW:
+		/* must be a multiple of 192 */
+		alignment = (TSPP_PACKET_LENGTH + 4);
+		break;
+
+	case TSPP_MODE_RAW_NO_SUFFIX:
+		/* must be a multiple of 188 */
+		alignment = TSPP_PACKET_LENGTH;
+		break;
+
+	case TSPP_MODE_DISABLED:
+	case TSPP_MODE_PES:
+	default:
+		/* no alignment requirement - give the user what he asks for */
+		alignment = 1;
+		break;
+	}
+	/* align up */
+	new_size = (((size + alignment - 1) / alignment) * alignment);
+	return new_size;
+}
+
+static void tspp_destroy_buffers(u32 channel_id, struct tspp_channel *channel)
+{
+	int i;
+	struct tspp_mem_buffer *pbuf, *temp;
+
+	pbuf = channel->data;
+	for (i = 0; i < channel->buffer_count; i++) {
+		if (pbuf->desc.phys_base) {
+			if (channel->memfree) {
+				channel->memfree(channel_id,
+					pbuf->desc.size,
+					pbuf->desc.virt_base,
+					pbuf->desc.phys_base,
+					channel->user_info);
+			} else {
+				dma_free_coherent(NULL,
+					pbuf->desc.size,
+					pbuf->desc.virt_base,
+					pbuf->desc.phys_base);
+			}
+			pbuf->desc.phys_base = 0;
+		}
+		pbuf->desc.virt_base = 0;
+		pbuf->state = TSPP_BUF_STATE_EMPTY;
+		temp = pbuf;
+		pbuf = pbuf->next;
+		kfree(temp);
+	}
+}
+
 /*** TSPP API functions ***/
-int tspp_open_stream(u32 dev, u32 channel_id, struct tspp_select_source *source)
+
+/**
+ * tspp_open_stream - open a TSPP stream for use.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
+ * @source: stream source parameters.
+ *
+ * Return  error status
+ *
+ */
+int tspp_open_stream(u32 dev, u32 channel_id,
+			struct tspp_select_source *source)
 {
 	u32 val;
 	struct tspp_device *pdev;
@@ -1063,6 +1170,7 @@
 
 	TSPP_DEBUG("tspp_open_stream %i %i %i %i",
 		dev, channel_id, source->source, source->mode);
+
 	if (dev >= TSPP_MAX_DEVICES) {
 		pr_err("tspp: device id out of range");
 		return -ENODEV;
@@ -1082,8 +1190,8 @@
 	channel->src = source->source;
 	tspp_set_tsif_mode(channel, source->mode);
 	tspp_set_signal_inversion(channel, source->clk_inverse,
-		source->data_inverse, source->sync_inverse,
-		source->enable_inverse);
+			source->data_inverse, source->sync_inverse,
+			source->enable_inverse);
 
 	switch (source->source) {
 	case TSPP_SOURCE_TSIF0:
@@ -1120,6 +1228,15 @@
 }
 EXPORT_SYMBOL(tspp_open_stream);
 
+/**
+ * tspp_close_stream - close a TSPP stream.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
+ *
+ * Return  error status
+ *
+ */
 int tspp_close_stream(u32 dev, u32 channel_id)
 {
 	u32 val;
@@ -1162,6 +1279,15 @@
 }
 EXPORT_SYMBOL(tspp_close_stream);
 
+/**
+ * tspp_open_channel - open a TSPP channel.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
+ *
+ * Return  error status
+ *
+ */
 int tspp_open_channel(u32 dev, u32 channel_id)
 {
 	int rc = 0;
@@ -1269,6 +1395,15 @@
 }
 EXPORT_SYMBOL(tspp_open_channel);
 
+/**
+ * tspp_close_channel - close a TSPP channel.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
+ *
+ * Return  error status
+ *
+ */
 int tspp_close_channel(u32 dev, u32 channel_id)
 {
 	int i;
@@ -1278,7 +1413,6 @@
 	struct sps_connect *config;
 	struct tspp_device *pdev;
 	struct tspp_channel *channel;
-	struct tspp_mem_buffer *pbuf, *temp;
 
 	if (channel_id >= TSPP_NUM_CHANNELS) {
 		pr_err("tspp: channel id out of range");
@@ -1333,21 +1467,12 @@
 	dma_free_coherent(NULL, config->desc.size, config->desc.base,
 		config->desc.phys_base);
 
-	pbuf = channel->data;
-	for (i = 0; i < channel->buffer_count; i++) {
-		if (pbuf->desc.phys_base) {
-			dma_free_coherent(NULL,
-				pbuf->desc.size,
-				pbuf->desc.virt_base,
-				pbuf->desc.phys_base);
-			pbuf->desc.phys_base = 0;
-		}
-		pbuf->desc.virt_base = 0;
-		pbuf->state = TSPP_BUF_STATE_EMPTY;
-		temp = pbuf;
-		pbuf = pbuf->next;
-		kfree(temp);
-	}
+	tspp_destroy_buffers(channel_id, channel);
+
+	channel->src = TSPP_SOURCE_NONE;
+	channel->mode = TSPP_MODE_DISABLED;
+	channel->memfree = NULL;
+	channel->user_info = NULL;
 	channel->buffer_count = 0;
 	channel->data = NULL;
 	channel->read = NULL;
@@ -1363,10 +1488,20 @@
 }
 EXPORT_SYMBOL(tspp_close_channel);
 
+/**
+ * tspp_add_filter - add a TSPP filter to a channel.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
+ * @filter: TSPP filter parameters
+ *
+ * Return  error status
+ *
+ */
 int tspp_add_filter(u32 dev, u32 channel_id,
 	struct tspp_filter *filter)
 {
-	int i;
+	int i, rc;
 	int other_channel;
 	int entry;
 	u32 val, pid, enabled;
@@ -1397,19 +1532,14 @@
 		return -ENOSR;
 	}
 
-	/* make sure this filter mode matches the channel mode */
-	switch (channel->mode) {
-	case TSPP_MODE_DISABLED:
-		channel->mode = filter->mode;
-		break;
-	case TSPP_MODE_RAW:
-	case TSPP_MODE_PES:
-	case TSPP_MODE_RAW_NO_SUFFIX:
-		if (filter->mode != channel->mode) {
-			pr_err("tspp: wrong filter mode");
-			return -EBADSLT;
-		}
-	}
+	channel->mode = filter->mode;
+	/*
+	 * if buffers are already allocated, verify they fulfil
+	 * the alignment requirements.
+	 */
+	if ((channel->buffer_count > 0) &&
+	   (!tspp_is_buffer_size_aligned(channel->buffer_size, channel->mode)))
+		pr_warn("tspp: buffers allocated with incorrect alignment\n");
 
 	if (filter->mode == TSPP_MODE_PES) {
 		for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
@@ -1468,13 +1598,22 @@
 	pdev->filters[channel->src]->
 		filter[filter->priority].filter = p.filter;
 
-	/* allocate buffers if needed */
-	tspp_allocate_buffers(dev, channel->id, channel->max_buffers,
-		channel->buffer_size, channel->int_freq, 0, 0);
-	if (channel->buffer_count < MIN_ACCEPTABLE_BUFFER_COUNT) {
-		pr_err("tspp: failed to allocate at least %i buffers",
-			MIN_ACCEPTABLE_BUFFER_COUNT);
-		return -ENOMEM;
+	/*
+	 * allocate buffers if needed (i.e. if user did has not already called
+	 * tspp_allocate_buffers() explicitly).
+	 */
+	if (channel->buffer_count == 0) {
+		channel->buffer_size =
+			tspp_align_buffer_size_by_mode(channel->buffer_size,
+							channel->mode);
+		rc = tspp_allocate_buffers(dev, channel->id,
+					channel->max_buffers,
+					channel->buffer_size,
+					channel->int_freq, NULL, NULL, NULL);
+		if (rc != 0) {
+			pr_err("tspp: tspp_allocate_buffers failed\n");
+			return rc;
+		}
 	}
 
 	/* reenable pipe */
@@ -1489,6 +1628,16 @@
 }
 EXPORT_SYMBOL(tspp_add_filter);
 
+/**
+ * tspp_remove_filter - remove a TSPP filter from a channel.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
+ * @filter: TSPP filter parameters
+ *
+ * Return  error status
+ *
+ */
 int tspp_remove_filter(u32 dev, u32 channel_id,
 	struct tspp_filter *filter)
 {
@@ -1541,6 +1690,16 @@
 }
 EXPORT_SYMBOL(tspp_remove_filter);
 
+/**
+ * tspp_set_key - set TSPP key in key table.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
+ * @key: TSPP key parameters
+ *
+ * Return  error status
+ *
+ */
 int tspp_set_key(u32 dev, u32 channel_id, struct tspp_key *key)
 {
 	int i;
@@ -1591,6 +1750,18 @@
 }
 EXPORT_SYMBOL(tspp_set_key);
 
+/**
+ * tspp_register_notification - register TSPP channel notification function.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
+ * @pNotify: notification function
+ * @userdata: user data to pass to notification function
+ * @timer_ms: notification for partially filled buffers
+ *
+ * Return  error status
+ *
+ */
 int tspp_register_notification(u32 dev, u32 channel_id,
 	tspp_notifier *pNotify, void *userdata, u32 timer_ms)
 {
@@ -1614,6 +1785,15 @@
 }
 EXPORT_SYMBOL(tspp_register_notification);
 
+/**
+ * tspp_unregister_notification - unregister TSPP channel notification function.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
+ *
+ * Return  error status
+ *
+ */
 int tspp_unregister_notification(u32 dev, u32 channel_id)
 {
 	struct tspp_channel *channel;
@@ -1635,6 +1815,15 @@
 }
 EXPORT_SYMBOL(tspp_unregister_notification);
 
+/**
+ * tspp_get_buffer - get TSPP data buffer.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
+ *
+ * Return  error status
+ *
+ */
 const struct tspp_data_descriptor *tspp_get_buffer(u32 dev, u32 channel_id)
 {
 	struct tspp_mem_buffer *buffer;
@@ -1675,6 +1864,16 @@
 }
 EXPORT_SYMBOL(tspp_get_buffer);
 
+/**
+ * tspp_release_buffer - release TSPP data buffer back to TSPP.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
+ * @descriptor_id: buffer descriptor ID
+ *
+ * Return  error status
+ *
+ */
 int tspp_release_buffer(u32 dev, u32 channel_id, u32 descriptor_id)
 {
 	int i, found = 0;
@@ -1726,8 +1925,27 @@
 }
 EXPORT_SYMBOL(tspp_release_buffer);
 
-int tspp_allocate_buffers(u32 dev, u32 channel_id,	u32 count,
-	u32 size, u32 int_freq, tspp_allocator *alloc, void *user)
+/**
+ * tspp_allocate_buffers - allocate TSPP data buffers.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
+ * @count: number of buffers to allocate
+ * @size: size of each buffer to allocate
+ * @int_freq: interrupt frequency
+ * @alloc: user defined memory allocator function. Pass NULL for default.
+ * @memfree: user defined memory free function. Pass NULL for default.
+ * @user: user data to pass to the memory allocator/free function
+ *
+ * Return  error status
+ *
+ * The user can optionally call this function explicitly to allocate the TSPP
+ * data buffers. Alternatively, if the user did not call this function, it
+ * is called implicitly by tspp_add_filter().
+ */
+int tspp_allocate_buffers(u32 dev, u32 channel_id, u32 count, u32 size,
+			u32 int_freq, tspp_allocator *alloc,
+			tspp_memfree *memfree, void *user)
 {
 	struct tspp_channel *channel;
 	struct tspp_device *pdev;
@@ -1736,56 +1954,62 @@
 	TSPP_DEBUG("tspp_allocate_buffers");
 
 	if (channel_id >= TSPP_NUM_CHANNELS) {
-		pr_err("tspp: channel id out of range");
+		pr_err("%s: channel id out of range", __func__);
 		return -ECHRNG;
 	}
+
 	pdev = tspp_find_by_id(dev);
 	if (!pdev) {
-		pr_err("tspp_alloc: can't find device %i", dev);
+		pr_err("%s: can't find device %i", __func__, dev);
 		return -ENODEV;
 	}
+
+	if (count < MIN_ACCEPTABLE_BUFFER_COUNT) {
+		pr_err("%s: tspp requires a minimum of %i buffers\n",
+			__func__, MIN_ACCEPTABLE_BUFFER_COUNT);
+		return -EINVAL;
+	}
+
 	channel = &pdev->channels[channel_id];
+	/* allow buffer allocation only if there was no previous buffer
+	 * allocation for this channel.
+	 */
+	if (channel->buffer_count > 0) {
+		pr_err("%s: buffers already allocated for channel %u",
+			__func__, channel_id);
+		return -EINVAL;
+	}
 
 	channel->max_buffers = count;
 
 	/* set up interrupt frequency */
-	if (int_freq > channel->max_buffers)
+	if (int_freq > channel->max_buffers) {
 		int_freq = channel->max_buffers;
-	channel->int_freq = int_freq;
-
-	switch (channel->mode) {
-	case TSPP_MODE_DISABLED:
-	case TSPP_MODE_PES:
-		/* give the user what he asks for */
-		channel->buffer_size = size;
-		break;
-
-	case TSPP_MODE_RAW:
-		/* must be a multiple of 192 */
-		if (size < (TSPP_PACKET_LENGTH+4))
-			channel->buffer_size = (TSPP_PACKET_LENGTH+4);
-		else
-			channel->buffer_size = (size /
-				(TSPP_PACKET_LENGTH+4)) *
-				(TSPP_PACKET_LENGTH+4);
-		break;
-
-	case TSPP_MODE_RAW_NO_SUFFIX:
-		/* must be a multiple of 188 */
-		channel->buffer_size = (size / TSPP_PACKET_LENGTH) *
-			TSPP_PACKET_LENGTH;
-		break;
+		pr_warn("%s: setting interrupt frequency to %u\n",
+			__func__, int_freq);
 	}
+	channel->int_freq = int_freq;
+	/*
+	 * it is the responsibility of the caller to tspp_allocate_buffers(),
+	 * whether it's the user or the driver, to make sure the size parameter
+	 * is compatible to the channel mode.
+	 */
+	channel->buffer_size = size;
 
-	for (; channel->buffer_count < channel->max_buffers;
+	/* save user defined memory free function for later use */
+	channel->memfree = memfree;
+	channel->user_info = user;
+
+	for (channel->buffer_count = 0;
+		channel->buffer_count < channel->max_buffers;
 		channel->buffer_count++) {
 
 		/* allocate the descriptor */
 		struct tspp_mem_buffer *desc = (struct tspp_mem_buffer *)
 			kmalloc(sizeof(struct tspp_mem_buffer), GFP_KERNEL);
 		if (!desc) {
-			pr_warn("tspp: Can't allocate desc %i",
-			channel->buffer_count);
+			pr_warn("%s: Can't allocate desc %i",
+				__func__, channel->buffer_count);
 			break;
 		}
 
@@ -1794,8 +2018,8 @@
 		if (tspp_alloc_buffer(channel_id, &desc->desc,
 			channel->buffer_size, alloc, user) != 0) {
 			kfree(desc);
-			pr_warn("tspp: Can't allocate buffer %i",
-				channel->buffer_count);
+			pr_warn("%s: Can't allocate buffer %i",
+				__func__, channel->buffer_count);
 			break;
 		}
 
@@ -1818,12 +2042,24 @@
 
 		/* start the transfer */
 		if (tspp_queue_buffer(channel, desc))
-			pr_err("tspp: can't queue buffer %i", desc->desc.id);
+			pr_err("%s: can't queue buffer %i",
+				__func__, desc->desc.id);
+	}
+
+	if (channel->buffer_count < channel->max_buffers) {
+		/*
+		 * we failed to allocate the requested number of buffers.
+		 * we don't allow a partial success, so need to clean up here.
+		 */
+		tspp_destroy_buffers(channel_id, channel);
+		channel->buffer_count = 0;
+		return -ENOMEM;
 	}
 
 	channel->waiting = channel->data;
 	channel->read = channel->data;
 	channel->locked = channel->data;
+
 	return 0;
 }
 EXPORT_SYMBOL(tspp_allocate_buffers);
@@ -1942,8 +2178,10 @@
 		transferred += size;
 		buffer->read_index += size;
 
-		/* after reading the end of the buffer, requeue it,
-			and set up for reading the next one */
+		/*
+		 * after reading the end of the buffer, requeue it,
+		 * and set up for reading the next one
+		 */
 		if (buffer->read_index == buffer->filled) {
 			buffer->state = TSPP_BUF_STATE_WAITING;
 			if (tspp_queue_buffer(channel, buffer))
@@ -2042,8 +2280,10 @@
 		pr_err("tspp: Unknown ioctl %i", param0);
 	}
 
-	/* normalize the return code in case one of the subfunctions does
-		something weird */
+	/*
+	 * normalize the return code in case one of the subfunctions does
+	 * something weird
+	 */
 	if (rc != 0)
 		rc = -ENOIOCTLCMD;
 
@@ -2136,13 +2376,14 @@
 {
 	int rc = -ENODEV;
 	u32 version;
-	u32 i;
+	u32 i, j;
 	struct msm_tspp_platform_data *data;
 	struct tspp_device *device;
 	struct resource *mem_tsif0;
 	struct resource *mem_tsif1;
 	struct resource *mem_tspp;
 	struct resource *mem_bam;
+	struct tspp_channel *channel;
 
 	/* must have platform data */
 	data = pdev->dev.platform_data;
@@ -2338,6 +2579,12 @@
 	return 0;
 
 err_channel:
+	/* uninitialize channels */
+	for (j = 0; j < i; j++) {
+		channel = &(device->channels[i]);
+		device_destroy(tspp_class, channel->cdev.dev);
+		cdev_del(&channel->cdev);
+	}
 err_clock:
 	sps_deregister_bam_device(device->bam_handle);
 err_bam:
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 254672f..8810b46 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1472,64 +1472,6 @@
 }
 EXPORT_SYMBOL(mmc_blk_init_packed_statistics);
 
-void print_mmc_packing_stats(struct mmc_card *card)
-{
-	int i;
-	int max_num_of_packed_reqs = 0;
-
-	if ((!card) || (!card->wr_pack_stats.packing_events))
-		return;
-
-	max_num_of_packed_reqs = card->ext_csd.max_packed_writes;
-
-	spin_lock(&card->wr_pack_stats.lock);
-
-	pr_info("%s: write packing statistics:\n",
-		mmc_hostname(card->host));
-
-	for (i = 1 ; i <= max_num_of_packed_reqs ; ++i) {
-		if (card->wr_pack_stats.packing_events[i] != 0)
-			pr_info("%s: Packed %d reqs - %d times\n",
-				mmc_hostname(card->host), i,
-				card->wr_pack_stats.packing_events[i]);
-	}
-
-	pr_info("%s: stopped packing due to the following reasons:\n",
-		mmc_hostname(card->host));
-
-	if (card->wr_pack_stats.pack_stop_reason[EXCEEDS_SEGMENTS])
-		pr_info("%s: %d times: exceedmax num of segments\n",
-			mmc_hostname(card->host),
-			card->wr_pack_stats.pack_stop_reason[EXCEEDS_SEGMENTS]);
-	if (card->wr_pack_stats.pack_stop_reason[EXCEEDS_SECTORS])
-		pr_info("%s: %d times: exceeding the max num of sectors\n",
-			mmc_hostname(card->host),
-			card->wr_pack_stats.pack_stop_reason[EXCEEDS_SECTORS]);
-	if (card->wr_pack_stats.pack_stop_reason[WRONG_DATA_DIR])
-		pr_info("%s: %d times: wrong data direction\n",
-			mmc_hostname(card->host),
-			card->wr_pack_stats.pack_stop_reason[WRONG_DATA_DIR]);
-	if (card->wr_pack_stats.pack_stop_reason[FLUSH_OR_DISCARD])
-		pr_info("%s: %d times: flush or discard\n",
-			mmc_hostname(card->host),
-			card->wr_pack_stats.pack_stop_reason[FLUSH_OR_DISCARD]);
-	if (card->wr_pack_stats.pack_stop_reason[EMPTY_QUEUE])
-		pr_info("%s: %d times: empty queue\n",
-			mmc_hostname(card->host),
-			card->wr_pack_stats.pack_stop_reason[EMPTY_QUEUE]);
-	if (card->wr_pack_stats.pack_stop_reason[REL_WRITE])
-		pr_info("%s: %d times: rel write\n",
-			mmc_hostname(card->host),
-			card->wr_pack_stats.pack_stop_reason[REL_WRITE]);
-	if (card->wr_pack_stats.pack_stop_reason[THRESHOLD])
-		pr_info("%s: %d times: Threshold\n",
-			mmc_hostname(card->host),
-			card->wr_pack_stats.pack_stop_reason[THRESHOLD]);
-
-	spin_unlock(&card->wr_pack_stats.lock);
-}
-EXPORT_SYMBOL(print_mmc_packing_stats);
-
 static u8 mmc_blk_prep_packed_list(struct mmc_queue *mq, struct request *req)
 {
 	struct request_queue *q = mq->queue;
@@ -1737,6 +1679,7 @@
 	brq->data.blksz = 512;
 	brq->data.blocks = mqrq->packed_blocks + 1;
 	brq->data.flags |= MMC_DATA_WRITE;
+	brq->data.fault_injected = false;
 
 	brq->stop.opcode = MMC_STOP_TRANSMISSION;
 	brq->stop.arg = 0;
@@ -2058,7 +2001,8 @@
 		/* complete ongoing async transfer before issuing discard */
 		if (card->host->areq)
 			mmc_blk_issue_rw_rq(mq, NULL);
-		if (req->cmd_flags & REQ_SECURE)
+		if (req->cmd_flags & REQ_SECURE &&
+			!(card->quirks & MMC_QUIRK_SEC_ERASE_TRIM_BROKEN))
 			ret = mmc_blk_issue_secdiscard_rq(mq, req);
 		else
 			ret = mmc_blk_issue_discard_rq(mq, req);
@@ -2360,7 +2304,7 @@
 	ret = device_create_file(disk_to_dev(md->disk),
 				 &md->num_wr_reqs_to_start_packing);
 	if (ret)
-		goto power_ro_lock_fail;
+		goto num_wr_reqs_to_start_packing_fail;
 
 	md->min_sectors_to_check_bkops_status.show =
 		min_sectors_to_check_bkops_status_show;
@@ -2373,14 +2317,19 @@
 	ret = device_create_file(disk_to_dev(md->disk),
 				 &md->min_sectors_to_check_bkops_status);
 	if (ret)
-		goto power_ro_lock_fail;
+		goto min_sectors_to_check_bkops_status_fails;
 
 	return ret;
 
+min_sectors_to_check_bkops_status_fails:
+	device_remove_file(disk_to_dev(md->disk),
+			   &md->num_wr_reqs_to_start_packing);
+num_wr_reqs_to_start_packing_fail:
+	device_remove_file(disk_to_dev(md->disk), &md->power_ro_lock);
 power_ro_lock_fail:
-		device_remove_file(disk_to_dev(md->disk), &md->force_ro);
+	device_remove_file(disk_to_dev(md->disk), &md->force_ro);
 force_ro_fail:
-		del_gendisk(md->disk);
+	del_gendisk(md->disk);
 
 	return ret;
 }
@@ -2388,6 +2337,7 @@
 #define CID_MANFID_SANDISK	0x2
 #define CID_MANFID_TOSHIBA	0x11
 #define CID_MANFID_MICRON	0x13
+#define CID_MANFID_SAMSUNG	0x15
 
 static const struct mmc_fixup blk_fixups[] =
 {
@@ -2428,6 +2378,28 @@
 	MMC_FIXUP("SEM04G", 0x45, CID_OEMID_ANY, add_quirk_mmc,
 		  MMC_QUIRK_INAND_DATA_TIMEOUT),
 
+	/*
+	 * On these Samsung MoviNAND parts, performing secure erase or
+	 * secure trim can result in unrecoverable corruption due to a
+	 * firmware bug.
+	 */
+	MMC_FIXUP("M8G2FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+		  MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+	MMC_FIXUP("MAG4FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+		  MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+	MMC_FIXUP("MBG8FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+		  MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+	MMC_FIXUP("MCGAFA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+		  MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+	MMC_FIXUP("VAL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+		  MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+	MMC_FIXUP("VYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+		  MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+	MMC_FIXUP("KYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+		  MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+	MMC_FIXUP("VZL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+		  MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+
 	END_FIXUP
 };
 
diff --git a/drivers/mmc/card/mmc_block_test.c b/drivers/mmc/card/mmc_block_test.c
index 2307d7a..c5551b8 100644
--- a/drivers/mmc/card/mmc_block_test.c
+++ b/drivers/mmc/card/mmc_block_test.c
@@ -221,6 +221,63 @@
 
 static struct mmc_block_test_data *mbtd;
 
+void print_mmc_packing_stats(struct mmc_card *card)
+{
+	int i;
+	int max_num_of_packed_reqs = 0;
+
+	if ((!card) || (!card->wr_pack_stats.packing_events))
+		return;
+
+	max_num_of_packed_reqs = card->ext_csd.max_packed_writes;
+
+	spin_lock(&card->wr_pack_stats.lock);
+
+	pr_info("%s: write packing statistics:\n",
+		mmc_hostname(card->host));
+
+	for (i = 1 ; i <= max_num_of_packed_reqs ; ++i) {
+		if (card->wr_pack_stats.packing_events[i] != 0)
+			pr_info("%s: Packed %d reqs - %d times\n",
+				mmc_hostname(card->host), i,
+				card->wr_pack_stats.packing_events[i]);
+	}
+
+	pr_info("%s: stopped packing due to the following reasons:\n",
+		mmc_hostname(card->host));
+
+	if (card->wr_pack_stats.pack_stop_reason[EXCEEDS_SEGMENTS])
+		pr_info("%s: %d times: exceedmax num of segments\n",
+			mmc_hostname(card->host),
+			card->wr_pack_stats.pack_stop_reason[EXCEEDS_SEGMENTS]);
+	if (card->wr_pack_stats.pack_stop_reason[EXCEEDS_SECTORS])
+		pr_info("%s: %d times: exceeding the max num of sectors\n",
+			mmc_hostname(card->host),
+			card->wr_pack_stats.pack_stop_reason[EXCEEDS_SECTORS]);
+	if (card->wr_pack_stats.pack_stop_reason[WRONG_DATA_DIR])
+		pr_info("%s: %d times: wrong data direction\n",
+			mmc_hostname(card->host),
+			card->wr_pack_stats.pack_stop_reason[WRONG_DATA_DIR]);
+	if (card->wr_pack_stats.pack_stop_reason[FLUSH_OR_DISCARD])
+		pr_info("%s: %d times: flush or discard\n",
+			mmc_hostname(card->host),
+			card->wr_pack_stats.pack_stop_reason[FLUSH_OR_DISCARD]);
+	if (card->wr_pack_stats.pack_stop_reason[EMPTY_QUEUE])
+		pr_info("%s: %d times: empty queue\n",
+			mmc_hostname(card->host),
+			card->wr_pack_stats.pack_stop_reason[EMPTY_QUEUE]);
+	if (card->wr_pack_stats.pack_stop_reason[REL_WRITE])
+		pr_info("%s: %d times: rel write\n",
+			mmc_hostname(card->host),
+			card->wr_pack_stats.pack_stop_reason[REL_WRITE]);
+	if (card->wr_pack_stats.pack_stop_reason[THRESHOLD])
+		pr_info("%s: %d times: Threshold\n",
+			mmc_hostname(card->host),
+			card->wr_pack_stats.pack_stop_reason[THRESHOLD]);
+
+	spin_unlock(&card->wr_pack_stats.lock);
+}
+
 /*
  * A callback assigned to the packed_test_fn field.
  * Called from block layer in mmc_blk_packed_hdr_wrq_prep.
@@ -499,11 +556,11 @@
 
 	switch (td->test_info.testcase) {
 	case TEST_STOP_DUE_TO_FLUSH:
-		return "Test stop due to flush";
+		return " stop due to flush";
 	case TEST_STOP_DUE_TO_FLUSH_AFTER_MAX_REQS:
-		return "Test stop due to flush after max-1 reqs";
+		return " stop due to flush after max-1 reqs";
 	case TEST_STOP_DUE_TO_READ:
-		return "Test stop due to read";
+		return " stop due to read";
 	case TEST_STOP_DUE_TO_READ_AFTER_MAX_REQS:
 		return "Test stop due to read after max-1 reqs";
 	case TEST_STOP_DUE_TO_EMPTY_QUEUE:
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index cc91646..8897f18a 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -201,11 +201,12 @@
 	if (!mq->queue)
 		return -ENOMEM;
 
+	memset(&mq->mqrq_cur, 0, sizeof(mq->mqrq_cur));
+	memset(&mq->mqrq_prev, 0, sizeof(mq->mqrq_prev));
+
 	INIT_LIST_HEAD(&mqrq_cur->packed_list);
 	INIT_LIST_HEAD(&mqrq_prev->packed_list);
 
-	memset(&mq->mqrq_cur, 0, sizeof(mq->mqrq_cur));
-	memset(&mq->mqrq_prev, 0, sizeof(mq->mqrq_prev));
 	mq->mqrq_cur = mqrq_cur;
 	mq->mqrq_prev = mqrq_prev;
 	mq->queue->queuedata = mq;
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 85d2737..de87e82 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -25,6 +25,7 @@
 	int (*power_save)(struct mmc_host *);
 	int (*power_restore)(struct mmc_host *);
 	int (*alive)(struct mmc_host *);
+	int (*change_bus_speed)(struct mmc_host *, unsigned long *);
 };
 
 void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 47fd9b9..a98ed3d 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -479,11 +479,11 @@
 				else
 					card->ext_csd.bkops_en = 1;
 			}
-			if (!card->ext_csd.bkops_en)
-				pr_info("%s: BKOPS_EN bit is not set\n",
-					mmc_hostname(card->host));
 		}
 
+		pr_info("%s: BKOPS_EN bit = %d\n",
+			mmc_hostname(card->host), card->ext_csd.bkops_en);
+
 		/* check whether the eMMC card supports HPI */
 		if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) {
 			card->ext_csd.hpi = 1;
@@ -821,6 +821,69 @@
 	return err;
 }
 
+/**
+ * mmc_change_bus_speed() - Change MMC card bus frequency at runtime
+ * @host: pointer to mmc host structure
+ * @freq: pointer to desired frequency to be set
+ *
+ * Change the MMC card bus frequency at runtime after the card is
+ * initialized. Callers are expected to make sure of the card's
+ * state (DATA/RCV/TRANSFER) beforing changing the frequency at runtime.
+ *
+ * If the frequency to change is greater than max. supported by card,
+ * *freq is changed to max. supported by card and if it is less than min.
+ * supported by host, *freq is changed to min. supported by host.
+ */
+static int mmc_change_bus_speed(struct mmc_host *host, unsigned long *freq)
+{
+	int err = 0;
+	struct mmc_card *card;
+
+	mmc_claim_host(host);
+	/*
+	 * Assign card pointer after claiming host to avoid race
+	 * conditions that may arise during removal of the card.
+	 */
+	card = host->card;
+
+	if (!card || !freq) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	if (mmc_card_highspeed(card) || mmc_card_hs200(card)
+			|| mmc_card_ddr_mode(card)) {
+		if (*freq > card->ext_csd.hs_max_dtr)
+			*freq = card->ext_csd.hs_max_dtr;
+	} else if (*freq > card->csd.max_dtr) {
+		*freq = card->csd.max_dtr;
+	}
+
+	if (*freq < host->f_min)
+		*freq = host->f_min;
+
+	mmc_set_clock(host, (unsigned int) (*freq));
+
+	if (mmc_card_hs200(card) && card->host->ops->execute_tuning) {
+		/*
+		 * We try to probe host driver for tuning for any
+		 * frequency, it is host driver responsibility to
+		 * perform actual tuning only when required.
+		 */
+		mmc_host_clk_hold(card->host);
+		err = card->host->ops->execute_tuning(card->host,
+				MMC_SEND_TUNING_BLOCK_HS200);
+		mmc_host_clk_release(card->host);
+
+		if (err)
+			pr_warn("%s: %s: tuning execution failed %d\n",
+				   mmc_hostname(card->host), __func__, err);
+	}
+out:
+	mmc_release_host(host);
+	return err;
+}
+
 /*
  * Handle the detection and initialisation of a card.
  *
@@ -1531,6 +1594,7 @@
 	.resume = NULL,
 	.power_restore = mmc_power_restore,
 	.alive = mmc_alive,
+	.change_bus_speed = mmc_change_bus_speed,
 };
 
 static const struct mmc_bus_ops mmc_ops_unsafe = {
@@ -1542,6 +1606,7 @@
 	.resume = mmc_resume,
 	.power_restore = mmc_power_restore,
 	.alive = mmc_alive,
+	.change_bus_speed = mmc_change_bus_speed,
 };
 
 static void mmc_attach_bus_ops(struct mmc_host *host)
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index ff5821b..8661929 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -609,6 +609,72 @@
 	return 0;
 }
 
+/**
+ * mmc_sd_change_bus_speed() - Change SD card bus frequency at runtime
+ * @host: pointer to mmc host structure
+ * @freq: pointer to desired frequency to be set
+ *
+ * Change the SD card bus frequency at runtime after the card is
+ * initialized. Callers are expected to make sure of the card's
+ * state (DATA/RCV/TRANSFER) beforing changing the frequency at runtime.
+ *
+ * If the frequency to change is greater than max. supported by card,
+ * *freq is changed to max. supported by card and if it is less than min.
+ * supported by host, *freq is changed to min. supported by host.
+ */
+static int mmc_sd_change_bus_speed(struct mmc_host *host, unsigned long *freq)
+{
+	int err = 0;
+	struct mmc_card *card;
+
+	mmc_claim_host(host);
+	/*
+	 * Assign card pointer after claiming host to avoid race
+	 * conditions that may arise during removal of the card.
+	 */
+	card = host->card;
+
+	/* sanity checks */
+	if (!card || !freq) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	if (mmc_card_uhs(card)) {
+		if (*freq > card->sw_caps.uhs_max_dtr)
+			*freq = card->sw_caps.uhs_max_dtr;
+	} else {
+		if (*freq > mmc_sd_get_max_clock(card))
+			*freq = mmc_sd_get_max_clock(card);
+	}
+
+	if (*freq < host->f_min)
+		*freq = host->f_min;
+
+	mmc_set_clock(host, (unsigned int) (*freq));
+
+	if (!mmc_host_is_spi(card->host) && mmc_sd_card_uhs(card)
+			&& card->host->ops->execute_tuning) {
+		/*
+		 * We try to probe host driver for tuning for any
+		 * frequency, it is host driver responsibility to
+		 * perform actual tuning only when required.
+		 */
+		mmc_host_clk_hold(card->host);
+		err = card->host->ops->execute_tuning(card->host,
+				MMC_SEND_TUNING_BLOCK);
+		mmc_host_clk_release(card->host);
+
+		if (err)
+			pr_warn("%s: %s: tuning execution failed %d\n",
+				   mmc_hostname(card->host), __func__, err);
+	}
+
+out:
+	mmc_release_host(host);
+	return err;
+}
+
 /*
  * UHS-I specific initialization procedure
  */
@@ -1191,6 +1257,7 @@
 	.resume = NULL,
 	.power_restore = mmc_sd_power_restore,
 	.alive = mmc_sd_alive,
+	.change_bus_speed = mmc_sd_change_bus_speed,
 };
 
 static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
@@ -1200,6 +1267,7 @@
 	.resume = mmc_sd_resume,
 	.power_restore = mmc_sd_power_restore,
 	.alive = mmc_sd_alive,
+	.change_bus_speed = mmc_sd_change_bus_speed,
 };
 
 static void mmc_sd_attach_bus_ops(struct mmc_host *host)
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 72f4a5c..de7e5bc 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -76,6 +76,7 @@
 #define SPS_MIN_XFER_SIZE		MCI_FIFOSIZE
 
 #define MSM_MMC_BUS_VOTING_DELAY	200 /* msecs */
+#define INVALID_TUNING_PHASE		-1
 
 #if defined(CONFIG_DEBUG_FS)
 static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
@@ -158,6 +159,8 @@
 static void msmsdcc_sg_start(struct msmsdcc_host *host);
 static int msmsdcc_vreg_reset(struct msmsdcc_host *host);
 static int msmsdcc_runtime_resume(struct device *dev);
+static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
+		u32 **out_array, int *len, int size);
 
 static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
 {
@@ -213,9 +216,9 @@
 #endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
 
 /**
- * Apply soft reset to all SDCC BAM pipes
+ * Apply reset
  *
- * This function applies soft reset to SDCC BAM pipe.
+ * This function resets SPS BAM and DML cores.
  *
  * This function should be called to recover from error
  * conditions encountered during CMD/DATA tranfsers with card.
@@ -223,43 +226,64 @@
  * @host - Pointer to driver's host structure
  *
  */
-static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
+static int msmsdcc_bam_dml_reset_and_restore(struct msmsdcc_host *host)
 {
 	int rc;
 
+	/* Reset and init DML */
+	rc = msmsdcc_dml_init(host);
+	if (rc) {
+		pr_err("%s: msmsdcc_dml_init error=%d\n",
+				mmc_hostname(host->mmc), rc);
+		goto out;
+	}
+
 	/* Reset all SDCC BAM pipes */
 	rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
-	if (rc)
-		pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
+	if (rc) {
+		pr_err("%s: msmsdcc_sps_reset_ep(prod) error=%d\n",
 				mmc_hostname(host->mmc), rc);
-	rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
-	if (rc)
-		pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
-				mmc_hostname(host->mmc), rc);
+		goto out;
+	}
 
-	if (host->sps.reset_device) {
-		rc = sps_device_reset(host->sps.bam_handle);
-		if (rc)
-			pr_err("%s: sps_device_reset error=%d\n",
+	rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
+	if (rc) {
+		pr_err("%s: msmsdcc_sps_reset_ep(cons) error=%d\n",
 				mmc_hostname(host->mmc), rc);
-		host->sps.reset_device = false;
+		goto out;
+	}
+
+	/* Reset BAM */
+	rc = sps_device_reset(host->sps.bam_handle);
+	if (rc) {
+		pr_err("%s: sps_device_reset error=%d\n",
+				mmc_hostname(host->mmc), rc);
+		goto out;
 	}
 
 	/* Restore all BAM pipes connections */
 	rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
-	if (rc)
-		pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
+	if (rc) {
+		pr_err("%s: msmsdcc_sps_restore_ep(prod) error=%d\n",
 				mmc_hostname(host->mmc), rc);
+		goto out;
+	}
+
 	rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
 	if (rc)
-		pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
+		pr_err("%s: msmsdcc_sps_restore_ep(cons) error=%d\n",
 				mmc_hostname(host->mmc), rc);
+	else
+		host->sps.reset_bam = false;
+
+out:
+	return rc;
 }
 
 /**
  * Apply soft reset
  *
- * This function applies soft reset to SDCC core and DML core.
+ * This function applies soft reset to SDCC core.
  *
  * This function should be called to recover from error
  * conditions encountered with CMD/DATA tranfsers with card.
@@ -277,6 +301,11 @@
 	 */
 	if (is_sw_reset_save_config(host)) {
 		ktime_t start;
+		uint32_t dll_config = 0;
+
+
+		if (is_sw_reset_save_config_broken(host))
+			dll_config = readl_relaxed(host->base + MCI_DLL_CONFIG);
 
 		writel_relaxed(readl_relaxed(host->base + MMCIPOWER)
 				| MCI_SW_RST_CFG, host->base + MMCIPOWER);
@@ -296,6 +325,11 @@
 				BUG();
 			}
 		}
+
+		if (is_sw_reset_save_config_broken(host)) {
+			writel_relaxed(dll_config, host->base + MCI_DLL_CONFIG);
+			mb();
+		}
 	} else {
 		writel_relaxed(0, host->base + MMCICOMMAND);
 		msmsdcc_sync_reg_wr(host);
@@ -354,25 +388,25 @@
 static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
 {
 	if (is_soft_reset(host)) {
-		if (is_sps_mode(host)) {
-			/* Reset DML first */
-			msmsdcc_dml_reset(host);
+		if (is_sps_mode(host))
 			/*
-			 * delay the SPS pipe reset in thread context as
+			 * delay the SPS BAM reset in thread context as
 			 * sps_connect/sps_disconnect APIs can be called
 			 * only from non-atomic context.
 			 */
-			host->sps.pipe_reset_pending = true;
-		}
-		mb();
+			host->sps.reset_bam = true;
+
 		msmsdcc_soft_reset(host);
 
 		pr_debug("%s: Applied soft reset to Controller\n",
 				mmc_hostname(host->mmc));
-
-		if (is_sps_mode(host))
-			msmsdcc_dml_init(host);
 	} else {
+		/*
+		 * When there is a requirement to use this hard reset,
+		 * BAM needs to be reconfigured as well by calling
+		 * msmsdcc_sps_exit and msmsdcc_sps_init.
+		 */
+
 		/* Give Clock reset (hard reset) to controller */
 		u32	mci_clk = 0;
 		u32	mci_mask0 = 0;
@@ -913,7 +947,7 @@
 	if ((host->dma.channel == -1) || (host->dma.crci == -1))
 		return -ENOENT;
 
-	BUG_ON((host->pdev_id < 1) || (host->pdev_id > 5));
+	BUG_ON((host->pdev->id < 1) || (host->pdev->id > 5));
 
 	host->dma.sg = data->sg;
 	host->dma.num_ents = data->sg_len;
@@ -1348,6 +1382,9 @@
 		    (host->tuning_in_progress &&
 		    (opcode == MMC_SEND_TUNING_BLOCK_HS200 ||
 		     opcode == MMC_SEND_TUNING_BLOCK)))) {
+			/* Execute full tuning in case of CRC/timeout errors */
+			host->saved_tuning_phase = INVALID_TUNING_PHASE;
+
 			if (status & MCI_DATACRCFAIL) {
 				pr_err("%s: Data CRC error\n",
 				       mmc_hostname(host->mmc));
@@ -1726,6 +1763,8 @@
 		pr_err("%s: CMD%d: Command CRC error\n",
 			mmc_hostname(host->mmc), cmd->opcode);
 		msmsdcc_dump_sdcc_state(host);
+		/* Execute full tuning in case of CRC errors */
+		host->saved_tuning_phase = INVALID_TUNING_PHASE;
 		cmd->error = -EILSEQ;
 	}
 
@@ -2086,6 +2125,7 @@
 {
 	struct msmsdcc_host *host = mmc_priv(mmc);
 	unsigned long		flags;
+	int retries = 5;
 
 	/*
 	 * Get the SDIO AL client out of LPM.
@@ -2094,10 +2134,14 @@
 	if (host->plat->is_sdio_al_client)
 		msmsdcc_sdio_al_lpm(mmc, false);
 
-	/* check if sps pipe reset is pending? */
-	if (is_sps_mode(host) && host->sps.pipe_reset_pending) {
-		msmsdcc_sps_pipes_reset_and_restore(host);
-		host->sps.pipe_reset_pending = false;
+	/* check if sps bam needs to be reset */
+	if (is_sps_mode(host) && host->sps.reset_bam) {
+		while (retries) {
+			if (!msmsdcc_bam_dml_reset_and_restore(host))
+				break;
+			pr_err("%s: msmsdcc_bam_dml_reset_and_restore returned error. %d attempts left.\n",
+					mmc_hostname(host->mmc), --retries);
+		}
 	}
 
 	spin_lock_irqsave(&host->lock, flags);
@@ -2118,8 +2162,9 @@
 	/*
 	 * Don't start the request if SDCC is not in proper state to handle it
 	 */
-	if (!host->pwr || !atomic_read(&host->clks_on)
-			|| host->sdcc_irq_disabled) {
+	if (!host->pwr || !atomic_read(&host->clks_on) ||
+			host->sdcc_irq_disabled ||
+			host->sps.reset_bam) {
 		WARN(1, "%s: %s: SDCC is in bad state. don't process"
 		     " new request (CMD%d)\n", mmc_hostname(host->mmc),
 		     __func__, mrq->cmd->opcode);
@@ -2178,7 +2223,9 @@
 		}
 
 		if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
-		    (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
+		    (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) ||
+		    ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) &&
+		     is_data_pend_for_cmd53(host)))
 			host->curr.use_wr_data_pend = true;
 	}
 
@@ -2310,7 +2357,7 @@
 		rc = msmsdcc_vreg_reset(host);
 		if (rc)
 			pr_err("msmsdcc.%d vreg reset failed (%d)\n",
-			       host->pdev_id, rc);
+			       host->pdev->id, rc);
 		goto out;
 	} else {
 		/* Deregister all regulators from regulator framework */
@@ -2940,6 +2987,27 @@
 	int rc = 0;
 	struct msm_bus_scale_pdata *use_cases;
 
+	if (host->pdev->dev.of_node) {
+		struct msm_mmc_bus_voting_data *data;
+		struct device *dev = &host->pdev->dev;
+
+		data = devm_kzalloc(dev,
+			sizeof(struct msm_mmc_bus_voting_data), GFP_KERNEL);
+		if (!data) {
+			dev_err(&host->pdev->dev,
+				"%s: failed to allocate memory\n", __func__);
+			rc = -ENOMEM;
+			goto out;
+		}
+
+		rc = msmsdcc_dt_get_array(dev, "qcom,bus-bw-vectors-bps",
+				&data->bw_vecs, &data->bw_vecs_size, 0);
+		if (!rc) {
+			data->use_cases = msm_bus_cl_get_pdata(host->pdev);
+			host->plat->msm_bus_voting_data = data;
+		}
+	}
+
 	if (host->plat->msm_bus_voting_data &&
 	    host->plat->msm_bus_voting_data->use_cases &&
 	    host->plat->msm_bus_voting_data->bw_vecs &&
@@ -2962,7 +3030,7 @@
 		host->msm_bus_vote.max_bw_vote =
 				msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
 	}
-
+out:
 	return rc;
 }
 
@@ -3993,6 +4061,7 @@
 	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 */
+	bool is_tuning_all_phases;
 
 	pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
 
@@ -4026,7 +4095,13 @@
 		goto out;
 	}
 
-	phase = 0;
+	is_tuning_all_phases = !(host->mmc->card &&
+		(host->saved_tuning_phase != INVALID_TUNING_PHASE));
+retry:
+	if (is_tuning_all_phases)
+		phase = 0; /* start from phase 0 during init */
+	else
+		phase = (u8)host->saved_tuning_phase;
 	do {
 		struct mmc_command cmd = {0};
 		struct mmc_data data = {0};
@@ -4058,9 +4133,16 @@
 		if (!cmd.error && !data.error &&
 			!memcmp(data_buf, tuning_block_pattern, size)) {
 			/* tuning is successful at this tuning point */
+			if (!is_tuning_all_phases)
+				goto kfree;
 			tuned_phases[tuned_phase_cnt++] = phase;
 			pr_debug("%s: %s: found good phase = %d\n",
 				mmc_hostname(mmc), __func__, phase);
+		} else if (!is_tuning_all_phases) {
+			pr_debug("%s: tuning failed at saved phase (%d), retrying\n",
+					mmc_hostname(mmc), (u32)phase);
+			is_tuning_all_phases = true;
+			goto retry;
 		}
 	} while (++phase < 16);
 
@@ -4079,6 +4161,8 @@
 		rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
 		if (rc)
 			goto kfree;
+		else
+			host->saved_tuning_phase = phase;
 		pr_debug("%s: %s: finally setting the tuning phase to %d\n",
 				mmc_hostname(mmc), __func__, phase);
 	} else {
@@ -4599,11 +4683,8 @@
 	BUG_ON(!is_sps_mode(host));
 
 	if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
-		/**
-		 * Reset the all endpoints along with reseting the sps device.
-		 */
-		host->sps.pipe_reset_pending = true;
-		host->sps.reset_device = true;
+		/* Reset all endpoints along with resetting bam. */
+		host->sps.reset_bam = true;
 
 		pr_err("%s: BAM Global ERROR IRQ happened\n",
 			mmc_hostname(host->mmc));
@@ -5019,6 +5100,10 @@
 			host->curr.data_xfered, host->curr.xfer_remain);
 	}
 
+	if (host->sps.reset_bam)
+		pr_err("%s: SPS BAM reset failed: sps reset_bam=%d\n",
+			mmc_hostname(host->mmc), host->sps.reset_bam);
+
 	pr_err("%s: got_dataend=%d, prog_enable=%d,"
 		" wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
 		" req_tout_ms=%d\n", mmc_hostname(host->mmc),
@@ -5186,7 +5271,7 @@
 	pull_data->on = pull;
 	pull_data->off = pull + pull_data->size;
 
-	ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-on",
+	ret = msmsdcc_dt_get_array(dev, "qcom,pad-pull-on",
 			&tmp, &len, pull_data->size);
 	if (!ret) {
 		for (i = 0; i < len; i++) {
@@ -5199,7 +5284,7 @@
 		goto err;
 	}
 
-	ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-pull-off",
+	ret = msmsdcc_dt_get_array(dev, "qcom,pad-pull-off",
 			&tmp, &len, pull_data->size);
 	if (!ret) {
 		for (i = 0; i < len; i++) {
@@ -5264,7 +5349,7 @@
 	drv_data->on = drv;
 	drv_data->off = drv + drv_data->size;
 
-	ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-on",
+	ret = msmsdcc_dt_get_array(dev, "qcom,pad-drv-on",
 			&tmp, &len, drv_data->size);
 	if (!ret) {
 		for (i = 0; i < len; i++) {
@@ -5277,7 +5362,7 @@
 		goto err;
 	}
 
-	ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-pad-drv-off",
+	ret = msmsdcc_dt_get_array(dev, "qcom,pad-drv-off",
 			&tmp, &len, drv_data->size);
 	if (!ret) {
 		for (i = 0; i < len; i++) {
@@ -5357,7 +5442,7 @@
 			char result[32];
 			pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
 			of_property_read_string_index(np,
-					"qcom,sdcc-gpio-names", i, &name);
+					"qcom,gpio-names", i, &name);
 
 			snprintf(result, 32, "%s-%s",
 					dev_name(dev), name ? name : "?");
@@ -5416,17 +5501,17 @@
 		vreg->name = vreg_name;
 
 		snprintf(prop_name, MAX_PROP_SIZE,
-				"qcom,sdcc-%s-always_on", vreg_name);
+				"qcom,%s-always-on", vreg_name);
 		if (of_get_property(np, prop_name, NULL))
 			vreg->always_on = true;
 
 		snprintf(prop_name, MAX_PROP_SIZE,
-				"qcom,sdcc-%s-lpm_sup", vreg_name);
+				"qcom,%s-lpm-sup", vreg_name);
 		if (of_get_property(np, prop_name, NULL))
 			vreg->lpm_sup = true;
 
 		snprintf(prop_name, MAX_PROP_SIZE,
-				"qcom,sdcc-%s-voltage_level", vreg_name);
+				"qcom,%s-voltage-level", vreg_name);
 		prop = of_get_property(np, prop_name, &len);
 		if (!prop || (len != (2 * sizeof(__be32)))) {
 			dev_warn(dev, "%s %s property\n",
@@ -5437,7 +5522,7 @@
 		}
 
 		snprintf(prop_name, MAX_PROP_SIZE,
-				"qcom,sdcc-%s-current_level", vreg_name);
+				"qcom,%s-current-level", vreg_name);
 		prop = of_get_property(np, prop_name, &len);
 		if (!prop || (len != (2 * sizeof(__be32)))) {
 			dev_warn(dev, "%s %s property\n",
@@ -5473,7 +5558,7 @@
 		goto err;
 	}
 
-	of_property_read_u32(np, "qcom,sdcc-bus-width", &bus_width);
+	of_property_read_u32(np, "qcom,bus-width", &bus_width);
 	if (bus_width == 8) {
 		pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
 	} else if (bus_width == 4) {
@@ -5483,7 +5568,7 @@
 		pdata->mmc_bus_width = 0;
 	}
 
-	ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-sup-voltages",
+	ret = msmsdcc_dt_get_array(dev, "qcom,sup-voltages",
 			&sup_voltages, &sup_volt_len, 0);
 	if (!ret) {
 		for (i = 0; i < sup_volt_len; i += 2) {
@@ -5498,7 +5583,7 @@
 		dev_dbg(dev, "OCR mask=0x%x\n", pdata->ocr_mask);
 	}
 
-	ret = msmsdcc_dt_get_array(dev, "qcom,sdcc-clk-rates",
+	ret = msmsdcc_dt_get_array(dev, "qcom,clk-rates",
 			&clk_table, &clk_table_len, 0);
 	if (!ret) {
 		pdata->sup_clk_table = clk_table;
@@ -5523,13 +5608,13 @@
 	if (msmsdcc_dt_parse_gpio_info(dev, pdata))
 		goto err;
 
-	len = of_property_count_strings(np, "qcom,sdcc-bus-speed-mode");
+	len = of_property_count_strings(np, "qcom,bus-speed-mode");
 
 	for (i = 0; i < len; i++) {
 		const char *name = NULL;
 
 		of_property_read_string_index(np,
-			"qcom,sdcc-bus-speed-mode", i, &name);
+			"qcom,bus-speed-mode", i, &name);
 		if (!name)
 			continue;
 
@@ -5555,7 +5640,7 @@
 						| MMC_CAP_UHS_DDR50;
 	}
 
-	of_property_read_u32(np, "qcom,sdcc-current-limit", &current_limit);
+	of_property_read_u32(np, "qcom,current-limit", &current_limit);
 	if (current_limit == 800)
 		pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_800;
 	else if (current_limit == 600)
@@ -5565,12 +5650,14 @@
 	else if (current_limit == 200)
 		pdata->uhs_caps |= MMC_CAP_MAX_CURRENT_200;
 
-	if (of_get_property(np, "qcom,sdcc-xpc", NULL))
+	if (of_get_property(np, "qcom,xpc", NULL))
 		pdata->xpc_cap = true;
-	if (of_get_property(np, "qcom,sdcc-nonremovable", NULL))
+	if (of_get_property(np, "qcom,nonremovable", NULL))
 		pdata->nonremovable = true;
-	if (of_get_property(np, "qcom,sdcc-disable_cmd23", NULL))
+	if (of_get_property(np, "qcom,disable-cmd23", NULL))
 		pdata->disable_cmd23 = true;
+	of_property_read_u32(np, "qcom,dat1-mpm-int",
+					&pdata->mpm_sdiowakeup_int);
 
 	return pdata;
 err:
@@ -5662,7 +5749,7 @@
 	}
 
 	host = mmc_priv(mmc);
-	host->pdev_id = pdev->id;
+	host->pdev = pdev;
 	host->plat = plat;
 	host->mmc = mmc;
 	host->curr.cmd = NULL;
@@ -5763,6 +5850,7 @@
 		dev_err(&pdev->dev, "Failed to read MCLK\n");
 
 	set_default_hw_caps(host);
+	host->saved_tuning_phase = INVALID_TUNING_PHASE;
 
 	/*
 	 * Set the register write delay according to min. clock frequency
@@ -5899,6 +5987,14 @@
 	disable_irq(core_irqres->start);
 	host->sdcc_irq_disabled = 1;
 
+	if (!plat->sdiowakeup_irq) {
+		/* Check if registered as IORESOURCE_IRQ */
+		plat->sdiowakeup_irq =
+			platform_get_irq_byname(pdev, "sdiowakeup_irq");
+		if (plat->sdiowakeup_irq < 0)
+			plat->sdiowakeup_irq = 0;
+	}
+
 	if (plat->sdiowakeup_irq) {
 		wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
 				mmc_hostname(mmc));
@@ -6145,7 +6241,7 @@
  vreg_deinit:
 	msmsdcc_vreg_init(host, false);
  clk_disable:
-	clk_disable(host->clk);
+	clk_disable_unprepare(host->clk);
 	msmsdcc_msm_bus_unregister(host);
  pm_qos_remove:
 	if (host->cpu_dma_latency)
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index c66d1a5..bb1b211 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -2,7 +2,7 @@
  *  linux/drivers/mmc/host/msmsdcc.h - QCT MSM7K SDC Controller
  *
  *  Copyright (C) 2008 Google, All Rights Reserved.
- *  Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ *  Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -321,8 +321,7 @@
 	unsigned int			dest_pipe_index;
 	unsigned int			busy;
 	unsigned int			xfer_req_cnt;
-	bool				pipe_reset_pending;
-	bool				reset_device;
+	bool				reset_bam;
 	struct tasklet_struct		tlet;
 };
 
@@ -347,7 +346,7 @@
 	void __iomem		*dml_base;
 	void __iomem		*bam_base;
 
-	int			pdev_id;
+	struct platform_device	*pdev;
 
 	struct msmsdcc_curr_req	curr;
 
@@ -428,6 +427,7 @@
 	struct dentry *debugfs_idle_tout;
 	struct dentry *debugfs_pio_mode;
 	struct dentry *debugfs_pm_stats;
+	int saved_tuning_phase;
 };
 
 #define MSMSDCC_VERSION_STEP_MASK	0x0000FFFF
@@ -446,6 +446,8 @@
 #define MSMSDCC_IO_PAD_PWR_SWITCH	(1 << 8)
 #define MSMSDCC_AUTO_CMD19	(1 << 9)
 #define MSMSDCC_AUTO_CMD21	(1 << 10)
+#define MSMSDCC_SW_RST_CFG_BROKEN	(1 << 11)
+#define MSMSDCC_DATA_PEND_FOR_CMD53	(1 << 12)
 
 #define set_hw_caps(h, val)		((h)->hw_caps |= val)
 #define is_sps_mode(h)			((h)->hw_caps & MSMSDCC_SPS_BAM_SUP)
@@ -459,6 +461,9 @@
 #define is_io_pad_pwr_switch(h)	((h)->hw_caps & MSMSDCC_IO_PAD_PWR_SWITCH)
 #define is_auto_cmd19(h)		((h)->hw_caps & MSMSDCC_AUTO_CMD19)
 #define is_auto_cmd21(h)		((h)->hw_caps & MSMSDCC_AUTO_CMD21)
+#define is_sw_reset_save_config_broken(h) \
+				((h)->hw_caps & MSMSDCC_SW_RST_CFG_BROKEN)
+#define is_data_pend_for_cmd53(h) ((h)->hw_caps & MSMSDCC_DATA_PEND_FOR_CMD53)
 
 /* Set controller capabilities based on version */
 static inline void set_default_hw_caps(struct msmsdcc_host *host)
@@ -490,7 +495,12 @@
 		host->hw_caps |= MSMSDCC_AUTO_CMD21;
 
 	if (step >= 0x2b) /* SDCC v4 2.1.0 and greater */
-		host->hw_caps |= MSMSDCC_SW_RST | MSMSDCC_AUTO_CMD21;
+		host->hw_caps |= MSMSDCC_SW_RST | MSMSDCC_SW_RST_CFG |
+				 MSMSDCC_AUTO_CMD21 |
+				 MSMSDCC_DATA_PEND_FOR_CMD53;
+
+	if (step == 0x2b)
+		host->hw_caps |= MSMSDCC_SW_RST_CFG_BROKEN;
 }
 
 int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave);
diff --git a/drivers/net/ethernet/msm/msm_rmnet.c b/drivers/net/ethernet/msm/msm_rmnet.c
index 41ad8af..4af2d8c 100644
--- a/drivers/net/ethernet/msm/msm_rmnet.c
+++ b/drivers/net/ethernet/msm/msm_rmnet.c
@@ -3,7 +3,7 @@
  * Virtual Ethernet Interface for MSM7K Networking
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -37,7 +37,7 @@
 #endif
 
 #include <mach/msm_smd.h>
-#include <mach/peripheral-loader.h>
+#include <mach/subsystem_restart.h>
 
 /* Debug message support */
 static int msm_rmnet_debug_mask;
@@ -403,7 +403,7 @@
 static void msm_rmnet_unload_modem(void *pil)
 {
 	if (pil)
-		pil_put(pil);
+		subsystem_put(pil);
 }
 
 static void *msm_rmnet_load_modem(struct net_device *dev)
@@ -412,7 +412,7 @@
 	int rc;
 	struct rmnet_private *p = netdev_priv(dev);
 
-	pil = pil_get("modem");
+	pil = subsystem_get("modem");
 	if (IS_ERR(pil))
 		pr_err("[%s] %s: modem load failed\n",
 			dev->name, __func__);
diff --git a/drivers/net/usb/rmnet_usb_ctrl.c b/drivers/net/usb/rmnet_usb_ctrl.c
index 7ed8ffa..f87b3b9 100644
--- a/drivers/net/usb/rmnet_usb_ctrl.c
+++ b/drivers/net/usb/rmnet_usb_ctrl.c
@@ -339,8 +339,10 @@
 
 int rmnet_usb_ctrl_suspend(struct rmnet_ctrl_dev *dev)
 {
-	if (!flush_work_sync(&dev->get_encap_work))
-		usb_kill_anchored_urbs(&dev->rx_submitted);
+	if (work_busy(&dev->get_encap_work))
+		return -EBUSY;
+
+	usb_kill_anchored_urbs(&dev->rx_submitted);
 
 	return 0;
 }
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 2bf857c..6e42fdb 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -25,9 +25,12 @@
 #include <linux/delay.h>
 #include <linux/of.h>
 #include <linux/of_gpio.h>
-#include <mach/peripheral-loader.h>
+#include <linux/clk.h>
+
 #include <mach/msm_smd.h>
 #include <mach/msm_iomap.h>
+#include <mach/subsystem_restart.h>
+
 #ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
 #include "wcnss_prealloc.h"
 #endif
@@ -43,6 +46,21 @@
 module_param(has_48mhz_xo, int, S_IWUSR | S_IRUGO);
 MODULE_PARM_DESC(has_48mhz_xo, "Is an external 48 MHz XO present");
 
+static DEFINE_SPINLOCK(reg_spinlock);
+
+#define MSM_RIVA_PHYS			0x03204000
+#define MSM_PRONTO_PHYS			0xfb21b000
+
+#define RIVA_SPARE_OFFSET		0x0b4
+#define RIVA_SUSPEND_BIT		BIT(24)
+
+#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 WCNSS_CTRL_CHANNEL			"WCNSS_CTRL"
 #define WCNSS_MAX_FRAME_SIZE		500
 #define WCNSS_VERSION_LEN			30
@@ -89,6 +107,7 @@
 	struct work_struct wcnssctrl_version_work;
 	struct work_struct wcnssctrl_rx_work;
 	struct wake_lock wcnss_wake_lock;
+	void __iomem *msm_wcnss_base;
 } *penv = NULL;
 
 static ssize_t wcnss_serial_number_show(struct device *dev,
@@ -160,15 +179,50 @@
 static DEVICE_ATTR(wcnss_version, S_IRUSR,
 		wcnss_version_show, NULL);
 
+/* wcnss_reset_intr() is invoked when host drivers fails to
+ * communicate with WCNSS over SMD; so logging these registers
+ * helps to know WCNSS failure reason */
+static void wcnss_log_ccpu_regs(void)
+{
+	void __iomem *ccu_base;
+	void __iomem *ccu_reg;
+	u32 reg = 0;
+
+	ccu_base = ioremap(MSM_RIVA_CCU_BASE, SZ_512);
+	if (!ccu_base) {
+		pr_err("%s: ioremap WCNSS CCU reg failed\n", __func__);
+		return;
+	}
+
+	ccu_reg = ccu_base + CCU_INVALID_ADDR_OFFSET;
+	reg = readl_relaxed(ccu_reg);
+	pr_info("%s: CCU_CCPU_INVALID_ADDR %08x\n", __func__, reg);
+
+	ccu_reg = ccu_base + CCU_LAST_ADDR0_OFFSET;
+	reg = readl_relaxed(ccu_reg);
+	pr_info("%s: CCU_CCPU_LAST_ADDR0 %08x\n", __func__, reg);
+
+	ccu_reg = ccu_base + CCU_LAST_ADDR1_OFFSET;
+	reg = readl_relaxed(ccu_reg);
+	pr_info("%s: CCU_CCPU_LAST_ADDR1 %08x\n", __func__, reg);
+
+	ccu_reg = ccu_base + CCU_LAST_ADDR2_OFFSET;
+	reg = readl_relaxed(ccu_reg);
+	pr_info("%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg);
+
+	iounmap(ccu_base);
+}
+
 /* interface to reset Riva by sending the reset interrupt */
 void wcnss_reset_intr(void)
 {
-	if (wcnss_hardware_type() == WCNSS_RIVA_HW) {
-		wmb();
-		__raw_writel(1 << 24, MSM_APCS_GCC_BASE + 0x8);
-	} else {
+	if (wcnss_hardware_type() != WCNSS_RIVA_HW) {
 		pr_err("%s: reset interrupt not supported\n", __func__);
+		return;
 	}
+	wcnss_log_ccpu_regs();
+	wmb();
+	__raw_writel(1 << 24, MSM_APCS_GCC_BASE + 0x8);
 }
 EXPORT_SYMBOL(wcnss_reset_intr);
 
@@ -487,6 +541,87 @@
 }
 EXPORT_SYMBOL(wcnss_get_serial_number);
 
+static int enable_wcnss_suspend_notify;
+
+static int enable_wcnss_suspend_notify_set(const char *val,
+				struct kernel_param *kp)
+{
+	int ret;
+
+	ret = param_set_int(val, kp);
+	if (ret)
+		return ret;
+
+	if (enable_wcnss_suspend_notify)
+		pr_debug("Suspend notification activated for wcnss\n");
+
+	return 0;
+}
+module_param_call(enable_wcnss_suspend_notify, enable_wcnss_suspend_notify_set,
+		param_get_int, &enable_wcnss_suspend_notify, S_IRUGO | S_IWUSR);
+
+
+void wcnss_suspend_notify(void)
+{
+	void __iomem *pmu_spare_reg;
+	u32 reg = 0;
+	unsigned long flags;
+	struct clk *cxo = clk_get(&penv->pdev->dev, "cxo");
+	int rc = 0;
+
+	if (!enable_wcnss_suspend_notify)
+		return;
+
+	if (wcnss_hardware_type() == WCNSS_PRONTO_HW)
+		return;
+
+	/* For Riva */
+	rc = clk_prepare_enable(cxo);
+	if (rc) {
+		pr_err("cxo enable failed\n");
+		return;
+	}
+	pmu_spare_reg = penv->msm_wcnss_base + RIVA_SPARE_OFFSET;
+	spin_lock_irqsave(&reg_spinlock, flags);
+	reg = readl_relaxed(pmu_spare_reg);
+	reg |= RIVA_SUSPEND_BIT;
+	writel_relaxed(reg, pmu_spare_reg);
+	spin_unlock_irqrestore(&reg_spinlock, flags);
+	clk_disable_unprepare(cxo);
+}
+EXPORT_SYMBOL(wcnss_suspend_notify);
+
+void wcnss_resume_notify(void)
+{
+	void __iomem *pmu_spare_reg;
+	u32 reg = 0;
+	unsigned long flags;
+	struct clk *cxo = clk_get(&penv->pdev->dev, "cxo");
+	int rc = 0;
+
+	if (!enable_wcnss_suspend_notify)
+		return;
+
+	if (wcnss_hardware_type() == WCNSS_PRONTO_HW)
+		return;
+
+	/* For Riva */
+	pmu_spare_reg = penv->msm_wcnss_base + RIVA_SPARE_OFFSET;
+
+	rc = clk_prepare_enable(cxo);
+	if (rc) {
+		pr_err("cxo enable failed\n");
+		return;
+	}
+	spin_lock_irqsave(&reg_spinlock, flags);
+	reg = readl_relaxed(pmu_spare_reg);
+	reg &= ~RIVA_SUSPEND_BIT;
+	writel_relaxed(reg, pmu_spare_reg);
+	spin_unlock_irqrestore(&reg_spinlock, flags);
+	clk_disable_unprepare(cxo);
+}
+EXPORT_SYMBOL(wcnss_resume_notify);
+
 static int wcnss_wlan_suspend(struct device *dev)
 {
 	if (penv && dev && (dev == &penv->pdev->dev) &&
@@ -610,6 +745,8 @@
 {
 	int ret;
 	struct qcom_wcnss_opts *pdata;
+	unsigned long wcnss_phys_addr;
+	int size = 0;
 	int has_pronto_hw = of_property_read_bool(pdev->dev.of_node,
 									"qcom,has_pronto_hw");
 
@@ -664,7 +801,7 @@
 	}
 
 	/* trigger initialization of the WCNSS */
-	penv->pil = pil_get(WCNSS_PIL_DEVICE);
+	penv->pil = subsystem_get(WCNSS_PIL_DEVICE);
 	if (IS_ERR(penv->pil)) {
 		dev_err(&pdev->dev, "Peripheral Loader failed on WCNSS.\n");
 		ret = PTR_ERR(penv->pil);
@@ -690,17 +827,34 @@
 
 	wake_lock_init(&penv->wcnss_wake_lock, WAKE_LOCK_SUSPEND, "wcnss");
 
+	if (wcnss_hardware_type() == WCNSS_PRONTO_HW) {
+		size = 0x3000;
+		wcnss_phys_addr = MSM_PRONTO_PHYS;
+	} else {
+		wcnss_phys_addr = MSM_RIVA_PHYS;
+		size = SZ_256;
+	}
+
+	penv->msm_wcnss_base = ioremap(wcnss_phys_addr, size);
+	if (!penv->msm_wcnss_base) {
+		ret = -ENOMEM;
+		pr_err("%s: ioremap wcnss physical failed\n", __func__);
+		goto fail_wake;
+	}
+
 	return 0;
 
+fail_wake:
+	wake_lock_destroy(&penv->wcnss_wake_lock);
 fail_res:
 	if (penv->pil)
-		pil_put(penv->pil);
+		subsystem_put(penv->pil);
 fail_pil:
 	wcnss_wlan_power(&pdev->dev, &penv->wlan_config,
 				WCNSS_WLAN_SWITCH_OFF);
 fail_power:
 	if (has_pronto_hw)
-		ret = wcnss_pronto_gpios_config(&pdev->dev, false);
+		wcnss_pronto_gpios_config(&pdev->dev, false);
 	else
 		wcnss_gpios_config(penv->gpios_5wire, false);
 fail_gpio_res:
@@ -840,7 +994,7 @@
 {
 	if (penv) {
 		if (penv->pil)
-			pil_put(penv->pil);
+			subsystem_put(penv->pil);
 
 
 		kfree(penv);
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 6b54b23..9a18a97 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -617,21 +617,6 @@
 	int error = 0;
 
 	/*
-	 * If a PCI device configured to wake up the system from sleep states
-	 * has been suspended at run time and there's a resume request pending
-	 * for it, this is equivalent to the device signaling wakeup, so the
-	 * system suspend operation should be aborted.
-	 */
-	pm_runtime_get_noresume(dev);
-	if (pm_runtime_barrier(dev) && device_may_wakeup(dev))
-		pm_wakeup_event(dev, 0);
-
-	if (pm_wakeup_pending()) {
-		pm_runtime_put_sync(dev);
-		return -EBUSY;
-	}
-
-	/*
 	 * PCI devices suspended at run time need to be resumed at this
 	 * point, because in general it is necessary to reconfigure them for
 	 * system suspend.  Namely, if the device is supposed to wake up the
@@ -654,8 +639,6 @@
 
 	if (drv && drv->pm && drv->pm->complete)
 		drv->pm->complete(dev);
-
-	pm_runtime_put_sync(dev);
 }
 
 #else /* !CONFIG_PM_SLEEP */
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index 25febff..e9c3371 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -2122,14 +2122,6 @@
 		SPS_DBG("sps:bamdma_restricted_pipes=0x%x.",
 			sps->bamdma_restricted_pipes);
 
-	if (of_property_read_u32((&pdev->dev)->of_node,
-				"qcom,device-type",
-				&d_type)) {
-		d_type = 1;
-		SPS_DBG("sps:default device type.\n");
-	} else
-		SPS_DBG("sps:device type is %d.", d_type);
-
 	resource  = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (resource) {
 		sps->bamdma_bam_phys_base = resource->start;
@@ -2174,6 +2166,14 @@
 	}
 #endif
 
+	if (of_property_read_u32((&pdev->dev)->of_node,
+				"qcom,device-type",
+				&d_type)) {
+		d_type = 1;
+		SPS_DBG("sps:default device type.\n");
+	} else
+		SPS_DBG("sps:device type is %d.", d_type);
+
 	return 0;
 }
 
diff --git a/drivers/platform/msm/sps/sps_dma.c b/drivers/platform/msm/sps/sps_dma.c
index f8b4f51d..335de9a 100644
--- a/drivers/platform/msm/sps/sps_dma.c
+++ b/drivers/platform/msm/sps/sps_dma.c
@@ -274,7 +274,6 @@
 {
 	struct bamdma_device *dev;
 	struct sps_bam_props *props;
-	u32 chan;
 	int result = SPS_ERROR;
 
 	mutex_lock(&bam_dma_lock);
@@ -343,14 +342,6 @@
 
 	dev->num_pipes = dev->bam->props.num_pipes;
 
-	/* Disable all channels */
-	if (dev->local)
-		for (chan = 0; chan < (dev->num_pipes / 2); chan++) {
-			dma_write_reg_field(dev->virt_addr,
-					    DMA_CHNL_CONFIG(chan),
-					    DMA_CHNL_ENABLE, 0);
-		}
-
 	result = 0;
 exit_err:
 	if (result) {
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 7b7e05e..bc2e2ae 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -333,6 +333,16 @@
 	  To compile this driver as a module, choose M here: the module will
 	  be called smb137b.
 
+config SMB137C_CHARGER
+	tristate "Summit SMB137C Battery Charger"
+	depends on I2C
+	depends on OF
+	help
+	  The SMB137C charger chip from Summit is a switching mode based
+	  charging solution.  This driver supports enabling and disabling
+	  charging, setting the input current limit, and enabling USB OTG mode
+	  in order to supply 5 V on the VBUS line.
+
 config SMB349_CHARGER
 	tristate "smb349 charger"
 	depends on I2C
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 3e74f35..990bd03 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -55,6 +55,7 @@
 obj-$(CONFIG_BATTERY_BQ27541)	+= bq27541_fuelgauger.o
 obj-$(CONFIG_BATTERY_BQ28400)	+= bq28400_battery.o
 obj-$(CONFIG_SMB137B_CHARGER)   += smb137b.o
+obj-$(CONFIG_SMB137C_CHARGER)	+= smb137c-charger.o
 obj-$(CONFIG_PM8XXX_CCADC)	+= pm8xxx-ccadc.o
 obj-$(CONFIG_PM8921_BMS)	+= pm8921-bms.o
 obj-$(CONFIG_QPNP_BMS)		+= qpnp-bms.o
diff --git a/drivers/power/bq28400_battery.c b/drivers/power/bq28400_battery.c
index 39d52cb..77e74fa 100644
--- a/drivers/power/bq28400_battery.c
+++ b/drivers/power/bq28400_battery.c
@@ -486,6 +486,8 @@
 	u16 battery_status;
 
 	battery_status = bq28400_read_reg(client, SBS_BATTERY_STATUS);
+	rsoc = bq28400_read_rsoc(client);
+	current_ma = bq28400_read_current(client);
 
 	if (battery_status & BAT_STATUS_EMPTY)
 		pr_debug("Battery report Empty.\n");
@@ -493,29 +495,31 @@
 	/* Battery may report FULL before rsoc is 100%
 	 * for protection and cell-balancing.
 	 * The FULL report may remain when rsoc drops from 100%.
+	 * If battery is full but DC-Jack is removed then report discahrging.
 	 */
 	if (battery_status & BAT_STATUS_FULL) {
 		pr_debug("Battery report Full.\n");
 		bq28400_enable_charging(bq28400_dev, false);
+		if (current_ma < 0)
+			return POWER_SUPPLY_STATUS_DISCHARGING;
 		return POWER_SUPPLY_STATUS_FULL;
 	}
 
-	rsoc = bq28400_read_rsoc(client);
-	current_ma = bq28400_read_current(client);
-
 	if (rsoc == 100) {
 		bq28400_enable_charging(bq28400_dev, false);
 		pr_debug("Full.\n");
 		return POWER_SUPPLY_STATUS_FULL;
 	}
 
+	/* Enable charging when battery is not full */
+	bq28400_enable_charging(bq28400_dev, true);
+
 	/*
 	* Positive current indicates charging
 	* Negative current indicates discharging.
 	* Charging is stopped at termination-current.
 	*/
 	if (current_ma < 0) {
-		bq28400_enable_charging(bq28400_dev, true);
 		pr_debug("Discharging.\n");
 		status = POWER_SUPPLY_STATUS_DISCHARGING;
 	} else if (current_ma > BQ_TERMINATION_CURRENT_MA) {
@@ -755,6 +759,12 @@
 static void bq28400_external_power_changed(struct power_supply *psy)
 {
 	pr_debug("Notify power_supply_changed.\n");
+
+	/* The battery gauge monitors the current and voltage every 1 second.
+	 * Therefore a delay from the time that the charger start/stop charging
+	 * until the battery gauge detects it.
+	 */
+	msleep(1000);
 	/* Update LEDs and notify uevents */
 	power_supply_changed(&bq28400_dev->batt_psy);
 }
@@ -818,6 +828,11 @@
 		return -EIO;
 	}
 
+	if (bq28400_read_reg(client, SBS_BATTERY_STATUS) < 0) {
+		pr_err("Device doesn't exist.\n");
+		return -ENODEV;
+	}
+
 	bq28400_dev = kzalloc(sizeof(*bq28400_dev), GFP_KERNEL);
 	if (!bq28400_dev) {
 		pr_err(" alloc fail.\n");
@@ -876,7 +891,8 @@
 }
 
 static const struct of_device_id bq28400_match[] = {
-	{ .compatible = "ti,bq28400-battery", },
+	{ .compatible = "ti,bq28400-battery" },
+	{ .compatible = "ti,bq30z55-battery" },
 	{ },
 	};
 
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 23903df..81be519 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -856,6 +856,22 @@
 	*val = cc_uah;
 }
 
+int pm8921_bms_cc_uah(int *cc_uah)
+{
+	int cc;
+
+	*cc_uah = 0;
+
+	if (!the_chip)
+		return -EINVAL;
+
+	read_cc(the_chip, &cc);
+	calculate_cc_uah(the_chip, cc, cc_uah);
+
+	return 0;
+}
+EXPORT_SYMBOL(pm8921_bms_cc_uah);
+
 static int calculate_termination_uuc(struct pm8921_bms_chip *chip,
 				 int batt_temp, int chargecycles,
 				int fcc_uah, int i_ma,
@@ -1398,7 +1414,7 @@
 						(s64)fcc_uah - uuc_uah);
 	soc_est = bound_soc(soc_est);
 
-	if (ibat_ua < 0) {
+	if (ibat_ua < 0 && pm8921_is_batfet_closed()) {
 		soc = charging_adjustments(chip, soc, vbat_uv, ibat_ua,
 				batt_temp, chargecycles,
 				fcc_uah, cc_uah, uuc_uah);
@@ -1895,7 +1911,8 @@
 	}
 
 	/* last_soc < soc  ... scale and catch up */
-	if (last_soc != -EINVAL && last_soc < soc && soc != 100)
+	if (last_soc != -EINVAL && last_soc < soc && soc != 100
+				&& chip->catch_up_time_us != 0)
 		soc = scale_soc_while_chg(chip, delta_time_us, soc, last_soc);
 
 	last_soc = soc;
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index cf34df5..cb6b23e 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -87,6 +87,7 @@
 #define EOC_CHECK_PERIOD_MS	10000
 /* check for USB unplug every 200 msecs */
 #define UNPLUG_CHECK_WAIT_PERIOD_MS 200
+#define USB_TRIM_ENTRIES 16
 
 enum chg_fsm_state {
 	FSM_STATE_OFF_0 = 0,
@@ -209,7 +210,6 @@
  * @dc_present:			present status of dc
  * @usb_charger_current:	usb current to charge the battery with used when
  *				the usb path is enabled or charging is resumed
- * @safety_time:		max time for which charging will happen
  * @update_time:		how frequently the userland needs to be updated
  * @max_voltage_mv:		the max volts the batt should be charged up to
  * @min_voltage_mv:		the min battery voltage before turning the FETon
@@ -230,12 +230,12 @@
 	unsigned int			usb_charger_current;
 	unsigned int			max_bat_chg_current;
 	unsigned int			pmic_chg_irq[PM_CHG_MAX_INTS];
-	unsigned int			safety_time;
 	unsigned int			ttrkl_time;
 	unsigned int			update_time;
 	unsigned int			max_voltage_mv;
 	unsigned int			min_voltage_mv;
 	unsigned int			uvd_voltage_mv;
+	unsigned int			safe_current_ma;
 	unsigned int			alarm_low_mv;
 	unsigned int			alarm_high_mv;
 	int				cool_temp_dc;
@@ -259,6 +259,7 @@
 	struct power_supply		batt_psy;
 	struct dentry			*dent;
 	struct bms_notify		bms_notify;
+	int				*usb_trim_table;
 	bool				keep_btm_on_suspend;
 	bool				ext_charging;
 	bool				ext_charge_done;
@@ -709,6 +710,46 @@
 	u8	value;
 };
 
+/* USB Trim tables */
+static int usb_trim_8038_table[USB_TRIM_ENTRIES] = {
+	0x0,
+	0x0,
+	-0x9,
+	0x0,
+	-0xD,
+	0x0,
+	-0x10,
+	-0x11,
+	0x0,
+	0x0,
+	-0x25,
+	0x0,
+	-0x28,
+	0x0,
+	-0x32,
+	0x0
+};
+
+static int usb_trim_8917_table[USB_TRIM_ENTRIES] = {
+	0x0,
+	0x0,
+	0xA,
+	0xC,
+	0x10,
+	0x10,
+	0x13,
+	0x14,
+	0x13,
+	0x16,
+	0x1A,
+	0x1D,
+	0x1D,
+	0x21,
+	0x24,
+	0x26
+};
+
+/* Maximum USB  setting table */
 static struct usb_ma_limit_entry usb_ma_table[] = {
 	{100, 0x0},
 	{200, 0x1},
@@ -728,18 +769,92 @@
 	{1600, 0xF},
 };
 
+#define REG_SBI_CONFIG		0x04F
+#define PAGE3_ENABLE_MASK	0x6
+#define USB_OVP_TRIM_MASK	0x3F
+#define USB_OVP_TRIM_MIN	0x00
+#define REG_USB_OVP_TRIM_ORIG_LSB	0x10A
+#define REG_USB_OVP_TRIM_ORIG_MSB	0x09C
+static int pm_chg_usb_trim(struct pm8921_chg_chip *chip, int index)
+{
+	u8 temp, sbi_config, msb, lsb;
+	s8 trim;
+	int rc = 0;
+	static u8 usb_trim_reg_orig = 0xFF;
+
+	/* No trim data for PM8921 */
+	if (!chip->usb_trim_table)
+		return 0;
+
+	if (usb_trim_reg_orig == 0xFF) {
+		rc = pm8xxx_readb(chip->dev->parent,
+				REG_USB_OVP_TRIM_ORIG_MSB, &msb);
+		if (rc) {
+			pr_err("error = %d reading sbi config reg\n", rc);
+			return rc;
+		}
+
+		rc = pm8xxx_readb(chip->dev->parent,
+				REG_USB_OVP_TRIM_ORIG_LSB, &lsb);
+		if (rc) {
+			pr_err("error = %d reading sbi config reg\n", rc);
+			return rc;
+		}
+
+		msb = msb >> 5;
+		lsb = lsb >> 5;
+		usb_trim_reg_orig = msb << 3 | lsb;
+	}
+
+	/* use the original trim value */
+	trim = usb_trim_reg_orig;
+
+	trim += chip->usb_trim_table[index];
+	if (trim < 0)
+		trim = 0;
+
+	pr_err("trim_orig %d write 0x%x index=%d value 0x%x to USB_OVP_TRIM\n",
+		usb_trim_reg_orig, trim, index, chip->usb_trim_table[index]);
+
+	rc = pm8xxx_readb(chip->dev->parent, REG_SBI_CONFIG, &sbi_config);
+	if (rc) {
+		pr_err("error = %d reading sbi config reg\n", rc);
+		return rc;
+	}
+
+	temp = sbi_config | PAGE3_ENABLE_MASK;
+	rc = pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, temp);
+	if (rc) {
+		pr_err("error = %d writing sbi config reg\n", rc);
+		return rc;
+	}
+
+	rc = pm_chg_masked_write(chip, USB_OVP_TRIM, USB_OVP_TRIM_MASK, trim);
+	if (rc) {
+		pr_err("error = %d writing USB_OVP_TRIM\n", rc);
+		return rc;
+	}
+
+	rc = pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, sbi_config);
+	if (rc) {
+		pr_err("error = %d writing sbi config reg\n", rc);
+		return rc;
+	}
+	return rc;
+}
+
 #define PM8921_CHG_IUSB_MASK 0x1C
 #define PM8921_CHG_IUSB_SHIFT 2
 #define PM8921_CHG_IUSB_MAX  7
 #define PM8921_CHG_IUSB_MIN  0
 #define PM8917_IUSB_FINE_RES BIT(0)
-static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int reg_val)
+static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int index)
 {
-	u8 temp, fineres;
+	u8 temp, fineres, reg_val;
 	int rc;
 
-	fineres = PM8917_IUSB_FINE_RES & usb_ma_table[reg_val].value;
-	reg_val = usb_ma_table[reg_val].value >> 1;
+	reg_val = usb_ma_table[index].value >> 1;
+	fineres = PM8917_IUSB_FINE_RES & usb_ma_table[index].value;
 
 	if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
 		pr_err("bad mA=%d asked to set\n", reg_val);
@@ -764,17 +879,25 @@
 		if (fineres) {
 			rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
 				PM8917_IUSB_FINE_RES, fineres);
-			if (rc)
+			if (rc) {
 				pr_err("Failed to write ISUB_FINE_RES rc=%d\n",
 					rc);
+				return rc;
+			}
 		}
 	} else {
 		rc = pm_chg_masked_write(chip, PBL_ACCESS2,
 			PM8921_CHG_IUSB_MASK, temp);
-		if (rc)
+		if (rc) {
 			pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
+			return rc;
+		}
 	}
 
+	rc = pm_chg_usb_trim(chip, index);
+	if (rc)
+			pr_err("unable to set usb trim rc = %d\n", rc);
+
 	return rc;
 }
 
@@ -1354,6 +1477,7 @@
 	POWER_SUPPLY_PROP_CURRENT_NOW,
 	POWER_SUPPLY_PROP_TEMP,
 	POWER_SUPPLY_PROP_ENERGY_FULL,
+	POWER_SUPPLY_PROP_CHARGE_NOW,
 };
 
 static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
@@ -1489,6 +1613,20 @@
 	return rc;
 }
 
+static int get_prop_batt_charge_now(struct pm8921_chg_chip *chip)
+{
+	int rc;
+	int cc_uah;
+
+	rc = pm8921_bms_cc_uah(&cc_uah);
+
+	if (rc == 0)
+		return cc_uah;
+
+	pr_err("unable to get batt fcc rc = %d\n", rc);
+	return rc;
+}
+
 static int get_prop_batt_health(struct pm8921_chg_chip *chip)
 {
 	int temp;
@@ -1627,6 +1765,9 @@
 	case POWER_SUPPLY_PROP_ENERGY_FULL:
 		val->intval = get_prop_batt_fcc(chip) * 1000;
 		break;
+	case POWER_SUPPLY_PROP_CHARGE_NOW:
+		val->intval = get_prop_batt_charge_now(chip);
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -1693,15 +1834,14 @@
 		}
 
 		/* Check if IUSB_FINE_RES is available */
-		if ((usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
+		while ((usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
 				&& !the_chip->iusb_fine_res)
 			i--;
 		if (i < 0)
 			i = 0;
 		rc = pm_chg_iusbmax_set(the_chip, i);
-		if (rc) {
+		if (rc)
 			pr_err("unable to set iusb to %d rc = %d\n", i, rc);
-		}
 	}
 }
 
@@ -2673,8 +2813,8 @@
 			goto check_again_later;
 		}
 	}
-
-	if (active_path & USB_ACTIVE_BIT) {
+	/* AICL only for usb wall charger */
+	if ((active_path & USB_ACTIVE_BIT) && usb_target_ma > 0) {
 		reg_loop = pm_chg_get_regulation_loop(chip);
 		pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
 		if ((reg_loop & VIN_ACTIVE_BIT) &&
@@ -2719,7 +2859,9 @@
 		unplug_ovp_fet_open(chip);
 	}
 
+	/* AICL only for usb wall charger */
 	if (!(reg_loop & VIN_ACTIVE_BIT) && (active_path & USB_ACTIVE_BIT)
+		&& usb_target_ma > 0
 		&& !charging_disabled) {
 		/* only increase iusb_max if vin loop not active */
 		if (usb_ma < usb_target_ma) {
@@ -3533,6 +3675,12 @@
 			chip->dc_present,
 			get_prop_batt_present(chip),
 			fsm_state);
+
+	/* Determine which USB trim column to use */
+	if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
+		chip->usb_trim_table = usb_trim_8917_table;
+	else if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8038)
+		chip->usb_trim_table = usb_trim_8038_table;
 }
 
 struct pm_chg_irq_init_data {
@@ -3739,11 +3887,15 @@
 #define CHG_BAT_TEMP_DIS_BIT	BIT(2)
 #define SAFE_CURRENT_MA		1500
 #define PM_SUB_REV		0x001
+#define MIN_CHARGE_CURRENT_MA	350
+#define DEFAULT_SAFETY_MINUTES	500
 static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
 {
 	int rc;
 	int vdd_safe;
 	u8 subrev;
+	int fcc_uah;
+	int safety_time = DEFAULT_SAFETY_MINUTES;
 
 	/* forcing 19p2mhz before accessing any charger registers */
 	pm8921_chg_force_19p2mhz_clk(chip);
@@ -3784,7 +3936,11 @@
 						chip->max_voltage_mv, rc);
 		return rc;
 	}
-	rc = pm_chg_ibatsafe_set(chip, SAFE_CURRENT_MA);
+
+	if (chip->safe_current_ma == 0)
+		chip->safe_current_ma = SAFE_CURRENT_MA;
+
+	rc = pm_chg_ibatsafe_set(chip, chip->safe_current_ma);
 	if (rc) {
 		pr_err("Failed to set max voltage to %d rc=%d\n",
 						SAFE_CURRENT_MA, rc);
@@ -3812,20 +3968,26 @@
 		return rc;
 	}
 
-	if (chip->safety_time != 0) {
-		rc = pm_chg_tchg_max_set(chip, chip->safety_time);
-		if (rc) {
-			pr_err("Failed to set max time to %d minutes rc=%d\n",
-							chip->safety_time, rc);
-			return rc;
-		}
+	fcc_uah = pm8921_bms_get_fcc();
+	if (fcc_uah > 0) {
+		safety_time = div_s64((s64)fcc_uah * 60,
+						1000 * MIN_CHARGE_CURRENT_MA);
+		/* add 20 minutes of buffer time */
+		safety_time += 20;
+	}
+
+	rc = pm_chg_tchg_max_set(chip, safety_time);
+	if (rc) {
+		pr_err("Failed to set max time to %d minutes rc=%d\n",
+						safety_time, rc);
+		return rc;
 	}
 
 	if (chip->ttrkl_time != 0) {
 		rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
 		if (rc) {
 			pr_err("Failed to set trkl time to %d minutes rc=%d\n",
-							chip->safety_time, rc);
+							chip->ttrkl_time, rc);
 			return rc;
 		}
 	}
@@ -4231,13 +4393,13 @@
 	}
 
 	chip->dev = &pdev->dev;
-	chip->safety_time = pdata->safety_time;
 	chip->ttrkl_time = pdata->ttrkl_time;
 	chip->update_time = pdata->update_time;
 	chip->max_voltage_mv = pdata->max_voltage;
 	chip->alarm_low_mv = pdata->alarm_low_mv;
 	chip->alarm_high_mv = pdata->alarm_high_mv;
 	chip->min_voltage_mv = pdata->min_voltage;
+	chip->safe_current_ma = pdata->safe_current_ma;
 	chip->uvd_voltage_mv = pdata->uvd_thresh_voltage;
 	chip->resume_voltage_delta = pdata->resume_voltage_delta;
 	chip->resume_charge_percent = pdata->resume_charge_percent;
@@ -4339,6 +4501,11 @@
 						vin_collapse_check_worker);
 	INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
 
+	INIT_WORK(&chip->bms_notify.work, bms_notify);
+	INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
+
+	INIT_DELAYED_WORK(&chip->update_heartbeat_work, update_heartbeat);
+
 	rc = request_irqs(chip, pdev);
 	if (rc) {
 		pr_err("couldn't register interrupts rc=%d\n", rc);
@@ -4375,19 +4542,13 @@
 	}
 	create_debugfs_entries(chip);
 
-	INIT_WORK(&chip->bms_notify.work, bms_notify);
-	INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
-
 	/* determine what state the charger is in */
 	determine_initial_state(chip);
 
-	if (chip->update_time) {
-		INIT_DELAYED_WORK(&chip->update_heartbeat_work,
-							update_heartbeat);
+	if (chip->update_time)
 		schedule_delayed_work(&chip->update_heartbeat_work,
 				      round_jiffies_relative(msecs_to_jiffies
 							(chip->update_time)));
-	}
 	return 0;
 
 free_irq:
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index bc012ca..b5559db 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -702,7 +702,7 @@
 }
 
 static int
-qpnp_chg_charge_dis(struct qpnp_chg_chip *chip, int disable)
+qpnp_chg_force_run_on_batt(struct qpnp_chg_chip *chip, int disable)
 {
 	/* This bit forces the charger to run off of the battery rather
 	 * than a connected charger */
@@ -784,11 +784,9 @@
 
 	switch (psp) {
 	case POWER_SUPPLY_PROP_CHARGING_ENABLED:
-		if (val->intval)
-			qpnp_chg_charge_en(chip, val->intval);
-		else
-			qpnp_chg_charge_dis(chip, val->intval);
 		chip->charging_disabled = !(val->intval);
+		qpnp_chg_charge_en(chip, !chip->charging_disabled);
+		qpnp_chg_force_run_on_batt(chip, chip->charging_disabled);
 		break;
 	default:
 		return -EINVAL;
@@ -1275,7 +1273,7 @@
 			qpnp_chg_is_usb_chg_plugged_in(chip));
 
 	qpnp_chg_charge_en(chip, !chip->charging_disabled);
-	qpnp_chg_charge_dis(chip, chip->charging_disabled);
+	qpnp_chg_force_run_on_batt(chip, chip->charging_disabled);
 
 	pr_info("Probe success !\n");
 	return 0;
diff --git a/drivers/power/smb137c-charger.c b/drivers/power/smb137c-charger.c
new file mode 100644
index 0000000..b865bd7
--- /dev/null
+++ b/drivers/power/smb137c-charger.c
@@ -0,0 +1,1352 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/i2c.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+
+struct smb137c_chip {
+	struct i2c_client	*client;
+	struct power_supply	psy;
+	struct power_supply	*usb_psy;
+	struct mutex		lock;
+	int			charge_current_limit_ua;
+	int			input_current_limit_ua;
+	int			term_current_ua;
+	bool			charging_enabled;
+	bool			otg_mode_enabled;
+	bool			charging_allowed;
+};
+
+struct input_current_config {
+	int			current_limit_ua;
+	u8			cmd_b_reg;
+	u8			var_func_reg;
+	u8			input_cur_reg;
+};
+
+struct term_current_config {
+	int			term_current_ua;
+	u8			charge_cur_reg;
+};
+
+#define INPUT_CURRENT(_current_limit_ua, _cmd_b_reg, _var_func_reg, \
+			_input_cur_reg) \
+	{ \
+		.current_limit_ua	= _current_limit_ua, \
+		.cmd_b_reg		= _cmd_b_reg, \
+		.var_func_reg		= _var_func_reg, \
+		.input_cur_reg		= _input_cur_reg, \
+	}
+
+#define CHARGE_CURRENT_REG		0x00
+#define CHARGE_CURRENT_FAST_CHG_MASK	0xE0
+#define CHARGE_CURRENT_FAST_CHG_SHIFT	5
+#define CHARGE_CURRENT_PRE_CHG_MASK	0x18
+#define CHARGE_CURRENT_PRE_CHG_SHIFT	3
+#define CHARGE_CURRENT_TERM_CUR_MASK	0x06
+
+#define INPUT_CURRENT_REG		0x01
+#define INPUT_CURRENT_LIMIT_MASK	0xE0
+
+#define FLOAT_VOLTAGE_REG		0x02
+#define FLOAT_VOLTAGE_MASK		0x7F
+#define FLOAT_VOLTAGE_SHIFT		0
+
+#define CTRL_A_REG			0x03
+#define CTRL_A_AUTO_RECHARGE_MASK	0x80
+#define CTRL_A_AUTO_RECHARGE_ENABLED	0x00
+#define CTRL_A_AUTO_RECHARGE_DISABLED	0x80
+#define CTRL_A_TERM_CUR_MASK		0x40
+#define CTRL_A_TERM_CUR_ENABLED		0x00
+#define CTRL_A_TERM_CUR_DISABLED	0x40
+#define CTRL_A_THRESH_VOLTAGE_MASK	0x38
+#define CTRL_A_THRESH_VOLTAGE_SHIFT	3
+#define CTRL_A_VOUTL_MASK		0x02
+#define CTRL_A_VOUTL_4250MV		0x00
+#define CTRL_A_VOUTL_4460MV		0x02
+#define CTRL_A_THERM_MONITOR_MASK	0x01
+#define CTRL_A_THERM_MONITOR_ENABLED	0x01
+#define CTRL_A_THERM_MONITOR_DISABLED	0x00
+
+#define PIN_CTRL_REG			0x05
+#define PIN_CTRL_DEAD_BATT_CHG_MASK	0x80
+#define PIN_CTRL_DEAD_BATT_CHG_ENABLED	0x80
+#define PIN_CTRL_DEAD_BATT_CHG_DISABLED	0x00
+#define PIN_CTRL_OTG_LBR_MASK		0x20
+#define PIN_CTRL_OTG			0x00
+#define PIN_CTRL_LBR			0x20
+#define PIN_CTRL_USB_CUR_LIMIT_MASK	0x10
+#define PIN_CTRL_USB_CUR_LIMIT_REG	0x00
+#define PIN_CTRL_USB_CUR_LIMIT_PIN	0x10
+#define PIN_CTRL_CHG_EN_MASK		0x0C
+#define PIN_CTRL_CHG_EN_REG_LOW		0x00
+#define PIN_CTRL_CHG_EN_REG_HIGH	0x04
+#define PIN_CTRL_CHG_EN_PIN_LOW		0x08
+#define PIN_CTRL_CHG_EN_PIN_HIGH	0x0C
+#define PIN_CTRL_OTG_CTRL_MASK		0x02
+#define PIN_CTRL_OTG_CTRL_REG		0x00
+#define PIN_CTRL_OTG_CTRL_PIN		0x02
+
+#define OTG_CTRL_REG			0x06
+#define OTG_CTRL_BMD_MASK		0x80
+#define OTG_CTRL_BMD_ENABLED		0x80
+#define OTG_CTRL_BMD_DISABLED		0x00
+#define OTG_CTRL_AUTO_RECHARGE_MASK	0x40
+#define OTG_CTRL_AUTO_RECHARGE_75MV	0x00
+#define OTG_CTRL_AUTO_RECHARGE_120MV	0x40
+
+#define TEMP_MON_REG			0x08
+#define TEMP_MON_THERM_CURRENT_MASK	0xC0
+#define TEMP_MON_THERM_CURRENT_SHIFT	6
+#define TEMP_MON_TEMP_LOW_MASK		0x38
+#define TEMP_MON_TEMP_LOW_SHIFT		3
+#define TEMP_MON_TEMP_HIGH_MASK		0x07
+#define TEMP_MON_TEMP_HIGH_SHIFT	0
+
+#define SAFETY_TIMER_REG		0x09
+#define SAFETY_TIMER_RELOAD_MASK	0x40
+#define SAFETY_TIMER_RELOAD_ENABLED	0x40
+#define SAFETY_TIMER_RELOAD_DISABLED	0x00
+#define SAFETY_TIMER_CHG_TIMEOUT_MASK	0x0C
+#define SAFETY_TIMER_CHG_TIMEOUT_SHIFT	2
+#define SAFETY_TIMER_PRE_CHG_TIME_MASK	0x03
+#define SAFETY_TIMER_PRE_CHG_TIME_SHIFT	0
+
+#define VAR_FUNC_REG			0x0C
+#define VAR_FUNC_USB_MODE_MASK		0x80
+#define VAR_FUNC_BMD_MASK		0x0C
+#define VAR_FUNC_BMD_DISABLED		0x00
+#define VAR_FUNC_BMD_ALGO_PERIODIC	0x04
+#define VAR_FUNC_BMD_ALGO		0x08
+#define VAR_FUNC_BMD_THERM		0x0C
+
+#define CMD_A_REG			0x30
+#define CMD_A_VOLATILE_WRITE_MASK	0x80
+#define CMD_A_VOLATILE_WRITE_ALLOW	0x80
+#define CMD_A_VOLATILE_WRITE_DISALLOW	0x00
+#define CMD_A_FAST_CHG_MASK		0x40
+#define CMD_A_FAST_CHG_ALLOW		0x40
+#define CMD_A_FAST_CHG_DISALLOW		0x00
+#define CMD_A_OTG_MASK			0x10
+#define CMD_A_OTG_ENABLED		0x10
+#define CMD_A_OTG_DISABLED		0x00
+#define CMD_A_CHARGING_MASK		0x02
+#define CMD_A_CHARGING_ENABLED		0x00
+#define CMD_A_CHARGING_DISABLED		0x02
+
+#define CMD_B_REG			0x31
+#define CMD_B_USB_MODE_MASK		0x03
+
+#define DEV_ID_REG			0x33
+#define DEV_ID_PART_MASK		0x80
+#define DEV_ID_PART_SMB137C		0x00
+#define DEV_ID_GUI_REV_MASK		0x70
+#define DEV_ID_GUI_REV_SHIFT		4
+#define DEV_ID_SILICON_REV_MASK		0x0F
+#define DEV_ID_SILICON_REV_SHIFT	0
+
+#define IRQ_STAT_A_REG			0x35
+#define IRQ_STAT_A_BATT_HOT		0x40
+#define IRQ_STAT_A_BATT_COLD		0x10
+
+#define IRQ_STAT_B_REG			0x36
+#define IRQ_STAT_B_BATT_OVERVOLT	0x40
+#define IRQ_STAT_B_BATT_MISSING		0x10
+#define IRQ_STAT_B_BATT_UNDERVOLT	0x04
+
+#define STAT_C_REG			0x3D
+#define STAT_C_CHG_ERROR		0x40
+#define STAT_C_VBATT_LEVEL_BELOW_2P1V	0x10
+#define STAT_C_CHG_STAT_MASK		0x06
+#define STAT_C_CHG_STAT_SHIFT		1
+#define STAT_C_CHG_ENABLED		0x01
+
+/* Charge status register values */
+enum smb137c_charge_status {
+	CHARGE_STAT_NO_CHG	= 0,
+	CHARGE_STAT_PRE_CHG	= 1,
+	CHARGE_STAT_FAST_CHG	= 2,
+	CHARGE_STAT_TAPER_CHG	= 3,
+};
+
+#define PRE_CHARGE_CURRENT_MIN_UA	50000
+#define PRE_CHARGE_CURRENT_MAX_UA	200000
+#define PRE_CHARGE_CURRENT_STEP_UA	50000
+
+#define FLOAT_VOLTAGE_MIN_UV		3460000
+#define FLOAT_VOLTAGE_MAX_UV		4730000
+#define FLOAT_VOLTAGE_STEP_UV		10000
+
+#define PRE_CHG_THRESH_VOLTAGE_MIN_UV	2400000
+#define PRE_CHG_THRESH_VOLTAGE_MAX_UV	3100000
+#define PRE_CHG_THRESH_VOLTAGE_STEP_UV	100000
+
+#define USB_MIN_CURRENT_UA		100000
+
+static int smb137c_read_reg(struct smb137c_chip *chip, u8 reg, u8 *val)
+{
+	int rc;
+
+	rc = i2c_smbus_read_byte_data(chip->client, reg);
+	if (rc < 0) {
+		pr_err("i2c_smbus_read_byte_data failed. reg=0x%02X, rc=%d\n",
+			reg, rc);
+	} else {
+		*val = rc;
+		rc = 0;
+		pr_debug("read(0x%02X)=0x%02X\n", reg, *val);
+	}
+
+	return rc;
+}
+
+static int smb137c_write_reg(struct smb137c_chip *chip, u8 reg, u8 val)
+{
+	int rc;
+
+	rc = i2c_smbus_write_byte_data(chip->client, reg, val);
+	if (rc < 0)
+		pr_err("i2c_smbus_write_byte_data failed. reg=0x%02X, rc=%d\n",
+			reg, rc);
+	else
+		pr_debug("write(0x%02X)=0x%02X\n", reg, val);
+
+	return rc;
+}
+
+static int smb137c_masked_write_reg(struct smb137c_chip *chip, u8 reg, u8 mask,
+					u8 val)
+{
+	u8 reg_val;
+	int rc;
+
+	pr_debug("masked write(0x%02X), mask=0x%02X, value=0x%02X\n", reg, mask,
+		val);
+
+	rc = smb137c_read_reg(chip, reg, &reg_val);
+	if (rc < 0)
+		return rc;
+
+	val = (reg_val & ~mask) | (val & mask);
+
+	if (val != reg_val)
+		rc = smb137c_write_reg(chip, reg, val);
+
+	return rc;
+}
+
+static int smb137c_enable_charging(struct smb137c_chip *chip)
+{
+	int rc = 0;
+
+	chip->charging_allowed = true;
+
+	if (chip->input_current_limit_ua > 0
+	    && chip->charge_current_limit_ua > 0) {
+		if (!chip->charging_enabled)
+			rc = smb137c_masked_write_reg(chip, CMD_A_REG,
+				CMD_A_CHARGING_MASK, CMD_A_CHARGING_ENABLED);
+		chip->charging_enabled = true;
+
+		if (!rc)
+			dev_dbg(&chip->client->dev, "%s\n", __func__);
+	}
+
+	return rc;
+}
+
+static int smb137c_disable_charging(struct smb137c_chip *chip)
+{
+	int rc = 0;
+
+	chip->charging_allowed = false;
+
+	if (chip->charging_enabled) {
+		rc = smb137c_masked_write_reg(chip, CMD_A_REG,
+			CMD_A_CHARGING_MASK, CMD_A_CHARGING_DISABLED);
+	}
+
+	chip->charging_enabled = false;
+
+	if (!rc)
+		dev_dbg(&chip->client->dev, "%s\n", __func__);
+
+	return rc;
+}
+
+static int smb137c_enable_otg_mode(struct smb137c_chip *chip)
+{
+	int rc = 0;
+
+	if (!chip->otg_mode_enabled) {
+		rc = smb137c_masked_write_reg(chip, CMD_A_REG, CMD_A_OTG_MASK,
+					CMD_A_OTG_ENABLED);
+		chip->otg_mode_enabled = true;
+	}
+
+	if (!rc)
+		dev_dbg(&chip->client->dev, "%s\n", __func__);
+
+	return rc;
+}
+
+static int smb137c_disable_otg_mode(struct smb137c_chip *chip)
+{
+	int rc = 0;
+
+	if (chip->otg_mode_enabled) {
+		rc = smb137c_masked_write_reg(chip, CMD_A_REG, CMD_A_OTG_MASK,
+					CMD_A_OTG_DISABLED);
+		chip->otg_mode_enabled = false;
+	}
+
+	if (!rc)
+		dev_dbg(&chip->client->dev, "%s\n", __func__);
+
+	return rc;
+}
+
+static struct input_current_config supported_input_current[] = {
+	INPUT_CURRENT(100000,  0x00, 0x00, 0x00),
+	INPUT_CURRENT(150000,  0x00, 0x80, 0x00),
+	INPUT_CURRENT(500000,  0x02, 0x00, 0x00),
+	INPUT_CURRENT(700000,  0x01, 0x00, 0x00),
+	INPUT_CURRENT(800000,  0x01, 0x00, 0x20),
+	INPUT_CURRENT(900000,  0x01, 0x00, 0x40),
+	INPUT_CURRENT(1000000, 0x01, 0x00, 0x60),
+	INPUT_CURRENT(1100000, 0x01, 0x00, 0x80),
+	INPUT_CURRENT(1200000, 0x01, 0x00, 0xA0),
+	INPUT_CURRENT(1300000, 0x01, 0x00, 0xC0),
+	INPUT_CURRENT(1500000, 0x01, 0x00, 0xE0),
+};
+
+static int smb137c_set_usb_input_current_limit(struct smb137c_chip *chip,
+					int current_limit_ua)
+{
+	struct input_current_config *config = NULL;
+	int rc = 0;
+	int i;
+
+	for (i = ARRAY_SIZE(supported_input_current) - 1; i >= 0; i--) {
+		if (current_limit_ua
+		    >= supported_input_current[i].current_limit_ua) {
+			config = &supported_input_current[i];
+			break;
+		}
+	}
+
+	if (config) {
+		if (chip->input_current_limit_ua != config->current_limit_ua) {
+			rc = smb137c_masked_write_reg(chip, INPUT_CURRENT_REG,
+			       INPUT_CURRENT_LIMIT_MASK, config->input_cur_reg);
+			if (rc)
+				return rc;
+
+			rc = smb137c_masked_write_reg(chip, VAR_FUNC_REG,
+				VAR_FUNC_USB_MODE_MASK, config->var_func_reg);
+			if (rc)
+				return rc;
+
+			rc = smb137c_masked_write_reg(chip, CMD_B_REG,
+				CMD_B_USB_MODE_MASK, config->cmd_b_reg);
+			if (rc)
+				return rc;
+
+			chip->input_current_limit_ua = config->current_limit_ua;
+		}
+
+		if (chip->charging_allowed)
+			rc = smb137c_enable_charging(chip);
+	} else {
+		/* Current limit is below all set points so disable charging. */
+		chip->input_current_limit_ua = 0;
+
+		rc = smb137c_disable_charging(chip);
+	}
+
+	if (!rc)
+		dev_dbg(&chip->client->dev, "%s: current=%d uA\n", __func__,
+			chip->input_current_limit_ua);
+
+	return rc;
+}
+
+static int fast_charge_current_ua[] = {
+	 500000,
+	 650000,
+	 750000,
+	 850000,
+	 950000,
+	1100000,
+	1300000,
+	1500000,
+};
+
+static int smb137c_set_charge_current_limit(struct smb137c_chip *chip,
+					int current_limit_ua)
+{
+	int fast_charge_limit_ua = 0;
+	int rc = 0;
+	u8 val = 0;
+	int i;
+
+	for (i = ARRAY_SIZE(fast_charge_current_ua) - 1; i >= 0; i--) {
+		if (current_limit_ua >= fast_charge_current_ua[i]) {
+			val = i << CHARGE_CURRENT_FAST_CHG_SHIFT;
+			fast_charge_limit_ua = fast_charge_current_ua[i];
+			break;
+		}
+	}
+
+	if (fast_charge_limit_ua
+	    && chip->charge_current_limit_ua != fast_charge_limit_ua)
+		rc = smb137c_masked_write_reg(chip, CHARGE_CURRENT_REG,
+					CHARGE_CURRENT_FAST_CHG_MASK, val);
+	else if (fast_charge_limit_ua == 0)
+		rc = smb137c_disable_charging(chip);
+
+	chip->charge_current_limit_ua = fast_charge_limit_ua;
+
+	if (!rc)
+		dev_dbg(&chip->client->dev, "%s: current=%d uA\n", __func__,
+			fast_charge_limit_ua);
+
+	return rc;
+}
+
+static int smb137c_get_charge_current_limit(struct smb137c_chip *chip)
+{
+	int fast_charge_limit_ua = 0;
+	u8 val = 0;
+	int rc, i;
+
+	rc = smb137c_read_reg(chip, CHARGE_CURRENT_REG, &val);
+	if (rc)
+		return rc;
+
+	i = (val & CHARGE_CURRENT_FAST_CHG_MASK)
+		>> CHARGE_CURRENT_FAST_CHG_SHIFT;
+
+	if (i >= 0 && i < ARRAY_SIZE(fast_charge_current_ua))
+		fast_charge_limit_ua = fast_charge_current_ua[i];
+
+	dev_dbg(&chip->client->dev, "%s: current=%d uA\n", __func__,
+		fast_charge_limit_ua);
+
+	return fast_charge_limit_ua;
+}
+
+static struct term_current_config term_current_ua[] = {
+	{ 35000, 0x06},
+	{ 50000, 0x00},
+	{100000, 0x02},
+	{150000, 0x04},
+};
+
+static int smb137c_set_term_current(struct smb137c_chip *chip,
+					int current_limit_ua)
+{
+	int term_current_limit_ua = 0;
+	int rc = 0;
+	u8 val = 0;
+	int i;
+
+	for (i = ARRAY_SIZE(term_current_ua) - 1; i >= 0; i--) {
+		if (current_limit_ua >= term_current_ua[i].term_current_ua) {
+			val = term_current_ua[i].charge_cur_reg;
+			term_current_limit_ua
+				= term_current_ua[i].term_current_ua;
+			break;
+		}
+	}
+
+	if (term_current_limit_ua) {
+		rc = smb137c_masked_write_reg(chip, CHARGE_CURRENT_REG,
+				CHARGE_CURRENT_TERM_CUR_MASK, val);
+		if (rc)
+			return rc;
+		rc = smb137c_masked_write_reg(chip, CTRL_A_REG,
+				CTRL_A_TERM_CUR_MASK, CTRL_A_TERM_CUR_ENABLED);
+	} else {
+		rc = smb137c_masked_write_reg(chip, CTRL_A_REG,
+				CTRL_A_TERM_CUR_MASK, CTRL_A_TERM_CUR_DISABLED);
+	}
+
+	if (!rc)
+		dev_dbg(&chip->client->dev, "%s: current=%d uA\n", __func__,
+			term_current_limit_ua);
+
+	return rc;
+}
+
+static int smb137c_set_pre_charge_current_limit(struct smb137c_chip *chip,
+					int current_limit_ua)
+{
+	int setpoint, rc;
+	u8 val;
+
+	if (current_limit_ua < PRE_CHARGE_CURRENT_MIN_UA ||
+	    current_limit_ua > PRE_CHARGE_CURRENT_MAX_UA) {
+		dev_err(&chip->client->dev, "%s: current limit out of bounds: %d\n",
+			__func__, current_limit_ua);
+		return -EINVAL;
+	}
+
+	setpoint = (current_limit_ua - PRE_CHARGE_CURRENT_MIN_UA)
+			/ PRE_CHARGE_CURRENT_STEP_UA;
+	val = setpoint << CHARGE_CURRENT_PRE_CHG_SHIFT;
+
+	rc = smb137c_masked_write_reg(chip, CHARGE_CURRENT_REG,
+			CHARGE_CURRENT_PRE_CHG_MASK, val);
+
+	if (!rc)
+		dev_dbg(&chip->client->dev, "%s: current=%d uA\n", __func__,
+			setpoint * PRE_CHARGE_CURRENT_STEP_UA
+			+ PRE_CHARGE_CURRENT_MIN_UA);
+
+	return rc;
+}
+
+static int smb137c_set_float_voltage(struct smb137c_chip *chip, int voltage_uv)
+{
+	int setpoint, rc;
+	u8 val;
+
+	if (voltage_uv < FLOAT_VOLTAGE_MIN_UV ||
+	    voltage_uv > FLOAT_VOLTAGE_MAX_UV) {
+		dev_err(&chip->client->dev, "%s: voltage out of bounds: %d\n",
+			__func__, voltage_uv);
+		return -EINVAL;
+	}
+
+	setpoint = (voltage_uv - FLOAT_VOLTAGE_MIN_UV) / FLOAT_VOLTAGE_STEP_UV;
+	val = setpoint << FLOAT_VOLTAGE_SHIFT;
+
+	rc = smb137c_masked_write_reg(chip, FLOAT_VOLTAGE_REG,
+			FLOAT_VOLTAGE_MASK, val);
+
+	if (!rc)
+		dev_dbg(&chip->client->dev, "%s: voltage=%d uV\n", __func__,
+		       setpoint * FLOAT_VOLTAGE_STEP_UV + FLOAT_VOLTAGE_MIN_UV);
+
+	return rc;
+}
+
+static int smb137c_set_pre_charge_threshold_voltage(struct smb137c_chip *chip,
+							int voltage_uv)
+{
+	int setpoint, rc;
+	u8 val;
+
+	if (voltage_uv < PRE_CHG_THRESH_VOLTAGE_MIN_UV ||
+	    voltage_uv > PRE_CHG_THRESH_VOLTAGE_MAX_UV) {
+		dev_err(&chip->client->dev, "%s: voltage out of bounds: %d\n",
+			__func__, voltage_uv);
+		return -EINVAL;
+	}
+
+	setpoint = (voltage_uv - PRE_CHG_THRESH_VOLTAGE_MIN_UV)
+			/ PRE_CHG_THRESH_VOLTAGE_STEP_UV;
+	val = setpoint << CTRL_A_THRESH_VOLTAGE_SHIFT;
+
+	rc = smb137c_masked_write_reg(chip, CTRL_A_REG,
+			CTRL_A_THRESH_VOLTAGE_MASK, val);
+
+	if (!rc)
+		dev_dbg(&chip->client->dev, "%s: voltage=%d uV\n", __func__,
+		       setpoint * PRE_CHG_THRESH_VOLTAGE_STEP_UV
+		       + PRE_CHG_THRESH_VOLTAGE_MIN_UV);
+
+	return rc;
+}
+
+static int smb137c_set_recharge_threshold_voltage(struct smb137c_chip *chip,
+							int voltage_uv)
+{
+	int rc;
+	u8 val;
+
+	if (voltage_uv == 75000) {
+		val = OTG_CTRL_AUTO_RECHARGE_75MV;
+	} else if (voltage_uv == 120000) {
+		val = OTG_CTRL_AUTO_RECHARGE_120MV;
+	} else {
+		dev_err(&chip->client->dev, "%s: voltage out of bounds: %d\n",
+			__func__, voltage_uv);
+		return -EINVAL;
+	}
+
+	rc = smb137c_masked_write_reg(chip, OTG_CTRL_REG,
+			OTG_CTRL_AUTO_RECHARGE_MASK, val);
+
+	if (!rc)
+		dev_dbg(&chip->client->dev, "%s: voltage=%d uV\n", __func__,
+		       voltage_uv);
+
+	return rc;
+}
+
+static int smb137c_set_system_voltage(struct smb137c_chip *chip, int voltage_uv)
+{
+	int rc;
+	u8 val;
+
+	if (voltage_uv == 4250000) {
+		val = CTRL_A_VOUTL_4250MV;
+	} else if (voltage_uv == 4460000) {
+		val = CTRL_A_VOUTL_4460MV;
+	} else {
+		dev_err(&chip->client->dev, "%s: voltage out of bounds: %d\n",
+			__func__, voltage_uv);
+		return -EINVAL;
+	}
+
+	rc = smb137c_masked_write_reg(chip, CTRL_A_REG, CTRL_A_VOUTL_MASK, val);
+
+	if (!rc)
+		dev_dbg(&chip->client->dev, "%s: voltage=%d uV\n", __func__,
+		       voltage_uv);
+
+	return rc;
+}
+
+static int charging_timeout[] = {
+	 382,
+	 764,
+	 1527,
+};
+
+static int smb137c_set_charging_timeout(struct smb137c_chip *chip, int timeout)
+{
+	int timeout_chosen = 0;
+	u8 val = 3 << SAFETY_TIMER_CHG_TIMEOUT_SHIFT;
+	int rc, i;
+
+	for (i = ARRAY_SIZE(charging_timeout) - 1; i >= 0; i--) {
+		if (timeout >= charging_timeout[i]) {
+			val = i << SAFETY_TIMER_CHG_TIMEOUT_SHIFT;
+			timeout_chosen = charging_timeout[i];
+			break;
+		}
+	}
+
+	rc = smb137c_masked_write_reg(chip, SAFETY_TIMER_REG,
+			SAFETY_TIMER_CHG_TIMEOUT_MASK, val);
+
+	if (!rc)
+		dev_dbg(&chip->client->dev, "%s: timeout=%d min\n", __func__,
+			timeout_chosen);
+
+	return rc;
+}
+
+static int pre_charge_timeout[] = {
+	 48,
+	 95,
+	 191,
+};
+
+static int smb137c_set_pre_charge_timeout(struct smb137c_chip *chip,
+					int timeout)
+{
+	int timeout_chosen = 0;
+	u8 val = 3 << SAFETY_TIMER_PRE_CHG_TIME_SHIFT;
+	int rc, i;
+
+	for (i = ARRAY_SIZE(pre_charge_timeout) - 1; i >= 0; i--) {
+		if (timeout >= pre_charge_timeout[i]) {
+			val = i << SAFETY_TIMER_PRE_CHG_TIME_SHIFT;
+			timeout_chosen = pre_charge_timeout[i];
+			break;
+		}
+	}
+
+	rc = smb137c_masked_write_reg(chip, SAFETY_TIMER_REG,
+			SAFETY_TIMER_PRE_CHG_TIME_MASK, val);
+
+	if (!rc)
+		dev_dbg(&chip->client->dev, "%s: timeout=%d min\n", __func__,
+			timeout_chosen);
+
+	return rc;
+}
+
+static int thermistor_current[] = {
+	100,
+	40,
+	20,
+	10,
+};
+
+static int smb137c_set_thermistor_current(struct smb137c_chip *chip,
+					int current_ua)
+{
+	bool found = false;
+	u8 val = 0;
+	int rc, i;
+
+	for (i = 0; i < ARRAY_SIZE(thermistor_current); i++) {
+		if (current_ua == thermistor_current[i]) {
+			found = true;
+			val = i << TEMP_MON_THERM_CURRENT_SHIFT;
+		}
+	}
+
+	if (!found) {
+		dev_err(&chip->client->dev, "%s: current out of bounds: %d\n",
+			__func__, current_ua);
+		return -EINVAL;
+	}
+
+	rc = smb137c_masked_write_reg(chip, TEMP_MON_REG,
+			TEMP_MON_THERM_CURRENT_MASK, val);
+
+	if (!rc)
+		dev_dbg(&chip->client->dev, "%s: current=%d uA\n", __func__,
+			current_ua);
+
+	return 0;
+}
+
+static int smb137c_set_temperature_low_limit(struct smb137c_chip *chip,
+					int value)
+{
+	int rc;
+
+	if (value < 0 || value > 7) {
+		dev_err(&chip->client->dev, "%s: temperature value out of bounds: %d\n",
+			__func__, value);
+		return -EINVAL;
+	}
+
+	rc = smb137c_masked_write_reg(chip, TEMP_MON_REG,
+		TEMP_MON_TEMP_LOW_MASK, value << TEMP_MON_TEMP_LOW_SHIFT);
+
+	if (!rc)
+		dev_dbg(&chip->client->dev, "%s: temperature value=%d\n",
+			__func__, value);
+
+	return rc;
+}
+
+static int smb137c_set_temperature_high_limit(struct smb137c_chip *chip,
+					int value)
+{
+	int rc;
+
+	if (value < 0 || value > 7) {
+		dev_err(&chip->client->dev, "%s: temperature value out of bounds: %d\n",
+			__func__, value);
+		return -EINVAL;
+	}
+
+	rc = smb137c_masked_write_reg(chip, TEMP_MON_REG,
+		TEMP_MON_TEMP_HIGH_MASK, value << TEMP_MON_TEMP_HIGH_SHIFT);
+
+	if (!rc)
+		dev_dbg(&chip->client->dev, "%s: temperature value=%d\n",
+			__func__, value);
+
+	return rc;
+}
+
+static int charge_status_type_map[] = {
+	[CHARGE_STAT_NO_CHG]	= POWER_SUPPLY_CHARGE_TYPE_NONE,
+	[CHARGE_STAT_PRE_CHG]	= POWER_SUPPLY_CHARGE_TYPE_TRICKLE,
+	[CHARGE_STAT_FAST_CHG]	= POWER_SUPPLY_CHARGE_TYPE_FAST,
+	[CHARGE_STAT_TAPER_CHG]	= POWER_SUPPLY_CHARGE_TYPE_FAST,
+};
+
+static const char * const charge_status_name[] = {
+	[CHARGE_STAT_NO_CHG]	= "none",
+	[CHARGE_STAT_PRE_CHG]	= "pre-charge",
+	[CHARGE_STAT_FAST_CHG]	= "fast-charge",
+	[CHARGE_STAT_TAPER_CHG]	= "taper-charge",
+};
+
+static int smb137c_get_property_status(struct smb137c_chip *chip)
+{
+	int status = POWER_SUPPLY_STATUS_DISCHARGING;
+	enum smb137c_charge_status charging_status;
+	bool charging_enabled;
+	bool charging_error;
+	int rc;
+	u8 val;
+
+	rc = smb137c_read_reg(chip, STAT_C_REG, &val);
+	if (rc)
+		return POWER_SUPPLY_STATUS_UNKNOWN;
+
+	charging_enabled = val & STAT_C_CHG_ENABLED;
+	charging_error = val & STAT_C_CHG_ERROR;
+	charging_status = (val & STAT_C_CHG_STAT_MASK) >> STAT_C_CHG_STAT_SHIFT;
+
+	if (charging_enabled && !charging_error
+	    && charging_status != CHARGE_STAT_NO_CHG)
+		status = POWER_SUPPLY_STATUS_CHARGING;
+
+	dev_dbg(&chip->client->dev, "%s: status=%s\n", __func__,
+		(status == POWER_SUPPLY_STATUS_CHARGING ? "charging"
+			: "discharging"));
+
+	return status;
+}
+
+static int smb137c_get_property_battery_present(struct smb137c_chip *chip)
+{
+	int rc;
+	u8 val;
+
+	rc = smb137c_read_reg(chip, IRQ_STAT_B_REG, &val);
+	if (rc || (val & IRQ_STAT_B_BATT_MISSING))
+		return 0;
+
+	/* Treat battery voltage less than 2.1 V as battery not present. */
+	rc = smb137c_read_reg(chip, STAT_C_REG, &val);
+	if (rc || (val & STAT_C_VBATT_LEVEL_BELOW_2P1V))
+		return 0;
+
+	return 1;
+}
+
+static int smb137c_get_property_battery_health(struct smb137c_chip *chip)
+{
+	int rc;
+	u8 val;
+
+	/* The health of a disconnected battery is unknown. */
+	if (!smb137c_get_property_battery_present(chip))
+		return POWER_SUPPLY_HEALTH_UNKNOWN;
+
+	rc = smb137c_read_reg(chip, IRQ_STAT_B_REG, &val);
+	if (rc)
+		return POWER_SUPPLY_HEALTH_UNKNOWN;
+
+	if (val & IRQ_STAT_B_BATT_OVERVOLT)
+		return POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+	else if (val & IRQ_STAT_B_BATT_UNDERVOLT)
+		return POWER_SUPPLY_HEALTH_DEAD;
+
+	rc = smb137c_read_reg(chip, IRQ_STAT_A_REG, &val);
+	if (rc)
+		return POWER_SUPPLY_HEALTH_UNKNOWN;
+
+	if (val & IRQ_STAT_A_BATT_HOT)
+		return POWER_SUPPLY_HEALTH_OVERHEAT;
+	else if (val & IRQ_STAT_A_BATT_COLD)
+		return POWER_SUPPLY_HEALTH_COLD;
+
+	return POWER_SUPPLY_HEALTH_GOOD;
+}
+
+static int smb137c_get_property_charge_type(struct smb137c_chip *chip)
+{
+	enum smb137c_charge_status status;
+	int charge_type = POWER_SUPPLY_CHARGE_TYPE_NONE;
+	bool charging_enabled;
+	bool charging_error;
+	int rc;
+	u8 val;
+
+	rc = smb137c_read_reg(chip, STAT_C_REG, &val);
+	if (rc)
+		return POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+
+	charging_enabled = val & STAT_C_CHG_ENABLED;
+	charging_error = val & STAT_C_CHG_ERROR;
+	status = (val & STAT_C_CHG_STAT_MASK) >> STAT_C_CHG_STAT_SHIFT;
+
+	if (!charging_enabled) {
+		dev_dbg(&chip->client->dev, "%s: not charging\n", __func__);
+	} else if (charging_error) {
+		dev_warn(&chip->client->dev, "%s: charger error detected\n",
+			__func__);
+	} else {
+		charge_type = charge_status_type_map[status];
+	}
+
+	dev_dbg(&chip->client->dev, "%s: charging status=%s\n", __func__,
+		charge_status_name[status]);
+
+	return charge_type;
+}
+
+static enum power_supply_property smb137c_power_properties[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_CHARGING_ENABLED,
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+	POWER_SUPPLY_PROP_CURRENT_MAX,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+	POWER_SUPPLY_PROP_MANUFACTURER,
+};
+
+static int smb137c_property_is_writeable(struct power_supply *psy,
+						enum power_supply_property psp)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CHARGING_ENABLED:
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		return 1;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int smb137c_power_set_property(struct power_supply *psy,
+				  enum power_supply_property psp,
+				  const union power_supply_propval *val)
+{
+	struct smb137c_chip *chip = container_of(psy, struct smb137c_chip, psy);
+
+	mutex_lock(&chip->lock);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CHARGING_ENABLED:
+		if (val->intval)
+			smb137c_enable_charging(chip);
+		else
+			smb137c_disable_charging(chip);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		smb137c_set_charge_current_limit(chip, val->intval);
+		break;
+	default:
+		mutex_unlock(&chip->lock);
+		return -EINVAL;
+	}
+
+	mutex_unlock(&chip->lock);
+
+	power_supply_changed(&chip->psy);
+	return 0;
+}
+
+static int smb137c_power_get_property(struct power_supply *psy,
+				       enum power_supply_property psp,
+				       union power_supply_propval *val)
+{
+	struct smb137c_chip *chip = container_of(psy, struct smb137c_chip, psy);
+
+	mutex_lock(&chip->lock);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = smb137c_get_property_status(chip);
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		val->intval = smb137c_get_property_battery_health(chip);
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = smb137c_get_property_battery_present(chip);
+		break;
+	case POWER_SUPPLY_PROP_CHARGING_ENABLED:
+		val->intval = chip->charging_enabled;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		val->intval = smb137c_get_property_charge_type(chip);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		val->intval = chip->charge_current_limit_ua;
+		break;
+	case POWER_SUPPLY_PROP_TECHNOLOGY:
+		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+		break;
+	case POWER_SUPPLY_PROP_MODEL_NAME:
+		val->strval = "SMB137C";
+		break;
+	case POWER_SUPPLY_PROP_MANUFACTURER:
+		val->strval = "Summit Microelectronics";
+		break;
+	default:
+		mutex_unlock(&chip->lock);
+		return -EINVAL;
+	}
+
+	mutex_unlock(&chip->lock);
+
+	return 0;
+}
+
+static void smb137c_external_power_changed(struct power_supply *psy)
+{
+	struct smb137c_chip *chip = container_of(psy, struct smb137c_chip, psy);
+	union power_supply_propval prop = {0,};
+
+	mutex_lock(&chip->lock);
+	dev_dbg(&chip->client->dev, "%s: start\n", __func__);
+
+	chip->usb_psy->get_property(chip->usb_psy, POWER_SUPPLY_PROP_ONLINE,
+					&prop);
+
+	if (prop.intval) {
+		/* USB online */
+		chip->usb_psy->get_property(chip->usb_psy,
+						POWER_SUPPLY_PROP_SCOPE, &prop);
+		if (prop.intval == POWER_SUPPLY_SCOPE_SYSTEM) {
+			/* USB host mode */
+			smb137c_enable_otg_mode(chip);
+			smb137c_disable_charging(chip);
+		} else {
+			/* USB device mode */
+			chip->usb_psy->get_property(chip->usb_psy,
+					POWER_SUPPLY_PROP_CURRENT_MAX, &prop);
+			smb137c_set_usb_input_current_limit(chip, prop.intval);
+			smb137c_enable_charging(chip);
+			smb137c_disable_otg_mode(chip);
+		}
+	} else {
+		/* USB offline */
+		smb137c_disable_charging(chip);
+		smb137c_disable_otg_mode(chip);
+		smb137c_set_usb_input_current_limit(chip, USB_MIN_CURRENT_UA);
+	}
+
+	dev_dbg(&chip->client->dev, "%s: end\n", __func__);
+	mutex_unlock(&chip->lock);
+
+	power_supply_changed(&chip->psy);
+}
+
+static int __devinit smb137c_set_register_defaults(struct smb137c_chip *chip)
+{
+	int rc;
+	u8 val, mask;
+
+	/* Allow volatile register writes. */
+	rc = smb137c_masked_write_reg(chip, CMD_A_REG,
+			CMD_A_VOLATILE_WRITE_MASK, CMD_A_VOLATILE_WRITE_ALLOW);
+	if (rc)
+		return rc;
+
+	/* Do not reset register values on USB reinsertion. */
+	rc = smb137c_masked_write_reg(chip, SAFETY_TIMER_REG,
+			SAFETY_TIMER_RELOAD_MASK, SAFETY_TIMER_RELOAD_DISABLED);
+	if (rc)
+		return rc;
+
+	/* Set various default control parameters. */
+	val = PIN_CTRL_DEAD_BATT_CHG_ENABLED | PIN_CTRL_OTG
+		| PIN_CTRL_USB_CUR_LIMIT_REG | PIN_CTRL_CHG_EN_REG_LOW
+		| PIN_CTRL_OTG_CTRL_REG;
+	mask = PIN_CTRL_DEAD_BATT_CHG_MASK | PIN_CTRL_OTG_LBR_MASK
+		| PIN_CTRL_USB_CUR_LIMIT_MASK | PIN_CTRL_CHG_EN_MASK
+		| PIN_CTRL_OTG_CTRL_MASK;
+	rc = smb137c_masked_write_reg(chip, PIN_CTRL_REG, mask, val);
+	if (rc)
+		return rc;
+
+	/* Disable charging, disable OTG mode, and allow fast-charge current. */
+	val = CMD_A_CHARGING_DISABLED | CMD_A_OTG_DISABLED
+		| CMD_A_FAST_CHG_ALLOW;
+	mask = CMD_A_CHARGING_MASK | CMD_A_OTG_MASK | CMD_A_FAST_CHG_MASK;
+	rc = smb137c_masked_write_reg(chip, CMD_A_REG, mask, val);
+	if (rc)
+		return rc;
+
+	/* Enable auto recharging and full-time THERM monitor. */
+	val = CTRL_A_AUTO_RECHARGE_ENABLED | CTRL_A_THERM_MONITOR_ENABLED;
+	mask = CTRL_A_AUTO_RECHARGE_MASK | CTRL_A_THERM_MONITOR_MASK;
+	rc = smb137c_masked_write_reg(chip, CTRL_A_REG, mask, val);
+
+	return rc;
+}
+
+static int __devinit smb137c_apply_dt_configs(struct smb137c_chip *chip)
+{
+	struct device *dev = &chip->client->dev;
+	struct device_node *node = chip->client->dev.of_node;
+	int ret, current_ma, voltage_mv, timeout, value;
+	int rc = 0;
+
+	/*
+	 * All device tree parameters are optional so it is ok if read calls
+	 * fail.
+	 */
+	ret = of_property_read_u32(node, "summit,chg-current-ma", &current_ma);
+	if (ret == 0) {
+		rc = smb137c_set_charge_current_limit(chip, current_ma * 1000);
+		if (rc) {
+			dev_err(dev, "%s: Failed to set charge current, rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+	} else {
+		chip->charge_current_limit_ua
+			= smb137c_get_charge_current_limit(chip);
+		rc = chip->charge_current_limit_ua;
+		if (rc < 0) {
+			dev_err(dev, "%s: Failed to get charge current, rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+	}
+
+	ret = of_property_read_u32(node, "summit,term-current-ma", &current_ma);
+	if (ret == 0) {
+		rc = smb137c_set_term_current(chip, current_ma * 1000);
+		if (rc) {
+			dev_err(dev, "%s: Failed to set termination current, rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+	}
+
+	ret = of_property_read_u32(node, "summit,pre-chg-current-ma",
+					&current_ma);
+	if (ret == 0) {
+		rc = smb137c_set_pre_charge_current_limit(chip,
+				current_ma * 1000);
+		if (rc) {
+			dev_err(dev, "%s: Failed to set pre-charge current limit, rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+	}
+
+	ret = of_property_read_u32(node, "summit,float-voltage-mv",
+					&voltage_mv);
+	if (ret == 0) {
+		rc = smb137c_set_float_voltage(chip, voltage_mv * 1000);
+		if (rc) {
+			dev_err(dev, "%s: Failed to set float voltage, rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+	}
+
+	ret = of_property_read_u32(node, "summit,thresh-voltage-mv",
+					&voltage_mv);
+	if (ret == 0) {
+		rc = smb137c_set_pre_charge_threshold_voltage(chip,
+				voltage_mv * 1000);
+		if (rc) {
+			dev_err(dev, "%s: Failed to set fast-charge threshold voltage, rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+	}
+
+	ret = of_property_read_u32(node, "summit,recharge-thresh-mv",
+					&voltage_mv);
+	if (ret == 0) {
+		rc = smb137c_set_recharge_threshold_voltage(chip,
+				voltage_mv * 1000);
+		if (rc) {
+			dev_err(dev, "%s: Failed to set recharge threshold voltage, rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+	}
+
+	ret = of_property_read_u32(node, "summit,system-voltage-mv",
+					&voltage_mv);
+	if (ret == 0) {
+		rc = smb137c_set_system_voltage(chip, voltage_mv * 1000);
+		if (rc) {
+			dev_err(dev, "%s: Failed to set system voltage, rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+	}
+
+	ret = of_property_read_u32(node, "summit,charging-timeout", &timeout);
+	if (ret == 0) {
+		rc = smb137c_set_charging_timeout(chip, timeout);
+		if (rc) {
+			dev_err(dev, "%s: Failed to set charging timeout, rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+	}
+
+	ret = of_property_read_u32(node, "summit,pre-charge-timeout", &timeout);
+	if (ret == 0) {
+		rc = smb137c_set_pre_charge_timeout(chip, timeout);
+		if (rc) {
+			dev_err(dev, "%s: Failed to set pre-charge timeout, rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+	}
+
+	ret = of_property_read_u32(node, "summit,therm-current-ua", &value);
+	if (ret == 0) {
+		rc = smb137c_set_thermistor_current(chip, value);
+		if (rc) {
+			dev_err(dev, "%s: Failed to set thermistor current, rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+	}
+
+	ret = of_property_read_u32(node, "summit,temperature-min", &value);
+	if (ret == 0) {
+		rc = smb137c_set_temperature_low_limit(chip, value);
+		if (rc) {
+			dev_err(dev, "%s: Failed to set low temperature limit, rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+	}
+
+	ret = of_property_read_u32(node, "summit,temperature-max", &value);
+	if (ret == 0) {
+		rc = smb137c_set_temperature_high_limit(chip, value);
+		if (rc) {
+			dev_err(dev, "%s: Failed to set high temperature limit, rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
+static int __devinit smb137c_probe(struct i2c_client *client,
+				  const struct i2c_device_id *id)
+{
+	struct smb137c_chip *chip;
+	struct device *dev = &client->dev;
+	struct device_node *node = client->dev.of_node;
+	int rc = 0;
+	int gui_rev, silicon_rev;
+	u8 dev_id;
+
+	if (!node) {
+		dev_err(dev, "%s: device tree information missing\n", __func__);
+		return -ENODEV;
+	}
+
+	if (!i2c_check_functionality(client->adapter,
+			I2C_FUNC_SMBUS_BYTE_DATA)) {
+		dev_err(dev, "%s: SMBUS_BYTE_DATA unsupported\n", __func__);
+		return -EIO;
+	}
+
+	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+	if (!chip) {
+		dev_err(dev, "%s: devm_kzalloc failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	mutex_init(&chip->lock);
+	chip->client = client;
+	i2c_set_clientdata(client, chip);
+
+	chip->usb_psy = power_supply_get_by_name("usb");
+	if (!chip->usb_psy) {
+		dev_dbg(dev, "%s: USB supply not found; deferring charger probe\n",
+			__func__);
+		return -EPROBE_DEFER;
+	}
+
+	rc = smb137c_read_reg(chip, DEV_ID_REG, &dev_id);
+	if (rc)
+		return rc;
+
+	if ((dev_id & DEV_ID_PART_MASK) != DEV_ID_PART_SMB137C) {
+		dev_err(dev, "%s: invalid device ID=0x%02X\n", __func__,
+			dev_id);
+		return -ENODEV;
+	}
+
+	gui_rev = (dev_id & DEV_ID_GUI_REV_MASK) >> DEV_ID_GUI_REV_SHIFT;
+	silicon_rev = (dev_id & DEV_ID_SILICON_REV_MASK)
+			>> DEV_ID_SILICON_REV_SHIFT;
+
+	rc = smb137c_set_register_defaults(chip);
+	if (rc)
+		return rc;
+
+	rc = smb137c_apply_dt_configs(chip);
+	if (rc)
+		return rc;
+
+	chip->psy.name			 = "battery";
+	chip->psy.type			 = POWER_SUPPLY_TYPE_BATTERY;
+	chip->psy.properties		 = smb137c_power_properties;
+	chip->psy.num_properties	 = ARRAY_SIZE(smb137c_power_properties);
+	chip->psy.get_property		 = smb137c_power_get_property;
+	chip->psy.set_property		 = smb137c_power_set_property;
+	chip->psy.property_is_writeable  = smb137c_property_is_writeable;
+	chip->psy.external_power_changed = smb137c_external_power_changed;
+
+	rc = power_supply_register(dev, &chip->psy);
+	if (rc < 0) {
+		dev_err(dev, "%s: power_supply_register failed, rc=%d\n",
+						__func__, rc);
+		return rc;
+	}
+
+	smb137c_external_power_changed(&chip->psy);
+
+	dev_info(dev, "%s: SMB137C charger probed successfully, gui_rev=%d, silicon_rev=%d\n",
+		__func__, gui_rev, silicon_rev);
+
+	return rc;
+}
+
+static int __devexit smb137c_remove(struct i2c_client *client)
+{
+	return 0;
+}
+
+static const struct i2c_device_id smb137c_id[] = {
+	{ .name = "smb137c", },
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, smb137c_id);
+
+/* TODO: should this be "summit,smb137c-charger"? */
+static const struct of_device_id smb137c_match[] = {
+	{ .compatible = "summit,smb137c", },
+	{ },
+};
+
+static struct i2c_driver smb137c_driver = {
+	.driver	= {
+		.name		= "smb137c",
+		.owner		= THIS_MODULE,
+		.of_match_table	= smb137c_match,
+	},
+	.probe		= smb137c_probe,
+	.remove		= __devexit_p(smb137c_remove),
+	.id_table	= smb137c_id,
+};
+
+static int __init smb137c_init(void)
+{
+	return i2c_add_driver(&smb137c_driver);
+}
+module_init(smb137c_init);
+
+static void __exit smb137c_exit(void)
+{
+	return i2c_del_driver(&smb137c_driver);
+}
+module_exit(smb137c_exit);
+
+MODULE_DESCRIPTION("SMB137C Charger");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("i2c:smb137c");
diff --git a/drivers/power/smb350_charger.c b/drivers/power/smb350_charger.c
index 93e208c..dc0c4bd 100644
--- a/drivers/power/smb350_charger.c
+++ b/drivers/power/smb350_charger.c
@@ -55,6 +55,8 @@
 #define CMD_B_REG			0x31	/* Volatile Read-Write */
 #define CMD_C_REG			0x33	/* Volatile Read-Write */
 
+#define HW_VERSION_REG			0x34	/* Volatile Read-Only */
+
 #define IRQ_STATUS_A_REG		0x35	/* Volatile Read-Only */
 #define IRQ_STATUS_B_REG		0x36	/* Volatile Read-Only */
 #define IRQ_STATUS_C_REG		0x37	/* Volatile Read-Only */
@@ -149,6 +151,7 @@
 	SMB350_DEBUG_REG(CMD_A),
 	SMB350_DEBUG_REG(CMD_B),
 	SMB350_DEBUG_REG(CMD_C),
+	SMB350_DEBUG_REG(HW_VERSION),
 	SMB350_DEBUG_REG(IRQ_STATUS_A),
 	SMB350_DEBUG_REG(IRQ_STATUS_B),
 	SMB350_DEBUG_REG(IRQ_STATUS_C),
@@ -212,21 +215,6 @@
 	return ret;
 }
 
-#define SMB350_FLOAT_VOLT_BASE_MV 6920
-#define SMB350_FLOAT_VOLT_STEP_MV   40
-#define SMB350_FLOAT_VOLT_MAX_MV  (6920 + 0x2F * 40)
-
-/* Fast-to-Taper charging volatge */
-static int smb350_get_float_voltage(struct i2c_client *client)
-{
-	u16 val = smb350_read_reg(client, STATUS_A_REG);
-
-	val = SMB350_FLOAT_VOLT_BASE_MV +
-		((val & 0x2F) * SMB350_FLOAT_VOLT_STEP_MV);
-
-	return val;
-}
-
 static bool smb350_is_dc_present(struct i2c_client *client)
 {
 	u16 irq_status_f = smb350_read_reg(client, IRQ_STATUS_F_REG);
@@ -398,7 +386,6 @@
 	POWER_SUPPLY_PROP_PRESENT,
 	POWER_SUPPLY_PROP_ONLINE,
 	POWER_SUPPLY_PROP_CHARGE_TYPE,
-	POWER_SUPPLY_PROP_VOLTAGE_NOW,
 	/* fixed */
 	POWER_SUPPLY_PROP_MANUFACTURER,
 	POWER_SUPPLY_PROP_MODEL_NAME,
@@ -429,10 +416,6 @@
 	case POWER_SUPPLY_PROP_CHARGE_TYPE:
 		val->intval = smb350_get_prop_charge_type(dev);
 		break;
-	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-		val->intval = smb350_get_float_voltage(client);
-		val->intval *= 1000; /* mV to uV */
-		break;
 	case POWER_SUPPLY_PROP_MODEL_NAME:
 		val->strval = SMB350_NAME;
 		break;
@@ -665,6 +648,7 @@
 	const struct smb350_platform_data *pdata;
 	struct device_node *dev_node = client->dev.of_node;
 	struct smb350_device *dev;
+	u8 version;
 
 	/* STAT pin change on start/stop charging */
 	u32 irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
@@ -753,13 +737,25 @@
 
 	i2c_set_clientdata(client, dev);
 
-	pr_debug("set charge-enable + not suspend.\n");
-	gpio_set_value_cansleep(dev->chg_en_n_gpio, 1);	/* Disable */
+	/* Disable battery charging by default on power up.
+	 * Battery charging is enabled by BMS or Battery-Gauge
+	 * by using the set_property callback.
+	 */
+	smb350_enable_charging(dev, false);
 	msleep(100);
 	gpio_set_value_cansleep(dev->chg_susp_n_gpio, 1); /* Normal */
 	msleep(100); /* Allow the device to exist shutdown */
 
-	smb350_read_reg(client, I2C_SLAVE_ADDR_REG);
+	/* I2C transaction allowed only after device exit suspend */
+	ret = smb350_read_reg(client, I2C_SLAVE_ADDR_REG);
+	if ((ret>>1) != client->addr) {
+		pr_err("No device.\n");
+		ret = -ENODEV;
+		goto err_no_dev;
+	}
+
+	version = smb350_read_reg(client, HW_VERSION_REG);
+	version &= 0x0F; /* bits 0..3 */
 
 	ret = smb350_set_volatile_params(dev);
 	if (ret)
@@ -784,7 +780,7 @@
 		goto err_irq;
 	}
 
-	smb350_enable_charging(dev, true);
+	pr_info("HW Version = 0x%X.\n", version);
 
 	return 0;
 
@@ -792,6 +788,7 @@
 err_debugfs:
 	if (dev->dent)
 		debugfs_remove_recursive(dev->dent);
+err_no_dev:
 err_set_params:
 	gpio_free(dev->chg_en_n_gpio);
 err_en_gpio:
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index 58a1d66..9c69f47 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -111,15 +111,16 @@
 static int msm_sat_enqueue(struct msm_slim_sat *sat, u32 *buf, u8 len)
 {
 	struct msm_slim_ctrl *dev = sat->dev;
-	spin_lock(&sat->lock);
+	unsigned long flags;
+	spin_lock_irqsave(&sat->lock, flags);
 	if ((sat->stail + 1) % SAT_CONCUR_MSG == sat->shead) {
-		spin_unlock(&sat->lock);
+		spin_unlock_irqrestore(&sat->lock, flags);
 		dev_err(dev->dev, "SAT QUEUE full!");
 		return -EXFULL;
 	}
 	memcpy(sat->sat_msgs[sat->stail], (u8 *)buf, len);
 	sat->stail = (sat->stail + 1) % SAT_CONCUR_MSG;
-	spin_unlock(&sat->lock);
+	spin_unlock_irqrestore(&sat->lock, flags);
 	return 0;
 }
 
@@ -618,6 +619,7 @@
 		u16 chh[40];
 		struct slim_ch prop;
 		u32 exp;
+		u16 *grph = NULL;
 		u8 coeff, cc;
 		u8 prrate = buf[6];
 		if (len <= 8)
@@ -638,6 +640,9 @@
 					return ret;
 				if (mc == SLIM_USR_MC_DEF_ACT_CHAN)
 					sat->satch[j].req_def++;
+				/* First channel in group from satellite */
+				if (i == 8)
+					grph = &sat->satch[j].chanh;
 				continue;
 			}
 			if (sat->nsatch >= MSM_MAX_SATCH)
@@ -649,6 +654,8 @@
 			sat->satch[j].chanh = chh[i - 8];
 			if (mc == SLIM_USR_MC_DEF_ACT_CHAN)
 				sat->satch[j].req_def++;
+			if (i == 8)
+				grph = &sat->satch[j].chanh;
 			sat->nsatch++;
 		}
 		prop.dataf = (enum slim_ch_dataf)((buf[3] & 0xE0) >> 5);
@@ -669,10 +676,12 @@
 					true, &chh[0]);
 		else
 			ret = slim_define_ch(&sat->satcl, &prop,
-					&chh[0], 1, false, NULL);
+					chh, 1, true, &chh[0]);
 		dev_dbg(dev->dev, "define sat grp returned:%d", ret);
 		if (ret)
 			return ret;
+		else if (grph)
+			*grph = chh[0];
 
 		/* part of group so activating 1 will take care of rest */
 		if (mc == SLIM_USR_MC_DEF_ACT_CHAN)
@@ -805,6 +814,8 @@
 						slim_control_ch(&sat->satcl,
 							sat->satch[i].chanh,
 							SLIM_CH_REMOVE, true);
+						slim_dealloc_ch(&sat->satcl,
+							sat->satch[i].chanh);
 						sat->satch[i].reconf = false;
 					}
 				}
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 1f2a95e..02e1952 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -144,6 +144,30 @@
 	return IRQ_HANDLED;
 }
 
+static int ngd_clk_pause_wakeup(struct slim_controller *ctrl)
+{
+	struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
+	return msm_slim_qmi_power_request(dev, true);
+}
+
+static int ngd_qmi_available(struct notifier_block *n, unsigned long code,
+				void *_cmd)
+{
+	struct msm_slim_qmi *qmi = container_of(n, struct msm_slim_qmi, nb);
+	pr_info("Slimbus QMI NGD CB received event:%ld", code);
+	switch (code) {
+	case QMI_SERVER_ARRIVE:
+		complete(&qmi->qmi_comp);
+		break;
+	case QMI_SERVER_EXIT:
+		/* SSR implementation */
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
 static int ngd_get_tid(struct slim_controller *ctrl, struct slim_msg_txn *txn,
 				u8 *tid, struct completion *done)
 {
@@ -184,16 +208,21 @@
 	u32 *pbuf;
 	u8 *puc;
 	int ret = 0;
-	int msgv = -1;
 	u8 la = txn->la;
 	u8 wbuf[SLIM_RX_MSGQ_BUF_LEN];
 
+	if (txn->mc == (SLIM_MSG_CLK_PAUSE_SEQ_FLG |
+			SLIM_MSG_MC_RECONFIGURE_NOW))
+		return msm_slim_qmi_power_request(dev, false);
+	else if (txn->mc & SLIM_MSG_CLK_PAUSE_SEQ_FLG)
+		return 0;
+
 	if (txn->mt == SLIM_MSG_MT_CORE &&
 		(txn->mc >= SLIM_MSG_MC_BEGIN_RECONFIGURATION &&
 		 txn->mc <= SLIM_MSG_MC_RECONFIGURE_NOW)) {
 		return 0;
 	}
-	msgv = msm_slim_get_ctrl(dev);
+	msm_slim_get_ctrl(dev);
 	mutex_lock(&dev->tx_lock);
 	if (txn->mc != SLIM_USR_MC_REPORT_SATELLITE &&
 		(dev->state == MSM_CTRL_ASLEEP ||
@@ -206,8 +235,7 @@
 		if (timeout) {
 			mutex_lock(&dev->tx_lock);
 		} else {
-			if (msgv >= 0)
-				msm_slim_put_ctrl(dev);
+			msm_slim_put_ctrl(dev);
 			return -EBUSY;
 		}
 	}
@@ -293,8 +321,7 @@
 			 */
 			dev->pipes[wbuf[1]].connected = false;
 			mutex_unlock(&dev->tx_lock);
-			if (msgv >= 0)
-				msm_slim_put_ctrl(dev);
+			msm_slim_put_ctrl(dev);
 			return 0;
 		}
 		if (dev->err) {
@@ -336,8 +363,7 @@
 		 txn->mc == SLIM_USR_MC_DISCONNECT_PORT)) {
 		int timeout;
 		mutex_unlock(&dev->tx_lock);
-		if (msgv >= 0)
-			msm_slim_put_ctrl(dev);
+		msm_slim_put_ctrl(dev);
 		timeout = wait_for_completion_timeout(txn->comp, HZ);
 		if (!timeout) {
 			pr_err("connect/disc :0x%x, tid:%d timed out", txn->mc,
@@ -353,8 +379,7 @@
 	}
 ngd_xfer_err:
 	mutex_unlock(&dev->tx_lock);
-	if (msgv >= 0)
-		msm_slim_put_ctrl(dev);
+	msm_slim_put_ctrl(dev);
 	return ret ? ret : dev->err;
 }
 
@@ -405,8 +430,9 @@
 			return -ENXIO;
 		}
 		if (txn.len == 0) {
+			/* Per protocol, only last 5 bits for client no. */
 			wbuf[txn.len++] = (u8) (slc->prop.dataf << 5) |
-					sb->laddr;
+					(sb->laddr & 0x1f);
 			wbuf[txn.len] = slc->seglen;
 			if (slc->coeff == SLIM_COEFF_3)
 				wbuf[txn.len] |= 1 << 5;
@@ -420,6 +446,7 @@
 			}
 		}
 		wbuf[txn.len++] = slc->chan;
+		pr_debug("slim define chan:%d, tid:0x%x", slc->chan, txn.tid);
 	}
 	if (txn.len) {
 		txn.mc = SLIM_USR_MC_DEF_ACT_CHAN;
@@ -448,8 +475,9 @@
 			return -ENXIO;
 		}
 		if (txn.len == 0) {
+			/* Per protocol, only last 5 bits for client no. */
 			wbuf[txn.len++] = (u8) (SLIM_CH_REMOVE << 6) |
-					sb->laddr;
+					(sb->laddr & 0x1f);
 			ret = ngd_get_tid(ctrl, &txn, &wbuf[txn.len++], &done);
 			if (ret) {
 				pr_err("no tid for channel define?");
@@ -457,6 +485,7 @@
 			}
 		}
 		wbuf[txn.len++] = slc->chan;
+		pr_debug("slim remove chan:%d, tid:0x%x", slc->chan, txn.tid);
 	}
 	if (txn.len) {
 		txn.mc = SLIM_USR_MC_CHAN_CTRL;
@@ -544,6 +573,7 @@
 		wbuf[3] = SAT_MSG_PROT;
 		txn.wbuf = wbuf;
 		txn.len = 4;
+		pr_info("SLIM SAT: Received master capability");
 		dev->use_rx_msgqs = 1;
 		msm_slim_sps_init(dev, dev->bam_mem,
 			NGD_BASE(dev->ctrl.nr, dev->ver) + NGD_STATUS, true);
@@ -557,6 +587,12 @@
 		ret = ngd_xfer_msg(&dev->ctrl, &txn);
 		if (!ret) {
 			dev->state = MSM_CTRL_AWAKE;
+
+			pm_runtime_use_autosuspend(dev->dev);
+			pm_runtime_set_autosuspend_delay(dev->dev,
+							MSM_SLIM_AUTOSUSPEND);
+			pm_runtime_set_active(dev->dev);
+			pm_runtime_enable(dev->dev);
 			complete(&dev->reconf);
 		}
 	}
@@ -595,6 +631,41 @@
 		complete(txn->comp);
 	}
 }
+
+static int ngd_slim_enable(struct msm_slim_ctrl *dev, bool enable)
+{
+	u32 ngd_int = (NGD_INT_RECFG_DONE | NGD_INT_TX_NACKED_2 |
+			NGD_INT_MSG_BUF_CONTE | NGD_INT_MSG_TX_INVAL |
+			NGD_INT_IE_VE_CHG | NGD_INT_DEV_ERR |
+			NGD_INT_TX_MSG_SENT | NGD_INT_RX_MSG_RCVD);
+	if (enable) {
+		int ret = msm_slim_qmi_init(dev, false);
+		if (ret)
+			return ret;
+		ret = msm_slim_qmi_power_request(dev, true);
+		if (ret)
+			return ret;
+		writel_relaxed(ngd_int, dev->base + NGD_INT_EN +
+					NGD_BASE(dev->ctrl.nr, dev->ver));
+		/*
+		 * Enable NGD. Configure NGD in register acc. mode until master
+		 * announcement is received
+		 */
+		writel_relaxed(1, dev->base + NGD_BASE(dev->ctrl.nr, dev->ver));
+		/* make sure NGD enabling goes through */
+		mb();
+	} else {
+		writel_relaxed(0, dev->base + NGD_BASE(dev->ctrl.nr, dev->ver));
+		writel_relaxed(0, dev->base + NGD_INT_EN +
+				NGD_BASE(dev->ctrl.nr, dev->ver));
+		/* make sure NGD disabling goes through */
+		mb();
+		msm_slim_qmi_exit(dev);
+	}
+
+	return 0;
+}
+
 static int ngd_slim_rx_msgq_thread(void *data)
 {
 	struct msm_slim_ctrl *dev = (struct msm_slim_ctrl *)data;
@@ -605,6 +676,14 @@
 	u32 buffer[10];
 	u8 msg_len = 0;
 
+	wait_for_completion_interruptible(&dev->qmi.qmi_comp);
+	ret = ngd_slim_enable(dev, true);
+	/* Exit the thread if component can't be enabled */
+	if (ret) {
+		pr_err("Enabling NGD failed:%d", ret);
+		return 0;
+	}
+
 	while (!kthread_should_stop()) {
 		set_current_state(TASK_INTERRUPTIBLE);
 		ret = wait_for_completion_interruptible(notify);
@@ -648,7 +727,6 @@
 	struct resource		*slim_mem;
 	struct resource		*irq, *bam_irq;
 	enum apr_subsys_state q6_state;
-	u32 ngd_int;
 
 	q6_state = apr_get_q6_state();
 	if (q6_state == APR_SUBSYS_DOWN) {
@@ -725,7 +803,7 @@
 	dev->ctrl.get_laddr = ngd_get_laddr;
 	dev->ctrl.allocbw = ngd_allocbw;
 	dev->ctrl.xfer_msg = ngd_xfer_msg;
-	dev->ctrl.wakeup =  NULL;
+	dev->ctrl.wakeup =  ngd_clk_pause_wakeup;
 	dev->ctrl.config_port = msm_config_port;
 	dev->ctrl.port_xfer = msm_slim_port_xfer;
 	dev->ctrl.port_xfer_status = msm_slim_port_xfer_status;
@@ -743,10 +821,6 @@
 	dev->ver = readl_relaxed(dev->base);
 	/* Version info in 16 MSbits */
 	dev->ver >>= 16;
-	ngd_int = (NGD_INT_RECFG_DONE | NGD_INT_TX_NACKED_2 |
-			NGD_INT_MSG_BUF_CONTE | NGD_INT_MSG_TX_INVAL |
-			NGD_INT_IE_VE_CHG | NGD_INT_DEV_ERR |
-			NGD_INT_TX_MSG_SENT | NGD_INT_RX_MSG_RCVD);
 	init_completion(&dev->rx_msgq_notify);
 
 	/* Register with framework */
@@ -768,6 +842,15 @@
 		goto err_request_irq_failed;
 	}
 
+	init_completion(&dev->qmi.qmi_comp);
+	dev->qmi.nb.notifier_call = ngd_qmi_available;
+	ret = qmi_svc_event_notifier_register(SLIMBUS_QMI_SVC_ID,
+				SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
+	if (ret) {
+		pr_err("Slimbus QMI service registration failed:%d", ret);
+		goto qmi_register_failed;
+	}
+
 	/* Fire up the Rx message queue thread */
 	dev->rx_msgq_thread = kthread_run(ngd_slim_rx_msgq_thread, dev,
 					NGD_SLIM_NAME "_ngd_msgq_thread");
@@ -777,30 +860,19 @@
 		goto err_thread_create_failed;
 	}
 
-	writel_relaxed(ngd_int, dev->base + NGD_INT_EN +
-				NGD_BASE(dev->ctrl.nr, dev->ver));
-	/*
-	 * Enable NGD. Configure NGD in register access mode until master
-	 * announcement is received
-	 */
-	writel_relaxed(1, dev->base + NGD_BASE(dev->ctrl.nr, dev->ver));
-	/* make sure NGD enabling goes through */
-	mb();
-
 	if (pdev->dev.of_node)
 		of_register_slim_devices(&dev->ctrl);
 
 	/* Add devices registered with board-info now that controller is up */
 	slim_ctrl_add_boarddevs(&dev->ctrl);
 
-	pm_runtime_use_autosuspend(&pdev->dev);
-	pm_runtime_set_autosuspend_delay(&pdev->dev, MSM_SLIM_AUTOSUSPEND);
-	pm_runtime_set_active(&pdev->dev);
-
 	dev_dbg(dev->dev, "NGD SB controller is up!\n");
 	return 0;
 
 err_thread_create_failed:
+	qmi_svc_event_notifier_unregister(SLIMBUS_QMI_SVC_ID,
+				SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
+qmi_register_failed:
 	free_irq(dev->irq, dev);
 err_request_irq_failed:
 	slim_del_controller(&dev->ctrl);
@@ -816,6 +888,9 @@
 static int __devexit ngd_slim_remove(struct platform_device *pdev)
 {
 	struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
+	ngd_slim_enable(dev, false);
+	qmi_svc_event_notifier_unregister(SLIMBUS_QMI_SVC_ID,
+				SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
 	pm_runtime_disable(&pdev->dev);
 	pm_runtime_set_suspended(&pdev->dev);
 	free_irq(dev->irq, dev);
diff --git a/drivers/slimbus/slim-msm.c b/drivers/slimbus/slim-msm.c
index 7cd34d3..c62ac27 100644
--- a/drivers/slimbus/slim-msm.c
+++ b/drivers/slimbus/slim-msm.c
@@ -582,3 +582,351 @@
 		sps_deregister_bam_device(dev->bam.hdl);
 	}
 }
+
+/* Slimbus QMI Messaging */
+#define SLIMBUS_QMI_SELECT_INSTANCE_REQ_V01 0x0020
+#define SLIMBUS_QMI_SELECT_INSTANCE_RESP_V01 0x0020
+#define SLIMBUS_QMI_POWER_REQ_V01 0x0021
+#define SLIMBUS_QMI_POWER_RESP_V01 0x0021
+
+enum slimbus_mode_enum_type_v01 {
+	/* To force a 32 bit signed enum. Do not change or use*/
+	SLIMBUS_MODE_ENUM_TYPE_MIN_ENUM_VAL_V01 = INT_MIN,
+	SLIMBUS_MODE_SATELLITE_V01 = 1,
+	SLIMBUS_MODE_MASTER_V01 = 2,
+	SLIMBUS_MODE_ENUM_TYPE_MAX_ENUM_VAL_V01 = INT_MAX,
+};
+
+enum slimbus_pm_enum_type_v01 {
+	/* To force a 32 bit signed enum. Do not change or use*/
+	SLIMBUS_PM_ENUM_TYPE_MIN_ENUM_VAL_V01 = INT_MIN,
+	SLIMBUS_PM_INACTIVE_V01 = 1,
+	SLIMBUS_PM_ACTIVE_V01 = 2,
+	SLIMBUS_PM_ENUM_TYPE_MAX_ENUM_VAL_V01 = INT_MAX,
+};
+
+struct slimbus_select_inst_req_msg_v01 {
+	/* Mandatory */
+	/* Hardware Instance Selection */
+	uint32_t instance;
+
+	/* Optional */
+	/* Optional Mode Request Operation */
+	/* Must be set to true if mode is being passed */
+	uint8_t mode_valid;
+	enum slimbus_mode_enum_type_v01 mode;
+};
+
+struct slimbus_select_inst_resp_msg_v01 {
+	/* Mandatory */
+	/* Result Code */
+	struct qmi_response_type_v01 resp;
+};
+
+struct slimbus_power_req_msg_v01 {
+	/* Mandatory */
+	/* Power Request Operation */
+	enum slimbus_pm_enum_type_v01 pm_req;
+};
+
+struct slimbus_power_resp_msg_v01 {
+	/* Mandatory */
+	/* Result Code */
+	struct qmi_response_type_v01 resp;
+};
+
+static struct elem_info slimbus_select_inst_req_msg_v01_ei[] = {
+	{
+		.data_type = QMI_UNSIGNED_4_BYTE,
+		.elem_len  = 1,
+		.elem_size = sizeof(uint32_t),
+		.is_array  = NO_ARRAY,
+		.tlv_type  = 0x01,
+		.offset    = offsetof(struct slimbus_select_inst_req_msg_v01,
+				      instance),
+		.ei_array  = NULL,
+	},
+	{
+		.data_type = QMI_OPT_FLAG,
+		.elem_len  = 1,
+		.elem_size = sizeof(uint8_t),
+		.is_array  = NO_ARRAY,
+		.tlv_type  = 0x10,
+		.offset    = offsetof(struct slimbus_select_inst_req_msg_v01,
+				      mode_valid),
+		.ei_array  = NULL,
+	},
+	{
+		.data_type = QMI_UNSIGNED_4_BYTE,
+		.elem_len  = 1,
+		.elem_size = sizeof(enum slimbus_mode_enum_type_v01),
+		.is_array  = NO_ARRAY,
+		.tlv_type  = 0x10,
+		.offset    = offsetof(struct slimbus_select_inst_req_msg_v01,
+				      mode),
+		.ei_array  = NULL,
+	},
+	{
+		.data_type = QMI_EOTI,
+		.elem_len  = 0,
+		.elem_size = 0,
+		.is_array  = NO_ARRAY,
+		.tlv_type  = 0x00,
+		.offset    = 0,
+		.ei_array  = NULL,
+	},
+};
+
+static struct elem_info slimbus_select_inst_resp_msg_v01_ei[] = {
+	{
+		.data_type = QMI_STRUCT,
+		.elem_len  = 1,
+		.elem_size = sizeof(struct qmi_response_type_v01),
+		.is_array  = NO_ARRAY,
+		.tlv_type  = 0x02,
+		.offset    = offsetof(struct slimbus_select_inst_resp_msg_v01,
+				      resp),
+		.ei_array  = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type = QMI_EOTI,
+		.elem_len  = 0,
+		.elem_size = 0,
+		.is_array  = NO_ARRAY,
+		.tlv_type  = 0x00,
+		.offset    = 0,
+		.ei_array  = NULL,
+	},
+};
+
+static struct elem_info slimbus_power_req_msg_v01_ei[] = {
+	{
+		.data_type = QMI_UNSIGNED_4_BYTE,
+		.elem_len  = 1,
+		.elem_size = sizeof(enum slimbus_pm_enum_type_v01),
+		.is_array  = NO_ARRAY,
+		.tlv_type  = 0x01,
+		.offset    = offsetof(struct slimbus_power_req_msg_v01, pm_req),
+		.ei_array  = NULL,
+	},
+	{
+		.data_type = QMI_EOTI,
+		.elem_len  = 0,
+		.elem_size = 0,
+		.is_array  = NO_ARRAY,
+		.tlv_type  = 0x00,
+		.offset    = 0,
+		.ei_array  = NULL,
+	},
+};
+
+static struct elem_info slimbus_power_resp_msg_v01_ei[] = {
+	{
+		.data_type = QMI_STRUCT,
+		.elem_len  = 1,
+		.elem_size = sizeof(struct qmi_response_type_v01),
+		.is_array  = NO_ARRAY,
+		.tlv_type  = 0x02,
+		.offset    = offsetof(struct slimbus_power_resp_msg_v01, resp),
+		.ei_array  = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type = QMI_EOTI,
+		.elem_len  = 0,
+		.elem_size = 0,
+		.is_array  = NO_ARRAY,
+		.tlv_type  = 0x00,
+		.offset    = 0,
+		.ei_array  = NULL,
+	},
+};
+
+static void msm_slim_qmi_recv_msg(struct kthread_work *work)
+{
+	int rc;
+	struct msm_slim_qmi *qmi =
+			container_of(work, struct msm_slim_qmi, kwork);
+
+	rc = qmi_recv_msg(qmi->handle);
+	if (rc < 0)
+		pr_err("%s: Error receiving QMI message\n", __func__);
+}
+
+static void msm_slim_qmi_notify(struct qmi_handle *handle,
+				enum qmi_event_type event, void *notify_priv)
+{
+	struct msm_slim_ctrl *dev = notify_priv;
+	struct msm_slim_qmi *qmi = &dev->qmi;
+
+	switch (event) {
+	case QMI_RECV_MSG:
+		queue_kthread_work(&qmi->kworker, &qmi->kwork);
+		break;
+	default:
+		break;
+	}
+}
+
+static const char *get_qmi_error(struct qmi_response_type_v01 *r)
+{
+	if (r->result == QMI_RESULT_SUCCESS_V01 || r->error == QMI_ERR_NONE_V01)
+		return "No Error";
+	else if (r->error == QMI_ERR_NO_MEMORY_V01)
+		return "Out of Memory";
+	else if (r->error == QMI_ERR_INTERNAL_V01)
+		return "Unexpected error occurred";
+	else if (r->error == QMI_ERR_INCOMPATIBLE_STATE_V01)
+		return "Slimbus s/w already configured to a different mode";
+	else if (r->error == QMI_ERR_INVALID_ID_V01)
+		return "Slimbus hardware instance is not valid";
+	else
+		return "Unknown error";
+}
+
+static int msm_slim_qmi_send_select_inst_req(struct msm_slim_ctrl *dev,
+				struct slimbus_select_inst_req_msg_v01 *req)
+{
+	struct slimbus_select_inst_resp_msg_v01 resp = { { 0, 0 } };
+	struct msg_desc req_desc, resp_desc;
+	int rc;
+
+	req_desc.msg_id = SLIMBUS_QMI_SELECT_INSTANCE_REQ_V01;
+	req_desc.max_msg_len = sizeof(*req);
+	req_desc.ei_array = slimbus_select_inst_req_msg_v01_ei;
+
+	resp_desc.msg_id = SLIMBUS_QMI_SELECT_INSTANCE_RESP_V01;
+	resp_desc.max_msg_len = sizeof(resp);
+	resp_desc.ei_array = slimbus_select_inst_resp_msg_v01_ei;
+
+	rc = qmi_send_req_wait(dev->qmi.handle, &req_desc, req, sizeof(*req),
+					&resp_desc, &resp, sizeof(resp), 5000);
+	if (rc < 0) {
+		pr_err("%s: QMI send req failed %d\n", __func__, rc);
+		return rc;
+	}
+
+	/* Check the response */
+	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+		pr_err("%s: QMI request failed 0x%x (%s)\n", __func__,
+				resp.resp.result, get_qmi_error(&resp.resp));
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int msm_slim_qmi_send_power_request(struct msm_slim_ctrl *dev,
+				struct slimbus_power_req_msg_v01 *req)
+{
+	struct slimbus_power_resp_msg_v01 resp = { { 0, 0 } };
+	struct msg_desc req_desc, resp_desc;
+	int rc;
+
+	req_desc.msg_id = SLIMBUS_QMI_POWER_REQ_V01;
+	req_desc.max_msg_len = sizeof(*req);
+	req_desc.ei_array = slimbus_power_req_msg_v01_ei;
+
+	resp_desc.msg_id = SLIMBUS_QMI_POWER_RESP_V01;
+	resp_desc.max_msg_len = sizeof(resp);
+	resp_desc.ei_array = slimbus_power_resp_msg_v01_ei;
+
+	rc = qmi_send_req_wait(dev->qmi.handle, &req_desc, req, sizeof(*req),
+					&resp_desc, &resp, sizeof(resp), 5000);
+	if (rc < 0) {
+		pr_err("%s: QMI send req failed %d\n", __func__, rc);
+		return rc;
+	}
+
+	/* Check the response */
+	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+		pr_err("%s: QMI request failed 0x%x (%s)\n", __func__,
+				resp.resp.result, get_qmi_error(&resp.resp));
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+int msm_slim_qmi_init(struct msm_slim_ctrl *dev, bool apps_is_master)
+{
+	int rc = 0;
+	struct qmi_handle *handle;
+	struct slimbus_select_inst_req_msg_v01 req;
+
+	init_kthread_worker(&dev->qmi.kworker);
+
+	dev->qmi.task = kthread_run(kthread_worker_fn,
+			&dev->qmi.kworker, "msm_slim_qmi_clnt%d", dev->ctrl.nr);
+
+	if (IS_ERR(dev->qmi.task)) {
+		pr_err("%s: Failed to create QMI client kthread\n", __func__);
+		return -ENOMEM;
+	}
+
+	init_kthread_work(&dev->qmi.kwork, msm_slim_qmi_recv_msg);
+
+	handle = qmi_handle_create(msm_slim_qmi_notify, dev);
+	if (!handle) {
+		rc = -ENOMEM;
+		pr_err("%s: QMI client handle alloc failed\n", __func__);
+		goto qmi_handle_create_failed;
+	}
+
+	rc = qmi_connect_to_service(handle, SLIMBUS_QMI_SVC_ID,
+						SLIMBUS_QMI_INS_ID);
+	if (rc < 0) {
+		pr_err("%s: QMI server not found\n", __func__);
+		goto qmi_connect_to_service_failed;
+	}
+
+	/* Instance is 0 based */
+	req.instance = dev->ctrl.nr - 1;
+	req.mode_valid = 1;
+
+	/* Mode indicates the role of the ADSP */
+	if (apps_is_master)
+		req.mode = SLIMBUS_MODE_SATELLITE_V01;
+	else
+		req.mode = SLIMBUS_MODE_MASTER_V01;
+
+	dev->qmi.handle = handle;
+
+	rc = msm_slim_qmi_send_select_inst_req(dev, &req);
+	if (rc) {
+		pr_err("%s: failed to select h/w instance\n", __func__);
+		goto qmi_select_instance_failed;
+	}
+
+	return 0;
+
+qmi_select_instance_failed:
+	dev->qmi.handle = NULL;
+qmi_connect_to_service_failed:
+	qmi_handle_destroy(handle);
+qmi_handle_create_failed:
+	flush_kthread_worker(&dev->qmi.kworker);
+	kthread_stop(dev->qmi.task);
+	dev->qmi.task = NULL;
+	return rc;
+}
+
+void msm_slim_qmi_exit(struct msm_slim_ctrl *dev)
+{
+	qmi_handle_destroy(dev->qmi.handle);
+	flush_kthread_worker(&dev->qmi.kworker);
+	kthread_stop(dev->qmi.task);
+	dev->qmi.task = NULL;
+	dev->qmi.handle = NULL;
+}
+
+int msm_slim_qmi_power_request(struct msm_slim_ctrl *dev, bool active)
+{
+	struct slimbus_power_req_msg_v01 req;
+
+	if (active)
+		req.pm_req = SLIMBUS_PM_ACTIVE_V01;
+	else
+		req.pm_req = SLIMBUS_PM_INACTIVE_V01;
+
+	return msm_slim_qmi_send_power_request(dev, &req);
+}
diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h
index 7d50620..3daf7ee 100644
--- a/drivers/slimbus/slim-msm.h
+++ b/drivers/slimbus/slim-msm.h
@@ -12,6 +12,10 @@
 
 #ifndef _SLIM_MSM_H
 #define _SLIM_MSM_H
+
+#include <linux/kthread.h>
+#include <mach/msm_qmi_interface.h>
+
 /* Per spec.max 40 bytes per received message */
 #define SLIM_RX_MSGQ_BUF_LEN	40
 
@@ -64,6 +68,10 @@
 #define MSM_MAX_NSATS	2
 #define MSM_MAX_SATCH	32
 
+/* Slimbus QMI service */
+#define SLIMBUS_QMI_SVC_ID 0x0301
+#define SLIMBUS_QMI_INS_ID 1
+
 #define PGD_THIS_EE(r, v) ((v) ? PGD_THIS_EE_V2(r) : PGD_THIS_EE_V1(r))
 #define PGD_PORT(r, p, v) ((v) ? PGD_PORT_V2(r, p) : PGD_PORT_V1(r, p))
 #define CFG_PORT(r, v) ((v) ? CFG_PORT_V2(r) : CFG_PORT_V1(r))
@@ -161,6 +169,15 @@
 	bool				connected;
 };
 
+struct msm_slim_qmi {
+	struct qmi_handle		*handle;
+	struct task_struct		*task;
+	struct kthread_work		kwork;
+	struct kthread_worker		kworker;
+	struct completion		qmi_comp;
+	struct notifier_block		nb;
+};
+
 struct msm_slim_ctrl {
 	struct slim_controller  ctrl;
 	struct slim_framer	framer;
@@ -197,6 +214,7 @@
 	enum msm_ctrl_state	state;
 	int			nsats;
 	u32			ver;
+	struct msm_slim_qmi	qmi;
 };
 
 struct msm_sat_chan {
@@ -249,4 +267,8 @@
 int msm_slim_sps_init(struct msm_slim_ctrl *dev, struct resource *bam_mem,
 			u32 pipe_reg, bool remote);
 void msm_slim_sps_exit(struct msm_slim_ctrl *dev);
+
+void msm_slim_qmi_exit(struct msm_slim_ctrl *dev);
+int msm_slim_qmi_init(struct msm_slim_ctrl *dev, bool apps_is_master);
+int msm_slim_qmi_power_request(struct msm_slim_ctrl *dev, bool active);
 #endif
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index 1e79dce..d5d6e0c 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -26,6 +26,7 @@
 #define SLIM_HDL_TO_PORT(hdl)	((u32)(hdl) & 0xFF)
 
 #define SLIM_HDL_TO_CHIDX(hdl)	((u16)(hdl) & 0xFF)
+#define SLIM_GRP_TO_NCHAN(hdl)	((u16)(hdl >> 8) & 0xFF)
 
 #define SLIM_SLAVE_PORT(p, la)	(((la)<<16) | (p))
 #define SLIM_MGR_PORT(p)	((0xFF << 16) | (p))
@@ -767,6 +768,7 @@
 	list_for_each_entry(sbdev, &ctrl->devs, dev_list) {
 		if (memcmp(sbdev->e_addr, e_addr, 6) == 0) {
 			struct slim_driver *sbdrv;
+			sbdev->laddr = *laddr;
 			if (sbdev->dev.driver) {
 				sbdrv = to_slim_driver(sbdev->dev.driver);
 				if (sbdrv->device_up)
@@ -1845,7 +1847,7 @@
 	}
 
 	if (grp)
-		*grph = chanh[0];
+		*grph = ((nchan << 8) | SLIM_HDL_TO_CHIDX(chanh[0]));
 	for (i = 0; i < nchan; i++) {
 		u8 chan = SLIM_HDL_TO_CHIDX(chanh[i]);
 		struct slim_ich *slc = &ctrl->chans[chan];
@@ -2868,6 +2870,7 @@
 	int ret = 0;
 	/* Get rid of the group flag in MSB if any */
 	u8 chan = SLIM_HDL_TO_CHIDX(chanh);
+	u8 nchan = 0;
 	struct slim_ich *slc = &ctrl->chans[chan];
 	if (!(slc->nextgrp & SLIM_START_GRP))
 		return -EINVAL;
@@ -2928,9 +2931,10 @@
 			}
 		}
 
-		if (!(slc->nextgrp & SLIM_END_GRP))
+		nchan++;
+		if (nchan < SLIM_GRP_TO_NCHAN(chanh))
 			chan = SLIM_HDL_TO_CHIDX(slc->nextgrp);
-	} while (!(slc->nextgrp & SLIM_END_GRP));
+	} while (nchan < SLIM_GRP_TO_NCHAN(chanh));
 	mutex_unlock(&ctrl->m_ctrl);
 	if (!ret && commit == true)
 		ret = slim_reconfigure_now(sb);
diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig
index 9a99238..43d17c2 100644
--- a/drivers/staging/android/Kconfig
+++ b/drivers/staging/android/Kconfig
@@ -67,6 +67,15 @@
 	---help---
 	  Register processes to be killed when memory is low
 
+config ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES
+	bool "Android Low Memory Killer: detect oom_adj values"
+	depends on ANDROID_LOW_MEMORY_KILLER
+	default y
+	---help---
+	  Detect oom_adj values written to
+	  /sys/module/lowmemorykiller/parameters/adj and convert them
+	  to oom_score_adj values.
+
 source "drivers/staging/android/switch/Kconfig"
 
 config ANDROID_INTF_ALARM_DEV
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index e73caf1..c67b75b 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -62,6 +62,81 @@
 			printk(x);			\
 	} while (0)
 
+static int nr_free_zone_mtype_pages(struct zone *zone, int mtype)
+{
+	int order;
+	int sum = 0;
+
+	for (order = 0; order < MAX_ORDER; ++order) {
+		unsigned long freecount = 0;
+		struct free_area *area;
+		struct list_head *curr;
+
+		area = &(zone->free_area[order]);
+
+		list_for_each(curr, &area->free_list[mtype])
+			freecount++;
+
+		sum += freecount << order;
+	}
+	return sum;
+}
+
+static int nr_free_zone_pages(struct zone *zone, gfp_t gfp_mask)
+{
+	int sum = 0;
+	int mtype = allocflags_to_migratetype(gfp_mask);
+	int i = 0;
+	int *mtype_fallbacks = get_migratetype_fallbacks(mtype);
+
+	sum = nr_free_zone_mtype_pages(zone, mtype);
+
+	/*
+	 * Also count the fallback pages
+	 */
+	for (i = 0;; i++) {
+		int fallbacktype = mtype_fallbacks[i];
+		sum += nr_free_zone_mtype_pages(zone, fallbacktype);
+
+		if (fallbacktype == MIGRATE_RESERVE)
+			break;
+	}
+
+	return sum;
+}
+
+static int nr_free_pages(gfp_t gfp_mask)
+{
+	struct zoneref *z;
+	struct zone *zone;
+	int sum = 0;
+
+	struct zonelist *zonelist = node_zonelist(numa_node_id(), gfp_mask);
+
+	for_each_zone_zonelist(zone, z, zonelist, gfp_zone(gfp_mask)) {
+		sum += nr_free_zone_pages(zone, gfp_mask);
+	}
+
+	return sum;
+}
+
+
+static int test_task_flag(struct task_struct *p, int flag)
+{
+	struct task_struct *t = p;
+
+	do {
+		task_lock(t);
+		if (test_tsk_thread_flag(t, flag)) {
+			task_unlock(t);
+			return 1;
+		}
+		task_unlock(t);
+	} while_each_thread(p, t);
+
+	return 0;
+}
+
 static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
 {
 	struct task_struct *tsk;
@@ -77,6 +152,15 @@
 	int other_file = global_page_state(NR_FILE_PAGES) -
 						global_page_state(NR_SHMEM);
 
+	if (sc->nr_to_scan > 0 && other_free > other_file) {
+		/*
+		 * If the number of free pages is going to affect the decision
+		 * of which process is selected then ensure only free pages
+		 * which can satisfy the request are considered.
+		 */
+		other_free = nr_free_pages(sc->gfp_mask);
+	}
+
 	if (lowmem_adj_size < array_size)
 		array_size = lowmem_adj_size;
 	if (lowmem_minfree_size < array_size)
@@ -111,16 +195,17 @@
 		if (tsk->flags & PF_KTHREAD)
 			continue;
 
+		if (time_before_eq(jiffies, lowmem_deathpending_timeout)) {
+			if (test_task_flag(tsk, TIF_MEMDIE)) {
+				rcu_read_unlock();
+				return 0;
+			}
+		}
+
 		p = find_lock_task_mm(tsk);
 		if (!p)
 			continue;
 
-		if (test_tsk_thread_flag(p, TIF_MEMDIE) &&
-		    time_before_eq(jiffies, lowmem_deathpending_timeout)) {
-			task_unlock(p);
-			rcu_read_unlock();
-			return 0;
-		}
 		oom_score_adj = p->signal->oom_score_adj;
 		if (oom_score_adj < min_score_adj) {
 			task_unlock(p);
@@ -174,9 +259,94 @@
 	unregister_shrinker(&lowmem_shrinker);
 }
 
+#ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES
+static int lowmem_oom_adj_to_oom_score_adj(int oom_adj)
+{
+	if (oom_adj == OOM_ADJUST_MAX)
+		return OOM_SCORE_ADJ_MAX;
+	else
+		return (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE;
+}
+
+static void lowmem_autodetect_oom_adj_values(void)
+{
+	int i;
+	int oom_adj;
+	int oom_score_adj;
+	int array_size = ARRAY_SIZE(lowmem_adj);
+
+	if (lowmem_adj_size < array_size)
+		array_size = lowmem_adj_size;
+
+	if (array_size <= 0)
+		return;
+
+	oom_adj = lowmem_adj[array_size - 1];
+	if (oom_adj > OOM_ADJUST_MAX)
+		return;
+
+	oom_score_adj = lowmem_oom_adj_to_oom_score_adj(oom_adj);
+	if (oom_score_adj <= OOM_ADJUST_MAX)
+		return;
+
+	lowmem_print(1, "lowmem_shrink: convert oom_adj to oom_score_adj:\n");
+	for (i = 0; i < array_size; i++) {
+		oom_adj = lowmem_adj[i];
+		oom_score_adj = lowmem_oom_adj_to_oom_score_adj(oom_adj);
+		lowmem_adj[i] = oom_score_adj;
+		lowmem_print(1, "oom_adj %d => oom_score_adj %d\n",
+			     oom_adj, oom_score_adj);
+	}
+}
+
+static int lowmem_adj_array_set(const char *val, const struct kernel_param *kp)
+{
+	int ret;
+
+	ret = param_array_ops.set(val, kp);
+
+	/* HACK: Autodetect oom_adj values in lowmem_adj array */
+	lowmem_autodetect_oom_adj_values();
+
+	return ret;
+}
+
+static int lowmem_adj_array_get(char *buffer, const struct kernel_param *kp)
+{
+	return param_array_ops.get(buffer, kp);
+}
+
+static void lowmem_adj_array_free(void *arg)
+{
+	param_array_ops.free(arg);
+}
+
+static struct kernel_param_ops lowmem_adj_array_ops = {
+	.set = lowmem_adj_array_set,
+	.get = lowmem_adj_array_get,
+	.free = lowmem_adj_array_free,
+};
+
+static const struct kparam_array __param_arr_adj = {
+	.max = ARRAY_SIZE(lowmem_adj),
+	.num = &lowmem_adj_size,
+	.ops = &param_ops_int,
+	.elemsize = sizeof(lowmem_adj[0]),
+	.elem = lowmem_adj,
+};
+#endif
+
 module_param_named(cost, lowmem_shrinker.seeks, int, S_IRUGO | S_IWUSR);
+#ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES
+__module_param_call(MODULE_PARAM_PREFIX, adj,
+		    &lowmem_adj_array_ops,
+		    .arr = &__param_arr_adj,
+		    S_IRUGO | S_IWUSR, -1);
+__MODULE_PARM_TYPE(adj, "array of int");
+#else
 module_param_array_named(adj, lowmem_adj, int, &lowmem_adj_size,
 			 S_IRUGO | S_IWUSR);
+#endif
 module_param_array_named(minfree, lowmem_minfree, uint, &lowmem_minfree_size,
 			 S_IRUGO | S_IWUSR);
 module_param_named(debug_level, lowmem_debug_level, uint, S_IRUGO | S_IWUSR);
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 8e13fbf..4cb93b8 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -558,6 +558,7 @@
 	int tsens9_point2 = 0, tsens10_point2 = 0;
 	int tsens_base2_data = 0, tsens_calibration_mode = 0, temp = 0;
 	uint32_t calib_data[6], calib_redun_sel, calib_data_backup[4];
+	uint32_t calib_tsens_point1_data[11], calib_tsens_point2_data[11];
 
 	if (tmdev->calibration_less_mode)
 		goto calibration_less_mode;
@@ -619,45 +620,46 @@
 			tsens10_point1 = (calib_data_backup[2] &
 				TSENS10_POINT1_MASK_BACKUP) >>
 				TSENS10_POINT1_BACKUP_SHIFT;
-	} else if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
-		pr_debug("backup two point calibrationless mode\n");
-		tsens_base2_data = (calib_data_backup[2] &
+		} else
+			goto calibration_less_mode;
+
+		if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
+			pr_debug("backup two point calibrationless mode\n");
+			tsens_base2_data = (calib_data_backup[2] &
 				TSENS_BASE2_BACKUP_MASK) >>
 				TSENS_POINT2_BASE_BACKUP_SHIFT;
-		tsens0_point2 = (calib_data_backup[2] &
+			tsens0_point2 = (calib_data_backup[2] &
 					TSENS0_POINT2_BACKUP_MASK) >>
 					TSENS0_POINT2_BACKUP_SHIFT;
-		tsens1_point2 = (calib_data_backup[3] &
+			tsens1_point2 = (calib_data_backup[3] &
 					TSENS1_POINT2_BACKUP_MASK);
-		tsens2_point2 = (calib_data_backup[3] &
+			tsens2_point2 = (calib_data_backup[3] &
 					TSENS2_POINT2_BACKUP_MASK) >>
 					TSENS2_POINT2_BACKUP_SHIFT;
-		tsens3_point2 = (calib_data_backup[3] &
+			tsens3_point2 = (calib_data_backup[3] &
 					TSENS3_POINT2_BACKUP_MASK) >>
 					TSENS3_POINT2_BACKUP_SHIFT;
-		tsens4_point2 = (calib_data_backup[3] &
+			tsens4_point2 = (calib_data_backup[3] &
 					TSENS4_POINT2_BACKUP_MASK) >>
 					TSENS4_POINT2_BACKUP_SHIFT;
-		tsens5_point2 = (calib_data[4] & TSENS5_POINT2_BACKUP_MASK) >>
-						TSENS5_POINT2_BACKUP_SHIFT;
-		tsens6_point2 = (calib_data[5] & TSENS6_POINT2_BACKUP_MASK);
-		tsens7_point2 = (calib_data[5] & TSENS7_POINT2_BACKUP_MASK) >>
-						TSENS7_POINT2_BACKUP_SHIFT;
-		tsens8_point2 = (calib_data[5] & TSENS8_POINT2_BACKUP_MASK) >>
-						TSENS8_POINT2_BACKUP_SHIFT;
-		tsens9_point2 = (calib_data[5] & TSENS9_POINT2_BACKUP_MASK) >>
-						TSENS9_POINT2_BACKUP_SHIFT;
-		tsens10_point2 = (calib_data[5] & TSENS10_POINT2_BACKUP_MASK)
-						>> TSENS10_POINT2_BACKUP_SHIFT;
-	} else {
-		pr_debug("TSENS:backup is calibrationless mode\n");
-		for (i = 0; i < tmdev->tsens_num_sensor; i++) {
-			tmdev->sensor[i].calib_data_point2 = 780;
-			tmdev->sensor[i].calib_data_point1 = 492;
+			tsens5_point2 = (calib_data[4] &
+					TSENS5_POINT2_BACKUP_MASK) >>
+					TSENS5_POINT2_BACKUP_SHIFT;
+			tsens6_point2 = (calib_data[5] &
+					TSENS6_POINT2_BACKUP_MASK);
+			tsens7_point2 = (calib_data[5] &
+					TSENS7_POINT2_BACKUP_MASK) >>
+					TSENS7_POINT2_BACKUP_SHIFT;
+			tsens8_point2 = (calib_data[5] &
+					TSENS8_POINT2_BACKUP_MASK) >>
+					TSENS8_POINT2_BACKUP_SHIFT;
+			tsens9_point2 = (calib_data[5] &
+					TSENS9_POINT2_BACKUP_MASK) >>
+					TSENS9_POINT2_BACKUP_SHIFT;
+			tsens10_point2 = (calib_data[5] &
+					TSENS10_POINT2_BACKUP_MASK)
+					>> TSENS10_POINT2_BACKUP_SHIFT;
 		}
-		tsens_calibration_mode = 0;
-		goto compute_intercept_slope;
-	}
 	} else {
 		tsens_calibration_mode = (calib_data[1] & TSENS_CAL_SEL_0_1)
 			>> TSENS_CAL_SEL_SHIFT;
@@ -690,7 +692,10 @@
 			tsens9_point1 = (calib_data[2] & TSENS9_POINT1_MASK);
 			tsens10_point1 = (calib_data[2] & TSENS10_POINT1_MASK)
 							>> TSENS10_POINT1_SHIFT;
-		} else if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
+		} else
+			goto calibration_less_mode;
+
+		if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
 			pr_debug("TSENS is two point calibrationless mode\n");
 			tsens_base2_data = (calib_data[2] & TSENS_BASE2_MASK) >>
 						TSENS_POINT2_BASE_SHIFT;
@@ -714,120 +719,145 @@
 						TSENS9_POINT2_SHIFT;
 			tsens10_point2 = (calib_data[4] & TSENS10_POINT2_MASK)
 						>> TSENS10_POINT2_SHIFT;
-		} else {
+		}
+
+		if (tsens_calibration_mode == 0) {
 calibration_less_mode:
 			pr_debug("TSENS is calibrationless mode\n");
 			for (i = 0; i < tmdev->tsens_num_sensor; i++)
-				tmdev->sensor[i].calib_data_point2 = 780;
-			tmdev->sensor[0].calib_data_point1 = 502;
-			tmdev->sensor[1].calib_data_point1 = 509;
-			tmdev->sensor[2].calib_data_point1 = 503;
-			tmdev->sensor[3].calib_data_point1 = 509;
-			tmdev->sensor[4].calib_data_point1 = 505;
-			tmdev->sensor[5].calib_data_point1 = 509;
-			tmdev->sensor[6].calib_data_point1 = 507;
-			tmdev->sensor[7].calib_data_point1 = 510;
-			tmdev->sensor[8].calib_data_point1 = 508;
-			tmdev->sensor[9].calib_data_point1 = 509;
-			tmdev->sensor[10].calib_data_point1 = 508;
+				calib_tsens_point2_data[i] = 780;
+			calib_tsens_point1_data[0] = 502;
+			calib_tsens_point1_data[1] = 509;
+			calib_tsens_point1_data[2] = 503;
+			calib_tsens_point1_data[3] = 509;
+			calib_tsens_point1_data[4] = 505;
+			calib_tsens_point1_data[5] = 509;
+			calib_tsens_point1_data[6] = 507;
+			calib_tsens_point1_data[7] = 510;
+			calib_tsens_point1_data[8] = 508;
+			calib_tsens_point1_data[9] = 509;
+			calib_tsens_point1_data[10] = 508;
 			goto compute_intercept_slope;
 		}
 	}
 
 	if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB) {
 		pr_debug("old one point calibration calculation\n");
-		tmdev->sensor[0].calib_data_point1 =
-		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens0_point1;
-		tmdev->sensor[1].calib_data_point1 =
-		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens1_point1;
-		tmdev->sensor[2].calib_data_point1 =
-		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens2_point1;
-		tmdev->sensor[3].calib_data_point1 =
-		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens3_point1;
-		tmdev->sensor[4].calib_data_point1 =
-		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens4_point1;
-		tmdev->sensor[5].calib_data_point1 =
-		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens5_point1;
-		tmdev->sensor[6].calib_data_point1 =
-		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens6_point1;
-		tmdev->sensor[7].calib_data_point1 =
-		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens7_point1;
-		tmdev->sensor[8].calib_data_point1 =
-		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens8_point1;
-		tmdev->sensor[9].calib_data_point1 =
-		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens9_point1;
-		tmdev->sensor[10].calib_data_point1 =
-		(((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens10_point1;
+		calib_tsens_point1_data[0] =
+			(((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
+							+ tsens0_point1;
+		calib_tsens_point1_data[1] =
+			(((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
+							+ tsens1_point1;
+		calib_tsens_point1_data[2] =
+			(((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
+							+ tsens2_point1;
+		calib_tsens_point1_data[3] =
+			(((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
+							+ tsens3_point1;
+		calib_tsens_point1_data[4] =
+			(((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
+							+ tsens4_point1;
+		calib_tsens_point1_data[5] =
+			(((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
+							+ tsens5_point1;
+		calib_tsens_point1_data[6] =
+			(((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
+							+ tsens6_point1;
+		calib_tsens_point1_data[7] =
+			(((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
+							+ tsens7_point1;
+		calib_tsens_point1_data[8] =
+			(((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
+							+ tsens8_point1;
+		calib_tsens_point1_data[9] =
+			(((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
+							+ tsens9_point1;
+		calib_tsens_point1_data[10] =
+			(((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
+							+ tsens10_point1;
 	}
 
 	if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
 			(tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
 		pr_debug("one and two point calibration calculation\n");
-
-		tmdev->sensor[0].calib_data_point1 =
-		((((tsens_base1_data) + tsens0_point1) << 2) |
+		calib_tsens_point1_data[0] =
+			((((tsens_base1_data) + tsens0_point1) << 2) |
 						TSENS_BIT_APPEND);
-		tmdev->sensor[1].calib_data_point1 =
-		((((tsens_base1_data) + tsens1_point1) << 2) |
+		calib_tsens_point1_data[1] =
+			((((tsens_base1_data) + tsens1_point1) << 2) |
 						TSENS_BIT_APPEND);
-		tmdev->sensor[2].calib_data_point1 =
-		((((tsens_base1_data) + tsens2_point1) << 2) |
+		calib_tsens_point1_data[2] =
+			((((tsens_base1_data) + tsens2_point1) << 2) |
 						TSENS_BIT_APPEND);
-		tmdev->sensor[3].calib_data_point1 =
-		((((tsens_base1_data) + tsens3_point1) << 2) |
+		calib_tsens_point1_data[3] =
+			((((tsens_base1_data) + tsens3_point1) << 2) |
 						TSENS_BIT_APPEND);
-		tmdev->sensor[4].calib_data_point1 =
-		((((tsens_base1_data) + tsens4_point1) << 2) |
+		calib_tsens_point1_data[4] =
+			((((tsens_base1_data) + tsens4_point1) << 2) |
 						TSENS_BIT_APPEND);
-		tmdev->sensor[5].calib_data_point1 =
-		((((tsens_base1_data) + tsens5_point1) << 2) |
+		calib_tsens_point1_data[5] =
+			((((tsens_base1_data) + tsens5_point1) << 2) |
 						TSENS_BIT_APPEND);
-		tmdev->sensor[6].calib_data_point1 =
-		((((tsens_base1_data) + tsens6_point1) << 2) |
+		calib_tsens_point1_data[6] =
+			((((tsens_base1_data) + tsens6_point1) << 2) |
 						TSENS_BIT_APPEND);
-		tmdev->sensor[7].calib_data_point1 =
-		((((tsens_base1_data) + tsens7_point1) << 2) |
+		calib_tsens_point1_data[7] =
+			((((tsens_base1_data) + tsens7_point1) << 2) |
 						TSENS_BIT_APPEND);
-		tmdev->sensor[8].calib_data_point1 =
-		((((tsens_base1_data) + tsens8_point1) << 2) |
+		calib_tsens_point1_data[8] =
+			((((tsens_base1_data) + tsens8_point1) << 2) |
 						TSENS_BIT_APPEND);
-		tmdev->sensor[9].calib_data_point1 =
-		((((tsens_base1_data) + tsens9_point1) << 2) |
+		calib_tsens_point1_data[9] =
+			((((tsens_base1_data) + tsens9_point1) << 2) |
 						TSENS_BIT_APPEND);
-		tmdev->sensor[10].calib_data_point1 =
-		((((tsens_base1_data) + tsens10_point1) << 2) |
+		calib_tsens_point1_data[10] =
+			((((tsens_base1_data) + tsens10_point1) << 2) |
 						TSENS_BIT_APPEND);
 	}
 
 	if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
 		pr_debug("two point calibration calculation\n");
-		tmdev->sensor[0].calib_data_point2 =
-		(((tsens_base2_data + tsens0_point2) << 2) | TSENS_BIT_APPEND);
-		tmdev->sensor[1].calib_data_point2 =
-		(((tsens_base2_data + tsens1_point2) << 2) | TSENS_BIT_APPEND);
-		tmdev->sensor[2].calib_data_point2 =
-		(((tsens_base2_data + tsens2_point2) << 2) | TSENS_BIT_APPEND);
-		tmdev->sensor[3].calib_data_point2 =
-		(((tsens_base2_data + tsens3_point2) << 2) | TSENS_BIT_APPEND);
-		tmdev->sensor[4].calib_data_point2 =
-		(((tsens_base2_data + tsens4_point2) << 2) | TSENS_BIT_APPEND);
-		tmdev->sensor[5].calib_data_point2 =
-		(((tsens_base2_data + tsens5_point2) << 2) | TSENS_BIT_APPEND);
-		tmdev->sensor[6].calib_data_point2 =
-		(((tsens_base2_data + tsens6_point2) << 2) | TSENS_BIT_APPEND);
-		tmdev->sensor[7].calib_data_point2 =
-		(((tsens_base2_data + tsens7_point2) << 2) | TSENS_BIT_APPEND);
-		tmdev->sensor[8].calib_data_point2 =
-		(((tsens_base2_data + tsens8_point2) << 2) | TSENS_BIT_APPEND);
-		tmdev->sensor[9].calib_data_point2 =
-		(((tsens_base2_data + tsens9_point2) << 2) | TSENS_BIT_APPEND);
-		tmdev->sensor[10].calib_data_point2 =
-		(((tsens_base2_data + tsens10_point2) << 2) | TSENS_BIT_APPEND);
+		calib_tsens_point2_data[0] =
+			(((tsens_base2_data + tsens0_point2) << 2) |
+					TSENS_BIT_APPEND);
+		calib_tsens_point2_data[1] =
+			(((tsens_base2_data + tsens1_point2) << 2) |
+					TSENS_BIT_APPEND);
+		calib_tsens_point2_data[2] =
+			(((tsens_base2_data + tsens2_point2) << 2) |
+					TSENS_BIT_APPEND);
+		calib_tsens_point2_data[3] =
+			(((tsens_base2_data + tsens3_point2) << 2) |
+					TSENS_BIT_APPEND);
+		calib_tsens_point2_data[4] =
+			(((tsens_base2_data + tsens4_point2) << 2) |
+					TSENS_BIT_APPEND);
+		calib_tsens_point2_data[5] =
+			(((tsens_base2_data + tsens5_point2) << 2) |
+					TSENS_BIT_APPEND);
+		calib_tsens_point2_data[6] =
+			(((tsens_base2_data + tsens6_point2) << 2) |
+					TSENS_BIT_APPEND);
+		calib_tsens_point2_data[7] =
+			(((tsens_base2_data + tsens7_point2) << 2) |
+					TSENS_BIT_APPEND);
+		calib_tsens_point2_data[8] =
+			(((tsens_base2_data + tsens8_point2) << 2) |
+					TSENS_BIT_APPEND);
+		calib_tsens_point2_data[9] =
+			(((tsens_base2_data + tsens9_point2) << 2) |
+					TSENS_BIT_APPEND);
+		calib_tsens_point2_data[10] =
+			(((tsens_base2_data + tsens10_point2) << 2) |
+					TSENS_BIT_APPEND);
 	}
 
 compute_intercept_slope:
 	for (i = 0; i < tmdev->tsens_num_sensor; i++) {
 		int32_t num = 0, den = 0;
+		tmdev->sensor[i].calib_data_point2 = calib_tsens_point2_data[i];
+		tmdev->sensor[i].calib_data_point1 = calib_tsens_point1_data[i];
 		if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
 			num = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT2;
 			den = tmdev->sensor[i].calib_data_point2 -
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 4a9c9a3..84cd3e7 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -168,6 +168,7 @@
 	struct work_struct clock_off_w; /* work for actual clock off */
 	struct workqueue_struct *hsuart_wq; /* hsuart workqueue */
 	struct mutex clk_mutex; /* mutex to guard against clock off/clock on */
+	bool tty_flush_receive;
 };
 
 #define MSM_UARTDM_BURST_SIZE 16   /* DM burst size (in bytes) */
@@ -1250,6 +1251,13 @@
 
 }
 
+static void msm_hs_flush_buffer(struct uart_port *uport)
+{
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+
+	msm_uport->tty_flush_receive = true;
+}
+
 /*
  *  Standard API, Break Signal
  *
@@ -1465,7 +1473,14 @@
 		 */
 		mb();
 		/* Complete DMA TX transactions and submit new transactions */
-		tx_buf->tail = (tx_buf->tail + tx->tx_count) & ~UART_XMIT_SIZE;
+
+		/* Do not update tx_buf.tail if uart_flush_buffer already
+						called in serial core */
+		if (!msm_uport->tty_flush_receive)
+			tx_buf->tail = (tx_buf->tail +
+					tx->tx_count) & ~UART_XMIT_SIZE;
+		else
+			msm_uport->tty_flush_receive = false;
 
 		tx->dma_in_flight = 0;
 
@@ -2209,6 +2224,7 @@
 	.config_port = msm_hs_config_port,
 	.release_port = msm_hs_release_port,
 	.request_port = msm_hs_request_port,
+	.flush_buffer = msm_hs_flush_buffer,
 };
 
 module_init(msm_serial_hs_init);
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index f065eaa..2f3f83d 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -149,12 +149,9 @@
 
 static int get_line(struct platform_device *pdev)
 {
-	const struct msm_serial_hslite_platform_data *pdata =
-					pdev->dev.platform_data;
-	if (pdata)
-		return pdata->line;
+	struct msm_hsl_port *msm_hsl_port = platform_get_drvdata(pdev);
 
-	return pdev->id;
+	return msm_hsl_port->uart.line;
 }
 
 static int clk_en(struct uart_port *port, int enable)
@@ -1357,18 +1354,32 @@
 	struct resource *uart_resource;
 	struct resource *gsbi_resource;
 	struct uart_port *port;
+	const struct msm_serial_hslite_platform_data *pdata;
 	const struct of_device_id *match;
+	u32 line;
 	int ret;
 
 	if (pdev->id == -1)
 		pdev->id = atomic_inc_return(&msm_serial_hsl_next_id) - 1;
 
-	if (unlikely(get_line(pdev) < 0 || get_line(pdev) >= UART_NR))
+	/* Use line (ttyHSLx) number from pdata or device tree if specified */
+	pdata = pdev->dev.platform_data;
+	if (pdata)
+		line = pdata->line;
+	else
+		line = pdev->id;
+
+	/* Use line number from device tree if present */
+	if (pdev->dev.of_node)
+		of_property_read_u32(pdev->dev.of_node, "cell-index", &line);
+
+	if (unlikely(line < 0 || line >= UART_NR))
 		return -ENXIO;
 
-	printk(KERN_INFO "msm_serial_hsl: detected port #%d\n", pdev->id);
+	printk(KERN_INFO "msm_serial_hsl: detected port #%d (ttyHSL%d)\n",
+	       pdev->id, line);
 
-	port = get_port_from_line(get_line(pdev));
+	port = get_port_from_line(line);
 	port->dev = &pdev->dev;
 	msm_hsl_port = UART_TO_MSM(port);
 
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index a292416..494ec49 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1405,7 +1405,6 @@
 	 * (This can't be done in usb_resume_interface()
 	 * above because it doesn't own the right set of locks.)
 	 */
-	pm_runtime_get_sync(dev->parent);
 	status = usb_resume_both(udev, msg);
 	if (status == 0) {
 		pm_runtime_disable(dev);
@@ -1413,7 +1412,6 @@
 		pm_runtime_enable(dev);
 		unbind_no_reset_resume_drivers_interfaces(udev);
 	}
-	pm_runtime_put_sync(dev->parent);
 
 	/* Avoid PM error messages for devices disconnected while suspended
 	 * as we'll display regular disconnect messages just a bit later.
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 0531f83..4073fc8 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -1262,6 +1262,17 @@
 	dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
 						0xC00000, 0x800000);
 
+	/* Sequence to put SSPHY in low power state:
+	 * 1. Clear REF_SS_PHY_EN in SS_PHY_CTRL_REG
+	 * 2. Clear REF_USE_PAD in SS_PHY_CTRL_REG
+	 * 3. Set TEST_POWERED_DOWN in SS_PHY_CTRL_REG to enable PHY retention
+	 * 4. Disable SSPHY ref clk
+	 */
+	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 8), 0x0);
+	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 28), 0x0);
+	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 26),
+								(1 << 26));
+
 	usleep_range(1000, 1200);
 	clk_disable_unprepare(mdwc->ref_clk);
 
@@ -1290,6 +1301,8 @@
 	if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability)
 		dwc3_hsusb_ldo_enable(0);
 
+	dwc3_ssusb_ldo_enable(0);
+	dwc3_ssusb_config_vddcx(0);
 	dwc3_hsusb_config_vddcx(0);
 	wake_unlock(&mdwc->wlock);
 	atomic_set(&mdwc->in_lpm, 1);
@@ -1328,6 +1341,8 @@
 	if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability)
 		dwc3_hsusb_ldo_enable(1);
 
+	dwc3_ssusb_ldo_enable(1);
+	dwc3_ssusb_config_vddcx(1);
 	dwc3_hsusb_config_vddcx(1);
 	clk_prepare_enable(mdwc->ref_clk);
 	usleep_range(1000, 1200);
@@ -1342,14 +1357,26 @@
 
 	dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0),
 	      dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)) | 0xF0000000);
-	/* 20usec delay required before de-asserting PHY RESET */
-	udelay(20);
+	/* 10usec delay required before de-asserting PHY RESET */
+	udelay(10);
 	dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0),
 	      dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)) & 0x7FFFFFFF);
 
 	/* Bring PHY out of suspend */
 	dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0xC00000, 0x0);
 
+	/* Assert SS PHY RESET */
+	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7),
+								(1 << 7));
+	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 28),
+								(1 << 28));
+	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 8),
+								(1 << 8));
+	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 26), 0x0);
+	/* 10usec delay required before de-asserting SS PHY RESET */
+	udelay(10);
+	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7), 0x0);
+
 	atomic_set(&mdwc->in_lpm, 0);
 
 	/* match disable_irq call from isr */
@@ -1741,7 +1768,9 @@
 	}
 
 	msm->ext_xceiv.otg_capability = of_property_read_bool(node,
-				"qcom,dwc-usb3-msm-otg-capability");
+				"qcom,otg-capability");
+	msm->charger.charging_disabled = of_property_read_bool(node,
+				"qcom,charging-disabled");
 
 	if (!msm->ext_xceiv.otg_capability) {
 		/* DWC3 has separate IRQ line for OTG events (ID/BSV etc.) */
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index 1aa8519..7b672c4 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -100,11 +100,23 @@
 static int dwc3_otg_start_host(struct usb_otg *otg, int on)
 {
 	struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+	struct dwc3 *dwc = dotg->dwc;
 	int ret = 0;
 
-	if (!dotg->dwc->xhci)
+	if (!dwc->xhci)
 		return -EINVAL;
 
+	if (!dotg->vbus_otg) {
+		dotg->vbus_otg = devm_regulator_get(dwc->dev->parent,
+							"vbus_dwc3");
+		if (IS_ERR(dotg->vbus_otg)) {
+			dev_err(dwc->dev, "Failed to get vbus regulator\n");
+			ret = PTR_ERR(dotg->vbus_otg);
+			dotg->vbus_otg = 0;
+			return ret;
+		}
+	}
+
 	if (on) {
 		dev_dbg(otg->phy->dev, "%s: turn on host\n", __func__);
 
@@ -119,7 +131,7 @@
 		 * anymore.
 		 */
 		dwc3_otg_set_host_regs(dotg);
-		ret = platform_device_add(dotg->dwc->xhci);
+		ret = platform_device_add(dwc->xhci);
 		if (ret) {
 			dev_err(otg->phy->dev,
 				"%s: failed to add XHCI pdev ret=%d\n",
@@ -131,7 +143,7 @@
 		ret = regulator_enable(dotg->vbus_otg);
 		if (ret) {
 			dev_err(otg->phy->dev, "unable to enable vbus_otg\n");
-			platform_device_del(dotg->dwc->xhci);
+			platform_device_del(dwc->xhci);
 			return ret;
 		}
 
@@ -140,7 +152,7 @@
 	} else {
 		dev_dbg(otg->phy->dev, "%s: turn off host\n", __func__);
 
-		platform_device_del(dotg->dwc->xhci);
+		platform_device_del(dwc->xhci);
 
 		ret = regulator_disable(dotg->vbus_otg);
 		if (ret) {
@@ -150,7 +162,7 @@
 		dwc3_otg_notify_host_mode(otg, on);
 
 		/* re-init core and OTG register as XHCI reset clears it */
-		dwc3_post_host_reset_core_init(dotg->dwc);
+		dwc3_post_host_reset_core_init(dwc);
 		dwc3_otg_reset(dotg);
 	}
 
@@ -381,11 +393,14 @@
 	struct dwc3_otg *dotg = container_of(phy->otg, struct dwc3_otg, otg);
 
 
-	if (!dotg->psy) {
-		dev_err(phy->dev, "no usb power supply registered\n");
+	if (!dotg->psy || !dotg->charger) {
+		dev_err(phy->dev, "no usb power supply/charger registered\n");
 		return 0;
 	}
 
+	if (dotg->charger->charging_disabled)
+		return 0;
+
 	if (dotg->charger->chg_type == DWC3_SDP_CHARGER)
 		power_supply_type = POWER_SUPPLY_TYPE_USB;
 	else if (dotg->charger->chg_type == DWC3_CDP_CHARGER)
@@ -769,13 +784,6 @@
 		return -ENOMEM;
 	}
 
-	dotg->vbus_otg = devm_regulator_get(dwc->dev->parent, "vbus_dwc3");
-	if (IS_ERR(dotg->vbus_otg)) {
-		dev_err(dwc->dev, "Unable to get vbus_dwc3 regulator\n");
-		ret = PTR_ERR(dotg->vbus_otg);
-		goto err1;
-	}
-
 	/* DWC3 has separate IRQ line for OTG events (ID/BSV etc.) */
 	dotg->irq = platform_get_irq_byname(to_platform_device(dwc->dev),
 								"otg_irq");
diff --git a/drivers/usb/dwc3/dwc3_otg.h b/drivers/usb/dwc3/dwc3_otg.h
index 4384888..c93ce5f 100644
--- a/drivers/usb/dwc3/dwc3_otg.h
+++ b/drivers/usb/dwc3/dwc3_otg.h
@@ -70,6 +70,7 @@
 struct dwc3_charger {
 	enum dwc3_chg_type	chg_type;
 	unsigned		max_power;
+	bool			charging_disabled;
 
 	/* start/stop charger detection, provided by external charger module */
 	void	(*start_detection)(struct dwc3_charger *charger, bool start);
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 9c1ebf8..6f903dd 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2551,7 +2551,7 @@
 	dev_set_name(&dwc->gadget.dev, "gadget");
 
 	dwc->gadget.ops			= &dwc3_gadget_ops;
-	dwc->gadget.max_speed		= USB_SPEED_HIGH;
+	dwc->gadget.max_speed		= USB_SPEED_SUPER;
 	dwc->gadget.speed		= USB_SPEED_UNKNOWN;
 	dwc->gadget.dev.parent		= dwc->dev;
 	dwc->gadget.sg_supported	= true;
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 52c19cf..b773d1a 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -24,6 +24,7 @@
 #include <linux/utsname.h>
 #include <linux/platform_device.h>
 #include <linux/pm_qos.h>
+#include <linux/of.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/composite.h>
@@ -107,9 +108,6 @@
 	char *dev_name;
 	struct device_attribute **attributes;
 
-	/* for android_conf.enabled_functions */
-	struct list_head enabled_list;
-
 	struct android_dev *android_dev;
 
 	/* Optional: initialization during gadget bind */
@@ -134,6 +132,14 @@
 					const struct usb_ctrlrequest *);
 };
 
+struct android_usb_function_holder {
+
+	struct android_usb_function *f;
+
+	/* for android_conf.enabled_functions */
+	struct list_head enabled_list;
+};
+
 struct android_dev {
 	const char *name;
 	struct android_usb_function **functions;
@@ -1713,15 +1719,15 @@
 android_bind_enabled_functions(struct android_dev *dev,
 			       struct usb_configuration *c)
 {
-	struct android_usb_function *f;
+	struct android_usb_function_holder *f_holder;
 	struct android_configuration *conf =
 		container_of(c, struct android_configuration, usb_config);
 	int ret;
 
-	list_for_each_entry(f, &conf->enabled_functions, enabled_list) {
-		ret = f->bind_config(f, c);
+	list_for_each_entry(f_holder, &conf->enabled_functions, enabled_list) {
+		ret = f_holder->f->bind_config(f_holder->f, c);
 		if (ret) {
-			pr_err("%s: %s failed", __func__, f->name);
+			pr_err("%s: %s failed", __func__, f_holder->f->name);
 			return ret;
 		}
 	}
@@ -1732,13 +1738,13 @@
 android_unbind_enabled_functions(struct android_dev *dev,
 			       struct usb_configuration *c)
 {
-	struct android_usb_function *f;
+	struct android_usb_function_holder *f_holder;
 	struct android_configuration *conf =
 		container_of(c, struct android_configuration, usb_config);
 
-	list_for_each_entry(f, &conf->enabled_functions, enabled_list) {
-		if (f->unbind_config)
-			f->unbind_config(f, c);
+	list_for_each_entry(f_holder, &conf->enabled_functions, enabled_list) {
+		if (f_holder->f->unbind_config)
+			f_holder->f->unbind_config(f_holder->f, c);
 	}
 }
 
@@ -1748,16 +1754,24 @@
 {
 	struct android_usb_function **functions = dev->functions;
 	struct android_usb_function *f;
+	struct android_usb_function_holder *f_holder;
 	while ((f = *functions++)) {
 		if (!strcmp(name, f->name)) {
-			if (f->android_dev)
-				pr_err("%s already enabled in other " \
-					"configuration or device\n",
+			if (f->android_dev && f->android_dev != dev)
+				pr_err("%s is enabled in other device\n",
 					f->name);
 			else {
-				list_add_tail(&f->enabled_list,
-					      &conf->enabled_functions);
+				f_holder = kzalloc(sizeof(*f_holder),
+						GFP_KERNEL);
+				if (!f_holder) {
+					pr_err("Failed to alloc f_holder\n");
+					return -ENOMEM;
+				}
+
 				f->android_dev = dev;
+				f_holder->f = f;
+				list_add_tail(&f_holder->enabled_list,
+					      &conf->enabled_functions);
 				return 0;
 			}
 		}
@@ -1817,7 +1831,7 @@
 {
 	struct android_dev *dev = dev_get_drvdata(pdev);
 	struct android_configuration *conf;
-	struct android_usb_function *f;
+	struct android_usb_function_holder *f_holder;
 	char *buff = buf;
 
 	mutex_lock(&dev->mutex);
@@ -1825,8 +1839,10 @@
 	list_for_each_entry(conf, &dev->configs, list_item) {
 		if (buff != buf)
 			*(buff-1) = ':';
-		list_for_each_entry(f, &conf->enabled_functions, enabled_list)
-			buff += snprintf(buff, PAGE_SIZE, "%s,", f->name);
+		list_for_each_entry(f_holder, &conf->enabled_functions,
+					enabled_list)
+			buff += snprintf(buff, PAGE_SIZE, "%s,",
+					f_holder->f->name);
 	}
 
 	mutex_unlock(&dev->mutex);
@@ -1841,10 +1857,10 @@
 			       const char *buff, size_t size)
 {
 	struct android_dev *dev = dev_get_drvdata(pdev);
-	struct android_usb_function *f;
 	struct list_head *curr_conf = &dev->configs;
 	struct android_configuration *conf;
 	char *conf_str;
+	struct android_usb_function_holder *f_holder;
 	char *name;
 	char buf[256], *b;
 	int err;
@@ -1858,8 +1874,15 @@
 
 	/* Clear previous enabled list */
 	list_for_each_entry(conf, &dev->configs, list_item) {
-		list_for_each_entry(f, &conf->enabled_functions, enabled_list)
-			f->android_dev = NULL;
+		while (conf->enabled_functions.next !=
+				&conf->enabled_functions) {
+			f_holder = list_entry(conf->enabled_functions.next,
+					typeof(*f_holder),
+					enabled_list);
+			f_holder->f->android_dev = NULL;
+			list_del(&f_holder->enabled_list);
+			kfree(f_holder);
+		}
 		INIT_LIST_HEAD(&conf->enabled_functions);
 	}
 
@@ -1916,7 +1939,7 @@
 {
 	struct android_dev *dev = dev_get_drvdata(pdev);
 	struct usb_composite_dev *cdev = dev->cdev;
-	struct android_usb_function *f;
+	struct android_usb_function_holder *f_holder;
 	struct android_configuration *conf;
 	int enabled = 0;
 
@@ -1938,20 +1961,20 @@
 		cdev->desc.bDeviceSubClass = device_desc.bDeviceSubClass;
 		cdev->desc.bDeviceProtocol = device_desc.bDeviceProtocol;
 		list_for_each_entry(conf, &dev->configs, list_item)
-			list_for_each_entry(f, &conf->enabled_functions,
+			list_for_each_entry(f_holder, &conf->enabled_functions,
 						enabled_list) {
-				if (f->enable)
-					f->enable(f);
+				if (f_holder->f->enable)
+					f_holder->f->enable(f_holder->f);
 			}
 		android_enable(dev);
 		dev->enabled = true;
 	} else if (!enabled && dev->enabled) {
 		android_disable(dev);
 		list_for_each_entry(conf, &dev->configs, list_item)
-			list_for_each_entry(f, &conf->enabled_functions,
+			list_for_each_entry(f_holder, &conf->enabled_functions,
 						enabled_list) {
-				if (f->disable)
-					f->disable(f);
+				if (f_holder->f->disable)
+					f_holder->f->disable(f_holder->f);
 			}
 		dev->enabled = false;
 	} else {
@@ -2199,6 +2222,7 @@
 	struct android_dev		*dev = cdev_to_android_dev(cdev);
 	struct usb_request		*req = cdev->req;
 	struct android_usb_function	*f;
+	struct android_usb_function_holder *f_holder;
 	struct android_configuration	*conf;
 	int value = -EOPNOTSUPP;
 	unsigned long flags;
@@ -2209,14 +2233,16 @@
 	gadget->ep0->driver_data = cdev;
 
 	list_for_each_entry(conf, &dev->configs, list_item)
-			list_for_each_entry(f,
-					    &conf->enabled_functions,
-					    enabled_list)
-				if (f->ctrlrequest) {
-					value = f->ctrlrequest(f, cdev, c);
-					if (value >= 0)
-						break;
-				}
+		list_for_each_entry(f_holder,
+				    &conf->enabled_functions,
+				    enabled_list) {
+			f = f_holder->f;
+			if (f->ctrlrequest) {
+				value = f->ctrlrequest(f, cdev, c);
+				if (value >= 0)
+					break;
+			}
+		}
 
 	/* Special case the accessory function.
 	 * It needs to handle control requests before it is enabled.
@@ -2384,11 +2410,26 @@
 
 static int __devinit android_probe(struct platform_device *pdev)
 {
-	struct android_usb_platform_data *pdata = pdev->dev.platform_data;
+	struct android_usb_platform_data *pdata;
 	struct android_dev *android_dev;
 	struct resource *res;
 	int ret = 0;
 
+	if (pdev->dev.of_node) {
+		dev_dbg(&pdev->dev, "device tree enabled\n");
+		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+		if (!pdata) {
+			pr_err("unable to allocate platform data\n");
+			return -ENOMEM;
+		}
+
+		of_property_read_u32(pdev->dev.of_node,
+				"qcom,android-usb-swfi-latency",
+				&pdata->swfi_latency);
+	} else {
+		pdata = pdev->dev.platform_data;
+	}
+
 	if (!android_class) {
 		android_class = class_create(THIS_MODULE, "android_usb");
 		if (IS_ERR(android_class))
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 576ea1e..4bc0da2 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -371,7 +371,8 @@
 	c->bConfigurationValue = config->bConfigurationValue;
 	c->iConfiguration = config->iConfiguration;
 	c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes;
-	c->bMaxPower = config->bMaxPower ? : (CONFIG_USB_GADGET_VBUS_DRAW / 2);
+	c->bMaxPower = config->bMaxPower ? :
+		(CONFIG_USB_GADGET_VBUS_DRAW / config->cdev->vbus_draw_units);
 
 	/* There may be e.g. OTG descriptors */
 	if (config->descriptors) {
@@ -688,7 +689,8 @@
 	}
 
 	/* when we return, be sure our power usage is valid */
-	power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW;
+	power = c->bMaxPower ? (cdev->vbus_draw_units * c->bMaxPower) :
+			CONFIG_USB_GADGET_VBUS_DRAW;
 done:
 	usb_gadget_vbus_draw(gadget, power);
 
@@ -1113,12 +1115,16 @@
 				count_configs(cdev, USB_DT_DEVICE);
 			cdev->desc.bMaxPacketSize0 =
 				cdev->gadget->ep0->maxpacket;
+			cdev->vbus_draw_units = 2;
 			if (gadget_is_superspeed(gadget)) {
 				if (gadget->speed >= USB_SPEED_SUPER) {
 					cdev->desc.bcdUSB = cpu_to_le16(0x0300);
 					cdev->desc.bMaxPacketSize0 = 9;
+					cdev->vbus_draw_units = 8;
+					DBG(cdev, "Config SS device in SS\n");
 				} else {
 					cdev->desc.bcdUSB = cpu_to_le16(0x0210);
+					DBG(cdev, "Config SS device in HS\n");
 				}
 			}
 
@@ -1576,7 +1582,8 @@
 		maxpower = cdev->config->bMaxPower;
 
 		usb_gadget_vbus_draw(gadget, maxpower ?
-			(2 * maxpower) : CONFIG_USB_GADGET_VBUS_DRAW);
+			(cdev->vbus_draw_units * maxpower) :
+			CONFIG_USB_GADGET_VBUS_DRAW);
 	}
 
 	cdev->suspended = 0;
diff --git a/drivers/usb/gadget/f_accessory.c b/drivers/usb/gadget/f_accessory.c
index 42a6c43..5659c79 100644
--- a/drivers/usb/gadget/f_accessory.c
+++ b/drivers/usb/gadget/f_accessory.c
@@ -132,6 +132,41 @@
 	.bInterfaceProtocol     = 0,
 };
 
+static struct usb_endpoint_descriptor acc_superspeed_in_desc = {
+	.bLength                = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType        = USB_DT_ENDPOINT,
+	.bEndpointAddress       = USB_DIR_IN,
+	.bmAttributes           = USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize         = __constant_cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor acc_superspeed_in_comp_desc = {
+	.bLength =		sizeof acc_superspeed_in_comp_desc,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 2 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+};
+
+static struct usb_endpoint_descriptor acc_superspeed_out_desc = {
+	.bLength                = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType        = USB_DT_ENDPOINT,
+	.bEndpointAddress       = USB_DIR_OUT,
+	.bmAttributes           = USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize         = __constant_cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor acc_superspeed_out_comp_desc = {
+	.bLength =		sizeof acc_superspeed_out_comp_desc,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 2 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+};
+
+
 static struct usb_endpoint_descriptor acc_highspeed_in_desc = {
 	.bLength                = USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType        = USB_DT_ENDPOINT,
@@ -176,6 +211,15 @@
 	NULL,
 };
 
+static struct usb_descriptor_header *ss_acc_descs[] = {
+	(struct usb_descriptor_header *) &acc_interface_desc,
+	(struct usb_descriptor_header *) &acc_superspeed_in_desc,
+	(struct usb_descriptor_header *) &acc_superspeed_in_comp_desc,
+	(struct usb_descriptor_header *) &acc_superspeed_out_desc,
+	(struct usb_descriptor_header *) &acc_superspeed_out_comp_desc,
+	NULL,
+};
+
 static struct usb_string acc_string_defs[] = {
 	[INTERFACE_STRING_INDEX].s	= "Android Accessory Interface",
 	{  },	/* end of list */
@@ -907,6 +951,14 @@
 			acc_fullspeed_out_desc.bEndpointAddress;
 	}
 
+	/* support super speed hardware */
+	if (gadget_is_superspeed(c->cdev->gadget)) {
+		acc_superspeed_in_desc.bEndpointAddress =
+			acc_fullspeed_in_desc.bEndpointAddress;
+		acc_superspeed_out_desc.bEndpointAddress =
+			acc_fullspeed_out_desc.bEndpointAddress;
+	}
+
 	DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
 			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
 			f->name, dev->ep_in->name, dev->ep_out->name);
@@ -1135,6 +1187,8 @@
 	dev->function.strings = acc_strings,
 	dev->function.descriptors = fs_acc_descs;
 	dev->function.hs_descriptors = hs_acc_descs;
+	if (gadget_is_superspeed(c->cdev->gadget))
+		dev->function.ss_descriptors = ss_acc_descs;
 	dev->function.bind = acc_function_bind;
 	dev->function.unbind = acc_function_unbind;
 	dev->function.set_alt = acc_function_set_alt;
diff --git a/drivers/usb/gadget/f_adb.c b/drivers/usb/gadget/f_adb.c
index 14e5b60..68c99a3 100644
--- a/drivers/usb/gadget/f_adb.c
+++ b/drivers/usb/gadget/f_adb.c
@@ -69,6 +69,40 @@
 	.bInterfaceProtocol     = 1,
 };
 
+static struct usb_endpoint_descriptor adb_superspeed_in_desc = {
+	.bLength                = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType        = USB_DT_ENDPOINT,
+	.bEndpointAddress       = USB_DIR_IN,
+	.bmAttributes           = USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize         = __constant_cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor adb_superspeed_in_comp_desc = {
+	.bLength =		sizeof adb_superspeed_in_comp_desc,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 2 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+};
+
+static struct usb_endpoint_descriptor adb_superspeed_out_desc = {
+	.bLength                = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType        = USB_DT_ENDPOINT,
+	.bEndpointAddress       = USB_DIR_OUT,
+	.bmAttributes           = USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize         = __constant_cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor adb_superspeed_out_comp_desc = {
+	.bLength =		sizeof adb_superspeed_out_comp_desc,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 2 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+};
+
 static struct usb_endpoint_descriptor adb_highspeed_in_desc = {
 	.bLength                = USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType        = USB_DT_ENDPOINT,
@@ -113,6 +147,15 @@
 	NULL,
 };
 
+static struct usb_descriptor_header *ss_adb_descs[] = {
+	(struct usb_descriptor_header *) &adb_interface_desc,
+	(struct usb_descriptor_header *) &adb_superspeed_in_desc,
+	(struct usb_descriptor_header *) &adb_superspeed_in_comp_desc,
+	(struct usb_descriptor_header *) &adb_superspeed_out_desc,
+	(struct usb_descriptor_header *) &adb_superspeed_out_comp_desc,
+	NULL,
+};
+
 static void adb_ready_callback(void);
 static void adb_closed_callback(void);
 
@@ -503,6 +546,13 @@
 		adb_highspeed_out_desc.bEndpointAddress =
 			adb_fullspeed_out_desc.bEndpointAddress;
 	}
+	/* support super speed hardware */
+	if (gadget_is_superspeed(c->cdev->gadget)) {
+		adb_superspeed_in_desc.bEndpointAddress =
+			adb_fullspeed_in_desc.bEndpointAddress;
+		adb_superspeed_out_desc.bEndpointAddress =
+			adb_fullspeed_out_desc.bEndpointAddress;
+	}
 
 	DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
 			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
@@ -605,6 +655,8 @@
 	dev->function.name = "adb";
 	dev->function.descriptors = fs_adb_descs;
 	dev->function.hs_descriptors = hs_adb_descs;
+	if (gadget_is_superspeed(c->cdev->gadget))
+		dev->function.ss_descriptors = ss_adb_descs;
 	dev->function.bind = adb_function_bind;
 	dev->function.unbind = adb_function_unbind;
 	dev->function.set_alt = adb_function_set_alt;
diff --git a/drivers/usb/gadget/f_diag.c b/drivers/usb/gadget/f_diag.c
index 87597d5..8f68234 100644
--- a/drivers/usb/gadget/f_diag.c
+++ b/drivers/usb/gadget/f_diag.c
@@ -73,6 +73,40 @@
 	.bInterval        =	0,
 };
 
+static struct usb_endpoint_descriptor ss_bulk_in_desc = {
+	.bLength          =	USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType  =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes     =	USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize   = __constant_cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor ss_bulk_in_comp_desc = {
+	.bLength =		sizeof ss_bulk_in_comp_desc,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 2 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+};
+
+static struct usb_endpoint_descriptor ss_bulk_out_desc = {
+	.bLength          =	USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType  =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes     =	USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize   = __constant_cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor ss_bulk_out_comp_desc = {
+	.bLength =		sizeof ss_bulk_out_comp_desc,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 2 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+};
+
 static struct usb_descriptor_header *fs_diag_desc[] = {
 	(struct usb_descriptor_header *) &intf_desc,
 	(struct usb_descriptor_header *) &fs_bulk_in_desc,
@@ -86,6 +120,15 @@
 	NULL,
 };
 
+static struct usb_descriptor_header *ss_diag_desc[] = {
+	(struct usb_descriptor_header *) &intf_desc,
+	(struct usb_descriptor_header *) &ss_bulk_in_desc,
+	(struct usb_descriptor_header *) &ss_bulk_in_comp_desc,
+	(struct usb_descriptor_header *) &ss_bulk_out_desc,
+	(struct usb_descriptor_header *) &ss_bulk_out_comp_desc,
+	NULL,
+};
+
 /**
  * struct diag_context - USB diag function driver private structure
  * @function: function structure for USB interface
@@ -551,6 +594,8 @@
 {
 	struct diag_context *ctxt = func_to_diag(f);
 
+	if (gadget_is_superspeed(c->cdev->gadget))
+		usb_free_descriptors(f->ss_descriptors);
 	if (gadget_is_dualspeed(c->cdev->gadget))
 		usb_free_descriptors(f->hs_descriptors);
 
@@ -580,6 +625,7 @@
 	ctxt->out = ep;
 	ep->driver_data = ctxt;
 
+	status = -ENOMEM;
 	/* copy descriptors, and track endpoint copies */
 	f->descriptors = usb_copy_descriptors(fs_diag_desc);
 	if (!f->descriptors)
@@ -593,9 +639,29 @@
 
 		/* copy descriptors, and track endpoint copies */
 		f->hs_descriptors = usb_copy_descriptors(hs_diag_desc);
+		if (!f->hs_descriptors)
+			goto fail;
+	}
+
+	if (gadget_is_superspeed(c->cdev->gadget)) {
+		ss_bulk_in_desc.bEndpointAddress =
+				fs_bulk_in_desc.bEndpointAddress;
+		ss_bulk_out_desc.bEndpointAddress =
+				fs_bulk_out_desc.bEndpointAddress;
+
+		/* copy descriptors, and track endpoint copies */
+		f->ss_descriptors = usb_copy_descriptors(ss_diag_desc);
+		if (!f->ss_descriptors)
+			goto fail;
 	}
 	return 0;
 fail:
+	if (f->ss_descriptors)
+		usb_free_descriptors(f->ss_descriptors);
+	if (f->hs_descriptors)
+		usb_free_descriptors(f->hs_descriptors);
+	if (f->descriptors)
+		usb_free_descriptors(f->descriptors);
 	if (ctxt->out)
 		ctxt->out->driver_data = NULL;
 	if (ctxt->in)
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 729910d..6b9295b 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -546,19 +546,19 @@
 	spin_lock_irqsave(&dev->lock, flags);
 
 	if (!atomic_read(&dev->online)) {
-		pr_info("dev:%p is not online\n", dev);
+		pr_err("dev:%p is not online\n", dev);
 		spin_unlock_irqrestore(&dev->lock, flags);
 		return;
 	}
 
 	if (!req) {
-		pr_info("dev:%p req is NULL\n", dev);
+		pr_err("dev:%p req is NULL\n", dev);
 		spin_unlock_irqrestore(&dev->lock, flags);
 		return;
 	}
 
 	if (!req->buf) {
-		pr_info("dev:%p req->buf is NULL\n", dev);
+		pr_err("dev:%p req->buf is NULL\n", dev);
 		spin_unlock_irqrestore(&dev->lock, flags);
 		return;
 	}
@@ -601,10 +601,10 @@
 		return -ENODEV;
 	}
 
-	pr_info("dev:%p port_num#%d\n", dev, dev->port_num);
+	pr_debug("dev:%p port_num#%d\n", dev, dev->port_num);
 
 	if (!atomic_read(&dev->online)) {
-		pr_info("dev:%p is not connected\n", dev);
+		pr_err("dev:%p is not connected\n", dev);
 		mbim_free_ctrl_pkt(cpkt);
 		return 0;
 	}
@@ -739,7 +739,7 @@
 	__le32				*data;
 	int				status;
 
-	pr_info("notify_state: %d", mbim->not_port.notify_state);
+	pr_debug("notify_state: %d", mbim->not_port.notify_state);
 
 	if (!req)
 		return;
@@ -827,7 +827,7 @@
 	 * notification is sent, then it will reset to send the SPEED
 	 * notificaion again (and again, and again), but it's not a problem
 	 */
-	pr_info("dev:%p\n", mbim);
+	pr_debug("dev:%p\n", mbim);
 
 	mbim->not_port.notify_state = NCM_NOTIFY_SPEED;
 	mbim_do_notify(mbim);
@@ -868,7 +868,7 @@
 	mbim_do_notify(mbim);
 	spin_unlock(&mbim->lock);
 
-	pr_info("dev:%p Exit\n", mbim);
+	pr_debug("dev:%p Exit\n", mbim);
 }
 
 static void mbim_ep0out_complete(struct usb_ep *ep, struct usb_request *req)
@@ -879,7 +879,7 @@
 	struct f_mbim		*mbim = func_to_mbim(f);
 	struct mbim_ntb_input_size *ntb = NULL;
 
-	pr_info("dev:%p\n", mbim);
+	pr_debug("dev:%p\n", mbim);
 
 	req->context = NULL;
 	if (req->status || req->actual != req->length) {
@@ -909,7 +909,7 @@
 		goto invalid;
 	}
 
-	pr_info("Set NTB INPUT SIZE %d\n", in_size);
+	pr_debug("Set NTB INPUT SIZE %d\n", in_size);
 
 	mbim->ntb_input_size = in_size;
 	return;
@@ -939,7 +939,7 @@
 		return;
 	}
 
-	pr_info("dev:%p port#%d\n", dev, dev->port_num);
+	pr_debug("dev:%p port#%d\n", dev, dev->port_num);
 
 	spin_lock(&dev->lock);
 	if (!dev->is_open) {
@@ -955,13 +955,14 @@
 		return;
 	}
 
-	pr_info("Add to cpkt_req_q packet with len = %d\n", len);
+	pr_debug("Add to cpkt_req_q packet with len = %d\n", len);
 	memcpy(cpkt->buf, req->buf, len);
+
 	list_add_tail(&cpkt->list, &dev->cpkt_req_q);
 	spin_unlock(&dev->lock);
 
 	/* wakeup read thread */
-	pr_info("Wake up read queue");
+	pr_debug("Wake up read queue");
 	wake_up(&dev->read_wq);
 
 	return;
@@ -993,7 +994,7 @@
 	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
 		| USB_CDC_RESET_FUNCTION:
 
-		pr_info("USB_CDC_RESET_FUNCTION");
+		pr_debug("USB_CDC_RESET_FUNCTION");
 		value = 0;
 		req->complete = fmbim_reset_cmd_complete;
 		req->context = mbim;
@@ -1002,10 +1003,10 @@
 	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
 		| USB_CDC_SEND_ENCAPSULATED_COMMAND:
 
-		pr_info("USB_CDC_SEND_ENCAPSULATED_COMMAND");
+		pr_debug("USB_CDC_SEND_ENCAPSULATED_COMMAND");
 
 		if (w_length > req->length) {
-			pr_err("w_length > req->length: %d > %d",
+			pr_debug("w_length > req->length: %d > %d",
 			w_length, req->length);
 		}
 		value = w_length;
@@ -1016,14 +1017,14 @@
 	case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
 		| USB_CDC_GET_ENCAPSULATED_RESPONSE:
 
-		pr_info("USB_CDC_GET_ENCAPSULATED_RESPONSE");
+		pr_debug("USB_CDC_GET_ENCAPSULATED_RESPONSE");
 
 		if (w_value) {
 			pr_err("w_length > 0: %d", w_length);
 			break;
 		}
 
-		pr_info("req%02x.%02x v%04x i%04x l%d\n",
+		pr_debug("req%02x.%02x v%04x i%04x l%d\n",
 			ctrl->bRequestType, ctrl->bRequest,
 			w_value, w_index, w_length);
 
@@ -1043,7 +1044,7 @@
 		memcpy(req->buf, cpkt->buf, value);
 		mbim_free_ctrl_pkt(cpkt);
 
-		pr_info("copied encapsulated_response %d bytes",
+		pr_debug("copied encapsulated_response %d bytes",
 			value);
 
 		break;
@@ -1051,7 +1052,7 @@
 	case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
 		| USB_CDC_GET_NTB_PARAMETERS:
 
-		pr_info("USB_CDC_GET_NTB_PARAMETERS");
+		pr_debug("USB_CDC_GET_NTB_PARAMETERS");
 
 		if (w_length == 0 || w_value != 0 || w_index != mbim->ctrl_id)
 			break;
@@ -1064,21 +1065,21 @@
 	case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
 		| USB_CDC_GET_NTB_INPUT_SIZE:
 
-		pr_info("USB_CDC_GET_NTB_INPUT_SIZE");
+		pr_debug("USB_CDC_GET_NTB_INPUT_SIZE");
 
 		if (w_length < 4 || w_value != 0 || w_index != mbim->ctrl_id)
 			break;
 
 		put_unaligned_le32(mbim->ntb_input_size, req->buf);
 		value = 4;
-		pr_info("Reply to host INPUT SIZE %d\n",
+		pr_debug("Reply to host INPUT SIZE %d\n",
 		     mbim->ntb_input_size);
 		break;
 
 	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
 		| USB_CDC_SET_NTB_INPUT_SIZE:
 
-		pr_info("USB_CDC_SET_NTB_INPUT_SIZE");
+		pr_debug("USB_CDC_SET_NTB_INPUT_SIZE");
 
 		if (w_length != 4 && w_length != 8) {
 			pr_err("wrong NTB length %d", w_length);
@@ -1100,7 +1101,7 @@
 	{
 		uint16_t format;
 
-		pr_info("USB_CDC_GET_NTB_FORMAT");
+		pr_debug("USB_CDC_GET_NTB_FORMAT");
 
 		if (w_length < 2 || w_value != 0 || w_index != mbim->ctrl_id)
 			break;
@@ -1108,25 +1109,25 @@
 		format = (mbim->parser_opts == &ndp16_opts) ? 0x0000 : 0x0001;
 		put_unaligned_le16(format, req->buf);
 		value = 2;
-		pr_info("NTB FORMAT: sending %d\n", format);
+		pr_debug("NTB FORMAT: sending %d\n", format);
 		break;
 	}
 
 	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
 		| USB_CDC_SET_NTB_FORMAT:
 	{
-		pr_info("USB_CDC_SET_NTB_FORMAT");
+		pr_debug("USB_CDC_SET_NTB_FORMAT");
 
 		if (w_length != 0 || w_index != mbim->ctrl_id)
 			break;
 		switch (w_value) {
 		case 0x0000:
 			mbim->parser_opts = &ndp16_opts;
-			pr_info("NCM16 selected\n");
+			pr_debug("NCM16 selected\n");
 			break;
 		case 0x0001:
 			mbim->parser_opts = &ndp32_opts;
-			pr_info("NCM32 selected\n");
+			pr_debug("NCM32 selected\n");
 			break;
 		default:
 			break;
@@ -1147,7 +1148,7 @@
 
 	 /* respond with data transfer or status phase? */
 	if (value >= 0) {
-		pr_info("control request: %02x.%02x v%04x i%04x l%d\n",
+		pr_debug("control request: %02x.%02x v%04x i%04x l%d\n",
 			ctrl->bRequestType, ctrl->bRequest,
 			w_value, w_index, w_length);
 		req->zero = (value < w_length);
@@ -1820,7 +1821,7 @@
 	struct f_mbim *mbim = fp->private_data;
 	int ret = 0;
 
-	pr_info("Received command %d", cmd);
+	pr_debug("Received command %d", cmd);
 
 	if (mbim_lock(&mbim->ioctl_excl))
 		return -EBUSY;
diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c
index ccbc330..82ffbba 100644
--- a/drivers/usb/gadget/f_mtp.c
+++ b/drivers/usb/gadget/f_mtp.c
@@ -129,6 +129,40 @@
 	.bInterfaceProtocol     = 1,
 };
 
+static struct usb_endpoint_descriptor mtp_superspeed_in_desc = {
+	.bLength                = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType        = USB_DT_ENDPOINT,
+	.bEndpointAddress       = USB_DIR_IN,
+	.bmAttributes           = USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize         = __constant_cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor mtp_superspeed_in_comp_desc = {
+	.bLength =		sizeof mtp_superspeed_in_comp_desc,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 2 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+};
+
+static struct usb_endpoint_descriptor mtp_superspeed_out_desc = {
+	.bLength                = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType        = USB_DT_ENDPOINT,
+	.bEndpointAddress       = USB_DIR_OUT,
+	.bmAttributes           = USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize         = __constant_cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor mtp_superspeed_out_comp_desc = {
+	.bLength =		sizeof mtp_superspeed_out_comp_desc,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 2 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+};
+
 static struct usb_endpoint_descriptor mtp_highspeed_in_desc = {
 	.bLength                = USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType        = USB_DT_ENDPOINT,
@@ -168,6 +202,16 @@
 	.bInterval              = 6,
 };
 
+static struct usb_ss_ep_comp_descriptor mtp_superspeed_intr_comp_desc = {
+	.bLength =		sizeof mtp_superspeed_intr_comp_desc,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 3 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+	.wBytesPerInterval =	cpu_to_le16(INTR_BUFFER_SIZE),
+};
+
 static struct usb_descriptor_header *fs_mtp_descs[] = {
 	(struct usb_descriptor_header *) &mtp_interface_desc,
 	(struct usb_descriptor_header *) &mtp_fullspeed_in_desc,
@@ -184,6 +228,17 @@
 	NULL,
 };
 
+static struct usb_descriptor_header *ss_mtp_descs[] = {
+	(struct usb_descriptor_header *) &mtp_interface_desc,
+	(struct usb_descriptor_header *) &mtp_superspeed_in_desc,
+	(struct usb_descriptor_header *) &mtp_superspeed_in_comp_desc,
+	(struct usb_descriptor_header *) &mtp_superspeed_out_desc,
+	(struct usb_descriptor_header *) &mtp_superspeed_out_comp_desc,
+	(struct usb_descriptor_header *) &mtp_intr_desc,
+	(struct usb_descriptor_header *) &mtp_superspeed_intr_comp_desc,
+	NULL,
+};
+
 static struct usb_descriptor_header *fs_ptp_descs[] = {
 	(struct usb_descriptor_header *) &ptp_interface_desc,
 	(struct usb_descriptor_header *) &mtp_fullspeed_in_desc,
@@ -200,6 +255,17 @@
 	NULL,
 };
 
+static struct usb_descriptor_header *ss_ptp_descs[] = {
+	(struct usb_descriptor_header *) &ptp_interface_desc,
+	(struct usb_descriptor_header *) &mtp_superspeed_in_desc,
+	(struct usb_descriptor_header *) &mtp_superspeed_in_comp_desc,
+	(struct usb_descriptor_header *) &mtp_superspeed_out_desc,
+	(struct usb_descriptor_header *) &mtp_superspeed_out_comp_desc,
+	(struct usb_descriptor_header *) &mtp_intr_desc,
+	(struct usb_descriptor_header *) &mtp_superspeed_intr_comp_desc,
+	NULL,
+};
+
 static struct usb_string mtp_string_defs[] = {
 	/* Naming interface "MTP" so libmtp will recognize us */
 	[INTERFACE_STRING_INDEX].s	= "MTP",
@@ -1126,6 +1192,14 @@
 			mtp_fullspeed_out_desc.bEndpointAddress;
 	}
 
+	/* support super speed hardware */
+	if (gadget_is_superspeed(c->cdev->gadget)) {
+		mtp_superspeed_in_desc.bEndpointAddress =
+			mtp_fullspeed_in_desc.bEndpointAddress;
+		mtp_superspeed_out_desc.bEndpointAddress =
+			mtp_fullspeed_out_desc.bEndpointAddress;
+	}
+
 	DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
 			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
 			f->name, dev->ep_in->name, dev->ep_out->name);
@@ -1239,9 +1313,13 @@
 	if (ptp_config) {
 		dev->function.descriptors = fs_ptp_descs;
 		dev->function.hs_descriptors = hs_ptp_descs;
+		if (gadget_is_superspeed(c->cdev->gadget))
+			dev->function.ss_descriptors = ss_ptp_descs;
 	} else {
 		dev->function.descriptors = fs_mtp_descs;
 		dev->function.hs_descriptors = hs_mtp_descs;
+		if (gadget_is_superspeed(c->cdev->gadget))
+			dev->function.ss_descriptors = ss_mtp_descs;
 	}
 	dev->function.bind = mtp_function_bind;
 	dev->function.unbind = mtp_function_unbind;
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index aa9daf3..4357e0d 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -147,6 +147,71 @@
 	NULL,
 };
 
+/* Super speed support */
+static struct usb_endpoint_descriptor rmnet_ss_notify_desc  = {
+	.bLength =		sizeof rmnet_ss_notify_desc,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	__constant_cpu_to_le16(RMNET_MAX_NOTIFY_SIZE),
+	.bInterval =		RMNET_NOTIFY_INTERVAL + 4,
+};
+
+static struct usb_ss_ep_comp_descriptor rmnet_ss_notify_comp_desc = {
+	.bLength =		sizeof rmnet_ss_notify_comp_desc,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 3 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+	.wBytesPerInterval =	cpu_to_le16(RMNET_MAX_NOTIFY_SIZE),
+};
+
+static struct usb_endpoint_descriptor rmnet_ss_in_desc = {
+	.bLength =		sizeof rmnet_ss_in_desc,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	__constant_cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor rmnet_ss_in_comp_desc = {
+	.bLength =		sizeof rmnet_ss_in_comp_desc,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 2 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+};
+
+static struct usb_endpoint_descriptor rmnet_ss_out_desc = {
+	.bLength =		sizeof rmnet_ss_out_desc,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	__constant_cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor rmnet_ss_out_comp_desc = {
+	.bLength =		sizeof rmnet_ss_out_comp_desc,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 2 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+};
+
+static struct usb_descriptor_header *rmnet_ss_function[] = {
+	(struct usb_descriptor_header *) &rmnet_interface_desc,
+	(struct usb_descriptor_header *) &rmnet_ss_notify_desc,
+	(struct usb_descriptor_header *) &rmnet_ss_notify_comp_desc,
+	(struct usb_descriptor_header *) &rmnet_ss_in_desc,
+	(struct usb_descriptor_header *) &rmnet_ss_in_comp_desc,
+	(struct usb_descriptor_header *) &rmnet_ss_out_desc,
+	(struct usb_descriptor_header *) &rmnet_ss_out_comp_desc,
+	NULL,
+};
+
 /* String descriptors */
 
 static struct usb_string rmnet_string_defs[] = {
@@ -460,6 +525,8 @@
 
 	pr_debug("%s: portno:%d\n", __func__, dev->port_num);
 
+	if (gadget_is_superspeed(c->cdev->gadget))
+		usb_free_descriptors(f->ss_descriptors);
 	if (gadget_is_dualspeed(c->cdev->gadget))
 		usb_free_descriptors(f->hs_descriptors);
 	usb_free_descriptors(f->descriptors);
@@ -964,6 +1031,7 @@
 	dev->notify_req->complete = frmnet_notify_complete;
 	dev->notify_req->context = dev;
 
+	ret = -ENOMEM;
 	f->descriptors = usb_copy_descriptors(rmnet_fs_function);
 
 	if (!f->descriptors)
@@ -984,6 +1052,21 @@
 			goto fail;
 	}
 
+	if (gadget_is_superspeed(cdev->gadget)) {
+		rmnet_ss_in_desc.bEndpointAddress =
+				rmnet_fs_in_desc.bEndpointAddress;
+		rmnet_ss_out_desc.bEndpointAddress =
+				rmnet_fs_out_desc.bEndpointAddress;
+		rmnet_ss_notify_desc.bEndpointAddress =
+				rmnet_fs_notify_desc.bEndpointAddress;
+
+		/* copy descriptors, and track endpoint copies */
+		f->ss_descriptors = usb_copy_descriptors(rmnet_ss_function);
+
+		if (!f->ss_descriptors)
+			goto fail;
+	}
+
 	pr_info("%s: RmNet(%d) %s Speed, IN:%s OUT:%s\n",
 			__func__, dev->port_num,
 			gadget_is_dualspeed(cdev->gadget) ? "dual" : "full",
@@ -992,8 +1075,14 @@
 	return 0;
 
 fail:
+	if (f->ss_descriptors)
+		usb_free_descriptors(f->ss_descriptors);
+	if (f->hs_descriptors)
+		usb_free_descriptors(f->hs_descriptors);
 	if (f->descriptors)
 		usb_free_descriptors(f->descriptors);
+	if (dev->notify_req)
+		frmnet_free_req(dev->notify, dev->notify_req);
 ep_notify_alloc_fail:
 	dev->notify->driver_data = NULL;
 	dev->notify = NULL;
diff --git a/drivers/usb/gadget/f_rmnet_smd.c b/drivers/usb/gadget/f_rmnet_smd.c
index 5e2c6ed..e8c1f2a 100644
--- a/drivers/usb/gadget/f_rmnet_smd.c
+++ b/drivers/usb/gadget/f_rmnet_smd.c
@@ -874,9 +874,6 @@
 	struct rmnet_smd_dev *dev = container_of(f, struct rmnet_smd_dev,
 								function);
 
-	if (!atomic_read(&dev->online))
-		return;
-
 	atomic_set(&dev->online, 0);
 
 	usb_ep_fifo_flush(dev->epnotify);
diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c
index 649fe14..43347b3 100644
--- a/drivers/usb/gadget/f_serial.c
+++ b/drivers/usb/gadget/f_serial.c
@@ -244,8 +244,37 @@
 	.bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
 };
 
+#ifdef CONFIG_MODEM_SUPPORT
+static struct usb_endpoint_descriptor gser_ss_notify_desc  = {
+	.bLength =		sizeof gser_ss_notify_desc,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	__constant_cpu_to_le16(GS_NOTIFY_MAXPACKET),
+	.bInterval =		GS_LOG2_NOTIFY_INTERVAL+4,
+};
+
+static struct usb_ss_ep_comp_descriptor gser_ss_notify_comp_desc = {
+	.bLength =		sizeof gser_ss_notify_comp_desc,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 2 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+	.wBytesPerInterval =	cpu_to_le16(GS_NOTIFY_MAXPACKET),
+};
+#endif
+
 static struct usb_descriptor_header *gser_ss_function[] = {
 	(struct usb_descriptor_header *) &gser_interface_desc,
+#ifdef CONFIG_MODEM_SUPPORT
+	(struct usb_descriptor_header *) &gser_header_desc,
+	(struct usb_descriptor_header *) &gser_call_mgmt_descriptor,
+	(struct usb_descriptor_header *) &gser_descriptor,
+	(struct usb_descriptor_header *) &gser_union_desc,
+	(struct usb_descriptor_header *) &gser_ss_notify_desc,
+	(struct usb_descriptor_header *) &gser_ss_notify_comp_desc,
+#endif
 	(struct usb_descriptor_header *) &gser_ss_in_desc,
 	(struct usb_descriptor_header *) &gser_ss_bulk_comp_desc,
 	(struct usb_descriptor_header *) &gser_ss_out_desc,
@@ -304,7 +333,6 @@
 		ret = ghsic_ctrl_setup(no_hsic_sports, USB_GADGET_SERIAL);
 		if (ret < 0)
 			return ret;
-		return 0;
 	}
 	if (no_hsuart_sports) {
 		port_idx = ghsuart_data_setup(no_hsuart_sports,
@@ -319,8 +347,6 @@
 				port_idx++;
 			}
 		}
-
-		return 0;
 	}
 	return ret;
 }
@@ -824,6 +850,10 @@
 			gser_fs_in_desc.bEndpointAddress;
 		gser_ss_out_desc.bEndpointAddress =
 			gser_fs_out_desc.bEndpointAddress;
+#ifdef CONFIG_MODEM_SUPPORT
+		gser_ss_notify_desc.bEndpointAddress =
+				gser_fs_notify_desc.bEndpointAddress;
+#endif
 
 		/* copy descriptors, and track endpoint copies */
 		f->ss_descriptors = usb_copy_descriptors(gser_ss_function);
@@ -839,6 +869,10 @@
 	return 0;
 
 fail:
+	if (f->ss_descriptors)
+		usb_free_descriptors(f->ss_descriptors);
+	if (f->hs_descriptors)
+		usb_free_descriptors(f->hs_descriptors);
 	if (f->descriptors)
 		usb_free_descriptors(f->descriptors);
 #ifdef CONFIG_MODEM_SUPPORT
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
index 12f70c3..c61591a 100644
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -178,12 +178,15 @@
 static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
 {
 	int i;
+	size_t align;
+
+	align = ((ehci->pool_64_bit_align) ? 64 : 32);
 
 	/* QTDs for control/bulk/intr transfers */
 	ehci->qtd_pool = dma_pool_create ("ehci_qtd",
 			ehci_to_hcd(ehci)->self.controller,
 			sizeof (struct ehci_qtd),
-			32 /* byte alignment (for hw parts) */,
+			align /* byte alignment (for hw parts) */,
 			4096 /* can't cross 4K */);
 	if (!ehci->qtd_pool) {
 		goto fail;
@@ -193,7 +196,7 @@
 	ehci->qh_pool = dma_pool_create ("ehci_qh",
 			ehci_to_hcd(ehci)->self.controller,
 			sizeof(struct ehci_qh_hw),
-			32 /* byte alignment (for hw parts) */,
+			align /* byte alignment (for hw parts) */,
 			4096 /* can't cross 4K */);
 	if (!ehci->qh_pool) {
 		goto fail;
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index cd02489..7b616e4 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -81,7 +81,6 @@
 	struct wake_lock	wlock;
 	int			peripheral_status_irq;
 	int			wakeup_irq;
-	int			wakeup_gpio;
 	bool			wakeup_irq_enabled;
 	atomic_t		pm_usage_cnt;
 	uint32_t		bus_perf_client;
@@ -525,22 +524,11 @@
 	if (rc < 0) {
 		dev_err(mehci->dev, "gpio request failed for HSIC DATA\n");
 		goto free_strobe;
-		}
-
-	if (mehci->wakeup_gpio) {
-		rc = gpio_request(mehci->wakeup_gpio, "HSIC_WAKEUP_GPIO");
-		if (rc < 0) {
-			dev_err(mehci->dev, "gpio request failed for HSIC WAKEUP\n");
-			goto free_data;
-		}
 	}
 
 	return 0;
 
 free_gpio:
-	if (mehci->wakeup_gpio)
-		gpio_free(mehci->wakeup_gpio);
-free_data:
 	gpio_free(pdata->data);
 free_strobe:
 	gpio_free(pdata->strobe);
@@ -1596,10 +1584,9 @@
 	if (res)
 		mehci->peripheral_status_irq = res->start;
 
-	res = platform_get_resource_byname(pdev, IORESOURCE_IO, "wakeup");
+	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "wakeup");
 	if (res) {
-		mehci->wakeup_gpio = res->start;
-		mehci->wakeup_irq = MSM_GPIO_TO_INT(res->start);
+		mehci->wakeup_irq = res->start;
 		dev_dbg(mehci->dev, "wakeup_irq: %d\n", mehci->wakeup_irq);
 	}
 
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index d238b4e2..07a232a 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -30,6 +30,7 @@
 
 	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/host/ehci.h b/drivers/usb/host/ehci.h
index f8b884a..cd17421 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -166,6 +166,7 @@
 	unsigned		has_hostpc:1;
 	unsigned		has_lpm:1;  /* support link power management */
 	unsigned		has_ppcd:1; /* support per-port change bits */
+	unsigned		pool_64_bit_align:1; /* for 64 bit alignment */
 	u8			sbrn;		/* packed release number */
 
 	/* irq statistics */
diff --git a/drivers/usb/misc/mdm_ctrl_bridge.c b/drivers/usb/misc/mdm_ctrl_bridge.c
index 2f7e2c3..abc7b86 100644
--- a/drivers/usb/misc/mdm_ctrl_bridge.c
+++ b/drivers/usb/misc/mdm_ctrl_bridge.c
@@ -320,7 +320,6 @@
 	dev_dbg(&dev->intf->dev, "%s:\n", __func__);
 
 	ctrl_bridge_set_cbits(dev->brdg->ch_id, 0);
-	usb_unlink_anchored_urbs(&dev->tx_submitted);
 
 	dev->brdg = NULL;
 }
@@ -718,6 +717,8 @@
 
 	platform_device_unregister(dev->pdev);
 
+	usb_unlink_anchored_urbs(&dev->tx_submitted);
+
 	kfree(dev->in_ctlreq);
 	kfree(dev->readbuf);
 	kfree(dev->intbuf);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 92cbe6f..d04c234 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -82,6 +82,11 @@
 MODULE_PARM_DESC(override_phy_init,
 	"Override HSUSB PHY Init Settings");
 
+unsigned int lpm_disconnect_thresh = 1000;
+module_param(lpm_disconnect_thresh , uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(lpm_disconnect_thresh,
+	"Delay before entering LPM on USB disconnect");
+
 static DECLARE_COMPLETION(pmic_vbus_init);
 static struct msm_otg *the_msm_otg;
 static bool debug_aca_enabled;
@@ -2440,7 +2445,12 @@
 			msm_otg_notify_charger(motg, 0);
 			msm_otg_reset(otg->phy);
 			pm_runtime_put_noidle(otg->phy->dev);
-			pm_runtime_suspend(otg->phy->dev);
+			/*
+			 * Only if autosuspend was enabled in probe, it will be
+			 * used here. Otherwise, no delay will be used.
+			 */
+			pm_runtime_mark_last_busy(otg->phy->dev);
+			pm_runtime_autosuspend(otg->phy->dev);
 		}
 		break;
 	case OTG_STATE_B_SRP_INIT:
@@ -3068,10 +3078,9 @@
 {
 	static bool init;
 	struct msm_otg *motg = the_msm_otg;
-	struct usb_otg *otg = motg->phy.otg;
 
-	/* In A Host Mode, ignore received BSV interrupts */
-	if (otg->phy->state >= OTG_STATE_A_IDLE)
+	/* Ignore received BSV interrupts, if ID pin is GND */
+	if (!test_bit(ID, &motg->inputs))
 		return;
 
 	if (online) {
@@ -3990,6 +3999,12 @@
 	pm_runtime_set_active(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
 
+	if (motg->pdata->delay_lpm_on_disconnect) {
+		pm_runtime_set_autosuspend_delay(&pdev->dev,
+			lpm_disconnect_thresh);
+		pm_runtime_use_autosuspend(&pdev->dev);
+	}
+
 	if (motg->pdata->bus_scale_table) {
 		motg->bus_perf_client =
 		    msm_bus_scale_register_client(motg->pdata->bus_scale_table);
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index 9f30041..7a92645 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -3022,8 +3022,6 @@
 	hdmi_msm_state->hdcp_activating = TRUE;
 	mutex_unlock(&hdmi_msm_state_mutex);
 
-	fill_black_screen();
-
 	mutex_lock(&hdcp_auth_state_mutex);
 	/*
 	 * Initialize this to zero here to make
@@ -3065,8 +3063,6 @@
 	if (ret)
 		goto error;
 
-	unfill_black_screen();
-
 	mutex_lock(&hdmi_msm_state_mutex);
 	hdmi_msm_state->hdcp_activating = FALSE;
 	mutex_unlock(&hdmi_msm_state_mutex);
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 25da094..0c526fd 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -1452,6 +1452,11 @@
 					      vsync_period);
 	if (diff_to_next > vsync_period)
 		return;
+	pr_debug("%s cur_time %d, pre_vsync %d, to_next %d\n",
+		 __func__,
+		 (int)ktime_to_ms(cur_time),
+		 (int)ktime_to_ms(pre_vsync),
+		 diff_to_next);
 	wakeup_time = ktime_add_ns(cur_time, diff_to_next * NSEC_PER_MSEC);
 	activate_event_timer(mfd->cpu_pm_hdl, wakeup_time);
 }
@@ -2528,8 +2533,6 @@
 #if defined(CONFIG_FB_MSM_MIPI_DSI) && defined(CONFIG_FB_MSM_MDP40)
 	struct mipi_panel_info *mipi;
 #endif
-	static int contSplash_update_done;
-	char *cp;
 	unsigned int mdp_r = 0;
 
 	if ((pdev->id == 0) && (pdev->num_resources > 0)) {
@@ -2613,57 +2616,6 @@
 	mfd->pdev = msm_fb_dev;
 	mfd->mdp_rev = mdp_rev;
 
-	if (mdp_pdata) {
-		if (mdp_pdata->cont_splash_enabled) {
-			mfd->cont_splash_done = 0;
-
-			if (!contSplash_update_done) {
-				uint32 bpp = 3;
-				/*read panel wxh and calculate splash screen
-				size*/
-				mdp_pdata->splash_screen_size =
-						inpdw(MDP_BASE + 0x90004);
-				mdp_pdata->splash_screen_size =
-				(((mdp_pdata->splash_screen_size >> 16) &
-					0x00000FFF) * (
-					mdp_pdata->splash_screen_size &
-					0x00000FFF)) * bpp;
-
-				mdp_pdata->splash_screen_addr =
-						inpdw(MDP_BASE + 0x90008);
-
-				mfd->copy_splash_buf = dma_alloc_coherent(NULL,
-					mdp_pdata->splash_screen_size,
-					(dma_addr_t *) &(mfd->copy_splash_phys),
-					GFP_KERNEL);
-
-				if (!mfd->copy_splash_buf) {
-					pr_err("DMA ALLOC FAILED for SPLASH\n");
-					return -ENOMEM;
-				}
-				cp = (char *)ioremap(
-						mdp_pdata->splash_screen_addr,
-						mdp_pdata->splash_screen_size);
-				if (!cp) {
-					pr_err("IOREMAP FAILED for SPLASH\n");
-					return -ENOMEM;
-				}
-				memcpy(mfd->copy_splash_buf, cp,
-					mdp_pdata->splash_screen_size);
-
-				MDP_OUTP(MDP_BASE + 0x90008,
-						mfd->copy_splash_phys);
-
-				if (mfd->panel.type == MIPI_VIDEO_PANEL ||
-				    mfd->panel.type == LCDC_PANEL)
-					mdp_pipe_ctrl(MDP_CMD_BLOCK,
-						MDP_BLOCK_POWER_ON, FALSE);
-				contSplash_update_done = 1;
-			}
-		} else
-			mfd->cont_splash_done = 1;
-	}
-
 	mfd->ov0_wb_buf = MDP_ALLOC(sizeof(struct mdp_buf_type));
 	mfd->ov1_wb_buf = MDP_ALLOC(sizeof(struct mdp_buf_type));
 	memset((void *)mfd->ov0_wb_buf, 0, sizeof(struct mdp_buf_type));
@@ -2694,6 +2646,53 @@
 		rc = -ENOMEM;
 		goto mdp_probe_err;
 	}
+
+	if (mdp_pdata) {
+		if (mdp_pdata->cont_splash_enabled &&
+				 mfd->panel_info.pdest == DISPLAY_1) {
+			char *cp;
+			uint32 bpp = 3;
+			/*read panel wxh and calculate splash screen
+			  size*/
+			mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
+			mdp_pdata->splash_screen_size =
+				inpdw(MDP_BASE + 0x90004);
+			mdp_pdata->splash_screen_size =
+				(((mdp_pdata->splash_screen_size >> 16) &
+				  0x00000FFF) * (
+					  mdp_pdata->splash_screen_size &
+					  0x00000FFF)) * bpp;
+
+			mdp_pdata->splash_screen_addr =
+				inpdw(MDP_BASE + 0x90008);
+
+			mfd->copy_splash_buf = dma_alloc_coherent(NULL,
+					mdp_pdata->splash_screen_size,
+					(dma_addr_t *) &(mfd->copy_splash_phys),
+					GFP_KERNEL);
+
+			if (!mfd->copy_splash_buf) {
+				pr_err("DMA ALLOC FAILED for SPLASH\n");
+				return -ENOMEM;
+			}
+			cp = (char *)ioremap(
+					mdp_pdata->splash_screen_addr,
+					mdp_pdata->splash_screen_size);
+			if (!cp) {
+				pr_err("IOREMAP FAILED for SPLASH\n");
+				return -ENOMEM;
+			}
+			memcpy(mfd->copy_splash_buf, cp,
+					mdp_pdata->splash_screen_size);
+
+			MDP_OUTP(MDP_BASE + 0x90008,
+					mfd->copy_splash_phys);
+		}
+
+		mfd->cont_splash_done = (1 - mdp_pdata->cont_splash_enabled);
+	}
+
 	/* data chain */
 	pdata = msm_fb_dev->dev.platform_data;
 	pdata->on = mdp_on;
@@ -2993,7 +2992,7 @@
 	}
 
 	/* req bus bandwidth immediately */
-	if (!(mfd->cont_splash_done))
+	if (!(mfd->cont_splash_done) && (mfd->panel_info.pdest == DISPLAY_1))
 		mdp_bus_scale_update_request(5);
 
 #endif
@@ -3120,7 +3119,7 @@
 {
 	mdp_suspend_sub();
 #ifdef CONFIG_FB_MSM_DTV
-	mdp4_dtv_set_black_screen();
+	mdp4_dtv_set_black_screen(FALSE);
 #endif
 	mdp_footswitch_ctrl(FALSE);
 }
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 3ea196a..d9da6f9 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -531,7 +531,7 @@
 }
 #endif /* CONFIG_FB_MSM_DTV */
 
-void mdp4_dtv_set_black_screen(void);
+void mdp4_dtv_set_black_screen(bool commit);
 
 int mdp4_overlay_dtv_set(struct msm_fb_data_type *mfd,
 			struct mdp4_overlay_pipe *pipe);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 1bd697e..11952f3 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -192,12 +192,19 @@
 		return;
 
 	if (pipe->flags & MDP_MEMORY_ID_TYPE_FB) {
-		if (pipe->put0_need)
+		pipe->flags &= ~MDP_MEMORY_ID_TYPE_FB;
+		if (pipe->put0_need) {
 			fput_light(pipe->srcp0_file, pipe->put0_need);
-		if (pipe->put1_need)
+			pipe->put0_need = 0;
+		}
+		if (pipe->put1_need) {
 			fput_light(pipe->srcp1_file, pipe->put1_need);
-		if (pipe->put2_need)
+			pipe->put1_need = 0;
+		}
+		if (pipe->put2_need) {
 			fput_light(pipe->srcp2_file, pipe->put2_need);
+			pipe->put2_need = 0;
+		}
 
 		pr_debug("%s: ndx=%d flags=%x put=%d\n", __func__,
 			pipe->pipe_ndx, pipe->flags, pipe->put0_need);
@@ -409,53 +416,34 @@
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 }
 
-#ifdef CONFIG_FB_MSM_HDMI_3D
-void unfill_black_screen(void) { return; }
-#else
-void unfill_black_screen(void)
+void fill_black_screen(bool on, uint8 pipe_num, uint8 mixer_num)
 {
-	uint32 temp_src_format;
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	/*
-	* VG2 Constant Color
-	*/
-	temp_src_format = inpdw(MDP_BASE + 0x30050);
-	MDP_OUTP(MDP_BASE + 0x30050, temp_src_format&(~BIT(22)));
-	/*
-	* MDP_OVERLAY_REG_FLUSH
-	*/
-	MDP_OUTP(MDP_BASE + 0x18000, BIT(3));
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-	return;
-}
-#endif
+	uint32 reg_base        = 0x010000;
+	uint32 const_color_reg = reg_base * (pipe_num + 2) + 0x1008;
+	uint32 src_fmt_reg     = reg_base * (pipe_num + 2) + 0x50;
+	uint32 color           = 0x00000000;
+	uint32 temp_src_format = 0x00000000;
+	uint8  bit             = pipe_num + 2;
 
-#ifdef CONFIG_FB_MSM_HDMI_3D
-void fill_black_screen(void) { return; }
-#else
-void fill_black_screen(void)
-{
-	/*Black color*/
-	uint32 color = 0x00000000;
-	uint32 temp_src_format;
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	/*
-	* VG2 Constant Color
-	*/
-	MDP_OUTP(MDP_BASE + 0x31008, color);
-	/*
-	* MDP_VG2_SRC_FORMAT
-	*/
-	temp_src_format = inpdw(MDP_BASE + 0x30050);
-	MDP_OUTP(MDP_BASE + 0x30050, temp_src_format | BIT(22));
-	/*
-	* MDP_OVERLAY_REG_FLUSH
-	*/
-	MDP_OUTP(MDP_BASE + 0x18000, BIT(3));
+
+	/* Fill constant color */
+	MDP_OUTP(MDP_BASE + const_color_reg, color);
+
+	/* Update source format for pipe */
+	temp_src_format = inpdw(MDP_BASE + src_fmt_reg);
+
+	if (on)
+		MDP_OUTP(MDP_BASE + src_fmt_reg, temp_src_format | BIT(22));
+	else
+		MDP_OUTP(MDP_BASE + src_fmt_reg, temp_src_format | (~BIT(22)));
+
+	/* MDP_OVERLAY_REG_FLUSH for pipe*/
+	MDP_OUTP(MDP_BASE + 0x18000, BIT(bit) | BIT(mixer_num));
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
 	return;
 }
-#endif
 
 void mdp4_overlay_dmae_xy(struct mdp4_overlay_pipe *pipe)
 {
@@ -730,8 +718,14 @@
 		op_mode &= ~(MDP4_OP_FLIP_LR + MDP4_OP_SCALEX_EN);
 		op_mode &= ~(MDP4_OP_FLIP_UD + MDP4_OP_SCALEY_EN);
 		outpdw(rgb_base + 0x0058, op_mode);/* MDP_RGB_OP_MODE */
-	} else
+	} else {
+		if (pipe->op_mode & MDP4_OP_FLIP_LR && mdp_rev >= MDP_REV_42) {
+			/* Enable x-scaling bit to enable LR flip */
+			/* for MDP > 4.2 targets */
+			pipe->op_mode |= 0x01;
+		}
 		outpdw(rgb_base + 0x0058, pipe->op_mode);/* MDP_RGB_OP_MODE */
+	}
 	outpdw(rgb_base + 0x005c, pipe->phasex_step);
 	outpdw(rgb_base + 0x0060, pipe->phasey_step);
 
@@ -1777,6 +1771,7 @@
 	struct mdp4_overlay_pipe *bspipe;
 	int ptype, pnum, pndx, mixer;
 	int format, alpha_enable, alpha;
+	struct mdp4_iommu_pipe_info iom;
 
 	if (pipe->pipe_type != OVERLAY_TYPE_BF)
 		return;
@@ -1791,6 +1786,7 @@
 		return;
 	}
 
+	iom = bspipe->iommu;
 	ptype = bspipe->pipe_type;
 	pnum = bspipe->pipe_num;
 	pndx = bspipe->pipe_ndx;
@@ -1804,6 +1800,7 @@
 	bspipe->src_format = format;
 	bspipe->alpha_enable = alpha_enable;
 	bspipe->alpha = alpha;
+	bspipe->iommu = iom;
 
 	bspipe->pipe_used++;	/* mark base layer pipe used */
 
@@ -3116,6 +3113,9 @@
 								__func__);
 	}
 
+	if (hdmi_prim_display)
+		fill_black_screen(FALSE, pipe->pipe_num, pipe->mixer_num);
+
 	mdp4_overlay_mdp_pipe_req(pipe, mfd);
 
 	mutex_unlock(&mfd->dma->ov_mutex);
@@ -3188,8 +3188,12 @@
 	if (pipe->mixer_num == MDP4_MIXER0) {
 
 	} else {	/* mixer1, DTV, ATV */
-		if (ctrl->panel_mode & MDP4_PANEL_DTV)
+		if (ctrl->panel_mode & MDP4_PANEL_DTV) {
+			if (hdmi_prim_display)
+				fill_black_screen(TRUE, pipe->pipe_num,
+					pipe->mixer_num);
 			mdp4_overlay_dtv_unset(mfd, pipe);
+		}
 	}
 
 	mdp4_stat.overlay_unset[pipe->mixer_num]++;
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index 10410a7..0015403 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -70,6 +70,7 @@
 	struct vsync_update vlist[2];
 	int vsync_enabled;
 	int clk_enabled;
+	int new_update;
 	int clk_control;
 	ktime_t vsync_time;
 	struct work_struct clk_work;
@@ -272,6 +273,8 @@
 	pipe = vctrl->base_pipe;
 	mixer = pipe->mixer_num;
 
+	mdp_update_pm(vctrl->mfd, vctrl->vsync_time);
+
 	if (vp->update_cnt == 0) {
 		mutex_unlock(&vctrl->update_lock);
 		return cnt;
@@ -421,6 +424,7 @@
 			mipi_dsi_clk_cfg(1);
 			mdp_clk_ctrl(1);
 			vctrl->clk_enabled = 1;
+			vctrl->new_update = 1;
 			clk_set_on = 1;
 		}
 		if (clk_set_on) {
@@ -517,6 +521,12 @@
 	spin_lock(&vctrl->spin_lock);
 	vctrl->vsync_time = ktime_get();
 
+	if (vctrl->new_update) {
+		vctrl->new_update = 0;
+		spin_unlock(&vctrl->spin_lock);
+		return;
+	}
+
 	complete_all(&vctrl->vsync_comp);
 	vctrl->wait_vsync_cnt = 0;
 
@@ -1037,6 +1047,7 @@
 	struct vsync_update *vp;
 	int undx;
 	int need_wait, cnt;
+	unsigned long flags;
 
 	pr_debug("%s+: pid=%d\n", __func__, current->pid);
 
@@ -1071,11 +1082,16 @@
 		}
 	}
 
-	/* message for system suspnded */
-	if (cnt > 10)
-		pr_err("%s:Error,  mdp clocks NOT off\n", __func__);
-	else
-		pr_debug("%s: mdp clocks off at cnt=%d\n", __func__, cnt);
+	if (cnt > 10) {
+		spin_lock_irqsave(&vctrl->spin_lock, flags);
+		vctrl->clk_control = 0;
+		vctrl->clk_enabled = 0;
+		vctrl->expire_tick = 0;
+		spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+		mipi_dsi_clk_cfg(0);
+		mdp_clk_ctrl(0);
+		pr_err("%s: Error, SET_CLK_OFF by force\n", __func__);
+	}
 
 	/* sanity check, free pipes besides base layer */
 	mdp4_overlay_unset_mixer(pipe->mixer_num);
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 5551c9d..501c4e6 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -56,6 +56,7 @@
 	int wait_vsync_cnt;
 	int blt_change;
 	int blt_free;
+	int blt_ctrl;
 	int sysfs_created;
 	struct mutex update_lock;
 	struct completion ov_comp;
@@ -498,9 +499,11 @@
 	int ret = 0;
 	int cndx = 0;
 	struct vsycn_ctrl *vctrl;
+	struct msm_panel_info *pinfo;
 
 	vctrl = &vsync_ctrl_db[cndx];
 	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+	pinfo = &mfd->panel_info;
 
 	if (!mfd)
 		return -ENODEV;
@@ -510,6 +513,7 @@
 
 	vctrl->mfd = mfd;
 	vctrl->dev = mfd->fbi->dev;
+	vctrl->blt_ctrl = pinfo->lcd.blt_ctrl;
 
 	/* mdp clock on */
 	mdp_clk_ctrl(1);
@@ -1011,6 +1015,7 @@
 	int cndx = 0;
 	struct vsycn_ctrl *vctrl;
 	struct mdp4_overlay_pipe *pipe;
+	long long vtime;
 
 	vctrl = &vsync_ctrl_db[cndx];
 	pipe = vctrl->base_pipe;
@@ -1047,8 +1052,32 @@
 		spin_unlock_irqrestore(&vctrl->spin_lock, flag);
 		return;
 	}
-
 	spin_unlock_irqrestore(&vctrl->spin_lock, flag);
+
+	if (vctrl->blt_ctrl == BLT_SWITCH_TG_OFF) {
+		int tg_enabled;
+
+		vctrl->blt_change = 0;
+		tg_enabled = inpdw(MDP_BASE + DSI_VIDEO_BASE) & 0x01;
+		if (tg_enabled) {
+			mdp4_dsi_video_wait4vsync(0, &vtime);
+			MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0);
+			mdp4_dsi_video_wait4dmap_done(0);
+		}
+		mdp4_overlayproc_cfg(pipe);
+		mdp4_overlay_dmap_xy(pipe);
+		if (tg_enabled) {
+			/*
+			* need wait for more than 1 ms to
+			* make sure dsi lanes' fifo is empty and
+			* lanes in stop state befroe reset
+			* controller
+			*/
+			usleep(2000);
+			mipi_dsi_sw_reset();
+			MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 1);
+		}
+	}
 }
 
 void mdp4_dsi_video_overlay_blt(struct msm_fb_data_type *mfd,
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index e71f49f..2d48781 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -1004,7 +1004,7 @@
 	spin_unlock(&vctrl->spin_lock);
 }
 
-void mdp4_dtv_set_black_screen(void)
+void mdp4_dtv_set_black_screen(bool commit)
 {
 	char *rgb_base;
 	/*Black color*/
@@ -1015,26 +1015,34 @@
 
 	vctrl = &vsync_ctrl_db[cndx];
 	if (vctrl->base_pipe == NULL || !hdmi_prim_display) {
-		pr_err("dtv_pipe is not configured yet\n");
+		pr_debug("dtv_pipe is not configured yet\n");
 		return;
 	}
-	rgb_base = MDP_BASE + MDP4_RGB_BASE;
-	rgb_base += (MDP4_RGB_OFF * vctrl->base_pipe->pipe_num);
+	rgb_base = MDP_BASE;
+	rgb_base += (MDP4_RGB_OFF * (vctrl->base_pipe->pipe_num + 2));
 
-	/*
-	* RGB Constant Color
-	*/
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
+	/* RGB Constant Color */
 	MDP_OUTP(rgb_base + 0x1008, color);
-	/*
-	* MDP_RGB_SRC_FORMAT
-	*/
+
+	/* MDP_RGB_SRC_FORMAT */
 	temp_src_format = inpdw(rgb_base + 0x0050);
 	MDP_OUTP(rgb_base + 0x0050, temp_src_format | BIT(22));
-	mdp4_overlay_reg_flush(vctrl->base_pipe, 1);
 
-	mdp4_mixer_stage_up(vctrl->base_pipe, 0);
-	mdp4_mixer_stage_commit(vctrl->base_pipe->mixer_num);
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+	if (commit) {
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+		mdp4_overlay_reg_flush(vctrl->base_pipe, 1);
+
+		mdp4_mixer_stage_up(vctrl->base_pipe, 0);
+		mdp4_mixer_stage_commit(vctrl->base_pipe->mixer_num);
+	} else {
+		/* MDP_OVERLAY_REG_FLUSH for pipe*/
+		MDP_OUTP(MDP_BASE + 0x18000,
+			BIT(vctrl->base_pipe->pipe_num + 2) | BIT(MDP4_MIXER1));
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+	}
 }
 
 static void mdp4_dtv_do_blt(struct msm_fb_data_type *mfd, int enable)
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index c2d5f28..d932bc9 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -15,9 +15,11 @@
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/iopoll.h>
 #include <linux/of_address.h>
 #include <linux/of_gpio.h>
 #include <linux/types.h>
+#include <mach/msm_hdmi_audio.h>
 
 #define REG_DUMP 0
 
@@ -36,12 +38,27 @@
 #define SW_RESET BIT(2)
 #define SW_RESET_PLL BIT(0)
 
+#define HPD_DISCONNECT_POLARITY 0
+#define HPD_CONNECT_POLARITY    1
+
 #define IFRAME_CHECKSUM_32(d)			\
 	((d & 0xff) + ((d >> 8) & 0xff) +	\
 	((d >> 16) & 0xff) + ((d >> 24) & 0xff))
 
+/* parameters for clock regeneration */
+struct hdmi_tx_audio_acr {
+	u32 n;
+	u32 cts;
+};
+
+struct hdmi_tx_audio_acr_arry {
+	u32 pclk;
+	struct hdmi_tx_audio_acr lut[HDMI_SAMPLE_RATE_MAX];
+};
+
 static int hdmi_tx_sysfs_enable_hpd(struct hdmi_tx_ctrl *hdmi_ctrl, int on);
 static irqreturn_t hdmi_tx_isr(int irq, void *data);
+static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl);
 
 struct mdss_hw hdmi_tx_hw = {
 	.hw_ndx = MDSS_HW_HDMI,
@@ -90,6 +107,27 @@
 	 0x07,	0x07,	0x07,	0x07,	0x02, 0x02, 0x02}  /*12*/
 };
 
+/* Audio constants lookup table for hdmi_tx_audio_acr_setup */
+/* Valid Pixel-Clock rates: 25.2MHz, 27MHz, 27.03MHz, 74.25MHz, 148.5MHz */
+static const struct hdmi_tx_audio_acr_arry hdmi_tx_audio_acr_lut[] = {
+	/*  25.200MHz  */
+	{25200, {{4096, 25200}, {6272, 28000}, {6144, 25200}, {12544, 28000},
+		{12288, 25200}, {25088, 28000}, {24576, 25200} } },
+	/*  27.000MHz  */
+	{27000, {{4096, 27000}, {6272, 30000}, {6144, 27000}, {12544, 30000},
+		{12288, 27000}, {25088, 30000}, {24576, 27000} } },
+	/*  27.027MHz */
+	{27030, {{4096, 27027}, {6272, 30030}, {6144, 27027}, {12544, 30030},
+		{12288, 27027}, {25088, 30030}, {24576, 27027} } },
+	/*  74.250MHz */
+	{74250, {{4096, 74250}, {6272, 82500}, {6144, 74250}, {12544, 82500},
+		{12288, 74250}, {25088, 82500}, {24576, 74250} } },
+	/* 148.500MHz */
+	{148500, {{4096, 148500}, {6272, 165000}, {6144, 148500},
+		{12544, 165000}, {12288, 148500}, {25088, 165000},
+		{24576, 148500} } },
+};
+
 const char *hdmi_tx_pm_name(enum hdmi_tx_power_module_type module)
 {
 	switch (module) {
@@ -335,8 +373,8 @@
 
 static inline u32 hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
-	struct dss_io_data *io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
-	return !(DSS_REG_R_ND(io, HDMI_CTRL) & BIT(1));
+	return hdmi_edid_get_sink_mode(
+		hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]) ? 0 : 1;
 } /* hdmi_tx_is_dvi_mode */
 
 static int hdmi_tx_init_panel_info(uint32_t resolution,
@@ -424,86 +462,8 @@
 	return status;
 } /* hdmi_tx_read_sink_info */
 
-static void hdmi_tx_hpd_state_work(struct work_struct *work)
-{
-	u32 hpd_state = false;
-	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
-	struct dss_io_data *io = NULL;
-
-	hdmi_ctrl = container_of(work, struct hdmi_tx_ctrl, hpd_state_work);
-	if (!hdmi_ctrl || !hdmi_ctrl->hpd_initialized) {
-		DEV_DBG("%s: invalid input\n", __func__);
-		return;
-	}
-
-	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
-	if (!io->base) {
-		DEV_ERR("%s: Core io is not initialized\n", __func__);
-		return;
-	}
-
-	DEV_DBG("%s: Got HPD interrupt\n", __func__);
-
-	hpd_state = (DSS_REG_R(io, HDMI_HPD_INT_STATUS) & BIT(1)) >> 1;
-	mutex_lock(&hdmi_ctrl->mutex);
-	if ((hdmi_ctrl->hpd_prev_state != hdmi_ctrl->hpd_state) ||
-		(hdmi_ctrl->hpd_state != hpd_state)) {
-
-		hdmi_ctrl->hpd_state = hpd_state;
-		hdmi_ctrl->hpd_prev_state = hdmi_ctrl->hpd_state;
-		hdmi_ctrl->hpd_stable = 0;
-
-		DEV_DBG("%s: state not stable yet, wait again (%d|%d|%d)\n",
-			__func__, hdmi_ctrl->hpd_prev_state,
-			hdmi_ctrl->hpd_state, hpd_state);
-
-		mutex_unlock(&hdmi_ctrl->mutex);
-
-		mod_timer(&hdmi_ctrl->hpd_state_timer, jiffies + HZ/2);
-
-		return;
-	}
-
-	if (hdmi_ctrl->hpd_stable) {
-		mutex_unlock(&hdmi_ctrl->mutex);
-		DEV_DBG("%s: no more timer, depending on IRQ now\n",
-			__func__);
-		return;
-	}
-
-	hdmi_ctrl->hpd_stable = 1;
-
-	/*
-	 *todo: Revisit cable chg detected condition when HPD support is ready
-	 */
-	hdmi_ctrl->hpd_cable_chg_detected = false;
-	mutex_unlock(&hdmi_ctrl->mutex);
-
-	if (hpd_state) {
-		/* todo: what if EDID read fails? */
-		hdmi_tx_read_sink_info(hdmi_ctrl);
-		DEV_INFO("HDMI HPD: sense CONNECTED: send ONLINE\n");
-		kobject_uevent(hdmi_ctrl->kobj, KOBJ_ONLINE);
-		switch_set_state(&hdmi_ctrl->sdev, 1);
-		DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
-			hdmi_ctrl->sdev.state);
-	} else {
-		DEV_INFO("HDMI HPD: sense DISCONNECTED: send OFFLINE\n");
-		kobject_uevent(hdmi_ctrl->kobj, KOBJ_OFFLINE);
-		switch_set_state(&hdmi_ctrl->sdev, 0);
-		DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
-			hdmi_ctrl->sdev.state);
-	}
-
-	/* Set IRQ for HPD */
-	DSS_REG_W(io, HDMI_HPD_INT_CTRL, 4 | (hpd_state ? 0 : 2));
-} /* hdmi_tx_hpd_state_work */
-
 static void hdmi_tx_hpd_int_work(struct work_struct *work)
 {
-	u32 hpd_int_status;
-	u32 hpd_int_ctrl;
-	u32 cable_detected;
 	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
 	struct dss_io_data *io = NULL;
 
@@ -519,23 +479,24 @@
 		return;
 	}
 
-	/* Process HPD Interrupt */
-	hpd_int_status = DSS_REG_R(io, HDMI_HPD_INT_STATUS);
-	hpd_int_ctrl = DSS_REG_R(io, HDMI_HPD_INT_CTRL);
+	DEV_DBG("%s: Got HPD interrupt\n", __func__);
 
-	DSS_REG_W(io, HDMI_HPD_INT_CTRL, BIT(2));
-
-	cable_detected = hpd_int_status & BIT(1);
-	mutex_lock(&hdmi_ctrl->mutex);
-	hdmi_ctrl->hpd_cable_chg_detected = true;
-	hdmi_ctrl->hpd_prev_state = cable_detected ? 0 : 1;
-	hdmi_ctrl->hpd_stable = 0;
-	mutex_unlock(&hdmi_ctrl->mutex);
-
-	mod_timer(&hdmi_ctrl->hpd_state_timer, jiffies + HZ/2);
-
-	DEV_DBG("%s: HPD<Ctrl=%04x, State=%04x>\n", __func__, hpd_int_ctrl,
-		hpd_int_status);
+	hdmi_ctrl->hpd_state =
+		(DSS_REG_R(io, HDMI_HPD_INT_STATUS) & BIT(1)) >> 1;
+	if (hdmi_ctrl->hpd_state) {
+		hdmi_tx_read_sink_info(hdmi_ctrl);
+		DEV_INFO("HDMI HPD: sense CONNECTED: send ONLINE\n");
+		kobject_uevent(hdmi_ctrl->kobj, KOBJ_ONLINE);
+		switch_set_state(&hdmi_ctrl->sdev, 1);
+		DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
+			hdmi_ctrl->sdev.state);
+	} else {
+		DEV_INFO("HDMI HPD: sense DISCONNECTED: send OFFLINE\n");
+		kobject_uevent(hdmi_ctrl->kobj, KOBJ_OFFLINE);
+		switch_set_state(&hdmi_ctrl->sdev, 0);
+		DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
+			hdmi_ctrl->sdev.state);
+	}
 } /* hdmi_tx_hpd_int_work */
 
 static int hdmi_tx_check_capability(struct dss_io_data *io)
@@ -976,17 +937,6 @@
 	DSS_REG_W(io, HDMI_GEN_PKT_CTRL, packet_control);
 } /* hdmi_tx_set_spd_infoframe */
 
-/* todo: revisit when new HPD debouncing logic is avialble */
-static void hdmi_tx_hpd_state_timer(unsigned long data)
-{
-	struct hdmi_tx_ctrl *hdmi_ctrl = (struct hdmi_tx_ctrl *)data;
-
-	if (hdmi_ctrl)
-		queue_work(hdmi_ctrl->workq, &hdmi_ctrl->hpd_state_work);
-	else
-		DEV_ERR("%s: invalid input\n", __func__);
-} /* hdmi_tx_hpd_state_timer */
-
 static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on)
 {
 	u32 reg_val = 0;
@@ -1133,6 +1083,8 @@
 	} else {
 		msm_dss_enable_clk(power_data->clk_config,
 			power_data->num_clk, 0);
+		msm_dss_clk_set_rate(power_data->clk_config,
+			power_data->num_clk);
 		msm_dss_enable_gpio(power_data->gpio_config,
 			power_data->num_gpio, 0);
 		msm_dss_enable_vreg(power_data->vreg_config,
@@ -1275,6 +1227,346 @@
 	DSS_REG_W_ND(io, HDMI_PHY_PD_CTRL0, 0x7F);
 } /* hdmi_tx_powerdown_phy */
 
+static int hdmi_tx_audio_acr_setup(struct hdmi_tx_ctrl *hdmi_ctrl,
+	bool enabled, int num_of_channels)
+{
+	/* Read first before writing */
+	u32 acr_pck_ctrl_reg;
+	struct dss_io_data *io = NULL;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: Invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	if (!io->base) {
+		DEV_ERR("%s: core io not inititalized\n", __func__);
+		return -EINVAL;
+	}
+
+	acr_pck_ctrl_reg = DSS_REG_R(io, HDMI_ACR_PKT_CTRL);
+
+	if (enabled) {
+		const struct hdmi_disp_mode_timing_type *timing =
+			hdmi_get_supported_mode(hdmi_ctrl->video_resolution);
+		const struct hdmi_tx_audio_acr_arry *audio_acr =
+			&hdmi_tx_audio_acr_lut[0];
+		const int lut_size = sizeof(hdmi_tx_audio_acr_lut)
+			/ sizeof(*hdmi_tx_audio_acr_lut);
+		u32 i, n, cts, layout, multiplier, aud_pck_ctrl_2_reg;
+
+		if (timing == NULL) {
+			DEV_WARN("%s: video format %d not supported\n",
+				__func__, hdmi_ctrl->video_resolution);
+			return -EPERM;
+		}
+
+		for (i = 0; i < lut_size;
+			audio_acr = &hdmi_tx_audio_acr_lut[++i]) {
+			if (audio_acr->pclk == timing->pixel_freq)
+				break;
+		}
+		if (i >= lut_size) {
+			DEV_WARN("%s: pixel clk %d not supported\n", __func__,
+				timing->pixel_freq);
+			return -EPERM;
+		}
+
+		n = audio_acr->lut[hdmi_ctrl->audio_sample_rate].n;
+		cts = audio_acr->lut[hdmi_ctrl->audio_sample_rate].cts;
+		layout = (MSM_HDMI_AUDIO_CHANNEL_2 == num_of_channels) ? 0 : 1;
+
+		if (
+		(HDMI_SAMPLE_RATE_192KHZ == hdmi_ctrl->audio_sample_rate) ||
+		(HDMI_SAMPLE_RATE_176_4KHZ == hdmi_ctrl->audio_sample_rate)) {
+			multiplier = 4;
+			n >>= 2; /* divide N by 4 and use multiplier */
+		} else if (
+		(HDMI_SAMPLE_RATE_96KHZ == hdmi_ctrl->audio_sample_rate) ||
+		(HDMI_SAMPLE_RATE_88_2KHZ == hdmi_ctrl->audio_sample_rate)) {
+			multiplier = 2;
+			n >>= 1; /* divide N by 2 and use multiplier */
+		} else {
+			multiplier = 1;
+		}
+		DEV_DBG("%s: n=%u, cts=%u, layout=%u\n", __func__, n, cts,
+			layout);
+
+		/* AUDIO_PRIORITY | SOURCE */
+		acr_pck_ctrl_reg |= 0x80000100;
+		/* N_MULTIPLE(multiplier) */
+		acr_pck_ctrl_reg |= (multiplier & 7) << 16;
+
+		if ((HDMI_SAMPLE_RATE_48KHZ == hdmi_ctrl->audio_sample_rate) ||
+		(HDMI_SAMPLE_RATE_96KHZ == hdmi_ctrl->audio_sample_rate) ||
+		(HDMI_SAMPLE_RATE_192KHZ == hdmi_ctrl->audio_sample_rate)) {
+			/* SELECT(3) */
+			acr_pck_ctrl_reg |= 3 << 4;
+			/* CTS_48 */
+			cts <<= 12;
+
+			/* CTS: need to determine how many fractional bits */
+			DSS_REG_W(io, HDMI_ACR_48_0, cts);
+			/* N */
+			DSS_REG_W(io, HDMI_ACR_48_1, n);
+		} else if (
+		(HDMI_SAMPLE_RATE_44_1KHZ == hdmi_ctrl->audio_sample_rate) ||
+		(HDMI_SAMPLE_RATE_88_2KHZ == hdmi_ctrl->audio_sample_rate) ||
+		(HDMI_SAMPLE_RATE_176_4KHZ == hdmi_ctrl->audio_sample_rate)) {
+			/* SELECT(2) */
+			acr_pck_ctrl_reg |= 2 << 4;
+			/* CTS_44 */
+			cts <<= 12;
+
+			/* CTS: need to determine how many fractional bits */
+			DSS_REG_W(io, HDMI_ACR_44_0, cts);
+			/* N */
+			DSS_REG_W(io, HDMI_ACR_44_1, n);
+		} else {	/* default to 32k */
+			/* SELECT(1) */
+			acr_pck_ctrl_reg |= 1 << 4;
+			/* CTS_32 */
+			cts <<= 12;
+
+			/* CTS: need to determine how many fractional bits */
+			DSS_REG_W(io, HDMI_ACR_32_0, cts);
+			/* N */
+			DSS_REG_W(io, HDMI_ACR_32_1, n);
+		}
+		/* Payload layout depends on number of audio channels */
+		/* LAYOUT_SEL(layout) */
+		aud_pck_ctrl_2_reg = 1 | (layout << 1);
+		/* override | layout */
+		DSS_REG_W(io, HDMI_AUDIO_PKT_CTRL2, aud_pck_ctrl_2_reg);
+
+		/* SEND | CONT */
+		acr_pck_ctrl_reg |= 0x00000003;
+	} else {
+		/* ~(SEND | CONT) */
+		acr_pck_ctrl_reg &= ~0x00000003;
+	}
+	DSS_REG_W(io, HDMI_ACR_PKT_CTRL, acr_pck_ctrl_reg);
+
+	return 0;
+} /* hdmi_tx_audio_acr_setup */
+
+static int hdmi_tx_audio_info_setup(void *priv_d, bool enabled,
+	u32 num_of_channels, u32 channel_allocation, u32 level_shift,
+	bool down_mix)
+{
+	struct hdmi_tx_ctrl *hdmi_ctrl = (struct hdmi_tx_ctrl *)priv_d;
+	struct dss_io_data *io = NULL;
+
+	u32 channel_count = 1; /* Def to 2 channels -> Table 17 in CEA-D */
+	u32 check_sum, audio_info_0_reg, audio_info_1_reg;
+	u32 audio_info_ctrl_reg;
+	u32 aud_pck_ctrl_2_reg;
+	u32 layout;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	if (!io->base) {
+		DEV_ERR("%s: core io not inititalized\n", __func__);
+		return -EINVAL;
+	}
+
+	layout = (MSM_HDMI_AUDIO_CHANNEL_2 == num_of_channels) ? 0 : 1;
+	aud_pck_ctrl_2_reg = 1 | (layout << 1);
+	DSS_REG_W(io, HDMI_AUDIO_PKT_CTRL2, aud_pck_ctrl_2_reg);
+
+	/*
+	 * Please see table 20 Audio InfoFrame in HDMI spec
+	 * FL  = front left
+	 * FC  = front Center
+	 * FR  = front right
+	 * FLC = front left center
+	 * FRC = front right center
+	 * RL  = rear left
+	 * RC  = rear center
+	 * RR  = rear right
+	 * RLC = rear left center
+	 * RRC = rear right center
+	 * LFE = low frequency effect
+	 */
+
+	/* Read first then write because it is bundled with other controls */
+	audio_info_ctrl_reg = DSS_REG_R(io, HDMI_INFOFRAME_CTRL0);
+
+	if (enabled) {
+		switch (num_of_channels) {
+		case MSM_HDMI_AUDIO_CHANNEL_2:
+			channel_allocation = 0;	/* Default to FR, FL */
+			break;
+		case MSM_HDMI_AUDIO_CHANNEL_4:
+			channel_count = 3;
+			/* FC, LFE, FR, FL */
+			channel_allocation = 0x3;
+			break;
+		case MSM_HDMI_AUDIO_CHANNEL_6:
+			channel_count = 5;
+			/* RR, RL, FC, LFE, FR, FL */
+			channel_allocation = 0xB;
+			break;
+		case MSM_HDMI_AUDIO_CHANNEL_8:
+			channel_count = 7;
+			/* FRC, FLC, RR, RL, FC, LFE, FR, FL */
+			channel_allocation = 0x1f;
+			break;
+		default:
+			DEV_ERR("%s: Unsupported num_of_channels = %u\n",
+				__func__, num_of_channels);
+			return -EINVAL;
+		}
+
+		/* Program the Channel-Speaker allocation */
+		audio_info_1_reg = 0;
+		/* CA(channel_allocation) */
+		audio_info_1_reg |= channel_allocation & 0xff;
+		/* Program the Level shifter */
+		audio_info_1_reg |= (level_shift << 11) & 0x00007800;
+		/* Program the Down-mix Inhibit Flag */
+		audio_info_1_reg |= (down_mix << 15) & 0x00008000;
+
+		DSS_REG_W(io, HDMI_AUDIO_INFO1, audio_info_1_reg);
+
+		/*
+		 * Calculate CheckSum: Sum of all the bytes in the
+		 * Audio Info Packet (See table 8.4 in HDMI spec)
+		 */
+		check_sum = 0;
+		/* HDMI_AUDIO_INFO_FRAME_PACKET_HEADER_TYPE[0x84] */
+		check_sum += 0x84;
+		/* HDMI_AUDIO_INFO_FRAME_PACKET_HEADER_VERSION[0x01] */
+		check_sum += 1;
+		/* HDMI_AUDIO_INFO_FRAME_PACKET_LENGTH[0x0A] */
+		check_sum += 0x0A;
+		check_sum += channel_count;
+		check_sum += channel_allocation;
+		/* See Table 8.5 in HDMI spec */
+		check_sum += (level_shift & 0xF) << 3 | (down_mix & 0x1) << 7;
+		check_sum &= 0xFF;
+		check_sum = (u8) (256 - check_sum);
+
+		audio_info_0_reg = 0;
+		/* CHECKSUM(check_sum) */
+		audio_info_0_reg |= check_sum & 0xff;
+		/* CC(channel_count) */
+		audio_info_0_reg |= (channel_count << 8) & 0x00000700;
+
+		DSS_REG_W(io, HDMI_AUDIO_INFO0, audio_info_0_reg);
+
+		/*
+		 * Set these flags
+		 * AUDIO_INFO_UPDATE |
+		 * AUDIO_INFO_SOURCE |
+		 * AUDIO_INFO_CONT   |
+		 * AUDIO_INFO_SEND
+		 */
+		audio_info_ctrl_reg |= 0x000000F0;
+	} else {
+		/*Clear these flags
+		 * ~(AUDIO_INFO_UPDATE |
+		 *   AUDIO_INFO_SOURCE |
+		 *   AUDIO_INFO_CONT   |
+		 *   AUDIO_INFO_SEND)
+		 */
+		audio_info_ctrl_reg &= ~0x000000F0;
+	}
+	DSS_REG_W(io, HDMI_INFOFRAME_CTRL0, audio_info_ctrl_reg);
+
+	dss_reg_dump(io->base, io->len,
+		enabled ? "HDMI-AUDIO-ON: " : "HDMI-AUDIO-OFF: ", REG_DUMP);
+
+	return 0;
+} /* hdmi_tx_audio_info_setup */
+
+static int hdmi_tx_audio_setup(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	int rc = 0;
+	const int channels = MSM_HDMI_AUDIO_CHANNEL_2;
+	struct dss_io_data *io = NULL;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	if (!io->base) {
+		DEV_ERR("%s: core io not inititalized\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = hdmi_tx_audio_acr_setup(hdmi_ctrl, true, channels);
+	if (rc) {
+		DEV_ERR("%s: hdmi_tx_audio_acr_setup failed. rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	rc = hdmi_tx_audio_info_setup(hdmi_ctrl, true, channels, 0, 0, false);
+	if (rc) {
+		DEV_ERR("%s: hdmi_tx_audio_info_setup failed. rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	DEV_INFO("HDMI Audio: Enabled\n");
+
+	return 0;
+} /* hdmi_tx_audio_setup */
+
+static void hdmi_tx_audio_off(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	u32 i, status, max_reads, timeout_us, timeout_sec = 15;
+	struct dss_io_data *io = NULL;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	if (!io->base) {
+		DEV_ERR("%s: core io not inititalized\n", __func__);
+		return;
+	}
+
+	/* Check if audio engine is turned off by QDSP or not */
+	/* send off notification after every 1 sec for 15 seconds */
+	for (i = 0; i < timeout_sec; i++) {
+		max_reads = 500;
+		timeout_us = 1000 * 2;
+
+		if (readl_poll_timeout_noirq((io->base + HDMI_AUDIO_CFG),
+			status, ((status & BIT(0)) == 0),
+			max_reads, timeout_us)) {
+
+			DEV_ERR("%s: audio still on after %d sec. try again\n",
+				__func__, i+1);
+
+			switch_set_state(&hdmi_ctrl->audio_sdev, 0);
+			continue;
+		}
+		break;
+	}
+	if (i == timeout_sec)
+		DEV_ERR("%s: Error: cannot turn off audio engine\n", __func__);
+
+	if (hdmi_tx_audio_info_setup(hdmi_ctrl, false, 0, 0, 0, false))
+		DEV_ERR("%s: hdmi_tx_audio_info_setup failed.\n", __func__);
+
+	if (hdmi_tx_audio_acr_setup(hdmi_ctrl, false, 0))
+		DEV_ERR("%s: hdmi_tx_audio_acr_setup failed.\n", __func__);
+
+	DEV_INFO("HDMI Audio: Disabled\n");
+} /* hdmi_tx_audio_off */
+
 static int hdmi_tx_start(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
 	int rc = 0;
@@ -1290,8 +1582,6 @@
 		return -EINVAL;
 	}
 
-	/* todo: Audio */
-
 	hdmi_tx_set_mode(hdmi_ctrl, false);
 	hdmi_tx_init_phy(hdmi_ctrl);
 	DSS_REG_W(io, HDMI_USEC_REFTIMER, 0x0001001B);
@@ -1299,14 +1589,25 @@
 	hdmi_tx_set_mode(hdmi_ctrl, true);
 
 	hdmi_tx_video_setup(hdmi_ctrl, hdmi_ctrl->video_resolution);
-	/* todo: Audio */
+
+	if (!hdmi_tx_is_dvi_mode(hdmi_ctrl)) {
+		rc = hdmi_tx_audio_setup(hdmi_ctrl);
+		if (rc) {
+			DEV_ERR("%s: hdmi_msm_audio_setup failed. rc=%d\n",
+				__func__, rc);
+			hdmi_tx_set_mode(hdmi_ctrl, false);
+			return rc;
+		}
+
+		switch_set_state(&hdmi_ctrl->audio_sdev, 1);
+		DEV_INFO("%s: hdmi_audio state switch to %d\n", __func__,
+			hdmi_ctrl->audio_sdev.state);
+	}
+
 	hdmi_tx_set_avi_infoframe(hdmi_ctrl);
 	/* todo: CONFIG_FB_MSM_HDMI_3D */
 	hdmi_tx_set_spd_infoframe(hdmi_ctrl);
 
-	/* Set IRQ for HPD */
-	DSS_REG_W(io, HDMI_HPD_INT_CTRL, 4 | (hdmi_ctrl->hpd_state ? 0 : 2));
-
 	/* todo: HDCP/CEC */
 
 	DEV_INFO("%s: HDMI Core: Initialized\n", __func__);
@@ -1314,21 +1615,107 @@
 	return rc;
 } /* hdmi_tx_start */
 
+static void hdmi_tx_hpd_polarity_setup(struct hdmi_tx_ctrl *hdmi_ctrl,
+	bool polarity)
+{
+	struct dss_io_data *io = NULL;
+	u32 cable_sense;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	if (!io->base) {
+		DEV_ERR("%s: core io is not initialized\n", __func__);
+		return;
+	}
+
+	if (polarity)
+		DSS_REG_W(io, HDMI_HPD_INT_CTRL, BIT(2) | BIT(1));
+	else
+		DSS_REG_W(io, HDMI_HPD_INT_CTRL, BIT(2));
+
+	cable_sense = (DSS_REG_R(io, HDMI_HPD_INT_STATUS) & BIT(1)) >> 1;
+	DEV_DBG("%s: listen = %s, sense = %s\n", __func__,
+		polarity ? "connect" : "disconnect",
+		cable_sense ? "connect" : "disconnect");
+
+	if (cable_sense == polarity) {
+		u32 reg_val = DSS_REG_R(io, HDMI_HPD_CTRL);
+
+		/* Toggle HPD circuit to trigger HPD sense */
+		DSS_REG_W(io, HDMI_HPD_CTRL, reg_val & ~BIT(28));
+		DSS_REG_W(io, HDMI_HPD_CTRL, reg_val | BIT(28));
+	}
+} /* hdmi_tx_hpd_polarity_setup */
+
+static void hdmi_tx_power_off_work(struct work_struct *work)
+{
+	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+	struct dss_io_data *io = NULL;
+
+	hdmi_ctrl = container_of(work, struct hdmi_tx_ctrl, power_off_work);
+	if (!hdmi_ctrl) {
+		DEV_DBG("%s: invalid input\n", __func__);
+		return;
+	}
+
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	if (!io->base) {
+		DEV_ERR("%s: Core io is not initialized\n", __func__);
+		return;
+	}
+
+	if (!hdmi_tx_is_dvi_mode(hdmi_ctrl)) {
+		switch_set_state(&hdmi_ctrl->audio_sdev, 0);
+		DEV_INFO("%s: hdmi_audio state switch to %d\n", __func__,
+			hdmi_ctrl->audio_sdev.state);
+
+		hdmi_tx_audio_off(hdmi_ctrl);
+	}
+
+	hdmi_tx_powerdown_phy(hdmi_ctrl);
+
+	/*
+	 * this is needed to avoid pll lock failure due to
+	 * clk framework's rate caching.
+	 */
+	hdmi_ctrl->pdata.power_data[HDMI_TX_CORE_PM].clk_config[0].rate = 0;
+
+	hdmi_tx_core_off(hdmi_ctrl);
+
+	mutex_lock(&hdmi_ctrl->mutex);
+	hdmi_ctrl->panel_power_on = false;
+	mutex_unlock(&hdmi_ctrl->mutex);
+
+	if (hdmi_ctrl->hpd_off_pending) {
+		hdmi_tx_hpd_off(hdmi_ctrl);
+		hdmi_ctrl->hpd_off_pending = false;
+	} else {
+		hdmi_tx_hpd_polarity_setup(hdmi_ctrl, HPD_CONNECT_POLARITY);
+	}
+
+	DEV_INFO("%s: HDMI Core: OFF\n", __func__);
+} /* hdmi_tx_power_off_work */
+
 static int hdmi_tx_power_off(struct mdss_panel_data *panel_data)
 {
 	struct hdmi_tx_ctrl *hdmi_ctrl =
 		hdmi_tx_get_drvdata_from_panel_data(panel_data);
 
-	if (!hdmi_ctrl) {
+	if (!hdmi_ctrl || !hdmi_ctrl->panel_power_on) {
 		DEV_ERR("%s: invalid input\n", __func__);
 		return -EINVAL;
 	}
 
-	DEV_INFO("%s: power: OFF (audio off, Reset Core)\n", __func__);
-	/* todo: Audio */
-	hdmi_tx_powerdown_phy(hdmi_ctrl);
-	hdmi_ctrl->panel_power_on = false;
-	hdmi_tx_core_off(hdmi_ctrl);
+	/*
+	 * Queue work item to handle power down sequence.
+	 * This is needed since we need to wait for the audio engine
+	 * to shutdown first before we shutdown the HDMI core.
+	 */
+	DEV_DBG("%s: Queuing work to power off HDMI core\n", __func__);
+	queue_work(hdmi_ctrl->workq, &hdmi_ctrl->power_off_work);
 
 	return 0;
 } /* hdmi_tx_power_off */
@@ -1350,6 +1737,15 @@
 		return -EINVAL;
 	}
 
+	if (!hdmi_ctrl->hpd_initialized) {
+		DEV_ERR("%s: HDMI on is not possible w/o cable detection.\n",
+			__func__);
+		return -EPERM;
+	}
+
+	/* If a power down is already underway, wait for it to finish */
+	flush_work_sync(&hdmi_ctrl->power_off_work);
+
 	DEV_INFO("power: ON (%dx%d %ld)\n", hdmi_ctrl->xres, hdmi_ctrl->yres,
 		hdmi_ctrl->pixel_clk);
 
@@ -1390,6 +1786,8 @@
 		hdmi_tx_is_controller_on(hdmi_ctrl) ? "ON" : "OFF" ,
 		hdmi_tx_is_dvi_mode(hdmi_ctrl) ? "ON" : "OFF");
 
+	hdmi_tx_hpd_polarity_setup(hdmi_ctrl, HPD_DISCONNECT_POLARITY);
+
 	return 0;
 } /* hdmi_tx_power_on */
 
@@ -1407,8 +1805,6 @@
 		return;
 	}
 
-	DEV_DBG("%s: (timer, 5V, IRQ off)\n", __func__);
-	del_timer_sync(&hdmi_ctrl->hpd_state_timer);
 	mdss_disable_irq(&hdmi_tx_hw);
 
 	hdmi_tx_set_mode(hdmi_ctrl, false);
@@ -1456,28 +1852,18 @@
 
 		DSS_REG_W(io, HDMI_USEC_REFTIMER, 0x0001001B);
 
-		/* set timeout to 4.1ms (max) for hardware debounce */
-		reg_val = DSS_REG_R(io, HDMI_HPD_CTRL) | 0x1FFF;
-
-		/* Toggle HPD circuit to trigger HPD sense */
-		DSS_REG_W(io, HDMI_HPD_CTRL,
-			~(1 << 28) & reg_val);
-		DSS_REG_W(io, HDMI_HPD_CTRL, (1 << 28) | reg_val);
+		mdss_enable_irq(&hdmi_tx_hw);
 
 		hdmi_ctrl->hpd_initialized = true;
 
-		/* Check HPD State */
-		mdss_enable_irq(&hdmi_tx_hw);
-	}
+		/* set timeout to 4.1ms (max) for hardware debounce */
+		reg_val = DSS_REG_R(io, HDMI_HPD_CTRL) | 0x1FFF;
 
-	/* Set HPD state machine: ensure at least 2 readouts */
-	mutex_lock(&hdmi_ctrl->mutex);
-	hdmi_ctrl->hpd_stable = 0;
-	hdmi_ctrl->hpd_prev_state = true;
-	hdmi_ctrl->hpd_state = false;
-	hdmi_ctrl->hpd_cable_chg_detected = true;
-	mutex_unlock(&hdmi_ctrl->mutex);
-	mod_timer(&hdmi_ctrl->hpd_state_timer, jiffies + HZ/2);
+		/* Turn on HPD HW circuit */
+		DSS_REG_W(io, HDMI_HPD_CTRL, reg_val | BIT(28));
+
+		hdmi_tx_hpd_polarity_setup(hdmi_ctrl, HPD_CONNECT_POLARITY);
+	}
 
 	return rc;
 } /* hdmi_tx_hpd_on */
@@ -1495,10 +1881,20 @@
 	if (on) {
 		rc = hdmi_tx_hpd_on(hdmi_ctrl);
 	} else {
-		hdmi_tx_hpd_off(hdmi_ctrl);
-		switch_set_state(&hdmi_ctrl->sdev, 0);
-		DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
-			hdmi_ctrl->sdev.state);
+		/* If power down is already underway, wait for it to finish */
+		flush_work_sync(&hdmi_ctrl->power_off_work);
+
+		if (!hdmi_ctrl->panel_power_on) {
+			hdmi_tx_hpd_off(hdmi_ctrl);
+		} else {
+			hdmi_ctrl->hpd_off_pending = true;
+
+			switch_set_state(&hdmi_ctrl->sdev, 0);
+			DEV_DBG("%s: Hdmi state switch to %d\n", __func__,
+				hdmi_ctrl->sdev.state);
+			DEV_DBG("HDMI HPD: sent fake OFFLINE event\n");
+			kobject_uevent(hdmi_ctrl->kobj, KOBJ_OFFLINE);
+		}
 	}
 
 	return rc;
@@ -1523,10 +1919,10 @@
 
 	if (DSS_REG_R(io, HDMI_HPD_INT_STATUS) & BIT(0)) {
 		/*
-		 * Turn off HPD irq and clear all interrupts,
-		 * worker will turn IRQ back on
+		 * Ack the current hpd interrupt and stop listening to
+		 * new hpd interrupt.
 		 */
-		DSS_REG_W(io, HDMI_HPD_INT_CTRL, ~BIT(2) | BIT(0));
+		DSS_REG_W(io, HDMI_HPD_INT_CTRL, BIT(0));
 		queue_work(hdmi_ctrl->workq, &hdmi_ctrl->hpd_int_work);
 	}
 
@@ -1546,8 +1942,8 @@
 	if (hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID])
 		hdmi_edid_deinit(hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]);
 
+	switch_dev_unregister(&hdmi_ctrl->audio_sdev);
 	switch_dev_unregister(&hdmi_ctrl->sdev);
-	del_timer_sync(&hdmi_ctrl->hpd_state_timer);
 	if (hdmi_ctrl->workq)
 		destroy_workqueue(hdmi_ctrl->workq);
 	mutex_destroy(&hdmi_ctrl->mutex);
@@ -1581,29 +1977,41 @@
 	hdmi_ctrl->workq = create_workqueue("hdmi_tx_workq");
 	if (!hdmi_ctrl->workq) {
 		DEV_ERR("%s: hdmi_tx_workq creation failed.\n", __func__);
+		rc = -EPERM;
 		goto fail_create_workq;
 	}
 
 	hdmi_ctrl->ddc_ctrl.io = &pdata->io[HDMI_TX_CORE_IO];
 	init_completion(&hdmi_ctrl->ddc_ctrl.ddc_sw_done);
 
-	INIT_WORK(&hdmi_ctrl->hpd_state_work, hdmi_tx_hpd_state_work);
+	hdmi_ctrl->hpd_state = false;
+	hdmi_ctrl->hpd_initialized = false;
+	hdmi_ctrl->hpd_off_pending = false;
 	INIT_WORK(&hdmi_ctrl->hpd_int_work, hdmi_tx_hpd_int_work);
-	init_timer(&hdmi_ctrl->hpd_state_timer);
-	hdmi_ctrl->hpd_state_timer.function = hdmi_tx_hpd_state_timer;
-	hdmi_ctrl->hpd_state_timer.data = (u32)hdmi_ctrl;
-	hdmi_ctrl->hpd_state_timer.expires = 0xffffffffL;
+
+	INIT_WORK(&hdmi_ctrl->power_off_work, hdmi_tx_power_off_work);
+
+	hdmi_ctrl->audio_sample_rate = HDMI_SAMPLE_RATE_48KHZ;
 
 	hdmi_ctrl->sdev.name = "hdmi";
 	if (switch_dev_register(&hdmi_ctrl->sdev) < 0) {
 		DEV_ERR("%s: Hdmi switch registration failed\n", __func__);
-		goto fail_switch_dev;
+		rc = -ENODEV;
+		goto fail_create_workq;
+	}
+
+	hdmi_ctrl->audio_sdev.name = "hdmi_audio";
+	if (switch_dev_register(&hdmi_ctrl->audio_sdev) < 0) {
+		DEV_ERR("%s: hdmi_audio switch registration failed\n",
+			__func__);
+		rc = -ENODEV;
+		goto fail_audio_switch_dev;
 	}
 
 	return 0;
 
-fail_switch_dev:
-	del_timer_sync(&hdmi_ctrl->hpd_state_timer);
+fail_audio_switch_dev:
+	switch_dev_unregister(&hdmi_ctrl->sdev);
 fail_create_workq:
 	if (hdmi_ctrl->workq)
 		destroy_workqueue(hdmi_ctrl->workq);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index 94e0fda..ce19355 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -41,23 +41,24 @@
 	struct hdmi_tx_platform_data pdata;
 	struct mdss_panel_data panel_data;
 
+	int audio_sample_rate;
+
 	struct mutex mutex;
 	struct kobject *kobj;
 	struct switch_dev sdev;
+	struct switch_dev audio_sdev;
 	struct workqueue_struct *workq;
 
 	uint32_t video_resolution;
 	u32 panel_power_on;
 
 	u32 hpd_initialized;
-	int hpd_stable;
-	u32 hpd_prev_state;
-	u32 hpd_cable_chg_detected;
 	u32 hpd_state;
+	u32 hpd_off_pending;
 	u32 hpd_feature_on;
-	struct work_struct hpd_state_work;
 	struct work_struct hpd_int_work;
-	struct timer_list hpd_state_timer;
+
+	struct work_struct power_off_work;
 
 	unsigned long pixel_clk;
 	u32 xres;
diff --git a/drivers/video/msm/mdss/mdss_io_util.c b/drivers/video/msm/mdss/mdss_io_util.c
index 5778525..0a14056 100644
--- a/drivers/video/msm/mdss/mdss_io_util.c
+++ b/drivers/video/msm/mdss/mdss_io_util.c
@@ -136,7 +136,7 @@
 			curr_vreg = &in_vreg[i];
 			curr_vreg->vreg = regulator_get(dev,
 				curr_vreg->vreg_name);
-			rc = IS_ERR(curr_vreg->vreg);
+			rc = PTR_RET(curr_vreg->vreg);
 			if (rc) {
 				DEV_ERR("%pS->%s: %s get failed. rc=%d\n",
 					 __builtin_return_address(0), __func__,
@@ -215,7 +215,7 @@
 	int i = 0, rc = 0;
 	if (enable) {
 		for (i = 0; i < num_vreg; i++) {
-			rc = IS_ERR(in_vreg[i].vreg);
+			rc = PTR_RET(in_vreg[i].vreg);
 			if (rc) {
 				DEV_ERR("%pS->%s: %s regulator error. rc=%d\n",
 					__builtin_return_address(0), __func__,
@@ -286,7 +286,7 @@
 
 	for (i = 0; i < num_clk; i++) {
 		clk_arry[i].clk = clk_get(dev, clk_arry[i].clk_name);
-		rc = IS_ERR(clk_arry[i].clk);
+		rc = PTR_RET(clk_arry[i].clk);
 		if (rc) {
 			DEV_ERR("%pS->%s: '%s' get failed. rc=%d\n",
 				__builtin_return_address(0), __func__,
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index c2d107a..11b0831 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -226,7 +226,7 @@
 		mdss_res->irq_mask &= ~ndx_bit;
 		if (mdss_res->irq_mask == 0) {
 			mdss_res->irq_ena = false;
-			disable_irq(mdss_res->irq);
+			disable_irq_nosync(mdss_res->irq);
 		}
 	}
 	spin_unlock_irqrestore(&mdss_lock, irq_flags);
@@ -292,7 +292,7 @@
 		msm_bus_scale_unregister_client(mdata->bus_hdl);
 }
 
-int mdss_mdp_bus_scale_set_quota(u32 ab_quota, u32 ib_quota)
+int mdss_mdp_bus_scale_set_quota(u64 ab_quota, u64 ib_quota)
 {
 	static int current_bus_idx;
 	int bus_idx;
@@ -310,6 +310,10 @@
 
 		bus_idx = (current_bus_idx % (num_cases - 1)) + 1;
 
+		/* aligning to avoid performing updates for small changes */
+		ab_quota = ALIGN(ab_quota, SZ_64M);
+		ib_quota = ALIGN(ib_quota, SZ_64M);
+
 		vect = mdp_bus_scale_table.usecase[current_bus_idx].vectors;
 		if ((ab_quota == vect->ab) && (ib_quota == vect->ib)) {
 			pr_debug("skip bus scaling, no change in vectors\n");
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 33028cb..808babb 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -276,7 +276,7 @@
 int mdss_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
 			       void (*fnc_ptr)(void *), void *arg);
 
-int mdss_mdp_bus_scale_set_quota(u32 ab_quota, u32 ib_quota);
+int mdss_mdp_bus_scale_set_quota(u64 ab_quota, u64 ib_quota);
 void mdss_mdp_set_clk_rate(unsigned long min_clk_rate);
 unsigned long mdss_mdp_get_clk_rate(u32 clk_idx);
 int mdss_mdp_vsync_clk_enable(int enable);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 73b8c60..b5f6ddf 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -20,8 +20,10 @@
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
 
+/* truncate at 1k */
+#define MDSS_MDP_BUS_FACTOR_SHIFT 10
 /* 1.5 bus fudge factor */
-#define MDSS_MDP_BUS_FUDGE_FACTOR(val) ALIGN((((val) * 3) / 2), SZ_16M)
+#define MDSS_MDP_BUS_FUDGE_FACTOR(val) (((val) / 2) * 3)
 /* 1.25 clock fudge factor */
 #define MDSS_MDP_CLK_FUDGE_FACTOR(val) (((val) * 5) / 4)
 
@@ -44,7 +46,7 @@
 	struct mdss_mdp_ctl *ctl;
 	int cnum;
 	unsigned long clk_rate = 0;
-	u32 bus_ab_quota = 0, bus_ib_quota = 0;
+	u64 bus_ab_quota = 0, bus_ib_quota = 0;
 
 	if (!flags) {
 		pr_err("nothing to update\n");
@@ -63,7 +65,9 @@
 		}
 	}
 	if (flags & MDSS_MDP_PERF_UPDATE_BUS) {
+		bus_ab_quota = bus_ab_quota << MDSS_MDP_BUS_FACTOR_SHIFT;
 		bus_ib_quota = MDSS_MDP_BUS_FUDGE_FACTOR(bus_ib_quota);
+		bus_ib_quota <<= MDSS_MDP_BUS_FACTOR_SHIFT;
 		mdss_mdp_bus_scale_set_quota(bus_ab_quota, bus_ib_quota);
 	}
 	if (flags & MDSS_MDP_PERF_UPDATE_CLK) {
@@ -116,6 +120,7 @@
 		if (is_writeback) {
 			/* perf for bus writeback */
 			*bus_ab_quota = fps * mixer->width * mixer->height * 3;
+			*bus_ab_quota >>= MDSS_MDP_BUS_FACTOR_SHIFT;
 			*bus_ib_quota = *bus_ab_quota;
 		}
 	}
@@ -148,13 +153,13 @@
 		if (mixer->rotator_mode)
 			rate /= 4; /* block mode fetch at 4 pix/clk */
 
-		*bus_ab_quota += quota;
-		*bus_ib_quota += ib_quota;
-		if (rate > *clk_rate)
-			*clk_rate = rate;
-
 		pr_debug("mixer=%d pnum=%d clk_rate=%u bus ab=%u ib=%u\n",
 			 mixer->num, pipe->num, rate, quota, ib_quota);
+
+		*bus_ab_quota += quota >> MDSS_MDP_BUS_FACTOR_SHIFT;
+		*bus_ib_quota += ib_quota >> MDSS_MDP_BUS_FACTOR_SHIFT;
+		if (rate > *clk_rate)
+			*clk_rate = rate;
 	}
 
 	pr_debug("final mixer=%d clk_rate=%u bus ab=%u ib=%u\n", mixer->num,
@@ -469,15 +474,25 @@
 	if (ctl->intf_num == MDSS_MDP_NO_INTF) {
 		ctl->dst_format = mfd->panel_info.out_format;
 	} else {
+		struct mdp_dither_cfg_data dither = {
+			.block = mfd->index + MDP_LOGICAL_BLOCK_DISP_0,
+			.flags = MDP_PP_OPS_DISABLE,
+		};
+
 		switch (mfd->panel_info.bpp) {
 		case 18:
 			ctl->dst_format = MDSS_MDP_PANEL_FORMAT_RGB666;
+			dither.flags = MDP_PP_OPS_ENABLE | MDP_PP_OPS_WRITE;
+			dither.g_y_depth = 2;
+			dither.r_cr_depth = 2;
+			dither.b_cb_depth = 2;
 			break;
 		case 24:
 		default:
 			ctl->dst_format = MDSS_MDP_PANEL_FORMAT_RGB888;
 			break;
 		}
+		mdss_mdp_dither_config(&dither, NULL);
 	}
 
 	if (ctl->mixer_right) {
@@ -564,6 +579,17 @@
 		goto start_fail;
 	}
 
+	/* request bus bandwidth for panel commands */
+	ctl->clk_rate = MDP_CLK_DEFAULT_RATE;
+	ctl->bus_ib_quota = SZ_1M;
+	mdss_mdp_ctl_perf_commit(MDSS_MDP_PERF_UPDATE_ALL);
+
+	ret = pdata->on(pdata);
+	if (ret) {
+		pr_err("panel power on failed ctl=%d\n", ctl->num);
+		goto panel_fail;
+	}
+
 	pr_debug("ctl_num=%d\n", ctl->num);
 
 	mixer = ctl->mixer_left;
@@ -591,17 +617,16 @@
 		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_OUT_SIZE, outsize);
 		mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_PACK_3D, 0);
 	}
-
-	/* request bus bandwidth for panel commands */
-	ctl->clk_rate = MDP_CLK_DEFAULT_RATE;
-	ctl->bus_ib_quota = SZ_1M;
-	mdss_mdp_ctl_perf_commit(MDSS_MDP_PERF_UPDATE_ALL);
-
-	ret = pdata->on(pdata);
-
+panel_fail:
+	if (ret && ctl->stop_fnc)
+		ctl->stop_fnc(ctl);
 start_fail:
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 	mutex_unlock(&ctl->lock);
+	if (ret) {
+		mdss_mdp_ctl_destroy(mfd);
+		mdss_mdp_ctl_perf_commit(MDSS_MDP_PERF_UPDATE_ALL);
+	}
 
 	return ret;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index d52df66..e4621d4 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -206,6 +206,11 @@
 	rot->src_rect.w = req->src_rect.w;
 	rot->src_rect.h = req->src_rect.h;
 
+	if (req->flags & MDP_DEINTERLACE) {
+		rot->rotations |= MDP_DEINTERLACE;
+		rot->src_rect.h /= 2;
+	}
+
 	rot->params_changed++;
 
 	req->id = rot->session_id;
@@ -325,6 +330,15 @@
 								__func__);
 	}
 
+	if (pipe->flags & MDP_DEINTERLACE) {
+		if (pipe->flags & MDP_SOURCE_ROTATED_90) {
+			pipe->src.w /= 2;
+			pipe->img_width /= 2;
+		} else {
+			pipe->src.h /= 2;
+		}
+	}
+
 	pipe->params_changed++;
 
 	req->id = pipe->ndx;
@@ -341,6 +355,9 @@
 {
 	int ret;
 
+	if (!mfd->panel_power_on)
+		return -EPERM;
+
 	if (req->flags & MDSS_MDP_ROT_ONLY) {
 		ret = mdss_mdp_overlay_rotator_setup(mfd, req);
 	} else {
@@ -468,6 +485,9 @@
 		return ret;
 	}
 
+	if (!mfd->ctl->power_on)
+		return 0;
+
 	for (i = 0; unset_ndx != ndx && i < MDSS_MDP_MAX_SSPP; i++) {
 		pipe_ndx = BIT(i);
 		if (pipe_ndx & ndx) {
@@ -617,6 +637,9 @@
 
 	pr_debug("play req id=%x\n", req->id);
 
+	if (!mfd->panel_power_on)
+		return -EPERM;
+
 	if (req->id & MDSS_MDP_ROT_SESSION_MASK)
 		ret = mdss_mdp_overlay_rotate(mfd, req);
 	else
@@ -960,7 +983,7 @@
 		}
 
 		if (ret) {
-			pr_err("OVERLAY_GET failed (%d)\n", ret);
+			pr_debug("OVERLAY_GET failed (%d)\n", ret);
 			ret = -EFAULT;
 		}
 		break;
@@ -974,7 +997,7 @@
 				ret = copy_to_user(argp, &req, sizeof(req));
 		}
 		if (ret) {
-			pr_err("OVERLAY_SET failed (%d)\n", ret);
+			pr_debug("OVERLAY_SET failed (%d)\n", ret);
 			ret = -EFAULT;
 		}
 		break;
@@ -1006,7 +1029,7 @@
 			}
 
 			if (ret) {
-				pr_err("OVERLAY_PLAY failed (%d)\n", ret);
+				pr_debug("OVERLAY_PLAY failed (%d)\n", ret);
 				ret = -EFAULT;
 			}
 		} else {
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index c90ce8c..c28bcfd 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -22,6 +22,7 @@
 #define SMP_MB_CNT (mdss_res->smp_mb_cnt)
 
 static DEFINE_MUTEX(mdss_mdp_sspp_lock);
+static DEFINE_MUTEX(mdss_mdp_smp_lock);
 static DECLARE_BITMAP(mdss_mdp_smp_mmb_pool, MDSS_MDP_SMP_MMB_BLOCKS);
 
 static struct mdss_mdp_pipe mdss_mdp_pipe_list[MDSS_MDP_MAX_SSPP];
@@ -69,9 +70,11 @@
 
 static void mdss_mdp_smp_free(struct mdss_mdp_pipe *pipe)
 {
+	mutex_lock(&mdss_mdp_smp_lock);
 	mdss_mdp_smp_mmb_free(&pipe->smp[0]);
 	mdss_mdp_smp_mmb_free(&pipe->smp[1]);
 	mdss_mdp_smp_mmb_free(&pipe->smp[2]);
+	mutex_unlock(&mdss_mdp_smp_lock);
 }
 
 static int mdss_mdp_smp_reserve(struct mdss_mdp_pipe *pipe)
@@ -83,7 +86,7 @@
 	    (pipe->type == MDSS_MDP_PIPE_TYPE_RGB))
 		return -EINVAL;
 
-	mutex_lock(&mdss_mdp_sspp_lock);
+	mutex_lock(&mdss_mdp_smp_lock);
 	for (i = 0; i < pipe->src_planes.num_planes; i++) {
 		num_blks = DIV_ROUND_UP(2 * pipe->src_planes.ystride[i],
 					mdss_res->smp_mb_size);
@@ -98,10 +101,11 @@
 
 	if (reserved < num_blks) {
 		pr_err("insufficient MMB blocks\n");
-		mdss_mdp_smp_free(pipe);
+		for (; i >= 0; i--)
+			mdss_mdp_smp_mmb_free(&pipe->smp[i]);
 		return -ENOMEM;
 	}
-	mutex_unlock(&mdss_mdp_sspp_lock);
+	mutex_unlock(&mdss_mdp_smp_lock);
 
 	return 0;
 }
@@ -141,10 +145,10 @@
 		return -EINVAL;
 	}
 
-	mutex_lock(&mdss_mdp_sspp_lock);
+	mutex_lock(&mdss_mdp_smp_lock);
 	for (i = 0; i < pipe->src_planes.num_planes; i++)
 		mdss_mdp_smp_mmb_set(client_id + i, &pipe->smp[i]);
-	mutex_unlock(&mdss_mdp_sspp_lock);
+	mutex_unlock(&mdss_mdp_smp_lock);
 	return 0;
 }
 
@@ -464,6 +468,7 @@
 static int mdss_mdp_image_setup(struct mdss_mdp_pipe *pipe)
 {
 	u32 img_size, src_size, src_xy, dst_size, dst_xy, ystride0, ystride1;
+	u32 width, height;
 
 	pr_debug("pnum=%d wh=%dx%d src={%d,%d,%d,%d} dst={%d,%d,%d,%d}\n",
 		   pipe->num, pipe->img_width, pipe->img_height,
@@ -473,10 +478,21 @@
 	if (mdss_mdp_scale_setup(pipe))
 		return -EINVAL;
 
-	mdss_mdp_get_plane_sizes(pipe->src_fmt->format, pipe->img_width,
-				 pipe->img_height, &pipe->src_planes);
+	width = pipe->img_width;
+	height = pipe->img_height;
+	mdss_mdp_get_plane_sizes(pipe->src_fmt->format, width, height,
+			&pipe->src_planes);
 
-	img_size = (pipe->img_height << 16) | pipe->img_width;
+	if ((pipe->flags & MDP_DEINTERLACE) &&
+			!(pipe->flags & MDP_SOURCE_ROTATED_90)) {
+		int i;
+		for (i = 0; i < pipe->src_planes.num_planes; i++)
+			pipe->src_planes.ystride[i] *= 2;
+		width *= 2;
+		height /= 2;
+	}
+
+	img_size = (height << 16) | width;
 	src_size = (pipe->src.h << 16) | pipe->src.w;
 	src_xy = (pipe->src.y << 16) | pipe->src.x;
 	dst_size = (pipe->dst.h << 16) | pipe->dst.w;
diff --git a/drivers/video/msm/mipi_dsi.c b/drivers/video/msm/mipi_dsi.c
index a58010e..cc19555 100644
--- a/drivers/video/msm/mipi_dsi.c
+++ b/drivers/video/msm/mipi_dsi.c
@@ -446,9 +446,6 @@
 	if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
 		return -ENOMEM;
 
-	if (!mfd->cont_splash_done)
-		cont_splash_clk_ctrl(1);
-
 	mdp_dev = platform_device_alloc("mdp", pdev->id);
 	if (!mdp_dev)
 		return -ENOMEM;
@@ -584,6 +581,9 @@
 
 	pdev_list[pdev_list_cnt++] = pdev;
 
+	if (!mfd->cont_splash_done)
+		cont_splash_clk_ctrl(1);
+
 return 0;
 
 mipi_dsi_probe_err:
diff --git a/drivers/video/msm/mipi_novatek_cmd_qhd_pt.c b/drivers/video/msm/mipi_novatek_cmd_qhd_pt.c
index f139f4c..4c1aa63 100644
--- a/drivers/video/msm/mipi_novatek_cmd_qhd_pt.c
+++ b/drivers/video/msm/mipi_novatek_cmd_qhd_pt.c
@@ -64,7 +64,7 @@
 	pinfo.is_3d_panel = FB_TYPE_3D_PANEL;
 	pinfo.lcd.vsync_enable = TRUE;
 	pinfo.lcd.hw_vsync_mode = TRUE;
-	pinfo.lcd.refx100 = 6000; /* adjust refx100 to prevent tearing */
+	pinfo.lcd.refx100 = 6200; /* adjust refx100 to prevent tearing */
 	pinfo.lcd.v_back_porch = 11;
 	pinfo.lcd.v_front_porch = 10;
 	pinfo.lcd.v_pulse_width = 5;
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 1994b1b..5189b6d 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -653,12 +653,6 @@
 	struct msm_fb_panel_data *pdata = NULL;
 	int ret = 0;
 
-	if (hdmi_prim_display) {
-		MSM_FB_INFO("%s: hdmi primary handles early suspend only\n",
-			__func__);
-		return 0;
-	}
-
 	if ((!mfd) || (mfd->key != MFD_KEY))
 		return 0;
 
@@ -684,12 +678,6 @@
 	struct msm_fb_panel_data *pdata = NULL;
 	int ret = 0;
 
-	if (hdmi_prim_display) {
-		MSM_FB_INFO("%s: hdmi primary handles early resume only\n",
-			__func__);
-		return 0;
-	}
-
 	if ((!mfd) || (mfd->key != MFD_KEY))
 		return 0;
 
@@ -714,8 +702,7 @@
 	.runtime_suspend = msm_fb_runtime_suspend,
 	.runtime_resume = msm_fb_runtime_resume,
 	.runtime_idle = msm_fb_runtime_idle,
-#if (defined(CONFIG_SUSPEND) && defined(CONFIG_FB_MSM_HDMI_MSM_PANEL) && \
-	!defined(CONFIG_FB_MSM_HDMI_AS_PRIMARY))
+#if (defined(CONFIG_SUSPEND) && defined(CONFIG_FB_MSM_HDMI_MSM_PANEL))
 	.suspend = msm_fb_ext_suspend,
 	.resume = msm_fb_ext_resume,
 #endif
@@ -749,9 +736,7 @@
 static void msmfb_early_suspend(struct early_suspend *h)
 {
 	struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
-						early_suspend);
-	struct msm_fb_panel_data *pdata = NULL;
-
+						    early_suspend);
 #if defined(CONFIG_FB_MSM_MDP303)
 	/*
 	* For MDP with overlay, set framebuffer with black pixels
@@ -769,37 +754,12 @@
 	}
 #endif
 	msm_fb_suspend_sub(mfd);
-
-	pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
-	if (hdmi_prim_display &&
-		(mfd->panel_info.type == HDMI_PANEL ||
-		 mfd->panel_info.type == DTV_PANEL)) {
-		/* Turn off the HPD circuitry */
-		if (pdata->power_ctrl) {
-			MSM_FB_INFO("%s: Turning off HPD circuitry\n",
-				__func__);
-			pdata->power_ctrl(FALSE);
-		}
-	}
 }
 
 static void msmfb_early_resume(struct early_suspend *h)
 {
 	struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
-						early_suspend);
-	struct msm_fb_panel_data *pdata = NULL;
-
-	pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
-	if (hdmi_prim_display &&
-		(mfd->panel_info.type == HDMI_PANEL ||
-		 mfd->panel_info.type == DTV_PANEL)) {
-		/* Turn on the HPD circuitry */
-		if (pdata->power_ctrl) {
-			MSM_FB_INFO("%s: Turning on HPD circuitry\n", __func__);
-			pdata->power_ctrl(TRUE);
-		}
-	}
-
+						    early_suspend);
 	msm_fb_resume_sub(mfd);
 }
 #endif
@@ -1510,10 +1470,7 @@
 	ret = 0;
 
 #ifdef CONFIG_HAS_EARLYSUSPEND
-
-	if (hdmi_prim_display ||
-	    (mfd->panel_info.type != DTV_PANEL &&
-	     mfd->panel_info.type != WRITEBACK_PANEL)) {
+	if (mfd->panel_info.type != DTV_PANEL) {
 		mfd->early_suspend.suspend = msmfb_early_suspend;
 		mfd->early_suspend.resume = msmfb_early_resume;
 		mfd->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 2;
@@ -3279,7 +3236,9 @@
 		ret = wait_for_completion_interruptible_timeout(
 		&mfd->msmfb_no_update_notify, 4*HZ);
 	}
-	return (ret > 0) ? 0 : -1;
+	if (ret == 0)
+		ret = -ETIMEDOUT;
+	return (ret > 0) ? 0 : ret;
 }
 
 static int msmfb_handle_pp_ioctl(struct msm_fb_data_type *mfd,
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index 1594825..7d8ad73 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -214,8 +214,7 @@
 void msm_fb_config_backlight(struct msm_fb_data_type *mfd);
 #endif
 
-void fill_black_screen(void);
-void unfill_black_screen(void);
+void fill_black_screen(bool on, uint8 pipe_num, uint8 mixer_num);
 int msm_fb_check_frame_rate(struct msm_fb_data_type *mfd,
 				struct fb_info *info);
 
diff --git a/drivers/video/msm/msm_fb_panel.h b/drivers/video/msm/msm_fb_panel.h
index 7fc7a2f..bdd4f3bb 100644
--- a/drivers/video/msm/msm_fb_panel.h
+++ b/drivers/video/msm/msm_fb_panel.h
@@ -56,6 +56,11 @@
 	MAX_PHYS_TARGET_NUM,
 } DISP_TARGET_PHYS;
 
+enum {
+	BLT_SWITCH_TG_OFF,
+	BLT_SWITCH_TG_ON
+};
+
 /* panel info type */
 struct lcd_panel_info {
 	__u32 vsync_enable;
@@ -65,6 +70,7 @@
 	__u32 v_pulse_width;
 	__u32 hw_vsync_mode;
 	__u32 vsync_notifier_period;
+	__u32 blt_ctrl;
 	__u32 rev;
 };
 
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_errors.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_errors.c
index 2af76f3..3646e8c 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_errors.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_errors.c
@@ -218,6 +218,7 @@
 			}
 			break;
 		}
+	case VIDC_1080P_ERROR_NON_IDR_FRAME_TYPE:
 	case VIDC_1080P_ERROR_BIT_STREAM_BUF_EXHAUST:
 	case VIDC_1080P_ERROR_DESCRIPTOR_TABLE_ENTRY_INVALID:
 	case VIDC_1080P_ERROR_MB_COEFF_NOT_DONE:
@@ -243,14 +244,16 @@
 	case VIDC_1080P_ERROR_NON_PAIRED_FIELD_NOT_SUPPORTED:
 	case VIDC_1080P_ERROR_DESCRIPTOR_BUFFER_EMPTY:
 		vcd_status = VCD_ERR_BITSTREAM_ERR;
-		DDL_MSG_ERROR("VIDC_BIT_STREAM_ERR");
+		DDL_MSG_ERROR("VIDC_BIT_STREAM_ERR (%u)",
+			(u32)ddl_context->cmd_err_status);
 		break;
 	case VIDC_1080P_ERROR_B_FRAME_NOT_SUPPORTED:
 	case VIDC_1080P_ERROR_UNSUPPORTED_FEATURE_IN_PROFILE:
 	case VIDC_1080P_ERROR_RESOLUTION_NOT_SUPPORTED:
 		if (ddl->decoding) {
 			vcd_status = VCD_ERR_BITSTREAM_ERR;
-			DDL_MSG_ERROR("VIDC_BIT_STREAM_ERR");
+			DDL_MSG_ERROR("VIDC_BIT_STREAM_ERR (%u)",
+				(u32)ddl_context->cmd_err_status);
 		}
 		break;
 	default:
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
index 8cfa95b..2c41ab4 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
@@ -493,6 +493,7 @@
 				ddl_get_state_string(ddl->client_state));
 			ddl_calc_core_proc_time(__func__, DEC_OP_TIME, ddl);
 			ddl_reset_core_time_variables(DEC_OP_TIME);
+			ddl_vidc_decode_reset_avg_time(ddl);
 			ddl->client_state = DDL_CLIENT_WAIT_FOR_FRAME;
 			ddl_vidc_decode_frame_run(ddl);
 			ret_status = false;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
index 31f60e5..4b5fbf5 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
@@ -13,7 +13,7 @@
 #include <linux/memory_alloc.h>
 #include <linux/delay.h>
 #include <mach/msm_subsystem_map.h>
-#include <mach/peripheral-loader.h>
+#include <mach/subsystem_restart.h>
 #include "vcd_ddl_utils.h"
 #include "vcd_ddl.h"
 #include "vcd_res_tracker_api.h"
@@ -70,7 +70,7 @@
 		alloc_size = (alloc_size+4095) & ~4095;
 		addr->alloc_handle = ion_alloc(
 		ddl_context->video_ion_client, alloc_size, SZ_4K,
-			res_trk_get_mem_type(), 0);
+			res_trk_get_mem_type(), res_trk_get_ion_flags());
 		if (IS_ERR_OR_NULL(addr->alloc_handle)) {
 			DDL_MSG_ERROR("%s() :DDL ION alloc failed\n",
 						 __func__);
@@ -361,12 +361,12 @@
 			pr_err("Failed to enable iommu clocks\n");
 			return false;
 		}
-		dram_base->pil_cookie = pil_get("vidc");
+		dram_base->pil_cookie = subsystem_get("vidc");
 		if (res_trk_disable_iommu_clocks())
 			pr_err("Failed to disable iommu clocks\n");
 		if (IS_ERR_OR_NULL(dram_base->pil_cookie)) {
 			res_trk_disable_footswitch();
-			pr_err("pil_get failed\n");
+			pr_err("subsystem_get failed\n");
 			return false;
 		}
 	} else {
@@ -398,7 +398,7 @@
 		pr_err("Failed to enable iommu clocks\n");
 		return;
 	}
-	pil_put(cookie);
+	subsystem_put(cookie);
 	if (res_trk_disable_iommu_clocks())
 		pr_err("Failed to disable iommu clocks\n");
 	if (res_trk_disable_footswitch())
diff --git a/drivers/video/msm/vidc/1080p/ddl/vidc.h b/drivers/video/msm/vidc/1080p/ddl/vidc.h
index 22fcd1c..117612b 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vidc.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vidc.h
@@ -103,6 +103,7 @@
 #define VIDC_1080P_ERROR_SPS_PARSE_ERROR         129
 #define VIDC_1080P_ERROR_PPS_PARSE_ERROR         130
 #define VIDC_1080P_ERROR_SLICE_PARSE_ERROR       131
+#define VIDC_1080P_ERROR_NON_IDR_FRAME_TYPE      132
 #define VIDC_1080P_ERROR_SYNC_POINT_NOT_RECEIVED  171
 
 #define VIDC_1080P_WARN_COMMAND_FLUSHED                  145
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
index 0bc2228..d9cadef 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
@@ -209,7 +209,8 @@
 			addr->alloc_handle = ion_alloc(
 					ddl_context->video_ion_client,
 					 alloc_size, SZ_4K,
-					res_trk_get_mem_type(), 0);
+					res_trk_get_mem_type(),
+					res_trk_get_ion_flags());
 			if (IS_ERR_OR_NULL(addr->alloc_handle)) {
 				DDL_MSG_ERROR("%s() :DDL ION alloc failed\n",
 						__func__);
@@ -452,6 +453,10 @@
 static struct ion_client *res_trk_create_ion_client(void){
 	struct ion_client *video_client;
 	video_client = msm_ion_client_create(-1, "video_client");
+	if (IS_ERR_OR_NULL(video_client)) {
+		VCDRES_MSG_ERROR("%s: Unable to create ION client\n", __func__);
+		video_client = NULL;
+	}
 	return video_client;
 }
 
@@ -826,17 +831,31 @@
 	if (resource_context.vidc_platform_data->enable_ion) {
 		if (res_trk_check_for_sec_session()) {
 			mem_type = ION_HEAP(mem_type);
-	if (resource_context.res_mem_type != DDL_FW_MEM)
-		mem_type |= ION_SECURE;
-	else if (res_trk_is_cp_enabled())
-		mem_type |= ION_SECURE;
 	} else
 		mem_type = (ION_HEAP(mem_type) |
 			ION_HEAP(ION_IOMMU_HEAP_ID));
 	}
+
 	return mem_type;
 }
 
+unsigned int res_trk_get_ion_flags(void)
+{
+	unsigned int flags = 0;
+	if (resource_context.res_mem_type == DDL_FW_MEM)
+		return flags;
+
+	if (resource_context.vidc_platform_data->enable_ion) {
+		if (res_trk_check_for_sec_session()) {
+			if (resource_context.res_mem_type != DDL_FW_MEM)
+				flags |= ION_SECURE;
+			else if (res_trk_is_cp_enabled())
+				flags |= ION_SECURE;
+		}
+	}
+	return flags;
+}
+
 u32 res_trk_is_cp_enabled(void)
 {
 	if (resource_context.vidc_platform_data->cp_enabled)
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h
index 2ae2512..ee876f4 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h
@@ -30,6 +30,7 @@
 u32 res_trk_get_core_type(void);
 u32 res_trk_get_firmware_addr(struct ddl_buf_addr *firm_addr);
 int res_trk_get_mem_type(void);
+unsigned int res_trk_get_ion_flags(void);
 u32 res_trk_get_enable_ion(void);
 u32 res_trk_is_cp_enabled(void);
 u32 res_trk_get_disable_fullhd(void);
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c
index 3b40640..9fb8162 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c
@@ -125,9 +125,8 @@
 					alloc_size,
 					SZ_4K,
 					buff_addr->mem_type, 0);
-		if (!buff_addr->alloc_handle) {
-			ERR("\n%s(): DDL ION alloc failed\n",
-					__func__);
+		if (IS_ERR_OR_NULL(buff_addr->alloc_handle)) {
+			ERR("\n%s(): DDL ION alloc failed\n", __func__);
 			goto bailout;
 		}
 		ret = ion_phys(ddl_context->video_ion_client,
diff --git a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
index aee9dfe..c83faa6 100644
--- a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
@@ -681,6 +681,10 @@
 	struct ion_client *video_client;
 	VCDRES_MSG_LOW("%s", __func__);
 	video_client = msm_ion_client_create(-1, "video_client");
+	if (IS_ERR_OR_NULL(video_client)) {
+		VCDRES_MSG_ERROR("%s: Unable to create ION client\n", __func__);
+		video_client = NULL;
+	}
 	return video_client;
 }
 
@@ -760,6 +764,11 @@
 	return 0;
 }
 
+u32 res_trk_get_ion_flags(void)
+{
+	return 0;
+}
+
 int res_trk_check_for_sec_session()
 {
 	return 0;
diff --git a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker_api.h b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker_api.h
index 75fdb3e..a20d9f2 100644
--- a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker_api.h
+++ b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker_api.h
@@ -29,6 +29,7 @@
 u32 res_trk_get_core_type(void);
 u32 res_trk_get_mem_type(void);
 u32 res_trk_get_disable_fullhd(void);
+u32 res_trk_get_ion_flags(void);
 u32 res_trk_get_enable_ion(void);
 u32 res_trk_is_cp_enabled(void);
 struct ion_client *res_trk_get_ion_client(void);
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index 5fdee02..a9709fb 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -92,8 +92,8 @@
 	} else {
 		map_buffer->alloc_handle = ion_alloc(
 			    cctxt->vcd_ion_client, sz, SZ_4K,
-			    memtype, 0);
-		if (!map_buffer->alloc_handle) {
+			    memtype, res_trk_get_ion_flags());
+		if (IS_ERR_OR_NULL(map_buffer->alloc_handle)) {
 			pr_err("%s() ION alloc failed", __func__);
 			goto bailout;
 		}
diff --git a/include/drm/kgsl_drm.h b/include/drm/kgsl_drm.h
index f1c7f4e..7ffae9d 100644
--- a/include/drm/kgsl_drm.h
+++ b/include/drm/kgsl_drm.h
@@ -19,6 +19,7 @@
 #define DRM_KGSL_GEM_UNLOCK_HANDLE 0x0C
 #define DRM_KGSL_GEM_UNLOCK_ON_TS 0x0D
 #define DRM_KGSL_GEM_CREATE_FD 0x0E
+#define DRM_KGSL_GEM_GET_ION_FD 0x0F
 
 #define DRM_IOCTL_KGSL_GEM_CREATE \
 DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_CREATE, struct drm_kgsl_gem_create)
@@ -75,6 +76,10 @@
 DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_CREATE_FD, \
 struct drm_kgsl_gem_create_fd)
 
+#define DRM_IOCTL_KGSL_GEM_GET_ION_FD \
+DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_GET_ION_FD, \
+struct drm_kgsl_gem_get_ion_fd)
+
 /* Maximum number of sub buffers per GEM object */
 #define DRM_KGSL_GEM_MAX_BUFFERS 2
 
@@ -189,4 +194,9 @@
 	uint32_t handle;
 };
 
+struct drm_kgsl_gem_get_ion_fd {
+	uint32_t ion_fd;
+	uint32_t handle;
+};
+
 #endif
diff --git a/include/linux/coresight-stm.h b/include/linux/coresight-stm.h
index bb3ebca..b156eba 100644
--- a/include/linux/coresight-stm.h
+++ b/include/linux/coresight-stm.h
@@ -1,5 +1,5 @@
-#ifndef __MACH_STM_H
-#define __MACH_STM_H
+#ifndef _LINUX_CORESIGHT_STM_H
+#define _LINUX_CORESIGHT_STM_H
 
 enum {
 	OST_ENTITY_NONE			= 0x00,
@@ -7,7 +7,8 @@
 	OST_ENTITY_TRACE_PRINTK		= 0x02,
 	OST_ENTITY_TRACE_MARKER		= 0x04,
 	OST_ENTITY_DEV_NODE		= 0x08,
-	OST_ENTITY_ALL			= 0x1F,
+	OST_ENTITY_QVIEW		= 0xFE,
+	OST_ENTITY_MAX			= 0xFF,
 };
 
 enum {
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 60fa04e..bb5f394 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -42,6 +42,7 @@
 #define DIAG_IOCTL_DCI_SUPPORT		22
 #define DIAG_IOCTL_DCI_REG		23
 #define DIAG_IOCTL_DCI_STREAM_INIT	24
+#define DIAG_IOCTL_DCI_HEALTH_STATS	25
 
 /* PC Tools IDs */
 #define APQ8060_TOOLS_ID	4062
diff --git a/include/linux/dma-attrs.h b/include/linux/dma-attrs.h
index 547ab56..18513e3 100644
--- a/include/linux/dma-attrs.h
+++ b/include/linux/dma-attrs.h
@@ -15,6 +15,8 @@
 	DMA_ATTR_WEAK_ORDERING,
 	DMA_ATTR_WRITE_COMBINE,
 	DMA_ATTR_NON_CONSISTENT,
+	DMA_ATTR_NO_KERNEL_MAPPING,
+	DMA_ATTR_STRONGLY_ORDERED,
 	DMA_ATTR_MAX,
 };
 
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index 348a231..fe23993 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/i2c/atmel_mxt_ts.h
@@ -74,6 +74,7 @@
 	u32 irq_gpio_flags;
 	int *key_codes;
 	bool need_calibration;
+	bool no_force_update;
 
 	u8(*read_chg) (void);
 	int (*init_hw) (bool);
diff --git a/include/linux/ion.h b/include/linux/ion.h
index 85e5002..211327f 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -222,11 +222,9 @@
  * ion_map_kernel - create mapping for the given handle
  * @client:	the client
  * @handle:	handle to map
- * @flags:	flags for this mapping
  *
  * Map the given handle into the kernel and return a kernel address that
- * can be used to access this address. If no flags are specified, this
- * will return a non-secure uncached mapping.
+ * can be used to access this address.
  */
 void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle);
 
@@ -418,7 +416,7 @@
 }
 
 static inline void *ion_map_kernel(struct ion_client *client,
-	struct ion_handle *handle, unsigned long flags)
+	struct ion_handle *handle)
 {
 	return ERR_PTR(-ENODEV);
 }
@@ -453,6 +451,12 @@
 	return -ENODEV;
 }
 
+static inline int ion_handle_get_size(struct ion_client *client,
+				struct ion_handle *handle, unsigned long *size)
+{
+	return -ENODEV;
+}
+
 static inline void ion_unmap_iommu(struct ion_client *client,
 			struct ion_handle *handle, int domain_num,
 			int partition_num)
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index f581c8f..37b1fdc 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -486,7 +486,7 @@
 		  __attribute__((section("__trace_printk_fmt"))) =	\
 			__builtin_constant_p(fmt) ? fmt : NULL;		\
 									\
-		__trace_bprintk(_THIS_IP_, trace_printk_fmt, ##args);	\
+		__trace_printk(_THIS_IP_, trace_printk_fmt, ##args);	\
 	} else								\
 		__trace_printk(_THIS_IP_, fmt, ##args);		\
 } while (0)
diff --git a/include/linux/mfd/pm8xxx/pm8038.h b/include/linux/mfd/pm8xxx/pm8038.h
index 574dab6..9e25b5c 100644
--- a/include/linux/mfd/pm8xxx/pm8038.h
+++ b/include/linux/mfd/pm8xxx/pm8038.h
@@ -83,6 +83,7 @@
 	struct pm8921_bms_platform_data		*bms_pdata;
 	struct pm8xxx_adc_platform_data		*adc_pdata;
 	struct pm8xxx_led_platform_data		*leds_pdata;
+	struct pm8xxx_vibrator_platform_data	*vibrator_pdata;
 	struct pm8xxx_ccadc_platform_data	*ccadc_pdata;
 	struct pm8xxx_spk_platform_data		*spk_pdata;
 };
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index 5f2fe9f..ba70c96 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -127,6 +127,15 @@
  *					soc stored in a coincell backed register
  */
 void pm8921_bms_invalidate_shutdown_soc(void);
+
+/**
+ * pm8921_bms_cc_uah -	function to get the coulomb counter based charge. Note
+ *			that the coulomb counter are reset when the current
+ *			consumption is low (below 8mA for more than 5 minutes),
+ *			This will lead in a very low coulomb counter charge
+ *			value upon wakeup from sleep.
+ */
+int pm8921_bms_cc_uah(int *cc_uah);
 #else
 static inline int pm8921_bms_get_vsense_avg(int *result)
 {
@@ -165,6 +174,10 @@
 static inline void pm8921_bms_invalidate_shutdown_soc(void)
 {
 }
+static inline int pm8921_bms_cc_uah(int *cc_uah)
+{
+	return -ENXIO;
+}
 #endif
 
 #endif
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index 130fb54..4ad55f4 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -58,7 +58,6 @@
 
 /**
  * struct pm8921_charger_platform_data -
- * @safety_time:	max charging time in minutes incl. fast and trkl
  *			valid range 4 to 512 min. PON default 120 min
  * @ttrkl_time:		max trckl charging time in minutes
  *			valid range 1 to 64 mins. PON default 15 min
@@ -70,6 +69,9 @@
  *			trickle to fast. This is also the minimum voltage the
  *			system operates at
  * @uvd_thresh_voltage:	the USB falling UVD threshold (mV) (PM8917 only)
+ * @safe_current_ma:	The upper limit of current allowed to be pushed in
+ *			battery. This ends up writing in a one time
+ *			programmable register.
  * @resume_voltage_delta:	the (mV) drop to wait for before resume charging
  *				after the battery has been fully charged
  * @resume_charge_percent:	the % SOC the charger will drop to after the
@@ -127,12 +129,12 @@
  */
 struct pm8921_charger_platform_data {
 	struct pm8xxx_charger_core_data	charger_cdata;
-	unsigned int			safety_time;
 	unsigned int			ttrkl_time;
 	unsigned int			update_time;
 	unsigned int			max_voltage;
 	unsigned int			min_voltage;
 	unsigned int			uvd_thresh_voltage;
+	unsigned int			safe_current_ma;
 	unsigned int			alarm_low_mv;
 	unsigned int			alarm_high_mv;
 	unsigned int			resume_voltage_delta;
diff --git a/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h b/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
index 4b7a32c..a1609b8 100644
--- a/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
+++ b/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
@@ -202,5 +202,7 @@
 #define WCD9XXX_A_MBHC_INSERT_DETECT__POR	(0x00)
 #define WCD9XXX_A_MBHC_INSERT_DET_STATUS	(0x14B) /* TAIKO and later */
 #define WCD9XXX_A_MBHC_INSERT_DET_STATUS__POR	(0x00)
+#define WCD9XXX_A_MAD_ANA_CTRL			(0x150)
+#define WCD9XXX_A_MAD_ANA_CTRL__POR		(0xF1)
 
 #endif
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index fb854ba..2046198 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -324,6 +324,7 @@
 #define MMC_QUIRK_BLK_NO_CMD23	(1<<7)		/* Avoid CMD23 for regular multiblock */
 #define MMC_QUIRK_BROKEN_BYTE_MODE_512 (1<<8)	/* Avoid sending 512 bytes in */
 #define MMC_QUIRK_LONG_READ_TIME (1<<9)		/* Data read time > CSD says */
+#define MMC_QUIRK_SEC_ERASE_TRIM_BROKEN (1<<10)	/* Skip secure for erase/trim */
 						/* byte mode */
 #define MMC_QUIRK_INAND_DATA_TIMEOUT  (1<<8)    /* For incorrect data timeout */
 
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index f8a3a10..08f74e6 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -61,6 +61,14 @@
 	MIGRATE_TYPES
 };
 
+/*
+ * Returns a list which contains the migrate types on to which
+ * an allocation falls back when the free list for the migrate
+ * type mtype is depleted.
+ * The end of the list is delimited by the type MIGRATE_RESERVE.
+ */
+extern int *get_migratetype_fallbacks(int mtype);
+
 #ifdef CONFIG_CMA
 #  define is_migrate_cma(migratetype) unlikely((migratetype) == MIGRATE_CMA)
 #  define cma_wmark_pages(zone)	zone->min_cma_pages
diff --git a/include/linux/msm_ion.h b/include/linux/msm_ion.h
index c1ea490..ec043dd 100644
--- a/include/linux/msm_ion.h
+++ b/include/linux/msm_ion.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -39,8 +39,10 @@
 	ION_CP_MFC_HEAP_ID = 12,
 	ION_CP_WB_HEAP_ID = 16, /* 8660 only */
 	ION_CAMERA_HEAP_ID = 20, /* 8660 only */
+	ION_PIL1_HEAP_ID = 23, /* Currently used for other PIL images */
 	ION_SF_HEAP_ID = 24,
 	ION_IOMMU_HEAP_ID = 25,
+	ION_PIL2_HEAP_ID = 26, /* Currently used for modem firmware images */
 	ION_QSECOM_HEAP_ID = 27,
 	ION_AUDIO_HEAP_ID = 28,
 
@@ -86,6 +88,8 @@
 #define ION_MFC_HEAP_NAME	"mfc"
 #define ION_WB_HEAP_NAME	"wb"
 #define ION_MM_FIRMWARE_HEAP_NAME	"mm_fw"
+#define ION_PIL1_HEAP_NAME  "pil_1"
+#define ION_PIL2_HEAP_NAME  "pil_2"
 #define ION_QSECOM_HEAP_NAME	"qsecom"
 #define ION_FMEM_HEAP_NAME	"fmem"
 
diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h
index d229ad3..1717cd9 100644
--- a/include/linux/of_irq.h
+++ b/include/linux/of_irq.h
@@ -11,7 +11,7 @@
 #include <linux/of.h>
 
 /*
- * irq_of_parse_and_map() is used ba all OF enabled platforms; but SPARC
+ * irq_of_parse_and_map() is used by all OF enabled platforms; but SPARC
  * implements it differently.  However, the prototype is the same for all,
  * so declare it here regardless of the CONFIG_OF_IRQ setting.
  */
@@ -76,5 +76,13 @@
 extern void of_irq_init(const struct of_device_id *matches);
 
 #endif /* CONFIG_OF_IRQ */
-#endif /* CONFIG_OF */
+
+#else /* !CONFIG_OF */
+static inline unsigned int irq_of_parse_and_map(struct device_node *dev,
+						int index)
+{
+	return 0;
+}
+#endif /* !CONFIG_OF */
+
 #endif /* __OF_IRQ_H */
diff --git a/include/linux/qmi_encdec.h b/include/linux/qmi_encdec.h
new file mode 100644
index 0000000..4c5f6d3
--- /dev/null
+++ b/include/linux/qmi_encdec.h
@@ -0,0 +1,169 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _QMI_ENCDEC_H_
+#define _QMI_ENCDEC_H_
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/list.h>
+#include <linux/socket.h>
+#include <linux/gfp.h>
+
+#define QMI_REQUEST_CONTROL_FLAG 0x00
+#define QMI_RESPONSE_CONTROL_FLAG 0x02
+#define QMI_INDICATION_CONTROL_FLAG 0x04
+#define QMI_HEADER_SIZE 7
+
+/**
+ * elem_type - Enum to identify the data type of elements in a data
+ *             structure.
+ */
+enum elem_type {
+	QMI_OPT_FLAG = 1,
+	QMI_DATA_LEN,
+	QMI_UNSIGNED_1_BYTE,
+	QMI_UNSIGNED_2_BYTE,
+	QMI_UNSIGNED_4_BYTE,
+	QMI_UNSIGNED_8_BYTE,
+	QMI_SIGNED_2_BYTE_ENUM,
+	QMI_SIGNED_4_BYTE_ENUM,
+	QMI_STRUCT,
+	QMI_EOTI,
+};
+
+/**
+ * array_type - Enum to identify if an element in a data structure is
+ *              an array. If so, then is it a static length array or a
+ *              variable length array.
+ */
+enum array_type {
+	NO_ARRAY = 0,
+	STATIC_ARRAY = 1,
+	VAR_LEN_ARRAY = 2,
+};
+
+/**
+ * elem_info - Data structure to specify information about an element
+ *               in a data structure. An array of this data structure
+ *               can be used to specify info about a complex data
+ *               structure to be encoded/decoded.
+ *
+ * @data_type: Data type of this element.
+ * @elem_len: Array length of this element, if an array.
+ * @elem_size: Size of a single instance of this data type.
+ * @is_array: Array type of this element.
+ * @tlv_type: QMI message specific type to identify which element
+ *            is present in an incoming message.
+ * @offset: To identify the address of the first instance of this
+ *          element in the data structure.
+ * @ei_array: Array to provide information about the nested structure
+ *            within a data structure to be encoded/decoded.
+ */
+struct elem_info {
+	enum elem_type data_type;
+	uint32_t elem_len;
+	uint32_t elem_size;
+	enum array_type is_array;
+	uint8_t tlv_type;
+	uint32_t offset;
+	struct elem_info *ei_array;
+};
+
+/**
+ * @msg_desc - Describe about the main/outer structure to be
+ *		  encoded/decoded.
+ *
+ * @max_msg_len: Maximum possible length of the QMI message.
+ * @ei_array: Array to provide information about a data structure.
+ */
+struct msg_desc {
+	uint16_t msg_id;
+	int max_msg_len;
+	struct elem_info *ei_array;
+};
+
+struct qmi_header {
+	unsigned char cntl_flag;
+	uint16_t txn_id;
+	uint16_t msg_id;
+	uint16_t msg_len;
+} __attribute__((__packed__));
+
+static inline void encode_qmi_header(unsigned char *buf,
+			unsigned char cntl_flag, uint16_t txn_id,
+			uint16_t msg_id, uint16_t msg_len)
+{
+	struct qmi_header *hdr = (struct qmi_header *)buf;
+
+	hdr->cntl_flag = cntl_flag;
+	hdr->txn_id = txn_id;
+	hdr->msg_id = msg_id;
+	hdr->msg_len = msg_len;
+}
+
+static inline void decode_qmi_header(unsigned char *buf,
+			unsigned char *cntl_flag, uint16_t *txn_id,
+			uint16_t *msg_id, uint16_t *msg_len)
+{
+	struct qmi_header *hdr = (struct qmi_header *)buf;
+
+	*cntl_flag = hdr->cntl_flag;
+	*txn_id = hdr->txn_id;
+	*msg_id = hdr->msg_id;
+	*msg_len = hdr->msg_len;
+}
+
+#ifdef CONFIG_QMI_ENCDEC
+/**
+ * qmi_kernel_encode() - Encode to QMI message wire format
+ * @desc: Pointer to structure descriptor.
+ * @out_buf: Buffer to hold the encoded QMI message.
+ * @out_buf_len: Length of the out buffer.
+ * @in_c_struct: C Structure to be encoded.
+ *
+ * @return: size of encoded message on success, < 0 on error.
+ */
+int qmi_kernel_encode(struct msg_desc *desc,
+		      void *out_buf, uint32_t out_buf_len,
+		      void *in_c_struct);
+
+/**
+ * qmi_kernel_decode() - Decode to C Structure format
+ * @desc: Pointer to structure descriptor.
+ * @out_c_struct: Buffer to hold the decoded C structure.
+ * @in_buf: Buffer containg the QMI message to be decoded.
+ * @in_buf_len: Length of the incoming QMI message.
+ *
+ * @return: 0 on success, < 0 on error.
+ */
+int qmi_kernel_decode(struct msg_desc *desc, void *out_c_struct,
+		      void *in_buf, uint32_t in_buf_len);
+
+#else
+static inline int qmi_kernel_encode(struct msg_desc *desc,
+				    void *out_buf, uint32_t out_buf_len,
+				    void *in_c_struct)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline int qmi_kernel_decode(struct msg_desc *desc,
+				    void *out_c_struct,
+				    void *in_buf, uint32_t in_buf_len)
+{
+	return -EOPNOTSUPP;
+}
+#endif
+
+#endif
diff --git a/include/linux/qpnp/pin.h b/include/linux/qpnp/pin.h
index fa9c30f..fff29ab 100644
--- a/include/linux/qpnp/pin.h
+++ b/include/linux/qpnp/pin.h
@@ -131,7 +131,7 @@
  *			the input is interpreted as a logical 1.
  * @out_strength:	the amount of current supplied for an output gpio,
  *			should be of the type QPNP_PIN_STRENGTH_*.
- * @select:		select alternate function for the pin. Certain pins
+ * @src_sel:		select alternate function for the pin. Certain pins
  *			can be paired (shorted) with each other. Some pins
  *			can act as alternate functions. In the context of
  *			gpio, this acts as a source select. For mpps,
@@ -159,7 +159,7 @@
 	int pull;
 	int vin_sel;
 	int out_strength;
-	int select;
+	int src_sel;
 	int master_en;
 	int aout_ref;
 	int ain_route;
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index e5516ab..9d5de90 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -137,7 +137,7 @@
 };
 
 #define QPNP_ADC_625_UV	625000
-#define QPNP_ADC_HWMON_NAME_LENGTH				16
+#define QPNP_ADC_HWMON_NAME_LENGTH				64
 
 /**
  * enum qpnp_adc_decimation_type - Sampling rate supported.
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 1f13da3..0a1428e 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -2041,6 +2041,7 @@
 extern unsigned int sysctl_sched_min_granularity;
 extern unsigned int sysctl_sched_wakeup_granularity;
 extern unsigned int sysctl_sched_child_runs_first;
+extern unsigned int sysctl_sched_wake_to_idle;
 
 enum sched_tunable_scaling {
 	SCHED_TUNABLESCALING_NONE,
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 6938a86..742b9e4 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -365,6 +365,13 @@
 
 	/* protects deactivations and delayed_status counts*/
 	spinlock_t			lock;
+
+	/*
+	 * specify the mA units for the bMaxPower field in
+	 * the configuration descriptor. Should be 2mA for HS
+	 * and 8mA for SS.
+	 */
+	int vbus_draw_units;
 };
 
 extern int usb_string_id(struct usb_composite_dev *c);
diff --git a/include/linux/usb/ehci_pdriver.h b/include/linux/usb/ehci_pdriver.h
index 1894f42..4c1b7a0 100644
--- a/include/linux/usb/ehci_pdriver.h
+++ b/include/linux/usb/ehci_pdriver.h
@@ -41,6 +41,7 @@
 	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 a998ac2..578b9f9 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -199,6 +199,8 @@
  *              is connected.
  * @core_clk_always_on_workaround: Don't disable core_clk when
  *              USB enters LPM.
+ * @delay_lpm_on_disconnect: Use a delay before entering LPM
+ *              upon USB cable disconnection.
  * @bus_scale_table: parameters for bus bandwidth requirements
  * @mhl_dev_name: MHL device name used to register with MHL driver.
  */
@@ -218,6 +220,7 @@
 	bool pnoc_errata_fix;
 	bool enable_lpm_on_dev_suspend;
 	bool core_clk_always_on_workaround;
+	bool delay_lpm_on_disconnect;
 	struct msm_bus_scale_pdata *bus_scale_table;
 	const char *mhl_dev_name;
 };
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index 7a194ca..6d2eee4 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -31,6 +31,8 @@
 };
 
 #define WCNSS_WLAN_IRQ_INVALID -1
+#define HAVE_WCNSS_SUSPEND_RESUME_NOTIFY 1
+#define HAVE_WCNSS_RESET_INTR 1
 
 struct device *wcnss_wlan_get_device(void);
 struct resource *wcnss_wlan_get_memory_map(struct device *dev);
@@ -59,6 +61,8 @@
 void *wcnss_prealloc_get(unsigned int size);
 int wcnss_prealloc_put(void *ptr);
 void wcnss_reset_intr(void);
+void wcnss_suspend_notify(void);
+void wcnss_resume_notify(void);
 
 #define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev)
 #define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data))
diff --git a/include/media/Kbuild b/include/media/Kbuild
index 4b6e6a9..70f6334 100644
--- a/include/media/Kbuild
+++ b/include/media/Kbuild
@@ -7,3 +7,4 @@
 header-y += msm_gestures.h
 header-y += msm_mercury.h
 header-y += msm_jpeg.h
+header-y += msm_media_info.h
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 9af15e3..a932011 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1981,6 +1981,7 @@
 	IRQ_ROUTER_DEV,
 	CPP_DEV,
 	CCI_DEV,
+	FLASH_DEV,
 };
 
 struct msm_mctl_set_sdev_data {
diff --git a/include/media/msm_media_info.h b/include/media/msm_media_info.h
new file mode 100644
index 0000000..3098bfe
--- /dev/null
+++ b/include/media/msm_media_info.h
@@ -0,0 +1,113 @@
+#ifndef __MEDIA_INFO_H__
+#define __MEDIA_INFO_H__
+
+#ifndef ALIGN
+#define ALIGN(__sz, __align) (((__sz) + (__align-1)) & (~(__align-1)))
+#endif
+
+enum color_fmts {
+	COLOR_FMT_NV12,
+};
+
+static inline unsigned int VENUS_Y_STRIDE(int color_fmt, int width)
+{
+	unsigned int alignment, stride = 0;
+	if (!width)
+		goto invalid_input;
+
+	switch (color_fmt) {
+	case COLOR_FMT_NV12:
+		alignment = 32;
+		stride = ALIGN(width, alignment);
+		break;
+	default:
+		break;
+	}
+invalid_input:
+	return stride;
+}
+
+static inline unsigned int VENUS_UV_STRIDE(int color_fmt, int width)
+{
+	unsigned int alignment, stride = 0;
+	if (!width)
+		goto invalid_input;
+
+	switch (color_fmt) {
+	case COLOR_FMT_NV12:
+		alignment = 32;
+		stride = ALIGN(((width + 1) >> 1), alignment) << 1;
+		break;
+	default:
+		break;
+	}
+invalid_input:
+	return stride;
+}
+
+static inline unsigned int VENUS_Y_SCANLINES(int color_fmt, int height)
+{
+	unsigned int alignment, sclines = 0;
+	if (!height)
+		goto invalid_input;
+
+	switch (color_fmt) {
+	case COLOR_FMT_NV12:
+		alignment = 32;
+		sclines = ALIGN(height, alignment);
+		break;
+	default:
+		break;
+	}
+invalid_input:
+	return sclines;
+}
+
+static inline unsigned int VENUS_UV_SCANLINES(int color_fmt, int height)
+{
+	unsigned int alignment, sclines = 0;
+	if (!height)
+		goto invalid_input;
+
+	switch (color_fmt) {
+	case COLOR_FMT_NV12:
+		alignment = 32;
+		sclines = ALIGN(((height + 1) >> 1), alignment);
+		break;
+	default:
+		break;
+	}
+invalid_input:
+	return sclines;
+}
+
+static inline unsigned int VENUS_BUFFER_SIZE(
+	int color_fmt, int width, int height)
+{
+	unsigned int uv_alignment;
+	unsigned int size = 0;
+	unsigned int y_plane, uv_plane, y_stride,
+		uv_stride, y_sclines, uv_sclines;
+	if (!width || !height)
+		goto invalid_input;
+
+	y_stride = VENUS_Y_STRIDE(color_fmt, width);
+	uv_stride = VENUS_UV_STRIDE(color_fmt, width);
+	y_sclines = VENUS_Y_SCANLINES(color_fmt, height);
+	uv_sclines = VENUS_UV_SCANLINES(color_fmt, height);
+	switch (color_fmt) {
+	case COLOR_FMT_NV12:
+		uv_alignment = 32;
+		y_plane = y_stride * y_sclines;
+		uv_plane = uv_stride * uv_sclines + uv_alignment;
+		size = y_plane + uv_plane;
+		size = ALIGN(size, 4096);
+		break;
+	default:
+		break;
+	}
+invalid_input:
+	return size;
+}
+
+#endif
diff --git a/include/media/radio-iris.h b/include/media/radio-iris.h
index db69518..0efeff4 100644
--- a/include/media/radio-iris.h
+++ b/include/media/radio-iris.h
@@ -363,6 +363,53 @@
 #define HCI_REQ_CANCELED  2
 #define HCI_REQ_STATUS    3
 
+#define MAX_RAW_RDS_GRPS	21
+
+#define RDSGRP_DATA_OFFSET	 0x1
+
+/*RT PLUS*/
+#define DUMMY_CLASS		0
+#define RT_PLUS_LEN_1_TAG	3
+#define RT_ERT_FLAG_BIT		5
+
+/*TAG1*/
+#define TAG1_MSB_OFFSET		3
+#define TAG1_MSB_MASK		7
+#define TAG1_LSB_OFFSET		5
+#define TAG1_POS_MSB_MASK	31
+#define TAG1_POS_MSB_OFFSET	1
+#define TAG1_POS_LSB_OFFSET	7
+#define TAG1_LEN_OFFSET		1
+#define TAG1_LEN_MASK		63
+
+/*TAG2*/
+#define TAG2_MSB_OFFSET		5
+#define TAG2_MSB_MASK		1
+#define TAG2_LSB_OFFSET		3
+#define TAG2_POS_MSB_MASK	7
+#define TAG2_POS_MSB_OFFSET	3
+#define TAG2_POS_LSB_OFFSET	5
+#define TAG2_LEN_MASK		31
+
+#define AGT_MASK		31
+/*Extract 5 left most bits of lsb of 2nd block*/
+#define AGT(x)			(x & AGT_MASK)
+/*16 bits of 4th block*/
+#define AID(lsb, msb)		((msb << 8) | (lsb))
+/*Extract 5 right most bits of msb of 2nd block*/
+#define GTC(blk2msb)		(blk2msb >> 3)
+
+#define GRP_3A			0x6
+#define RT_PLUS_AID		0x4bd7
+
+/*ERT*/
+#define ERT_AID			0x6552
+#define CARRIAGE_RETURN		0x000D
+#define MAX_ERT_SEGMENT		31
+#define ERT_FORMAT_DIR_BIT	1
+
+#define EXTRACT_BIT(data, bit_pos) ((data & (1 << bit_pos)) >> bit_pos)
+
 struct hci_ev_tune_status {
 	__u8    sub_event;
 	__le32  station_freq;
@@ -375,9 +422,19 @@
 	__u8	intf_det_th;
 } __packed;
 
+struct rds_blk_data {
+	__u8	rdsMsb;
+	__u8	rdsLsb;
+	__u8	blockStatus;
+} __packed;
+
+struct rds_grp_data {
+	struct rds_blk_data rdsBlk[4];
+} __packed;
+
 struct hci_ev_rds_rx_data {
 	__u8    num_rds_grps;
-	__u8    rds_grp_data[12];
+	struct  rds_grp_data rds_grp_data[MAX_RAW_RDS_GRPS];
 } __packed;
 
 struct hci_ev_prg_service {
@@ -628,7 +685,10 @@
 	IRIS_EVT_NEW_AF_LIST,
 	IRIS_EVT_TXRDSDAT,
 	IRIS_EVT_TXRDSDONE,
-	IRIS_EVT_RADIO_DISABLED
+	IRIS_EVT_RADIO_DISABLED,
+	IRIS_EVT_NEW_ODA,
+	IRIS_EVT_NEW_RT_PLUS,
+	IRIS_EVT_NEW_ERT,
 };
 enum emphasis_type {
 	FM_RX_EMP75 = 0x0,
@@ -660,7 +720,7 @@
 	IRIS_REGION_OTHER
 };
 
-#define STD_BUF_SIZE        (128)
+#define STD_BUF_SIZE        (256)
 
 enum iris_buf_t {
 	IRIS_BUF_SRCH_LIST,
@@ -674,7 +734,9 @@
 	IRIS_BUF_RDS_CNTRS,
 	IRIS_BUF_RD_DEFAULT,
 	IRIS_BUF_CAL_DATA,
-	IRIS_BUF_MAX
+	IRIS_BUF_RT_PLUS,
+	IRIS_BUF_ERT,
+	IRIS_BUF_MAX,
 };
 
 enum iris_xfr_t {
diff --git a/include/media/tavarua.h b/include/media/tavarua.h
index 1cccb2b..881b851 100644
--- a/include/media/tavarua.h
+++ b/include/media/tavarua.h
@@ -52,7 +52,7 @@
 #define SRCH_MASK                  (1 << SRCH200KHZ_OFFSET)
 
 /* Standard buffer size */
-#define STD_BUF_SIZE               (128)
+#define STD_BUF_SIZE               (256)
 /* Search direction */
 #define SRCH_DIR_UP                 (0)
 #define SRCH_DIR_DOWN               (1)
diff --git a/include/media/vcap_fmt.h b/include/media/vcap_fmt.h
index 3b1bd7c2..84d9b42 100644
--- a/include/media/vcap_fmt.h
+++ b/include/media/vcap_fmt.h
@@ -24,12 +24,13 @@
 #define VCAP_VC_NPL_OFLOW_ERR_EVENT 4
 #define VCAP_VC_LBUF_OFLOW_ERR_EVENT 5
 #define VCAP_VC_BUF_OVERWRITE_EVENT 6
-#define VCAP_VP_REG_R_ERR_EVENT 7
-#define VCAP_VP_REG_W_ERR_EVENT 8
-#define VCAP_VP_IN_HEIGHT_ERR_EVENT 9
-#define VCAP_VP_IN_WIDTH_ERR_EVENT 10
-#define VCAP_VC_UNEXPECT_BUF_DONE 11
-#define VCAP_MAX_NOTIFY_EVENT 12
+#define VCAP_VC_VSYNC_SEQ_ERR 7
+#define VCAP_VP_REG_R_ERR_EVENT 8
+#define VCAP_VP_REG_W_ERR_EVENT 9
+#define VCAP_VP_IN_HEIGHT_ERR_EVENT 10
+#define VCAP_VP_IN_WIDTH_ERR_EVENT 11
+#define VCAP_VC_UNEXPECT_BUF_DONE 12
+#define VCAP_MAX_NOTIFY_EVENT 13
 
 enum hal_vcap_mode {
 	HAL_VCAP_MODE_PRO = 0,
@@ -119,8 +120,14 @@
 	VP_OUT_TYPE,
 };
 
+enum vcap_stride {
+	VC_STRIDE_16,
+	VC_STRIDE_32,
+};
+
 struct vcap_priv_fmt {
 	enum vcap_type type;
+	enum vcap_stride stride;
 	union {
 		struct v4l2_format_vc_ext timing;
 		struct v4l2_pix_format pix;
diff --git a/include/media/vcap_v4l2.h b/include/media/vcap_v4l2.h
index 3db949c..39aa1b9 100644
--- a/include/media/vcap_v4l2.h
+++ b/include/media/vcap_v4l2.h
@@ -39,10 +39,10 @@
 
 #define VCAP_USEC (1000000)
 
-#define VCAP_STRIDE_ALIGN 0x10
-#define VCAP_STRIDE_CALC(x) (((x / VCAP_STRIDE_ALIGN) + \
-			(!(!(x % VCAP_STRIDE_ALIGN)))) * \
-			VCAP_STRIDE_ALIGN)
+#define VCAP_STRIDE_ALIGN_16 0x10
+#define VCAP_STRIDE_ALIGN_32 0x20
+#define VCAP_STRIDE_CALC(x, align) (((x / align) + \
+			(!(!(x % align)))) * align)
 
 #define VCAP_BASE (dev->vcapbase)
 #define VCAP_OFFSET(off) (VCAP_BASE + off)
@@ -109,7 +109,7 @@
 	uint8_t					tot_buf;
 	uint8_t					buf_num;
 
-	bool					top_field;
+	bool					field1;
 	bool					field_dropped;
 
 	struct timeval			vc_ts;
@@ -241,6 +241,7 @@
 	enum vcap_op_mode		op_mode;
 
 	struct v4l2_format_vc_ext vc_format;
+	enum vcap_stride		stride;
 
 	enum v4l2_buf_type		vp_buf_type_field;
 	struct vp_format_data	vp_in_fmt;
@@ -254,6 +255,8 @@
 	uint32_t				hold_vc;
 	uint32_t				hold_vp;
 
+	/* Mutex ensures only one thread is dq buffer or turning streamoff */
+	struct mutex			mutex;
 	spinlock_t				cap_slock;
 	bool					streaming;
 
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 8c35ada..bfd7208 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -61,7 +61,7 @@
 #define RT_PROXY_PORT_001_TX	0x2001    /* index = 31 */
 #define SECONDARY_PCM_RX 12			/* index = 32 */
 #define SECONDARY_PCM_TX 13			/* index = 33 */
-
+#define PSEUDOPORT_01           0x8001    /* index =34 */
 
 #define AFE_PORT_INVALID 0xFFFF
 #define SLIMBUS_EXTPROC_RX AFE_PORT_INVALID
@@ -157,6 +157,55 @@
 	u16 reserved;
 } __attribute__ ((packed));
 
+/*
+ * Opcode for AFE to start DTMF.
+ */
+#define AFE_PORTS_CMD_DTMF_CTL	0x00010102
+
+/** DTMF payload.*/
+struct afe_dtmf_generation_command {
+	struct apr_hdr hdr;
+
+	/*
+	 * Duration of the DTMF tone in ms.
+	 * -1      -> continuous,
+	 *  0      -> disable
+	 */
+	int64_t                   duration_in_ms;
+
+	/*
+	 * The DTMF high tone frequency.
+	 */
+	uint16_t                  high_freq;
+
+	/*
+	 * The DTMF low tone frequency.
+	 */
+	uint16_t                  low_freq;
+
+	/*
+	 * The DTMF volume setting
+	 */
+	uint16_t                  gain;
+
+	/*
+	 * The number of ports to enable/disable on.
+	 */
+	uint16_t                  num_ports;
+
+	/*
+	 * The Destination ports - array  .
+	 * For DTMF on multiple ports, portIds needs to
+	 * be populated numPorts times.
+	 */
+	uint16_t                  port_ids;
+
+	/*
+	 * variable for 32 bit alignment of APR packet.
+	 */
+	uint16_t                  reserved;
+} __packed;
+
 #define AFE_PCM_CFG_MODE_PCM			0x0
 #define AFE_PCM_CFG_MODE_AUX			0x1
 #define AFE_PCM_CFG_SYNC_EXT			0x0
@@ -299,6 +348,14 @@
 	int	num_ch;		/* 1 to 8 */
 } __packed;
 
+struct afe_port_pseudo_cfg {
+	u16 bit_width;
+	u16 num_channels;
+	u16 data_format;
+	u16 timing_mode;
+	u16 reserved;
+} __packed;
+
 #define AFE_PORT_AUDIO_IF_CONFIG 0x000100d3
 #define AFE_PORT_AUDIO_SLIM_SCH_CONFIG 0x000100e4
 #define AFE_PORT_MULTI_CHAN_HDMI_AUDIO_IF_CONFIG	0x000100D9
@@ -312,6 +369,7 @@
 	struct afe_port_slimbus_cfg	  slimbus;
 	struct afe_port_slimbus_sch_cfg	  slim_sch;
 	struct afe_port_rtproxy_cfg       rtproxy;
+	struct afe_port_pseudo_cfg        pseudo;
 } __attribute__((packed));
 
 struct afe_audioif_config_command {
@@ -574,6 +632,19 @@
 	u32 rate;
 	u8 dev_channel_mapping[8];
 } __packed;
+
+struct adm_multi_channel_copp_open_v3 {
+	struct apr_hdr hdr;
+	u16 flags;
+	u16 mode;
+	u16 endpoint_id1;
+	u16 endpoint_id2;
+	u32 topology_id;
+	u16 channel_config;
+	u16 bit_width;
+	u32 rate;
+	u8  dev_channel_mapping[8];
+};
 #define ADM_CMD_MEMORY_MAP				0x00010C30
 struct adm_cmd_memory_map{
 	struct apr_hdr	hdr;
@@ -914,7 +985,38 @@
 				 * An unused channel is set to zero.
 				 */
 };
+struct asm_dts_enc_cfg {
+	uint32_t	sample_rate;
+	/*
+	* Samples at which input is to be encoded.
+	* Supported values:
+	* 44100 -- encode at 44.1 Khz
+	* 48000 -- encode at 48 Khz
+	*/
 
+	uint32_t	num_channels;
+	/*
+	* Number of channels for multi-channel encoding.
+	* Supported values: 1 to 6
+	*/
+
+	uint8_t		channel_mapping[6];
+	/*
+	* Channel array of size 16. Channel[i] mapping describes channel I.
+	* Each element i of the array describes channel I inside the buffer
+	* where num_channels. An unused channel is set to zero. Only first
+	* num_channels elements are valid
+
+	* Supported values:
+	* - # PCM_CHANNEL_L
+	* - # PCM_CHANNEL_R
+	* - # PCM_CHANNEL_C
+	* - # PCM_CHANNEL_LS
+	* - # PCM_CHANNEL_RS
+	* - # PCM_CHANNEL_LFE
+	*/
+
+};
 struct asm_adpcm_cfg {
 	u16 ch_cfg;
 	u16 bits_per_sample;
@@ -1107,6 +1209,7 @@
 		struct asm_sbc_read_cfg     sbc;
 		struct asm_amrwb_read_cfg   amrwb;
 		struct asm_multi_channel_pcm_fmt_blk      mpcm;
+		struct asm_dts_enc_cfg      dts;
 	} __attribute__((packed)) cfg;
 };
 
@@ -1209,6 +1312,148 @@
 	u32	flags;
 	u32	format;
 } __packed;
+#define ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK     0x00010DBA
+struct asm_stream_cmd_open_transcode_loopback {
+	struct apr_hdr hdr;
+	uint32_t	mode_flags;
+	/*
+	* All bits are reserved. Clients must set them to zero.
+	*/
+
+	uint32_t	src_format_id;
+	/*
+	* Specifies the media format of the input audio stream.
+
+	* Supported values:
+	* - #ASM_MEDIA_FMT_LINEAR_PCM
+	* - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM
+	*/
+
+	uint32_t	sink_format_id;
+	/*
+	* Specifies the media format of the output stream.
+
+	* Supported values:
+	* - #ASM_MEDIA_FMT_LINEAR_PCM
+	* - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM
+	* - #ASM_MEDIA_FMT_DTS
+	*/
+
+	uint32_t	audproc_topo_id;
+	/*
+	* Postprocessing topology ID, which specifies the topology (order of
+	* processing) of postprocessing algorithms.
+
+	* Supported values:
+	* - #ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT
+	* - #ASM_STREAM_POSTPROC_TOPO_ID_PEAKMETER
+	* - #ASM_STREAM_POSTPROC_TOPO_ID_NONE
+	* - #ASM_STREAM_POSTPROC_TOPO_ID_MCH_PEAK_VOL
+	*/
+
+	uint16_t	src_endpoint_type;
+	/*
+	* Specifies the source endpoint that provides the input samples.
+
+	* Supported values:
+	* - 0 -- Tx device matrix or stream router
+	* (gateway to the hardware ports)
+	* - All other values are reserved
+
+	* Clients must set this field to zero. Otherwise, an error is returned.
+	*/
+
+	uint16_t	sink_endpoint_type;
+	/*
+	* Specifies the sink endpoint type.
+
+	* Supported values:
+	* - 0 -- Rx device matrix or stream router
+	* (gateway to the hardware ports)
+	* - All other values are reserved
+
+	* Clients must set this field to zero. Otherwise, an error is returned.
+	*/
+
+	uint16_t	bits_per_sample;
+	/*
+	* Number of bits per sample processed by the ASM modules.
+	* Supported values: 16, 24
+	*/
+
+	uint16_t	reserved;
+	/*
+	* This field must be set to zero.
+	*/
+} __packed;
+
+/*
+* ID of the DTS mix LFE channel to front channels parameter in the
+* #ASM_STREAM_CMD_SET_ENCDEC_PARAM command.
+* asm_dts_generic_param_t
+* ASM_PARAM_ID_DTS_MIX_LFE_TO_FRONT
+*/
+#define ASM_PARAM_ID_DTS_MIX_LFE_TO_FRONT                          0x00010DB6
+
+/*
+* ID of the DTS DRC ratio parameter in the
+* #ASM_STREAM_CMD_SET_ENCDEC_PARAM command.
+* asm_dts_generic_param_t
+* ASM_PARAM_ID_DTS_DRC_RATIO
+*/
+#define ASM_PARAM_ID_DTS_DRC_RATIO                                   0x00010DB7
+
+/*
+* ID of the DTS enable dialog normalization parameter in the
+* #ASM_STREAM_CMD_SET_ENCDEC_PARAM command.
+
+* asm_dts_generic_param_t
+* ASM_PARAM_ID_DTS_ENABLE_DIALNORM
+*/
+#define ASM_PARAM_ID_DTS_ENABLE_DIALNORM                             0x00010DB8
+
+/*
+* ID of the DTS enable parse REV2AUX parameter in the
+* #ASM_STREAM_CMD_SET_ENCDEC_PARAM command.
+* asm_dts_generic_param_t
+* ASM_PARAM_ID_DTS_ENABLE_PARSE_REV2AUX
+*/
+#define ASM_PARAM_ID_DTS_ENABLE_PARSE_REV2AUX                         0x00010DB9
+
+struct asm_dts_generic_param {
+	int32_t		generic_parameter;
+	/*
+	* #ASM_PARAM_ID_DTS_MIX_LFE_TO_FRONT:
+	* - if enabled, mixes LFE channel to front
+	* while downmixing (if necessary)
+	* - Supported values: 1-> enable, 0-> disable
+	* - Default: disabled
+
+	* #ASM_PARAM_ID_DTS_DRC_RATIO:
+	* - percentage of DRC ratio.
+	* - Supported values: 0-100
+	* - Default: 0, DRC is disabled.
+
+	* #ASM_PARAM_ID_DTS_ENABLE_DIALNORM:
+	* - flag to enable dialog normalization post processing.
+	* - Supported values: 1-> enable, 0-> disable.
+	* - Default: enabled.
+
+	* #ASM_PARAM_ID_DTS_ENABLE_PARSE_REV2AUX:
+	* - flag to enable parsing of rev2aux chunk in the bitstream.
+	* This chunk contains broadcast metadata.
+	* - Supported values: 1-> enable, 0-> disable.
+	* - Default: disabled.
+	*/
+};
+
+struct asm_stream_cmd_dts_dec_param {
+	struct apr_hdr hdr;
+	u32            param_id;
+	u32            param_size;
+	struct asm_dts_generic_param generic_param;
+} __packed;
+
 
 #define ASM_STREAM_CMD_OPEN_READWRITE                    0x00010BCC
 
@@ -1238,7 +1483,7 @@
 	u8	session_id; /*ASM session ID*/
 	u16	afe_port_id;
 	u32	num_channels;
-	u32	sampleing_rate;
+	u32	sampling_rate;
 } __packed;
 
 #define ASM_STREAM_CMD_SET_ENCDEC_PARAM                  0x00010C10
diff --git a/include/sound/compress_params.h b/include/sound/compress_params.h
index 02d69ea..b95fa3c 100644
--- a/include/sound/compress_params.h
+++ b/include/sound/compress_params.h
@@ -88,6 +88,7 @@
 #define SND_AUDIOCODEC_DTS_TRANSCODE_LOOPBACK ((__u32) 0x00000014)
 #define SND_AUDIOCODEC_PASS_THROUGH          ((__u32) 0x00000015)
 #define SND_AUDIOCODEC_MP2                   ((__u32) 0x00000016)
+#define SND_AUDIOCODEC_DTS_LBR_PASS_THROUGH  ((__u32) 0x00000017)
 /*
  * Profile and modes are listed with bit masks. This allows for a
  * more compact representation of fields that will not evolve
@@ -417,6 +418,8 @@
 	__u32 ch_mode;
 	__u32 format;
 	__u32 align;
+	__u32 transcode_dts;
+	struct snd_dec_dts dts;
 	union snd_codec_options options;
 	__u32 reserved[3];
 };
diff --git a/include/sound/cs8427.h b/include/sound/cs8427.h
index 2004ec3..a1e988d 100644
--- a/include/sound/cs8427.h
+++ b/include/sound/cs8427.h
@@ -209,7 +209,8 @@
 	int irq_base;
 	int num_irqs;
 	int reset_gpio;
-	int (*enable) (int enable);
+	int (*enable) (int enable, int gpio);
+	int ls_gpio;
 };
 
 struct snd_pcm_substream;
diff --git a/include/sound/q6adm.h b/include/sound/q6adm.h
index 676c4cb..70c68a8 100644
--- a/include/sound/q6adm.h
+++ b/include/sound/q6adm.h
@@ -37,6 +37,8 @@
 
 int adm_close(int port);
 
+int adm_pseudo_close(int port);
+
 int adm_matrix_map(int session_id, int path, int num_copps,
 				unsigned int *port_id, int copp_id);
 
@@ -45,6 +47,12 @@
 
 void adm_ec_ref_rx_id(int  port_id);
 
+int adm_connect_afe_port_v2(int mode, int session_id, int port_id,
+					int sample_rate, int channels);
+
+int adm_multi_ch_copp_pseudo_open_v3(int port_id, int path, int rate,
+				int channel_mode, int topology);
+
 #ifdef CONFIG_RTAC
 int adm_get_copp_id(int port_id);
 #endif
diff --git a/include/sound/q6afe.h b/include/sound/q6afe.h
index a7264e8..1e12d48 100644
--- a/include/sound/q6afe.h
+++ b/include/sound/q6afe.h
@@ -70,6 +70,7 @@
 	IDX_RT_PROXY_PORT_001_TX = 31,
 	IDX_SECONDARY_PCM_RX = 32,
 	IDX_SECONDARY_PCM_TX = 33,
+	IDX_PSEUDOPORT_01 = 34,
 	AFE_MAX_PORTS
 };
 
@@ -87,7 +88,10 @@
 int afe_cmd_memory_map_nowait(u32 dma_addr_p, u32 dma_buf_sz);
 int afe_cmd_memory_unmap(u32 dma_addr_p);
 int afe_cmd_memory_unmap_nowait(u32 dma_addr_p);
-
+void afe_set_dtmf_gen_rx_portid(u16 rx_port_id, int set);
+int afe_dtmf_generate_rx(int64_t duration_in_ms,
+			 uint16_t high_freq,
+			 uint16_t low_freq, uint16_t gain);
 int afe_register_get_events(u16 port_id,
 		void (*cb) (uint32_t opcode,
 		uint32_t token, uint32_t *payload, void *priv),
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index b0d74ba..6b4c17b 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -55,6 +55,7 @@
 #define ENCDEC_SBCBITRATE   0x0001
 #define ENCDEC_IMMEDIATE_DECODE 0x0002
 #define ENCDEC_CFG_BLK          0x0003
+#define DTS_ENC_SAMPLE_RATE48k	48000
 
 #define CMD_PAUSE          0x0001
 #define CMD_FLUSH          0x0002
@@ -194,6 +195,11 @@
 
 int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format);
 
+int q6asm_open_transcode_loopback(struct audio_client *ac, uint32_t channels);
+
+int q6asm_enc_cfg_blk_dts(struct audio_client *ac,
+				uint32_t sample_rate, uint32_t channels);
+
 int q6asm_open_read_write(struct audio_client *ac,
 			uint32_t rd_format,
 			uint32_t wr_format);
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 9885a9e..b175073 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -77,6 +77,14 @@
 unsigned int sysctl_sched_child_runs_first __read_mostly;
 
 /*
+ * Controls whether, when SD_SHARE_PKG_RESOURCES is on, if all
+ * tasks go to idle CPUs when woken. If this is off, note that the
+ * per-task flag PF_WAKE_ON_IDLE can still cause a task to go to an
+ * idle CPU upon being woken.
+ */
+unsigned int __read_mostly sysctl_sched_wake_to_idle;
+
+/*
  * SCHED_OTHER wake-up granularity.
  * (default: 1 msec * (1 + ilog(ncpus)), units: nanoseconds)
  *
@@ -2654,7 +2662,8 @@
 	if (target == prev_cpu && idle_cpu(prev_cpu))
 		return prev_cpu;
 
-	if (!(current->flags & PF_WAKE_UP_IDLE) &&
+	if (!sysctl_sched_wake_to_idle &&
+	    !(current->flags & PF_WAKE_UP_IDLE) &&
 	    !(p->flags & PF_WAKE_UP_IDLE))
 		return target;
 
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index b693142..b390dad 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -264,6 +264,13 @@
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec,
 	},
+	{
+		.procname	= "sched_wake_to_idle",
+		.data		= &sysctl_sched_wake_to_idle,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec,
+	},
 #ifdef CONFIG_SCHED_DEBUG
 	{
 		.procname	= "sched_min_granularity_ns",
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index b9d1a73..700d2ae 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -1630,7 +1630,7 @@
 	memcpy(&entry->buf, trace_buf, len);
 	entry->buf[len] = '\0';
 	if (!filter_check_discard(call, entry, buffer, event)) {
-		stm_log(OST_ENTITY_TRACE_PRINTK, event, size);
+		stm_log(OST_ENTITY_TRACE_PRINTK, entry->buf, len + 1);
 		ring_buffer_unlock_commit(buffer, event);
 		ftrace_trace_stack(buffer, irq_flags, 6, pc);
 	}
@@ -3825,10 +3825,11 @@
 	if (entry->buf[cnt - 1] != '\n') {
 		entry->buf[cnt] = '\n';
 		entry->buf[cnt + 1] = '\0';
-	} else
+		stm_log(OST_ENTITY_TRACE_MARKER, entry->buf, cnt + 2);
+	} else {
 		entry->buf[cnt] = '\0';
-
-	stm_log(OST_ENTITY_TRACE_MARKER, event, size);
+		stm_log(OST_ENTITY_TRACE_MARKER, entry->buf, cnt + 1);
+	}
 	ring_buffer_unlock_commit(buffer, event);
 
 	written = cnt;
diff --git a/lib/Kconfig b/lib/Kconfig
index 4a8aba2..f1621d5 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -378,4 +378,13 @@
 	  Digital signature verification. Currently only RSA is supported.
 	  Implementation is done using GnuPG MPI library
 
+config QMI_ENCDEC
+	bool
+	help
+	  Library to encode & decode QMI messages from within
+	  the kernel. The kernel drivers encode the C structure into
+	  QMI message wire format and then send it over a transport.
+	  The kernel drivers receive the QMI message over a transport
+	  and then decode it into a C structure.
+
 endmenu
diff --git a/lib/Makefile b/lib/Makefile
index acd6869..0fbcb04 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -123,6 +123,8 @@
 
 obj-$(CONFIG_CLZ_TAB) += clz_tab.o
 
+obj-$(CONFIG_QMI_ENCDEC) += qmi_encdec.o
+
 hostprogs-y	:= gen_crc32table
 clean-files	:= crc32table.h
 
diff --git a/lib/qmi_encdec.c b/lib/qmi_encdec.c
new file mode 100644
index 0000000..d759885
--- /dev/null
+++ b/lib/qmi_encdec.c
@@ -0,0 +1,492 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/string.h>
+#include <linux/qmi_encdec.h>
+
+#include "qmi_encdec_priv.h"
+
+#define TLV_LEN_SIZE sizeof(uint16_t)
+#define TLV_TYPE_SIZE sizeof(uint8_t)
+
+static int _qmi_kernel_encode(struct elem_info *ei_array,
+			      void *out_buf, void *in_c_struct,
+			      int enc_level);
+
+static int _qmi_kernel_decode(struct elem_info *ei_array,
+			      void *out_c_struct,
+			      void *in_buf, uint32_t in_buf_len,
+			      int dec_level);
+
+/**
+ * qmi_kernel_encode() - Encode to QMI message wire format
+ * @desc: Pointer to structure descriptor.
+ * @out_buf: Buffer to hold the encoded QMI message.
+ * @out_buf_len: Length of the out buffer.
+ * @in_c_struct: C Structure to be encoded.
+ *
+ * @return: size of encoded message on success, < 0 for error.
+ */
+int qmi_kernel_encode(struct msg_desc *desc,
+		      void *out_buf, uint32_t out_buf_len,
+		      void *in_c_struct)
+{
+	int enc_level = 1;
+
+	if (!desc || !desc->ei_array)
+		return -EINVAL;
+
+	if (!out_buf || !in_c_struct)
+		return -EINVAL;
+
+	if (desc->max_msg_len < out_buf_len)
+		return -ETOOSMALL;
+
+	return _qmi_kernel_encode(desc->ei_array, out_buf,
+				  in_c_struct, enc_level);
+}
+EXPORT_SYMBOL(qmi_kernel_encode);
+
+/**
+ * qmi_encode_basic_elem() - Encodes elements of basic/primary data type
+ * @buf_dst: Buffer to store the encoded information.
+ * @buf_src: Buffer containing the elements to be encoded.
+ * @elem_len: Number of elements, in the buf_src, to be encoded.
+ * @elem_size: Size of a single instance of the element to be encoded.
+ *
+ * @return: number of bytes of encoded information.
+ *
+ * This function encodes the "elem_len" number of data elements, each of
+ * size "elem_size" bytes from the source buffer "buf_src" and stores the
+ * encoded information in the destination buffer "buf_dst". The elements are
+ * of primary data type which include uint8_t - uint64_t or similar. This
+ * function returns the number of bytes of encoded information.
+ */
+static int qmi_encode_basic_elem(void *buf_dst, void *buf_src,
+				 uint32_t elem_len, uint32_t elem_size)
+{
+	uint32_t i, rc = 0;
+
+	for (i = 0; i < elem_len; i++) {
+		QMI_ENCDEC_ENCODE_N_BYTES(buf_dst, buf_src, elem_size);
+		rc += elem_size;
+	}
+
+	return rc;
+}
+
+/**
+ * qmi_encode_struct_elem() - Encodes elements of struct data type
+ * @ei_array: Struct info array descibing the struct element.
+ * @buf_dst: Buffer to store the encoded information.
+ * @buf_src: Buffer containing the elements to be encoded.
+ * @elem_len: Number of elements, in the buf_src, to be encoded.
+ * @enc_level: Depth of the nested structure from the main structure.
+ *
+ * @return: Mumber of bytes of encoded information, on success.
+ *          < 0 on error.
+ *
+ * This function encodes the "elem_len" number of struct elements, each of
+ * size "ei_array->elem_size" bytes from the source buffer "buf_src" and
+ * stores the encoded information in the destination buffer "buf_dst". The
+ * elements are of struct data type which includes any C structure. This
+ * function returns the number of bytes of encoded information.
+ */
+static int qmi_encode_struct_elem(struct elem_info *ei_array,
+				  void *buf_dst, void *buf_src,
+				  uint32_t elem_len, int enc_level)
+{
+	int i, rc, encoded_bytes = 0;
+	struct elem_info *temp_ei = ei_array;
+
+	for (i = 0; i < elem_len; i++) {
+		rc = _qmi_kernel_encode(temp_ei->ei_array,
+					buf_dst, buf_src, enc_level);
+		if (rc < 0) {
+			pr_err("%s: STRUCT Encode failure\n", __func__);
+			return rc;
+		}
+		buf_dst = buf_dst + rc;
+		buf_src = buf_src + temp_ei->elem_size;
+		encoded_bytes += rc;
+	}
+
+	return encoded_bytes;
+}
+
+/**
+ * skip_to_next_elem() - Skip to next element in the structure to be encoded
+ * @ei_array: Struct info describing the element to be skipped.
+ *
+ * @return: Struct info of the next element that can be encoded.
+ *
+ * This function is used while encoding optional elements. If the flag
+ * corresponding to an optional element is not set, then encoding the
+ * optional element can be skipped. This function can be used to perform
+ * that operation.
+ */
+static struct elem_info *skip_to_next_elem(struct elem_info *ei_array)
+{
+	struct elem_info *temp_ei = ei_array;
+	uint8_t tlv_type;
+
+	do {
+		tlv_type = temp_ei->tlv_type;
+		temp_ei = temp_ei + 1;
+	} while (tlv_type == temp_ei->tlv_type);
+
+	return temp_ei;
+}
+
+/**
+ * _qmi_kernel_encode() - Core Encode Function
+ * @ei_array: Struct info array describing the structure to be encoded.
+ * @out_buf: Buffer to hold the encoded QMI message.
+ * @in_c_struct: Pointer to the C structure to be encoded.
+ * @enc_level: Encode level to indicate the depth of the nested structure,
+ *             within the main structure, being encoded.
+ *
+ * @return: Number of bytes of encoded information, on success.
+ *          < 0 on error.
+ */
+static int _qmi_kernel_encode(struct elem_info *ei_array,
+			      void *out_buf, void *in_c_struct,
+			      int enc_level)
+{
+	struct elem_info *temp_ei = ei_array;
+	uint8_t opt_flag_value = 0;
+	uint32_t data_len_value = 0, data_len_sz;
+	uint8_t *buf_dst = (uint8_t *)out_buf;
+	uint8_t *tlv_pointer;
+	uint32_t tlv_len;
+	uint8_t tlv_type;
+	uint32_t encoded_bytes = 0;
+	void *buf_src;
+	int encode_tlv = 0;
+	int rc;
+
+	tlv_pointer = buf_dst;
+	tlv_len = 0;
+	buf_dst = buf_dst + (TLV_LEN_SIZE + TLV_TYPE_SIZE);
+
+	while (temp_ei->data_type != QMI_EOTI) {
+		buf_src = in_c_struct + temp_ei->offset;
+		tlv_type = temp_ei->tlv_type;
+
+		if (temp_ei->is_array == NO_ARRAY) {
+			data_len_value = 1;
+		} else if (temp_ei->is_array == STATIC_ARRAY) {
+			data_len_value = temp_ei->elem_len;
+		} else if (data_len_value <= 0 ||
+			    temp_ei->elem_len < data_len_value) {
+			pr_err("%s: Invalid data length\n", __func__);
+			return -EINVAL;
+		}
+
+		switch (temp_ei->data_type) {
+		case QMI_OPT_FLAG:
+			rc = qmi_encode_basic_elem(&opt_flag_value, buf_src,
+						   1, sizeof(uint8_t));
+			if (opt_flag_value)
+				temp_ei = temp_ei + 1;
+			else
+				temp_ei = skip_to_next_elem(temp_ei);
+			break;
+
+		case QMI_DATA_LEN:
+			memcpy(&data_len_value, buf_src, temp_ei->elem_size);
+			data_len_sz = temp_ei->elem_size == sizeof(uint8_t) ?
+					sizeof(uint8_t) : sizeof(uint16_t);
+			rc = qmi_encode_basic_elem(buf_dst, &data_len_value,
+						   1, data_len_sz);
+			if (data_len_value) {
+				UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
+					encoded_bytes, tlv_len, encode_tlv, rc);
+				encode_tlv = 0;
+			} else {
+				temp_ei = skip_to_next_elem(temp_ei);
+			}
+			break;
+
+		case QMI_UNSIGNED_1_BYTE:
+		case QMI_UNSIGNED_2_BYTE:
+		case QMI_UNSIGNED_4_BYTE:
+		case QMI_UNSIGNED_8_BYTE:
+		case QMI_SIGNED_2_BYTE_ENUM:
+		case QMI_SIGNED_4_BYTE_ENUM:
+			rc = qmi_encode_basic_elem(buf_dst, buf_src,
+				data_len_value, temp_ei->elem_size);
+			UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
+				encoded_bytes, tlv_len, encode_tlv, rc);
+			break;
+
+		case QMI_STRUCT:
+			rc = qmi_encode_struct_elem(temp_ei, buf_dst, buf_src,
+				data_len_value, (enc_level + 1));
+			if (rc < 0)
+				return rc;
+			UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
+				encoded_bytes, tlv_len, encode_tlv, rc);
+			break;
+
+		default:
+			pr_err("%s: Unrecognized data type\n", __func__);
+			return -EINVAL;
+
+		}
+
+		if (encode_tlv && enc_level == 1) {
+			QMI_ENCDEC_ENCODE_TLV(tlv_type, tlv_len, tlv_pointer);
+			encoded_bytes += (TLV_TYPE_SIZE + TLV_LEN_SIZE);
+			tlv_pointer = buf_dst;
+			tlv_len = 0;
+			buf_dst = buf_dst + TLV_LEN_SIZE + TLV_TYPE_SIZE;
+			encode_tlv = 0;
+		}
+	}
+	return encoded_bytes;
+}
+
+/**
+ * qmi_kernel_decode() - Decode to C Structure format
+ * @desc: Pointer to structure descriptor.
+ * @out_c_struct: Buffer to hold the decoded C structure.
+ * @in_buf: Buffer containg the QMI message to be decoded.
+ * @in_buf_len: Length of the incoming QMI message.
+ *
+ * @return: 0 on success, < 0 on error.
+ */
+int qmi_kernel_decode(struct msg_desc *desc, void *out_c_struct,
+		      void *in_buf, uint32_t in_buf_len)
+{
+	int dec_level = 1;
+	int rc = 0;
+
+	if (!desc || !desc->ei_array)
+		return -EINVAL;
+
+	if (!out_c_struct || !in_buf || !in_buf_len)
+		return -EINVAL;
+
+	if (desc->max_msg_len < in_buf_len)
+		return -EINVAL;
+
+	rc = _qmi_kernel_decode(desc->ei_array, out_c_struct,
+				in_buf, in_buf_len, dec_level);
+	if (rc < 0)
+		return rc;
+	else
+		return 0;
+}
+EXPORT_SYMBOL(qmi_kernel_decode);
+
+/**
+ * qmi_decode_basic_elem() - Decodes elements of basic/primary data type
+ * @buf_dst: Buffer to store the decoded element.
+ * @buf_src: Buffer containing the elements in QMI wire format.
+ * @elem_len: Number of elements to be decoded.
+ * @elem_size: Size of a single instance of the element to be decoded.
+ *
+ * @return: Total size of the decoded data elements, in bytes.
+ *
+ * This function decodes the "elem_len" number of elements in QMI wire format,
+ * each of size "elem_size" bytes from the source buffer "buf_src" and stores
+ * the decoded elements in the destination buffer "buf_dst". The elements are
+ * of primary data type which include uint8_t - uint64_t or similar. This
+ * function returns the number of bytes of decoded information.
+ */
+static int qmi_decode_basic_elem(void *buf_dst, void *buf_src,
+				 uint32_t elem_len, uint32_t elem_size)
+{
+	uint32_t i, rc = 0;
+
+	for (i = 0; i < elem_len; i++) {
+		QMI_ENCDEC_DECODE_N_BYTES(buf_dst, buf_src, elem_size);
+		rc += elem_size;
+	}
+
+	return rc;
+}
+
+/**
+ * qmi_decode_struct_elem() - Decodes elements of struct data type
+ * @ei_array: Struct info array descibing the struct element.
+ * @buf_dst: Buffer to store the decoded element.
+ * @buf_src: Buffer containing the elements in QMI wire format.
+ * @elem_len: Number of elements to be decoded.
+ * @tlv_len: Total size of the encoded inforation corresponding to
+ *           this struct element.
+ * @dec_level: Depth of the nested structure from the main structure.
+ *
+ * @return: Total size of the decoded data elements, on success.
+ *          < 0 on error.
+ *
+ * This function decodes the "elem_len" number of elements in QMI wire format,
+ * each of size "(tlv_len/elem_len)" bytes from the source buffer "buf_src"
+ * and stores the decoded elements in the destination buffer "buf_dst". The
+ * elements are of struct data type which includes any C structure. This
+ * function returns the number of bytes of decoded information.
+ */
+static int qmi_decode_struct_elem(struct elem_info *ei_array, void *buf_dst,
+				  void *buf_src, uint32_t elem_len,
+				  uint32_t tlv_len, int dec_level)
+{
+	int i, rc, decoded_bytes = 0;
+	struct elem_info *temp_ei = ei_array;
+
+	for (i = 0; i < elem_len; i++) {
+		rc = _qmi_kernel_decode(temp_ei->ei_array, buf_dst, buf_src,
+					(tlv_len/elem_len), dec_level);
+		if (rc < 0)
+			return rc;
+		if (rc != (tlv_len/elem_len)) {
+			pr_err("%s: Fault in decoding\n", __func__);
+			return -EFAULT;
+		}
+		buf_src = buf_src + rc;
+		buf_dst = buf_dst + temp_ei->elem_size;
+		decoded_bytes += rc;
+	}
+
+	return decoded_bytes;
+}
+
+/**
+ * find_ei() - Find element info corresponding to TLV Type
+ * @ei_array: Struct info array of the message being decoded.
+ * @type: TLV Type of the element being searched.
+ *
+ * @return: Pointer to struct info, if found
+ *
+ * Every element that got encoded in the QMI message will have a type
+ * information associated with it. While decoding the QMI message,
+ * this function is used to find the struct info regarding the element
+ * that corresponds to the type being decoded.
+ */
+static struct elem_info *find_ei(struct elem_info *ei_array,
+				   uint32_t type)
+{
+	struct elem_info *temp_ei = ei_array;
+	while (temp_ei->data_type != QMI_EOTI) {
+		if (temp_ei->tlv_type == (uint8_t)type)
+			return temp_ei;
+		temp_ei = temp_ei + 1;
+	}
+	return NULL;
+}
+
+/**
+ * _qmi_kernel_decode() - Core Decode Function
+ * @ei_array: Struct info array describing the structure to be decoded.
+ * @out_c_struct: Buffer to hold the decoded C struct
+ * @in_buf: Buffer containing the QMI message to be decoded
+ * @in_buf_len: Length of the QMI message to be decoded
+ * @dec_level: Decode level to indicate the depth of the nested structure,
+ *             within the main structure, being decoded
+ *
+ * @return: Number of bytes of decoded information, on success
+ *          < 0 on error.
+ */
+static int _qmi_kernel_decode(struct elem_info *ei_array,
+			      void *out_c_struct,
+			      void *in_buf, uint32_t in_buf_len,
+			      int dec_level)
+{
+	struct elem_info *temp_ei = ei_array;
+	uint8_t opt_flag_value = 1;
+	uint32_t data_len_value = 0, data_len_sz = 0;
+	uint8_t *buf_dst = out_c_struct;
+	uint8_t *tlv_pointer;
+	uint32_t tlv_len = 0;
+	uint32_t tlv_type;
+	uint32_t decoded_bytes = 0;
+	void *buf_src = in_buf;
+	int rc;
+
+	while (decoded_bytes < in_buf_len) {
+		if (dec_level == 1) {
+			tlv_pointer = buf_src;
+			QMI_ENCDEC_DECODE_TLV(&tlv_type,
+					      &tlv_len, tlv_pointer);
+			buf_src += (TLV_TYPE_SIZE + TLV_LEN_SIZE);
+			decoded_bytes += (TLV_TYPE_SIZE + TLV_LEN_SIZE);
+			temp_ei = find_ei(ei_array, tlv_type);
+			if (!temp_ei) {
+				pr_err("%s: Inval element info\n", __func__);
+				return -EINVAL;
+			}
+		}
+
+		buf_dst = out_c_struct + temp_ei->offset;
+		if (temp_ei->data_type == QMI_OPT_FLAG) {
+			memcpy(buf_dst, &opt_flag_value, sizeof(uint8_t));
+			temp_ei = temp_ei + 1;
+			buf_dst = out_c_struct + temp_ei->offset;
+		}
+
+		if (temp_ei->data_type == QMI_DATA_LEN) {
+			data_len_sz = temp_ei->elem_size == sizeof(uint8_t) ?
+					sizeof(uint8_t) : sizeof(uint16_t);
+			rc = qmi_decode_basic_elem(&data_len_value, buf_src,
+						   1, data_len_sz);
+			memcpy(buf_dst, &data_len_value, sizeof(uint32_t));
+			temp_ei = temp_ei + 1;
+			buf_dst = out_c_struct + temp_ei->offset;
+			UPDATE_DECODE_VARIABLES(buf_src, decoded_bytes, rc);
+		}
+
+		if (temp_ei->is_array == NO_ARRAY) {
+			data_len_value = 1;
+		} else if (temp_ei->is_array == STATIC_ARRAY) {
+			data_len_value = temp_ei->elem_len;
+		} else if (data_len_value > temp_ei->elem_len) {
+			pr_err("%s: Data len %d > max spec %d\n",
+				__func__, data_len_value, temp_ei->elem_len);
+			return -ETOOSMALL;
+		}
+
+		switch (temp_ei->data_type) {
+		case QMI_UNSIGNED_1_BYTE:
+		case QMI_UNSIGNED_2_BYTE:
+		case QMI_UNSIGNED_4_BYTE:
+		case QMI_UNSIGNED_8_BYTE:
+		case QMI_SIGNED_2_BYTE_ENUM:
+		case QMI_SIGNED_4_BYTE_ENUM:
+			rc = qmi_decode_basic_elem(buf_dst, buf_src,
+				data_len_value, temp_ei->elem_size);
+			UPDATE_DECODE_VARIABLES(buf_src, decoded_bytes, rc);
+			break;
+
+		case QMI_STRUCT:
+			rc = qmi_decode_struct_elem(temp_ei, buf_dst, buf_src,
+				data_len_value, tlv_len, (dec_level + 1));
+			if (rc < 0)
+				return rc;
+			UPDATE_DECODE_VARIABLES(buf_src, decoded_bytes, rc);
+			break;
+		default:
+			pr_err("%s: Unrecognized data type\n", __func__);
+			return -EINVAL;
+		}
+		temp_ei = temp_ei + 1;
+	}
+	return decoded_bytes;
+}
+MODULE_DESCRIPTION("QMI kernel enc/dec");
+MODULE_LICENSE("GPL v2");
diff --git a/lib/qmi_encdec_priv.h b/lib/qmi_encdec_priv.h
new file mode 100644
index 0000000..97fe45b
--- /dev/null
+++ b/lib/qmi_encdec_priv.h
@@ -0,0 +1,66 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _QMI_ENCDEC_PRIV_H_
+#define _QMI_ENCDEC_PRIV_H_
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/list.h>
+#include <linux/socket.h>
+#include <linux/gfp.h>
+#include <linux/qmi_encdec.h>
+
+#define QMI_ENCDEC_ENCODE_TLV(type, length, p_dst) do { \
+	*p_dst++ = type; \
+	*p_dst++ = ((uint8_t)((length) & 0xFF)); \
+	*p_dst++ = ((uint8_t)(((length) >> 8) & 0xFF)); \
+} while (0)
+
+#define QMI_ENCDEC_DECODE_TLV(p_type, p_length, p_src) do { \
+	*p_type = (uint8_t)*p_src++; \
+	*p_length = (uint8_t)*p_src++; \
+	*p_length |= ((uint8_t)*p_src) << 8; \
+} while (0)
+
+#define QMI_ENCDEC_ENCODE_N_BYTES(p_dst, p_src, size) \
+do { \
+	memcpy(p_dst, p_src, size); \
+	p_dst = (uint8_t *)p_dst + size; \
+	p_src = (uint8_t *)p_src + size; \
+} while (0)
+
+#define QMI_ENCDEC_DECODE_N_BYTES(p_dst, p_src, size) \
+do { \
+	memcpy(p_dst, p_src, size); \
+	p_dst = (uint8_t *)p_dst + size; \
+	p_src = (uint8_t *)p_src + size; \
+} while (0)
+
+#define UPDATE_ENCODE_VARIABLES(temp_si, buf_dst, \
+				encoded_bytes, tlv_len, encode_tlv, rc) \
+do { \
+	buf_dst = (uint8_t *)buf_dst + rc; \
+	encoded_bytes += rc; \
+	tlv_len += rc; \
+	temp_si = temp_si + 1; \
+	encode_tlv = 1; \
+} while (0)
+
+#define UPDATE_DECODE_VARIABLES(buf_src, decoded_bytes, rc) \
+do { \
+	buf_src = (uint8_t *)buf_src + rc; \
+	decoded_bytes += rc; \
+} while (0)
+
+#endif
diff --git a/mm/Kconfig b/mm/Kconfig
index 84489cd..4cde97f 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -379,3 +379,14 @@
 	  in a negligible performance hit.
 
 	  If unsure, say Y to enable cleancache
+
+config MEMORY_HOLE_CARVEOUT
+        bool
+        help
+          MEMORY_HOLE_CARVEOUT is needed to include the msm_mem_hole driver
+          which is needed to enable/disable memblock-remove features for
+          device tree nodes that set compatible="qcom,msm-mem-hole". The
+          corresponding device tree node provides the address and size of
+          the memory corresponding to the hole to be removed using memblock-
+          remove.
+
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 831509c..c3142e8 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -913,6 +913,11 @@
 	[MIGRATE_ISOLATE]     = { MIGRATE_RESERVE }, /* Never used */
 };
 
+int *get_migratetype_fallbacks(int mtype)
+{
+	return fallbacks[mtype];
+}
+
 /*
  * Move the free pages in a range to the free lists of the requested type.
  * Note that start_page and end_pages are not aligned on a pageblock
diff --git a/sound/soc/codecs/cs8427.c b/sound/soc/codecs/cs8427.c
index 23870a4..6e08742 100644
--- a/sound/soc/codecs/cs8427.c
+++ b/sound/soc/codecs/cs8427.c
@@ -110,7 +110,7 @@
 	 * with CS8427 chip
 	 */
 	if (pdata->enable) {
-		err = pdata->enable(1);
+		err = pdata->enable(1, pdata->ls_gpio);
 		if (err < 0) {
 			dev_err(&chip->client->dev,
 				"failed to enable the level shifter\n");
@@ -124,7 +124,7 @@
 	 * with CS8427 chip
 	 */
 	if (pdata->enable) {
-		err = pdata->enable(0);
+		err = pdata->enable(0, pdata->ls_gpio);
 		if (err < 0) {
 			dev_err(&chip->client->dev,
 				"failed to disable the level shifter\n");
@@ -192,7 +192,7 @@
 	 * with CS8427 chip
 	 */
 	if (pdata->enable) {
-		err = pdata->enable(1);
+		err = pdata->enable(1, pdata->ls_gpio);
 		if (err < 0) {
 			dev_err(&chip->client->dev,
 				"failed to enable the level shifter\n");
@@ -207,7 +207,7 @@
 	 * with CS8427 chip
 	 */
 	if (pdata->enable) {
-		err = pdata->enable(0);
+		err = pdata->enable(0, pdata->ls_gpio);
 		if (err < 0) {
 			dev_err(&chip->client->dev,
 				"failed to disable the level shifter\n");
@@ -239,7 +239,7 @@
 	 * with CS8427 chip
 	 */
 	if (pdata->enable) {
-		err = pdata->enable(1);
+		err = pdata->enable(1, pdata->ls_gpio);
 		if (err < 0) {
 			dev_err(&chip->client->dev,
 				"failed to enable the level shifter\n");
@@ -262,7 +262,7 @@
 	 * with CS8427 chip
 	 */
 	if (pdata->enable) {
-		err = pdata->enable(0);
+		err = pdata->enable(0, pdata->ls_gpio);
 		if (err < 0) {
 			dev_err(&chip->client->dev,
 				"failed to disable the level shifter\n");
@@ -734,6 +734,16 @@
 	struct cs8427_platform_data *pdata = chip->client->dev.platform_data;
 	int ret = 0;
 
+	if (pdata->enable) {
+		ret = gpio_request(pdata->ls_gpio, "cs8427 ls");
+		if (ret < 0) {
+			dev_err(&chip->client->dev,
+				 "failed to request the gpio %d\n",
+					pdata->reset_gpio);
+			return ret;
+		}
+	}
+
 	ret = gpio_request(pdata->reset_gpio, "cs8427 reset");
 	if (ret < 0) {
 		dev_err(&chip->client->dev,
@@ -928,8 +938,10 @@
 	}
 	pdata = chip->client->dev.platform_data;
 	gpio_free(pdata->reset_gpio);
-	if (pdata->enable)
-		pdata->enable(0);
+	if (pdata->enable) {
+		pdata->enable(0, pdata->ls_gpio);
+		gpio_free(pdata->ls_gpio);
+	}
 	kfree(chip);
 	return 0;
 }
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 5dcfefd..412090f 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -1238,9 +1238,9 @@
 		snd_soc_update_bits(codec, lineout_gain_reg, 0x10, 0x10);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
-		pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
+		pr_debug("%s: sleeping 32 ms after %s PA turn on\n",
 				__func__, w->name);
-		usleep_range(16000, 16000);
+		usleep_range(32000, 32000);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		snd_soc_update_bits(codec, lineout_gain_reg, 0x10, 0x00);
@@ -2056,6 +2056,24 @@
 	return 0;
 }
 
+static int sitar_ear_pa_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		pr_debug("%s: Sleeping 20ms after enabling EAR PA\n",
+				 __func__);
+		msleep(20);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		pr_debug("%s: Sleeping 20ms after disabling EAR PA\n",
+				 __func__);
+		msleep(20);
+		break;
+	}
+	return 0;
+}
+
 static const struct snd_soc_dapm_widget sitar_dapm_i2s_widgets[] = {
 	SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", SITAR_A_CDC_CLK_RX_I2S_CTL,
 	4, 0, NULL, 0),
@@ -2067,7 +2085,9 @@
 	/*RX stuff */
 	SND_SOC_DAPM_OUTPUT("EAR"),
 
-	SND_SOC_DAPM_PGA("EAR PA", SITAR_A_RX_EAR_EN, 4, 0, NULL, 0),
+	SND_SOC_DAPM_PGA_E("EAR PA", SITAR_A_RX_EAR_EN, 4, 0, NULL, 0,
+				sitar_ear_pa_event, SND_SOC_DAPM_POST_PMU |
+				SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_MIXER("DAC1", SITAR_A_RX_EAR_EN, 6, 0, dac1_switch,
 		ARRAY_SIZE(dac1_switch)),
 	SND_SOC_DAPM_SUPPLY("EAR DRIVER", SITAR_A_RX_EAR_EN, 3, 0, NULL, 0),
@@ -5137,6 +5157,8 @@
 	SITAR_REG_VAL(SITAR_A_RX_EAR_GAIN, 0x02),
 	SITAR_REG_VAL(SITAR_A_RX_EAR_VCM, 0x03),
 
+	SITAR_REG_VAL(SITAR_A_RX_LINE_BIAS_PA, 0xA7),
+
 	SITAR_REG_VAL(SITAR_A_CDC_RX1_B5_CTL, 0x78),
 	SITAR_REG_VAL(SITAR_A_CDC_RX2_B5_CTL, 0x78),
 	SITAR_REG_VAL(SITAR_A_CDC_RX3_B5_CTL, 0x78),
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 6b3287e..f28fd774 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -1889,6 +1889,8 @@
 pr_err:
 	pr_err("%s: RX%u is used by current requesting AIF_PB itself\n",
 		__func__, port_id + 1);
+	mutex_unlock(&codec->mutex);
+	return 0;
 err:
 	mutex_unlock(&codec->mutex);
 	return -EINVAL;
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 95df162..9f4babb 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -2084,7 +2084,6 @@
 		/* Let MBHC module know so micbias switch to be off */
 		wcd9xxx_resmgr_notifier_call(&taiko->resmgr, e_pre_on);
 
-		snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
 		/* Get cfilt */
 		wcd9xxx_resmgr_cfilt_get(&taiko->resmgr, cfilt_sel_val);
 
@@ -4471,9 +4470,6 @@
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX5_B6_CTL, 0x80),
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX6_B6_CTL, 0x80),
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX7_B6_CTL, 0x80),
-
-	/* TX VHIGH comparator */
-	TAIKO_REG_VAL(TAIKO_A_TX_SUP_SWITCH_CTRL_2, 0x90),
 };
 
 static const struct taiko_reg_mask_val taiko_1_0_reg_defaults[] = {
@@ -4497,6 +4493,19 @@
 	TAIKO_REG_VAL(TAIKO_A_RX_EAR_BIAS_PA, 0x76),
 	/* Reduce LINE DAC bias to 70% */
 	TAIKO_REG_VAL(TAIKO_A_RX_LINE_BIAS_PA, 0x78),
+
+	/*
+	 * There is a diode to pull down the micbias while doing
+	 * insertion detection.  This diode can cause leakage.
+	 * Set bit 0 to 1 to prevent leakage.
+	 * Setting this bit of micbias 2 prevents leakage for all other micbias.
+	 */
+	TAIKO_REG_VAL(TAIKO_A_MICB_2_MBHC, 0x41),
+
+	/* Disable TX7 internal biasing path which can cause leakage */
+	TAIKO_REG_VAL(TAIKO_A_TX_SUP_SWITCH_CTRL_1, 0xBF),
+	/* Enable MICB 4 VDDIO switch to prevent leakage */
+	TAIKO_REG_VAL(TAIKO_A_MICB_4_MBHC, 0x81),
 };
 
 static void taiko_update_reg_defaults(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 653effa..0f2a19c 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -9,6 +9,7 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/firmware.h>
@@ -566,15 +567,6 @@
 		 ins ? "insert" : "removal");
 	/* Disable detection to avoid glitch */
 	snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT, 1, 0);
-	/* Override mbhc power switch to avoid false IRQs */
-	snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MICB_1_MBHC, 1 << 2,
-			    !ins << 2);
-	snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MICB_2_MBHC, 1 << 2,
-			    !ins << 2);
-	snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MICB_3_MBHC, 1 << 2,
-			    !ins << 2);
-	snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MICB_4_MBHC, 1 << 2,
-			    !ins << 2);
 	snd_soc_write(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT,
 		      (0x68 | (ins ? (1 << 1) : 0)));
 	/* Re-enable detection */
@@ -938,6 +930,23 @@
 	return abs(mic_volt - mic_volt_prev) > threshold;
 }
 
+static void wcd9xxx_onoff_vddio_switch(struct wcd9xxx_mbhc *mbhc, bool on)
+{
+	if (on) {
+		snd_soc_update_bits(mbhc->codec, mbhc->mbhc_bias_regs.mbhc_reg,
+				    1 << 7, 1 << 7);
+		snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MAD_ANA_CTRL,
+				    1 << 4, 0);
+	} else {
+		snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MAD_ANA_CTRL,
+				    1 << 4, 1 << 4);
+		snd_soc_update_bits(mbhc->codec, mbhc->mbhc_bias_regs.mbhc_reg,
+				    1 << 7, 0);
+	}
+	if (on)
+		usleep_range(10000, 10000);
+}
+
 /* called under codec_resource_lock acquisition and mbhc override = 1 */
 static enum wcd9xxx_mbhc_plug_type
 wcd9xxx_codec_get_plug_type(struct wcd9xxx_mbhc *mbhc, bool highhph)
@@ -988,8 +997,7 @@
 			scaled = mic_mv[i];
 		} else {
 			if (vddioswitch)
-				__wcd9xxx_switch_micbias(mbhc, 1,
-							     false, false);
+				wcd9xxx_onoff_vddio_switch(mbhc, true);
 			if (gndswitch)
 				wcd9xxx_codec_hphr_gnd_switch(codec, true);
 			mb_v[i] = __wcd9xxx_codec_sta_dce(mbhc, 1, true, true);
@@ -1012,8 +1020,7 @@
 			if (gndswitch)
 				wcd9xxx_codec_hphr_gnd_switch(codec, false);
 			if (vddioswitch)
-				__wcd9xxx_switch_micbias(mbhc, 0,
-							     false, false);
+				wcd9xxx_onoff_vddio_switch(mbhc, false);
 			/* claim UNSUPPORTED plug insertion when
 			 * good headset is detected but HPHR GND switch makes
 			 * delta difference */
@@ -1577,7 +1584,7 @@
 	vddio = (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
 		 mbhc->mbhc_micbias_switched);
 	if (vddio)
-		__wcd9xxx_switch_micbias(mbhc, 0, false, true);
+		wcd9xxx_onoff_vddio_switch(mbhc, true);
 
 	if (mbhc->mbhc_cfg->detect_extn_cable &&
 	    !wcd9xxx_swch_level_remove(mbhc))
@@ -1591,7 +1598,7 @@
 	 * switch is off by time now and shouldn't be turn on again from here
 	 */
 	if (vddio && mbhc->current_plug == PLUG_TYPE_HEADSET)
-		__wcd9xxx_switch_micbias(mbhc, 1, true, true);
+		wcd9xxx_onoff_vddio_switch(mbhc, true);
 	WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
 
 	return IRQ_HANDLED;
@@ -2483,7 +2490,7 @@
 
 static void wcd9xxx_mbhc_cal(struct wcd9xxx_mbhc *mbhc)
 {
-	u8 cfilt_mode, bg_mode;
+	u8 cfilt_mode;
 	struct snd_soc_codec *codec = mbhc->codec;
 
 	pr_debug("%s: enter\n", __func__);
@@ -2501,8 +2508,6 @@
 	 */
 	cfilt_mode = snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl);
 	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
-	bg_mode = snd_soc_update_bits(codec, WCD9XXX_A_BIAS_CENTRAL_BG_CTL,
-				      0x02, 0x02);
 
 	/*
 	 * Micbias, CFILT, LDOH, MBHC MUX mode settings
@@ -2555,14 +2560,13 @@
 	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
 	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl, 0x40,
 			    cfilt_mode);
-	snd_soc_update_bits(codec, WCD9XXX_A_BIAS_CENTRAL_BG_CTL, 0x02,
-			    bg_mode);
 
 	snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x84);
 	usleep_range(100, 100);
 
 	wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
 	wcd9xxx_turn_onoff_rel_detection(codec, true);
+
 	pr_debug("%s: leave\n", __func__);
 }
 
@@ -3031,7 +3035,7 @@
 		break;
 	/* PA usage change */
 	case WCD9XXX_EVENT_PRE_HPHL_PA_ON:
-		if (!(snd_soc_read(codec, mbhc->mbhc_bias_regs.ctl_reg & 0x80)))
+		if (!(snd_soc_read(codec, mbhc->mbhc_bias_regs.ctl_reg) & 0x80))
 			/* if micbias is enabled, switch to vddio */
 			wcd9xxx_switch_micbias(mbhc, 1);
 		break;
@@ -3187,10 +3191,6 @@
 		return ret;
 	}
 
-	mbhc->mbhc_cfg = kzalloc(sizeof(*mbhc->mbhc_cfg), GFP_KERNEL);
-	if (!mbhc->mbhc_cfg)
-		return -ENOMEM;
-
 	INIT_DELAYED_WORK(&mbhc->mbhc_firmware_dwork, wcd9xxx_mbhc_fw_read);
 	INIT_DELAYED_WORK(&mbhc->mbhc_btn_dwork, wcd9xxx_btn_lpress_fn);
 	INIT_DELAYED_WORK(&mbhc->mbhc_insert_dwork, wcd9xxx_mbhc_insert_work);
@@ -3300,8 +3300,6 @@
 	wcd9xxx_resmgr_unregister_notifier(mbhc->resmgr, &mbhc->nblock);
 
 	wcd9xxx_cleanup_debugfs(mbhc);
-
-	kfree(mbhc->mbhc_cfg);
 }
 EXPORT_SYMBOL_GPL(wcd9xxx_mbhc_deinit);
 
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c
index 5dfa41c..3952dd5 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr.c
@@ -111,7 +111,7 @@
 	blocking_notifier_call_chain(&resmgr->notifier, e, resmgr);
 }
 
-static void wcd9xxx_codec_disable_bg(struct wcd9xxx_resmgr *resmgr)
+static void wcd9xxx_disable_bg(struct wcd9xxx_resmgr *resmgr)
 {
 	/* Notify bg mode change */
 	wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_PRE_BG_OFF);
@@ -122,18 +122,28 @@
 	wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_POST_BG_OFF);
 }
 
-static void wcd9xxx_codec_enable_bg_audio(struct wcd9xxx_resmgr *resmgr)
+/*
+ * BG enablement should always enable in slow mode.
+ * The fast mode doesn't need to be enabled as fast mode BG is to be driven
+ * by MBHC override.
+ */
+static void wcd9xxx_enable_bg(struct wcd9xxx_resmgr *resmgr)
 {
 	struct snd_soc_codec *codec = resmgr->codec;
 
-	/* Notify bandgap mode change */
-	wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_PRE_BG_AUDIO_ON);
-	/* Enable bg */
+	/* Enable BG in slow mode and precharge */
 	snd_soc_update_bits(codec, WCD9XXX_A_BIAS_CENTRAL_BG_CTL, 0x80, 0x80);
 	snd_soc_update_bits(codec, WCD9XXX_A_BIAS_CENTRAL_BG_CTL, 0x04, 0x04);
 	snd_soc_update_bits(codec, WCD9XXX_A_BIAS_CENTRAL_BG_CTL, 0x01, 0x01);
 	usleep_range(1000, 1000);
 	snd_soc_update_bits(codec, WCD9XXX_A_BIAS_CENTRAL_BG_CTL, 0x80, 0x00);
+}
+
+static void wcd9xxx_enable_bg_audio(struct wcd9xxx_resmgr *resmgr)
+{
+	/* Notify bandgap mode change */
+	wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_PRE_BG_AUDIO_ON);
+	wcd9xxx_enable_bg(resmgr);
 	/* Notify bandgap mode change */
 	wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_POST_BG_AUDIO_ON);
 }
@@ -146,28 +156,15 @@
 	wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_PRE_BG_MBHC_ON);
 
 	/*
-	 * bandgap mode becomes fast,
 	 * mclk should be off or clk buff source souldn't be VBG
 	 * Let's turn off mclk always
 	 */
 	WARN_ON(snd_soc_read(codec, WCD9XXX_A_CLK_BUFF_EN2) & (1 << 2));
-	snd_soc_update_bits(codec, WCD9XXX_A_BIAS_CENTRAL_BG_CTL, 0x2, 0x2);
-	snd_soc_update_bits(codec, WCD9XXX_A_BIAS_CENTRAL_BG_CTL, 0x80, 0x80);
-	snd_soc_update_bits(codec, WCD9XXX_A_BIAS_CENTRAL_BG_CTL, 0x4, 0x4);
-	snd_soc_update_bits(codec, WCD9XXX_A_BIAS_CENTRAL_BG_CTL, 0x01, 0x01);
-	usleep_range(1000, 1000);
-	snd_soc_update_bits(codec, WCD9XXX_A_BIAS_CENTRAL_BG_CTL, 0x80, 0x00);
-
+	wcd9xxx_enable_bg(resmgr);
 	/* Notify bandgap mode change */
 	wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_POST_BG_MBHC_ON);
 }
 
-static void wcd9xxx_disable_bg(struct wcd9xxx_resmgr *resmgr)
-{
-	struct snd_soc_codec *codec = resmgr->codec;
-	snd_soc_write(codec, WCD9XXX_A_BIAS_CENTRAL_BG_CTL, 0x00);
-}
-
 static void wcd9xxx_disable_clock_block(struct wcd9xxx_resmgr *resmgr)
 {
 	struct snd_soc_codec *codec = resmgr->codec;
@@ -223,14 +220,14 @@
 			/* BG mode can be changed only with clock off */
 			clock_save = wcd9xxx_save_clock(resmgr);
 			/* Swtich BG mode */
-			wcd9xxx_codec_disable_bg(resmgr);
-			wcd9xxx_codec_enable_bg_audio(resmgr);
+			wcd9xxx_disable_bg(resmgr);
+			wcd9xxx_enable_bg_audio(resmgr);
 			/* restore clock */
 			wcd9xxx_restore_clock(resmgr, clock_save);
 		} else if (resmgr->bg_audio_users == 1) {
 			/* currently off, just enable it */
 			WARN_ON(resmgr->bandgap_type != WCD9XXX_BANDGAP_OFF);
-			wcd9xxx_codec_enable_bg_audio(resmgr);
+			wcd9xxx_enable_bg_audio(resmgr);
 		}
 		resmgr->bandgap_type = WCD9XXX_BANDGAP_AUDIO_MODE;
 		break;
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index 99302eb..a261184 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -58,7 +58,7 @@
 
 snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-multi-ch-pcm-q6.o msm-lowlatency-pcm-q6.o msm-pcm-routing.o msm-dai-fe.o msm-compr-q6.o msm-dai-stub.o
 obj-$(CONFIG_SND_SOC_MSM_QDSP6_HDMI_AUDIO) += msm-dai-q6-hdmi.o
-obj-$(CONFIG_SND_SOC_VOICE) += msm-pcm-voice.o msm-pcm-voip.o
+obj-$(CONFIG_SND_SOC_VOICE) += msm-pcm-voice.o msm-pcm-voip.o msm-pcm-dtmf.o
 snd-soc-qdsp6-objs += msm-pcm-lpa.o msm-pcm-afe.o
 obj-$(CONFIG_SND_SOC_QDSP6) += snd-soc-qdsp6.o
 
diff --git a/sound/soc/msm/mdm9615.c b/sound/soc/msm/mdm9615.c
index 5a47efe..0125c1a 100644
--- a/sound/soc/msm/mdm9615.c
+++ b/sound/soc/msm/mdm9615.c
@@ -2014,6 +2014,21 @@
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 		.ignore_suspend = 1,
 	},
+	{
+		.name = "DTMF RX Hostless",
+		.stream_name = "DTMF RX Hostless",
+		.cpu_dai_name	= "DTMF_RX_HOSTLESS",
+		.platform_name  = "msm-pcm-dtmf",
+		.dynamic = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.ignore_suspend = 1,
+		.be_id = MSM_FRONTEND_DAI_DTMF_RX,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+	},
+
 	/* Backend BT DAI Links */
 	{
 		.name = LPASS_BE_INT_BT_SCO_RX,
diff --git a/sound/soc/msm/mpq8064.c b/sound/soc/msm/mpq8064.c
index 016ef94..90c96b4 100644
--- a/sound/soc/msm/mpq8064.c
+++ b/sound/soc/msm/mpq8064.c
@@ -1486,6 +1486,20 @@
 		.ignore_pmdown_time = 1, /* dainlink has playback support */
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
+
+	},
+	{
+		.name = "MSM8960 Pseudo",
+		.stream_name = "Pseudo",
+		.cpu_dai_name   = "Pseudo",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_PSEUDO,
 	},
 	/* Backend DAI Links */
 	{
@@ -1624,6 +1638,18 @@
 		.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
 		.be_hw_params_fixup = mpq8064_auxpcm_be_params_fixup,
 	},
+	{
+		.name = LPASS_BE_PSEUDO,
+		.stream_name = "PSEUDO Playback",
+		.cpu_dai_name = "msm-dai-q6.32769",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_PSEUDO_PORT,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_pmdown_time = 1,
+	},
 };
 
 
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index 8202982..6ac4562 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -143,6 +143,10 @@
 			atomic_set(&prtd->pending_buffer, 0);
 		if (runtime->status->hw_ptr >= runtime->control->appl_ptr) {
 			runtime->render_flag |= SNDRV_RENDER_STOPPED;
+			atomic_set(&prtd->pending_buffer, 1);
+			pr_debug("%s:compr driver underrun hw_ptr = %ld appl_ptr = %ld\n",
+				__func__, runtime->status->hw_ptr,
+				runtime->control->appl_ptr);
 			break;
 		}
 		buf = prtd->audio_client->port[IN].buf;
@@ -382,6 +386,7 @@
 		break;
 	case SND_AUDIOCODEC_AC3_PASS_THROUGH:
 	case SND_AUDIOCODEC_DTS_PASS_THROUGH:
+	case SND_AUDIOCODEC_DTS_LBR_PASS_THROUGH:
 		pr_debug("compressd playback, no need to send decoder params");
 		pr_debug("decoder id: %d\n",
 			compr->info.codec_param.codec.id);
@@ -473,7 +478,23 @@
 	default:
 		return -EINVAL;
 	}
-
+	if (compr->info.codec_param.codec.transcode_dts) {
+		msm_pcm_routing_reg_pseudo_stream(
+			MSM_FRONTEND_DAI_PSEUDO,
+			prtd->enc_audio_client->perf_mode,
+			prtd->enc_audio_client->session,
+			SNDRV_PCM_STREAM_CAPTURE,
+			48000, runtime->channels > 6 ?
+			6 : runtime->channels);
+		pr_debug("%s: cmd: DTS ENCDEC CFG BLK\n", __func__);
+		ret = q6asm_enc_cfg_blk_dts(prtd->enc_audio_client,
+				DTS_ENC_SAMPLE_RATE48k,
+				runtime->channels > 6 ?
+				6 : runtime->channels);
+		if (ret < 0)
+			pr_err("%s: CMD: DTS ENCDEC CFG BLK failed\n",
+				__func__);
+	}
 	prtd->enabled = 1;
 	prtd->cmd_ack = 0;
 
@@ -649,6 +670,8 @@
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		pr_debug("%s: Trigger start\n", __func__);
 		q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+		if (prtd->enc_audio_client)
+			q6asm_run_nowait(prtd->enc_audio_client, 0, 0, 0);
 		atomic_set(&prtd->start, 1);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
@@ -659,6 +682,8 @@
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
 		q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+		if (prtd->enc_audio_client)
+			q6asm_cmd_nowait(prtd->enc_audio_client, CMD_PAUSE);
 		atomic_set(&prtd->start, 0);
 		runtime->render_flag &= ~SNDRV_RENDER_STOPPED;
 		break;
@@ -675,7 +700,7 @@
 {
 	pr_debug("%s\n", __func__);
 	/* MP3 Block */
-	compr->info.compr_cap.num_codecs = 13;
+	compr->info.compr_cap.num_codecs = 14;
 	compr->info.compr_cap.min_fragment_size = runtime->hw.period_bytes_min;
 	compr->info.compr_cap.max_fragment_size = runtime->hw.period_bytes_max;
 	compr->info.compr_cap.min_fragments = runtime->hw.periods_min;
@@ -693,6 +718,7 @@
 	compr->info.compr_cap.codecs[10] = SND_AUDIOCODEC_PASS_THROUGH;
 	compr->info.compr_cap.codecs[11] = SND_AUDIOCODEC_PCM;
 	compr->info.compr_cap.codecs[12] = SND_AUDIOCODEC_MP2;
+	compr->info.compr_cap.codecs[13] = SND_AUDIOCODEC_DTS_LBR_PASS_THROUGH;
 	/* Add new codecs here and update num_codecs*/
 }
 
@@ -809,21 +835,30 @@
 	atomic_set(&prtd->pending_buffer, 0);
 	prtd->pcm_irq_pos = 0;
 	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+	if (prtd->enc_audio_client)
+		q6asm_cmd(prtd->enc_audio_client, CMD_CLOSE);
 	compressed_audio.prtd = NULL;
 	q6asm_audio_client_buf_free_contiguous(dir,
 				prtd->audio_client);
-	if ((compr->info.codec_param.codec.id !=
-			SND_AUDIOCODEC_AC3_PASS_THROUGH) &&
-			(compr->info.codec_param.codec.id !=
-			SND_AUDIOCODEC_DTS_PASS_THROUGH))
+	switch (compr->info.codec_param.codec.id) {
+	case SND_AUDIOCODEC_AC3_PASS_THROUGH:
+	case SND_AUDIOCODEC_DTS_PASS_THROUGH:
+	case SND_AUDIOCODEC_DTS_LBR_PASS_THROUGH:
+		msm_pcm_routing_reg_psthr_stream(
+			soc_prtd->dai_link->be_id,
+			prtd->session_id, substream->stream,
+			0);
+	default:
 		msm_pcm_routing_dereg_phy_stream(
 			soc_prtd->dai_link->be_id,
 			SNDRV_PCM_STREAM_PLAYBACK);
-	else
-		msm_pcm_routing_reg_psthr_stream(
-					soc_prtd->dai_link->be_id,
-					prtd->session_id, substream->stream,
-					0);
+	}
+	if (compr->info.codec_param.codec.transcode_dts) {
+		msm_pcm_routing_dereg_pseudo_stream(MSM_FRONTEND_DAI_PSEUDO,
+			prtd->enc_audio_client->session);
+	}
+	if (prtd->enc_audio_client)
+		q6asm_audio_client_free(prtd->enc_audio_client);
 	q6asm_audio_client_free(prtd->audio_client);
 	kfree(prtd);
 	return 0;
@@ -840,6 +875,7 @@
 	pr_debug("%s\n", __func__);
 	atomic_set(&prtd->pending_buffer, 0);
 	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+	compressed_audio.prtd = NULL;
 	q6asm_audio_client_buf_free_contiguous(dir,
 				prtd->audio_client);
 	if (compr->info.codec_param.codec.id ==
@@ -941,6 +977,7 @@
 		switch (compr->info.codec_param.codec.id) {
 		case SND_AUDIOCODEC_AC3_PASS_THROUGH:
 		case SND_AUDIOCODEC_DTS_PASS_THROUGH:
+		case SND_AUDIOCODEC_DTS_LBR_PASS_THROUGH:
 			ret = q6asm_open_write_compressed(prtd->audio_client,
 					compr->codec);
 
@@ -964,6 +1001,29 @@
 				prtd->session_id,
 				substream->stream);
 
+			if (compr->info.codec_param.codec.transcode_dts) {
+				prtd->enc_audio_client =
+					q6asm_audio_client_alloc(
+					(app_cb)compr_event_handler, compr);
+				if (!prtd->enc_audio_client) {
+					pr_err("%s: Could not allocate " \
+							"memory\n", __func__);
+					return -ENOMEM;
+				}
+				prtd->enc_audio_client->perf_mode = false;
+				pr_debug("%s Setting up loopback path\n",
+						__func__);
+				ret = q6asm_open_transcode_loopback(
+					prtd->enc_audio_client,
+					params_channels(params));
+				if (ret < 0) {
+					pr_err("%s: Session transcode " \
+						"loopback open failed\n",
+						__func__);
+					return -ENODEV;
+				}
+			}
+
 			break;
 		}
 	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
@@ -1113,6 +1173,22 @@
 			pr_err("%s: ERROR: copy from user\n", __func__);
 			return rc;
 		}
+		/*
+		* DTS Security needed for the transcode path
+		*/
+		if (compr->info.codec_param.codec.transcode_dts) {
+			char modelId[128];
+			struct snd_dec_dts opt_dts =
+				compr->info.codec_param.codec.dts;
+			int modelIdLength = opt_dts.modelIdLength;
+			if (copy_from_user(modelId, (void *)opt_dts.modelId,
+				modelIdLength))
+				pr_err("%s: ERROR: copy modelId\n", __func__);
+			modelId[modelIdLength] = '\0';
+			pr_debug("%s: Received modelId =%s,length=%d\n",
+				__func__, modelId, modelIdLength);
+			core_set_dts_model_id(modelIdLength, modelId);
+		}
 		switch (compr->info.codec_param.codec.id) {
 		case SND_AUDIOCODEC_MP3:
 			/* For MP3 we dont need any other parameter */
@@ -1139,10 +1215,14 @@
 			pr_debug("SND_AUDIOCODEC_DTS_PASS_THROUGH\n");
 			compr->codec = FORMAT_DTS;
 			break;
+		case SND_AUDIOCODEC_DTS_LBR_PASS_THROUGH:
+			pr_debug("SND_AUDIOCODEC_DTS_LBR_PASS_THROUGH\n");
+			compr->codec = FORMAT_DTS_LBR;
+			break;
 		case SND_AUDIOCODEC_DTS: {
 			char modelId[128];
 			struct snd_dec_dts opt_dts =
-				compr->info.codec_param.codec.options.dts;
+				compr->info.codec_param.codec.dts;
 			int modelIdLength = opt_dts.modelIdLength;
 			pr_debug("SND_AUDIOCODEC_DTS\n");
 			if (copy_from_user(modelId, (void *)opt_dts.modelId,
@@ -1158,7 +1238,7 @@
 		case SND_AUDIOCODEC_DTS_LBR:{
 			char modelId[128];
 			struct snd_dec_dts opt_dts =
-				compr->info.codec_param.codec.options.dts;
+				compr->info.codec_param.codec.dts;
 			int modelIdLength = opt_dts.modelIdLength;
 			pr_debug("SND_AUDIOCODEC_DTS_LBR\n");
 			if (copy_from_user(modelId, (void *)opt_dts.modelId,
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index dc8d9e6..51c9ed7 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -289,6 +289,78 @@
 	},
 	{
 		.playback = {
+			.stream_name = "SLIMBUS1 Hostless Playback",
+			.aif_name = "SLIM1_DL_HL",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min =     8000,
+			.rate_max =     48000,
+		},
+		.capture = {
+			.stream_name = "SLIMBUS1 Hostless Capture",
+			.aif_name = "SLIM1_UL_HL",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min =     8000,
+			.rate_max =     48000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "SLIMBUS1_HOSTLESS",
+	},
+	{
+		.playback = {
+			.stream_name = "SLIMBUS3 Hostless Playback",
+			.aif_name = "SLIM3_DL_HL",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min =     8000,
+			.rate_max =     48000,
+		},
+		.capture = {
+			.stream_name = "SLIMBUS3 Hostless Capture",
+			.aif_name = "SLIM3_UL_HL",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min =     8000,
+			.rate_max =     48000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "SLIMBUS3_HOSTLESS",
+	},
+	{
+		.playback = {
+			.stream_name = "SLIMBUS4 Hostless Playback",
+			.aif_name = "SLIM4_DL_HL",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min =     8000,
+			.rate_max =     48000,
+		},
+		.capture = {
+			.stream_name = "SLIMBUS4 Hostless Capture",
+			.aif_name = "SLIM4_UL_HL",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min =     8000,
+			.rate_max =     48000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "SLIMBUS4_HOSTLESS",
+	},
+	{
+		.playback = {
 			.stream_name = "INT_FM Hostless Playback",
 			.aif_name = "INTFM_DL_HL",
 			.rates = SNDRV_PCM_RATE_8000_48000,
@@ -477,6 +549,46 @@
 		.ops = &msm_fe_dai_ops,
 		.name = "SGLTE",
 	},
+	{
+		.playback = {
+			.stream_name = "Pseudo Playback",
+			.aif_name = "MM_DL9",
+			.rates = (SNDRV_PCM_RATE_8000_48000 |
+					SNDRV_PCM_RATE_KNOT),
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 8,
+			.rate_min =	8000,
+			.rate_max = 48000,
+		},
+		.capture = {
+			.stream_name = "Pseudo Capture",
+			.aif_name = "MM_UL9",
+			.rates = (SNDRV_PCM_RATE_8000_48000|
+					SNDRV_PCM_RATE_KNOT),
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 8,
+			.rate_min =     8000,
+			.rate_max =	48000,
+		},
+		.ops = &msm_fe_Multimedia_dai_ops,
+		.name = "Pseudo",
+	},
+	{
+		.playback = {
+			.stream_name = "DTMF_RX Hostless Playback",
+			.aif_name = "DTMF_DL_HL",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min =	8000,
+			.rate_max = 48000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "DTMF_RX_HOSTLESS",
+	},
 };
 
 static __devinit int msm_fe_dai_dev_probe(struct platform_device *pdev)
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index 18c2329..8cc0eaa 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -660,6 +660,24 @@
 	return 0;
 }
 
+static int msm_dai_q6_pseudo_hw_params(struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+	dai_data->rate = params_rate(params);
+	dai_data->channels = params_channels(params) > 6 ?
+				params_channels(params) : 6;
+
+	dai_data->port_config.pseudo.bit_width = 16;
+	dai_data->port_config.pseudo.num_channels =
+			dai_data->channels;
+	dai_data->port_config.pseudo.data_format = 0;
+	dai_data->port_config.pseudo.timing_mode = 1;
+	dai_data->port_config.pseudo.reserved = 16;
+	return 0;
+}
+
 /* Current implementation assumes hw_param is called once
  * This may not be the case but what to do when ADM and AFE
  * port are already opened and parameter changes
@@ -703,6 +721,9 @@
 	case RT_PROXY_DAI_002_RX:
 		rc = msm_dai_q6_afe_rtproxy_hw_params(params, dai);
 		break;
+	case PSEUDOPORT_01:
+		rc = msm_dai_q6_pseudo_hw_params(params, dai);
+		break;
 	case VOICE_PLAYBACK_TX:
 	case VOICE_RECORD_RX:
 	case VOICE_RECORD_TX:
@@ -1819,6 +1840,20 @@
 	.probe = msm_dai_q6_dai_probe,
 	.remove = msm_dai_q6_dai_remove,
 };
+static struct snd_soc_dai_driver msm_dai_q6_pseudo_dai = {
+	.playback = {
+		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+		SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 6,
+		.rate_min = 8000,
+		.rate_max = 48000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
 
 /* To do: change to register DAIs as batch */
 static __devinit int msm_dai_q6_dev_probe(struct platform_device *pdev)
@@ -1915,6 +1950,10 @@
 		rc = snd_soc_register_dai(&pdev->dev,
 						&msm_dai_q6_incall_record_dai);
 		break;
+	case PSEUDOPORT_01:
+		rc = snd_soc_register_dai(&pdev->dev,
+					&msm_dai_q6_pseudo_dai);
+		break;
 	default:
 		rc = -ENODEV;
 		break;
diff --git a/sound/soc/msm/msm-multi-ch-pcm-q6.c b/sound/soc/msm/msm-multi-ch-pcm-q6.c
index bd4a521..6cad0af 100644
--- a/sound/soc/msm/msm-multi-ch-pcm-q6.c
+++ b/sound/soc/msm/msm-multi-ch-pcm-q6.c
@@ -236,6 +236,11 @@
 			}
 			atomic_set(&prtd->start, 1);
 			break;
+		case ASM_STREAM_CMD_FLUSH:
+			pr_debug("ASM_STREAM_CMD_FLUSH\n");
+			prtd->cmd_ack = 1;
+			wake_up(&the_locks.flush_wait);
+			break;
 		default:
 			break;
 		}
@@ -800,13 +805,52 @@
 	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
 	return 0;
 }
+static int msm_pcm_ioctl(struct snd_pcm_substream *substream,
+			unsigned int cmd, void *arg)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	int ret = 0, rc;
+
+	pr_debug("%s\n", __func__);
+	ret = snd_pcm_lib_ioctl(substream, cmd, arg);
+	if (ret < 0) {
+		pr_err("%s, snd_pcm_lib_ioctl error\n", __func__);
+		return ret;
+	}
+
+	switch (cmd) {
+	case SNDRV_PCM_IOCTL1_RESET:
+		pr_debug("%s, SNDRV_PCM_IOCTL1_RESET\n", __func__);
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			prtd->cmd_ack = 0;
+			rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
+			if (rc < 0) {
+				pr_err("%s: flush cmd failed rc=%d\n",
+					 __func__, rc);
+				break;
+			}
+			rc = wait_event_timeout(the_locks.flush_wait,
+				 prtd->cmd_ack, 5 * HZ);
+			if (rc < 0)
+				pr_err("Flush cmd timeout\n");
+			prtd->pcm_irq_pos = 0;
+			atomic_set(&prtd->out_count, runtime->periods);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
 
 static struct snd_pcm_ops msm_pcm_ops = {
 	.open           = msm_pcm_open,
 	.copy		= msm_pcm_copy,
 	.hw_params	= msm_pcm_hw_params,
 	.close          = msm_pcm_close,
-	.ioctl          = snd_pcm_lib_ioctl,
+	.ioctl          = msm_pcm_ioctl,
 	.prepare        = msm_pcm_prepare,
 	.trigger        = msm_pcm_trigger,
 	.pointer        = msm_pcm_pointer,
@@ -894,6 +938,7 @@
 	init_waitqueue_head(&the_locks.eos_wait);
 	init_waitqueue_head(&the_locks.write_wait);
 	init_waitqueue_head(&the_locks.read_wait);
+	init_waitqueue_head(&the_locks.flush_wait);
 
 	return platform_driver_register(&msm_pcm_driver);
 }
diff --git a/sound/soc/msm/msm-pcm-dtmf.c b/sound/soc/msm/msm-pcm-dtmf.c
new file mode 100644
index 0000000..04ab7a9
--- /dev/null
+++ b/sound/soc/msm/msm-pcm-dtmf.c
@@ -0,0 +1,100 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/q6afe.h>
+
+static int msm_dtmf_rx_generate_put(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	uint16_t low_freq = ucontrol->value.integer.value[0];
+	uint16_t high_freq = ucontrol->value.integer.value[1];
+	int64_t duration = ucontrol->value.integer.value[2];
+	uint16_t gain = ucontrol->value.integer.value[3];
+
+	pr_debug("%s: low_freq=%d high_freq=%d duration=%d gain=%d\n",
+		 __func__, low_freq, high_freq, (int)duration, gain);
+	afe_dtmf_generate_rx(duration, high_freq, low_freq, gain);
+	return 0;
+}
+
+static int msm_dtmf_rx_generate_get(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s:\n", __func__);
+	ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
+static struct snd_kcontrol_new msm_dtmf_controls[] = {
+	SOC_SINGLE_MULTI_EXT("DTMF_Generate Rx Low High Duration Gain",
+			     SND_SOC_NOPM, 0, 5000, 0, 4,
+			     msm_dtmf_rx_generate_get,
+			     msm_dtmf_rx_generate_put),
+};
+
+static int msm_pcm_dtmf_probe(struct snd_soc_platform *platform)
+{
+	snd_soc_add_platform_controls(platform, msm_dtmf_controls,
+				      ARRAY_SIZE(msm_dtmf_controls));
+	return 0;
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {};
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+	.ops		= &msm_pcm_ops,
+	.probe		= msm_pcm_dtmf_probe,
+};
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+	pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+	return snd_soc_register_platform(&pdev->dev,
+					 &msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_pcm_driver = {
+	.driver = {
+		.name = "msm-pcm-dtmf",
+		.owner = THIS_MODULE,
+	},
+	.probe = msm_pcm_probe,
+	.remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+	return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("DTMF platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-pcm-q6.h b/sound/soc/msm/msm-pcm-q6.h
index 2678498..86e5c54 100644
--- a/sound/soc/msm/msm-pcm-q6.h
+++ b/sound/soc/msm/msm-pcm-q6.h
@@ -59,6 +59,7 @@
 	uint16_t source; /* Encoding source bit mask */
 
 	struct audio_client *audio_client;
+	struct audio_client *enc_audio_client;
 
 	uint16_t session_id;
 
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 800bea8..1ddb6c9 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -194,6 +194,7 @@
 	{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
 	{ SECONDARY_PCM_RX, 0, 0, 0, 0, 0},
 	{ SECONDARY_PCM_TX, 0, 0, 0, 0, 0},
+	{ PSEUDOPORT_01, 0, 0, 0, 0, 0},
 };
 
 
@@ -215,7 +216,8 @@
 	{INVALID_SESSION, INVALID_SESSION},
 	/* MULTIMEDIA8 */
 	{INVALID_SESSION, INVALID_SESSION},
-
+	/* PSEUDO */
+	{INVALID_SESSION, INVALID_SESSION},
 };
 
 static uint8_t is_be_dai_extproc(int be_dai)
@@ -298,6 +300,59 @@
 	mutex_unlock(&routing_lock);
 }
 
+void msm_pcm_routing_reg_pseudo_stream(int fedai_id, bool perf_mode,
+					int dspst_id, int stream_type,
+					int sample_rate, int channels)
+{
+	int i, session_type, path_type, port_type, mode, ret;
+	struct route_payload payload;
+	pr_debug("%s:fedai_id = %d dspst_id = %d stream_type %d",
+				__func__, fedai_id, dspst_id, stream_type);
+
+	if (stream_type == SNDRV_PCM_STREAM_PLAYBACK) {
+		session_type = SESSION_TYPE_RX;
+		path_type = ADM_PATH_PLAYBACK;
+		port_type = MSM_AFE_PORT_TYPE_RX;
+	} else {
+		session_type = SESSION_TYPE_TX;
+		path_type = ADM_PATH_LIVE_REC;
+		port_type = MSM_AFE_PORT_TYPE_TX;
+	}
+
+	mutex_lock(&routing_lock);
+
+	payload.num_copps = 0;
+	adm_multi_ch_copp_pseudo_open_v3(PSEUDOPORT_01,
+					path_type, sample_rate, channels,
+					DEFAULT_COPP_TOPOLOGY);
+
+	payload.copp_ids[payload.num_copps++] = PSEUDOPORT_01;
+
+	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+		if (test_bit(fedai_id, &msm_bedais[i].fe_sessions))
+			msm_bedais[i].perf_mode = perf_mode;
+		if (!is_be_dai_extproc(i) &&
+		   (msm_bedais[i].active) &&
+		   (test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
+
+			mode = afe_get_port_type(msm_bedais[i].port_id);
+			ret = adm_connect_afe_port_v2(mode, dspst_id,
+						msm_bedais[i].port_id,
+						msm_bedais[i].sample_rate,
+						msm_bedais[i].channel);
+
+			if (ret < 0)
+				pr_err("%s: adm_connect_afe_port_v2 failed\n",
+					__func__);
+		}
+	}
+	if (payload.num_copps)
+		adm_matrix_map(dspst_id, path_type,
+			payload.num_copps, payload.copp_ids, 0);
+
+	mutex_unlock(&routing_lock);
+}
+
 void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode, int dspst_id,
 							int stream_type)
 {
@@ -375,6 +430,32 @@
 	mutex_unlock(&routing_lock);
 }
 
+void msm_pcm_routing_dereg_pseudo_stream(int fedai_id, int dspst_id)
+{
+	int i, mode, ret;
+	pr_debug("%s:fedai_id = %d dspst_id = %d",
+			__func__, fedai_id, dspst_id);
+
+	mutex_lock(&routing_lock);
+
+	adm_pseudo_close(PSEUDOPORT_01);
+	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+		if (!is_be_dai_extproc(i) &&
+			(msm_bedais[i].active) &&
+			(test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
+
+			mode = afe_get_port_type(msm_bedais[i].port_id);
+			ret = adm_disconnect_afe_port(mode, dspst_id,
+					msm_bedais[i].port_id);
+			if (ret < 0)
+				pr_err("%s: adm_connect_afe_port_v2 failed\n",
+					__func__);
+		}
+	}
+
+	mutex_unlock(&routing_lock);
+
+}
 void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type)
 {
 	int i, port_type, session_type;
@@ -574,6 +655,14 @@
 	else
 		clear_bit(val, &msm_bedais[reg].fe_sessions);
 
+	if (val == MSM_FRONTEND_DAI_DTMF_RX &&
+	    afe_get_port_type(msm_bedais[reg].port_id) ==
+						MSM_AFE_PORT_TYPE_RX) {
+		pr_debug("%s(): set=%d port id=0x%x for dtmf generation\n",
+			 __func__, set, msm_bedais[reg].port_id);
+		afe_set_dtmf_gen_rx_portid(msm_bedais[reg].port_id, set);
+	}
+
 	mutex_unlock(&routing_lock);
 
 	if (afe_get_port_type(msm_bedais[reg].port_id) ==
@@ -1210,6 +1299,9 @@
 	SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SEC_I2S_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("Pseudo", MSM_BACKEND_DAI_SEC_I2S_RX,
+	MSM_FRONTEND_DAI_PSEUDO, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = {
@@ -1291,6 +1383,17 @@
 	SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_HDMI_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("Pseudo", MSM_BACKEND_DAI_HDMI_RX,
+	MSM_FRONTEND_DAI_PSEUDO, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+static const struct snd_kcontrol_new pseudo_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PSEUDO_PORT,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_PSEUDO_PORT,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 	/* incall music delivery mixer */
 static const struct snd_kcontrol_new incall_music_delivery_mixer_controls[] = {
@@ -1493,6 +1596,9 @@
 	SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_PRI_I2S_RX,
 	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
 	msm_routing_put_voice_stub_mixer),
+	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_PRI_I2S_RX,
+	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
 };
 
 static const struct snd_kcontrol_new sec_i2s_rx_voice_mixer_controls[] = {
@@ -1508,6 +1614,9 @@
 	SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_SEC_I2S_RX,
 	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SEC_I2S_RX,
+	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new slimbus_rx_voice_mixer_controls[] = {
@@ -1523,6 +1632,9 @@
 	SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
 	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
+	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new bt_sco_rx_voice_mixer_controls[] = {
@@ -1541,6 +1653,9 @@
 	SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
 	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
+	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new mi2s_rx_voice_mixer_controls[] = {
@@ -1556,6 +1671,9 @@
 	SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_MI2S_RX,
 	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_MI2S_RX,
+	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new afe_pcm_rx_voice_mixer_controls[] = {
@@ -1574,6 +1692,9 @@
 	SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_AFE_PCM_RX,
 	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_AFE_PCM_RX,
+	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new aux_pcm_rx_voice_mixer_controls[] = {
@@ -1592,6 +1713,9 @@
 	SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_AUXPCM_RX,
 	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_AUXPCM_RX,
+	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new sec_aux_pcm_rx_voice_mixer_controls[] = {
@@ -1607,6 +1731,9 @@
 	SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
 	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new hdmi_rx_voice_mixer_controls[] = {
@@ -1625,6 +1752,9 @@
 	SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_HDMI_RX,
 	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_HDMI_RX,
+	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new stub_rx_mixer_controls[] = {
@@ -2163,6 +2293,7 @@
 	SND_SOC_DAPM_AIF_IN("MM_DL6", "MultiMedia6 Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("MM_DL7", "MultiMedia7 Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("MM_DL8", "MultiMedia8 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("MM_DL9", "Pseudo Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("VOIP_DL", "VoIP Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
@@ -2192,6 +2323,8 @@
 		0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MI2S_UL_HL", "MI2S_TX_HOSTLESS Capture",
 		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("DTMF_DL_HL", "DTMF_RX_HOSTLESS Playback",
+		0, 0, 0, 0),
 
 	/* Backend AIF */
 	/* Stream name equals to backend dai link stream name
@@ -2201,6 +2334,7 @@
 				0, 0, 0 , 0),
 	SND_SOC_DAPM_AIF_OUT("SLIMBUS_0_RX", "Slimbus Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("HDMI", "HDMI Playback", 0, 0, 0 , 0),
+	SND_SOC_DAPM_AIF_OUT("PSEUDO", "PSEUDO Playback", 0, 0, 0 , 0),
 	SND_SOC_DAPM_AIF_OUT("MI2S_RX", "MI2S Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("PRI_I2S_TX", "Primary I2S Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("SEC_I2S_TX", "Secondary I2S Capture", 0, 0, 0, 0),
@@ -2260,6 +2394,8 @@
 	slimbus_rx_mixer_controls, ARRAY_SIZE(slimbus_rx_mixer_controls)),
 	SND_SOC_DAPM_MIXER("HDMI Mixer", SND_SOC_NOPM, 0, 0,
 	hdmi_mixer_controls, ARRAY_SIZE(hdmi_mixer_controls)),
+	SND_SOC_DAPM_MIXER("PSEUDO Mixer", SND_SOC_NOPM, 0, 0,
+	pseudo_mixer_controls, ARRAY_SIZE(pseudo_mixer_controls)),
 	SND_SOC_DAPM_MIXER("MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
 	mi2s_rx_mixer_controls, ARRAY_SIZE(mi2s_rx_mixer_controls)),
 	SND_SOC_DAPM_MIXER("MultiMedia1 Mixer", SND_SOC_NOPM, 0, 0,
@@ -2398,6 +2534,7 @@
 	{"SEC_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
 	{"SEC_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
 	{"SEC_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+	{"SEC_RX Audio Mixer", "Pseudo", "MM_DL9"},
 	{"SEC_I2S_RX", NULL, "SEC_RX Audio Mixer"},
 
 	{"SLIMBUS_0_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -2418,8 +2555,12 @@
 	{"HDMI Mixer", "MultiMedia6", "MM_DL6"},
 	{"HDMI Mixer", "MultiMedia7", "MM_DL7"},
 	{"HDMI Mixer", "MultiMedia8", "MM_DL8"},
+	{"HDMI Mixer", "Pseudo", "MM_DL9"},
 	{"HDMI", NULL, "HDMI Mixer"},
 
+	{"PSEUDO Mixer", "MultiMedia4", "MM_DL4"},
+	{"PSEUDO", NULL, "PSEUDO Mixer"},
+
 		/* incall */
 	{"Incall_Music Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"Incall_Music Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -2502,48 +2643,56 @@
 	{"PRI_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
 	{"PRI_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"PRI_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+	{"PRI_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
 	{"PRI_I2S_RX", NULL, "PRI_RX_Voice Mixer"},
 
 	{"SEC_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
 	{"SEC_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
 	{"SEC_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
 	{"SEC_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"SEC_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
 	{"SEC_I2S_RX", NULL, "SEC_RX_Voice Mixer"},
 
 	{"SLIM_0_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
 	{"SLIM_0_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
 	{"SLIM_0_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
 	{"SLIM_0_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"SLIM_0_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
 	{"SLIMBUS_0_RX", NULL, "SLIM_0_RX_Voice Mixer"},
 
 	{"INTERNAL_BT_SCO_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
 	{"INTERNAL_BT_SCO_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
 	{"INTERNAL_BT_SCO_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
 	{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"INTERNAL_BT_SCO_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
 	{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX_Voice Mixer"},
 
 	{"AFE_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
 	{"AFE_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
 	{"AFE_PCM_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
 	{"AFE_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"AFE_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
 	{"PCM_RX", NULL, "AFE_PCM_RX_Voice Mixer"},
 
 	{"AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
 	{"AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
 	{"AUX_PCM_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
 	{"AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
 	{"AUX_PCM_RX", NULL, "AUX_PCM_RX_Voice Mixer"},
 
 	{"SEC_AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
 	{"SEC_AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
 	{"SEC_AUX_PCM_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
 	{"SEC_AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"SEC_AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
 	{"SEC_AUX_PCM_RX", NULL, "SEC_AUX_PCM_RX_Voice Mixer"},
 
 	{"HDMI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
 	{"HDMI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
 	{"HDMI_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
 	{"HDMI_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"HDMI_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
 	{"HDMI", NULL, "HDMI_RX_Voice Mixer"},
 	{"HDMI", NULL, "HDMI_DL_HL"},
 
@@ -2665,6 +2814,7 @@
 	{"BE_OUT", NULL, "SLIMBUS_3_RX"},
 	{"BE_OUT", NULL, "SLIMBUS_4_RX"},
 	{"BE_OUT", NULL, "HDMI"},
+	{"BE_OUT", NULL, "PSEUDO"},
 	{"BE_OUT", NULL, "MI2S_RX"},
 	{"PRI_I2S_TX", NULL, "BE_IN"},
 	{"SEC_I2S_TX", NULL, "BE_IN"},
@@ -2784,7 +2934,14 @@
 	for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
 		if (fe_dai_map[i][session_type] != INVALID_SESSION) {
 			channels = bedai->channel;
-			if ((playback || capture)
+			if (bedai->port_id == PSEUDOPORT_01) {
+				adm_multi_ch_copp_pseudo_open_v3(bedai->port_id,
+							path_type,
+							bedai->sample_rate,
+							channels > 6 ? 6 :
+							channels,
+							DEFAULT_COPP_TOPOLOGY);
+			} else if ((playback || capture)
 				&& ((channels == 2) || (channels == 1)) &&
 				bedai->perf_mode) {
 				adm_multi_ch_copp_open(bedai->port_id,
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index e11133e..0c0d3b4 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -18,6 +18,7 @@
 #define LPASS_BE_SLIMBUS_0_RX "SLIMBUS_0_RX"
 #define LPASS_BE_SLIMBUS_0_TX "SLIMBUS_0_TX"
 #define LPASS_BE_HDMI "HDMI"
+#define LPASS_BE_PSEUDO "PSEUDO"
 #define LPASS_BE_INT_BT_SCO_RX "INT_BT_SCO_RX"
 #define LPASS_BE_INT_BT_SCO_TX "INT_BT_SCO_TX"
 #define LPASS_BE_INT_FM_RX "INT_FM_RX"
@@ -61,6 +62,7 @@
 	MSM_FRONTEND_DAI_MULTIMEDIA6,
 	MSM_FRONTEND_DAI_MULTIMEDIA7,
 	MSM_FRONTEND_DAI_MULTIMEDIA8,
+	MSM_FRONTEND_DAI_PSEUDO,
 	MSM_FRONTEND_DAI_CS_VOICE,
 	MSM_FRONTEND_DAI_VOIP,
 	MSM_FRONTEND_DAI_AFE_RX,
@@ -68,11 +70,12 @@
 	MSM_FRONTEND_DAI_VOICE_STUB,
 	MSM_FRONTEND_DAI_VOLTE,
 	MSM_FRONTEND_DAI_SGLTE,
+	MSM_FRONTEND_DAI_DTMF_RX,
 	MSM_FRONTEND_DAI_MAX,
 };
 
-#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA8 + 1)
-#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA8
+#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_PSEUDO + 1)
+#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_PSEUDO
 
 enum {
 	MSM_BACKEND_DAI_PRI_I2S_RX = 0,
@@ -106,6 +109,7 @@
 	MSM_BACKEND_DAI_EXTPROC_EC_TX,
 	MSM_BACKEND_DAI_SEC_AUXPCM_RX,
 	MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+	MSM_BACKEND_DAI_PSEUDO_PORT,
 	MSM_BACKEND_DAI_MAX,
 };
 
@@ -118,6 +122,12 @@
 void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
 		int stream_type, int enable);
 
+void msm_pcm_routing_reg_pseudo_stream(int fedai_id, bool perf_mode,
+				int dspst_id, int stream_type, int sample_rate,
+				int channels);
+
+void msm_pcm_routing_dereg_pseudo_stream(int fedai_id, int dspst_id);
+
 void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type);
 
 int lpa_set_volume(unsigned volume);
diff --git a/sound/soc/msm/msm-pcm-voip.c b/sound/soc/msm/msm-pcm-voip.c
index 359414b..4d2b253 100644
--- a/sound/soc/msm/msm-pcm-voip.c
+++ b/sound/soc/msm/msm-pcm-voip.c
@@ -43,6 +43,25 @@
 #define MODE_AMR		0x5
 #define MODE_AMR_WB		0xD
 #define MODE_PCM		0xC
+#define MODE_G711		0xA
+#define MODE_G711A		0xF
+
+enum msm_audio_g711a_frame_type {
+	MVS_G711A_SPEECH_GOOD,
+	MVS_G711A_SID,
+	MVS_G711A_NO_DATA,
+	MVS_G711A_ERASURE
+};
+
+enum msm_audio_g711a_mode {
+	MVS_G711A_MODE_MULAW,
+	MVS_G711A_MODE_ALAW
+};
+
+enum msm_audio_g711_mode {
+	MVS_G711_MODE_MULAW,
+	MVS_G711_MODE_ALAW
+};
 
 enum format {
 	FORMAT_S16_LE = 2,
@@ -135,7 +154,7 @@
 	unsigned int pcm_capture_buf_pos;       /* position in buffer */
 };
 
-static int voip_get_media_type(uint32_t mode,
+static int voip_get_media_type(uint32_t mode, uint32_t rate_type,
 				unsigned int samp_rate);
 static int voip_get_rate_type(uint32_t mode,
 				uint32_t rate,
@@ -309,6 +328,79 @@
 			list_add_tail(&buf_node->list, &prtd->out_queue);
 			break;
 		}
+		case MODE_G711:
+		case MODE_G711A:{
+			/* G711 frames are 10ms each, but the DSP works with
+			 * 20ms frames and sends two 10ms frames per buffer.
+			 * Extract the two frames and put them in separate
+			 * buffers.
+			 */
+			/* Remove the first DSP frame info header.
+			 * Header format: G711A
+			 * Bits 0-1: Frame type
+			 * Bits 2-3: Frame rate
+			 *
+			 * Header format: G711
+			 * Bits 2-3: Frame rate
+			 */
+			if (prtd->mode == MODE_G711A)
+				buf_node->frame.header.frame_type =
+							(*voc_pkt) & 0x03;
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+			/* There are two frames in the buffer. Length of the
+			 * first frame:
+			 */
+			buf_node->frame.len = (pkt_len -
+					       2 * DSP_FRAME_HDR_LEN) / 2;
+
+			memcpy(&buf_node->frame.voc_pkt[0],
+			       voc_pkt,
+			       buf_node->frame.len);
+			voc_pkt = voc_pkt + buf_node->frame.len;
+
+			list_add_tail(&buf_node->list, &prtd->out_queue);
+
+			/* Get another buffer from the free Q and fill in the
+			 * second frame.
+			 */
+			if (!list_empty(&prtd->free_out_queue)) {
+				buf_node =
+					list_first_entry(&prtd->free_out_queue,
+							 struct voip_buf_node,
+							 list);
+				list_del(&buf_node->list);
+
+				/* Remove the second DSP frame info header.
+				 * Header format:
+				 * Bits 0-1: Frame type
+				 * Bits 2-3: Frame rate
+				 */
+
+				if (prtd->mode == MODE_G711A)
+					buf_node->frame.header.frame_type =
+							(*voc_pkt) & 0x03;
+				voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+				/* There are two frames in the buffer. Length
+				 * of the second frame:
+				 */
+				buf_node->frame.len = (pkt_len -
+					2 * DSP_FRAME_HDR_LEN) / 2;
+
+				memcpy(&buf_node->frame.voc_pkt[0],
+				       voc_pkt,
+				       buf_node->frame.len);
+
+				list_add_tail(&buf_node->list,
+					      &prtd->out_queue);
+			} else {
+				/* Drop the second frame */
+				pr_err("%s: UL data dropped, read is slow\n",
+				       __func__);
+			}
+			break;
+		}
 		default: {
 			buf_node->frame.len = pkt_len;
 			memcpy(&buf_node->frame.voc_pkt[0],
@@ -383,6 +475,67 @@
 			list_add_tail(&buf_node->list, &prtd->free_in_queue);
 			break;
 		}
+		case MODE_G711:
+		case MODE_G711A:{
+			/* G711 frames are 10ms each but the DSP expects 20ms
+			 * worth of data, so send two 10ms frames per buffer.
+			 */
+			/* Add the first DSP frame info header. Header format:
+			 * Bits 0-1: Frame type
+			 * Bits 2-3: Frame rate
+			 */
+
+			*voc_pkt = ((prtd->rate_type  & 0x0F) << 2) |
+				    (buf_node->frame.header.frame_type & 0x03);
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+			*pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
+
+			memcpy(voc_pkt,
+			       &buf_node->frame.voc_pkt[0],
+			       buf_node->frame.len);
+			voc_pkt = voc_pkt + buf_node->frame.len;
+
+			list_add_tail(&buf_node->list, &prtd->free_in_queue);
+
+			if (!list_empty(&prtd->in_queue)) {
+				/* Get the second buffer. */
+				buf_node = list_first_entry(&prtd->in_queue,
+							struct voip_buf_node,
+							list);
+				list_del(&buf_node->list);
+
+				/* Add the second DSP frame info header.
+				 * Header format:
+				 * Bits 0-1: Frame type
+				 * Bits 2-3: Frame rate
+				 */
+				*voc_pkt = ((prtd->rate_type & 0x0F) << 2) |
+				(buf_node->frame.header.frame_type & 0x03);
+				voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+				*pkt_len = *pkt_len +
+					buf_node->frame.len + DSP_FRAME_HDR_LEN;
+
+				memcpy(voc_pkt,
+				       &buf_node->frame.voc_pkt[0],
+				       buf_node->frame.len);
+
+				list_add_tail(&buf_node->list,
+					      &prtd->free_in_queue);
+			} else {
+				/* Only 10ms worth of data is available, signal
+				 * erasure frame.
+				 */
+				*voc_pkt = ((prtd->rate_type & 0x0F) << 2) |
+					    (MVS_G711A_ERASURE & 0x03);
+
+				*pkt_len = *pkt_len + DSP_FRAME_HDR_LEN;
+				pr_debug("%s, Only 10ms read, erase 2nd frame\n",
+					 __func__);
+			}
+			break;
+		}
 		default: {
 			*pkt_len = buf_node->frame.len;
 
@@ -753,7 +906,8 @@
 	if ((runtime->format != FORMAT_SPECIAL) &&
 		 ((prtd->mode == MODE_AMR) || (prtd->mode == MODE_AMR_WB) ||
 		 (prtd->mode == MODE_IS127) || (prtd->mode == MODE_4GV_NB) ||
-		 (prtd->mode == MODE_4GV_WB))) {
+		 (prtd->mode == MODE_4GV_WB) || (prtd->mode == MODE_G711) ||
+		 (prtd->mode == MODE_G711A))) {
 		pr_err("mode:%d and format:%u are not mached\n",
 			prtd->mode, (uint32_t)runtime->format);
 		ret =  -EINVAL;
@@ -781,6 +935,7 @@
 		}
 		prtd->rate_type = rate_type;
 		media_type = voip_get_media_type(prtd->mode,
+						prtd->rate_type,
 						prtd->play_samp_rate);
 		if (media_type < 0) {
 			pr_err("fail at getting media_type\n");
@@ -1041,6 +1196,10 @@
 		}
 		break;
 	}
+	case MODE_G711:
+	case MODE_G711A:
+		*rate_type = rate;
+		break;
 	default:
 		pr_err("wrong mode type.\n");
 		ret = -EINVAL;
@@ -1050,7 +1209,7 @@
 	return ret;
 }
 
-static int voip_get_media_type(uint32_t mode,
+static int voip_get_media_type(uint32_t mode, uint32_t rate_type,
 				unsigned int samp_rate)
 {
 	uint32_t media_type;
@@ -1079,6 +1238,13 @@
 	case MODE_4GV_WB: /* EVRC-WB */
 		media_type = VSS_MEDIA_ID_4GV_WB_MODEM;
 		break;
+	case MODE_G711:
+	case MODE_G711A:
+		if (rate_type == MVS_G711A_MODE_MULAW)
+			media_type = VSS_MEDIA_ID_G711_MULAW;
+		else
+			media_type = VSS_MEDIA_ID_G711_ALAW;
+		break;
 	default:
 		pr_debug(" input mode is not supported\n");
 		media_type = -EINVAL;
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index b3db9e1..42699c9 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -183,9 +183,9 @@
 				pm8xxx_spk_enable(MSM8930_SPK_ON);
 			}
 
-			pr_debug("%s: slepping 4 ms after turning on external "
+			pr_debug("%s: sleeping 10 ms after turning on external "
 				" Left Speaker Ampl\n", __func__);
-			usleep_range(4000, 4000);
+			usleep_range(10000, 10000);
 		}
 
 	} else  {
@@ -218,9 +218,9 @@
 
 		pm8xxx_spk_enable(MSM8930_SPK_OFF);
 		msm8930_ext_spk_pamp = 0;
-		pr_debug("%s: slepping 4 ms after turning on external "
+		pr_debug("%s: slepping 10 ms after turning on external "
 			" Left Speaker Ampl\n", __func__);
-		usleep_range(4000, 4000);
+		usleep_range(10000, 10000);
 
 	} else  {
 
@@ -788,6 +788,18 @@
 	return 0;
 }
 
+static int msm8930_proxy_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+
+	return 0;
+}
+
 static int msm8930_aux_pcm_get_gpios(void)
 {
 	int ret = 0;
@@ -1195,6 +1207,7 @@
 		.codec_dai_name = "msm-stub-rx",
 		.no_pcm = 1,
 		.be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
+		.be_hw_params_fixup = msm8930_proxy_be_hw_params_fixup,
 		.ignore_pmdown_time = 1, /* this dainlink has playback support */
 	},
 	{
@@ -1206,6 +1219,7 @@
 		.codec_dai_name = "msm-stub-tx",
 		.no_pcm = 1,
 		.be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
+		.be_hw_params_fixup = msm8930_proxy_be_hw_params_fixup,
 	},
 	/* AUX PCM Backend DAI Links */
 	{
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index e8ea058..58205e9 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -343,18 +343,20 @@
 		if (!codec_clk) {
 			dev_err(codec->dev, "%s: did not get Taiko MCLK\n",
 				__func__);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto exit;
 		}
 
 		clk_users++;
 		if (clk_users != 1)
-			return ret;
+			goto exit;
 
 		ret = qpnp_clkdiv_enable(codec_clk);
 		if (ret) {
 			dev_err(codec->dev, "%s: Error enabling taiko MCLK\n",
 			       __func__);
-			return -ENODEV;
+			ret = -ENODEV;
+			goto exit;
 		}
 		taiko_mclk_enable(codec, 1, dapm);
 	} else {
@@ -367,8 +369,10 @@
 		} else {
 			pr_err("%s: Error releasing Tabla MCLK\n", __func__);
 			ret = -EINVAL;
+			goto exit;
 		}
 	}
+exit:
 	mutex_unlock(&cdc_mclk_mutex);
 	return ret;
 }
@@ -811,8 +815,8 @@
 	btn_high = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg,
 					       MBHC_BTN_DET_V_BTN_HIGH);
 	btn_low[0] = -50;
-	btn_high[0] = 34;
-	btn_low[1] = 35;
+	btn_high[0] = 10;
+	btn_low[1] = 11;
 	btn_high[1] = 52;
 	btn_low[2] = 53;
 	btn_high[2] = 94;
@@ -1070,6 +1074,48 @@
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 	},
+	{
+		.name = "SLIMBUS_1 Hostless",
+		.stream_name = "SLIMBUS_1 Hostless",
+		.cpu_dai_name = "SLIMBUS1_HOSTLESS",
+		.platform_name = "msm-pcm-hostless",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* dai link has playback support */
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
+	{
+		.name = "SLIMBUS_3 Hostless",
+		.stream_name = "SLIMBUS_3 Hostless",
+		.cpu_dai_name = "SLIMBUS3_HOSTLESS",
+		.platform_name = "msm-pcm-hostless",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* dai link has playback support */
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
+	{
+		.name = "SLIMBUS_4 Hostless",
+		.stream_name = "SLIMBUS_4 Hostless",
+		.cpu_dai_name = "SLIMBUS4_HOSTLESS",
+		.platform_name = "msm-pcm-hostless",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* dai link has playback support */
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
 	/* Backend BT/FM DAI Links */
 	{
 		.name = LPASS_BE_INT_BT_SCO_RX,
@@ -1226,6 +1272,84 @@
 		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
 		.ops = &msm8974_be_ops,
 	},
+	{
+		.name = LPASS_BE_SLIMBUS_1_RX,
+		.stream_name = "Slimbus1 Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.16386",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "taiko_codec",
+		.codec_dai_name	= "taiko_rx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_1_RX,
+		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+		.ops = &msm8974_be_ops,
+		/* dai link has playback support */
+		.ignore_pmdown_time = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_1_TX,
+		.stream_name = "Slimbus1 Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16387",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "taiko_codec",
+		.codec_dai_name	= "taiko_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
+		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+		.ops = &msm8974_be_ops,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_3_RX,
+		.stream_name = "Slimbus3 Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.16390",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "taiko_codec",
+		.codec_dai_name	= "taiko_rx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_3_RX,
+		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+		.ops = &msm8974_be_ops,
+		/* dai link has playback support */
+		.ignore_pmdown_time = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_3_TX,
+		.stream_name = "Slimbus3 Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16391",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "taiko_codec",
+		.codec_dai_name	= "taiko_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_3_TX,
+		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+		.ops = &msm8974_be_ops,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_4_RX,
+		.stream_name = "Slimbus4 Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.16392",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "taiko_codec",
+		.codec_dai_name	= "taiko_rx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_4_RX,
+		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+		.ops = &msm8974_be_ops,
+		/* dai link has playback support */
+		.ignore_pmdown_time = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_4_TX,
+		.stream_name = "Slimbus4 Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16393",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "taiko_codec",
+		.codec_dai_name	= "taiko_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
+		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+		.ops = &msm8974_be_ops,
+	},
 };
 
 struct snd_soc_card snd_soc_card_msm8974 = {
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index c6970f1..00394aa 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -45,7 +45,7 @@
 static struct acdb_cal_block mem_addr_audvol[MAX_AUDPROC_TYPES];
 
 static struct adm_ctl			this_adm;
-
+static int pseudo_copp[2];
 
 int srs_trumedia_open(int port_id, int srs_tech_id, void *srs_params)
 {
@@ -293,6 +293,8 @@
 			case ADM_CMD_MATRIX_MAP_ROUTINGS:
 			case ADM_CMD_CONNECT_AFE_PORT:
 			case ADM_CMD_DISCONNECT_AFE_PORT:
+			case ADM_CMD_CONNECT_AFE_PORT_V2:
+			case ADM_CMD_MULTI_CHANNEL_COPP_OPEN_V3:
 				atomic_set(&this_adm.copp_stat[index], 1);
 				wake_up(&this_adm.wait);
 				break;
@@ -305,9 +307,10 @@
 		}
 
 		switch (data->opcode) {
+
+		case ADM_CMDRSP_MULTI_CHANNEL_COPP_OPEN_V3:
 		case ADM_CMDRSP_COPP_OPEN:
-		case ADM_CMDRSP_MULTI_CHANNEL_COPP_OPEN:
-		case ADM_CMDRSP_MULTI_CHANNEL_COPP_OPEN_V3: {
+		case ADM_CMDRSP_MULTI_CHANNEL_COPP_OPEN: {
 			struct adm_copp_open_respond *open = data->payload;
 			if (open->copp_id == INVALID_COPP_ID) {
 				pr_err("%s: invalid coppid rxed %d\n",
@@ -316,6 +319,10 @@
 				wake_up(&this_adm.wait);
 				break;
 			}
+			if (index == IDX_PSEUDOPORT_01)
+				pseudo_copp[
+				atomic_read(&this_adm.copp_cnt[index])] =
+					open->copp_id;
 			atomic_set(&this_adm.copp_id[index], open->copp_id);
 			atomic_set(&this_adm.copp_stat[index], 1);
 			pr_debug("%s: coppid rxed=%d\n", __func__,
@@ -337,6 +344,79 @@
 	return 0;
 }
 
+int adm_connect_afe_port_v2(int mode, int session_id, int port_id,
+				int sample_rate, int channels)
+{
+	struct adm_cmd_connect_afe_port_v2 cmd;
+	int ret = 0;
+	int index;
+
+	pr_debug("%s: port %d session id:%d\n", __func__,
+				port_id, session_id);
+
+	port_id = afe_convert_virtual_to_portid(port_id);
+
+	if (afe_validate_port(port_id) < 0) {
+		pr_err("%s port idi[%d] is invalid\n", __func__, port_id);
+		return -ENODEV;
+	}
+	if (this_adm.apr == NULL) {
+		this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
+						0xFFFFFFFF, &this_adm);
+		if (this_adm.apr == NULL) {
+			pr_err("%s: Unable to register ADM\n", __func__);
+			ret = -ENODEV;
+			return ret;
+		}
+		rtac_set_adm_handle(this_adm.apr);
+	}
+	index = afe_get_port_index(port_id);
+	pr_debug("%s: Port ID %d, index %d\n", __func__, port_id, index);
+
+	cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+			APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cmd.hdr.pkt_size = sizeof(cmd);
+	cmd.hdr.src_svc = APR_SVC_ADM;
+	cmd.hdr.src_domain = APR_DOMAIN_APPS;
+	cmd.hdr.src_port = port_id;
+	cmd.hdr.dest_svc = APR_SVC_ADM;
+	cmd.hdr.dest_domain = APR_DOMAIN_ADSP;
+	cmd.hdr.dest_port = port_id;
+	cmd.hdr.token = port_id;
+	cmd.hdr.opcode = ADM_CMD_CONNECT_AFE_PORT_V2;
+
+	cmd.mode = mode;
+	cmd.session_id = session_id;
+	cmd.afe_port_id = port_id;
+	cmd.num_channels = channels;
+	cmd.sampling_rate = sample_rate;
+
+	atomic_set(&this_adm.copp_stat[index], 0);
+	ret = apr_send_pkt(this_adm.apr, (uint32_t *)&cmd);
+	if (ret < 0) {
+		pr_err("%s:ADM enable for port %d failed\n",
+					__func__, port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	ret = wait_event_timeout(this_adm.wait,
+		atomic_read(&this_adm.copp_stat[index]),
+		msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s ADM connect AFE failed for port %d\n", __func__,
+							port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	atomic_inc(&this_adm.copp_cnt[index]);
+	return 0;
+
+fail_cmd:
+
+	return ret;
+
+}
+
 static int send_adm_cal_block(int port_id, struct acdb_cal_block *aud_cal)
 {
 	s32				result = 0;
@@ -718,6 +798,138 @@
 	return ret;
 }
 
+int adm_multi_ch_copp_pseudo_open_v3(int port_id, int path,
+				int rate, int channel_mode,
+				int topology)
+{
+	struct adm_multi_channel_copp_open_v3	open;
+	int ret = 0;
+	int index;
+
+	pr_debug("%s: port %d path:%d rate:%d mode:%d\n", __func__,
+				port_id, path, rate, channel_mode);
+
+	port_id = afe_convert_virtual_to_portid(port_id);
+
+	if (afe_validate_port(port_id) < 0) {
+		pr_err("%s port idi[%d] is invalid\n", __func__, port_id);
+		return -ENODEV;
+	}
+
+	index = afe_get_port_index(port_id);
+	pr_debug("%s: Port ID %d, index %d\n", __func__, port_id, index);
+
+	if (this_adm.apr == NULL) {
+		this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
+						0xFFFFFFFF, &this_adm);
+		if (this_adm.apr == NULL) {
+			pr_err("%s: Unable to register ADM\n", __func__);
+			ret = -ENODEV;
+			return ret;
+		}
+		rtac_set_adm_handle(this_adm.apr);
+	}
+
+
+	{
+		open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+		open.hdr.pkt_size = sizeof(open);
+		open.hdr.src_svc = APR_SVC_ADM;
+		open.hdr.src_domain = APR_DOMAIN_APPS;
+		open.hdr.src_port = port_id;
+		open.hdr.dest_svc = APR_SVC_ADM;
+		open.hdr.dest_domain = APR_DOMAIN_ADSP;
+		open.hdr.dest_port = port_id;
+		open.hdr.token = port_id;
+		open.hdr.opcode = ADM_CMD_MULTI_CHANNEL_COPP_OPEN_V3;
+		memset(open.dev_channel_mapping, 0, 8);
+
+		if (channel_mode == 1)	{
+			open.dev_channel_mapping[0] = PCM_CHANNEL_FC;
+		} else if (channel_mode == 2) {
+			open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
+			open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
+		} else if (channel_mode == 4) {
+			open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
+			open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
+			open.dev_channel_mapping[2] = PCM_CHANNEL_RB;
+			open.dev_channel_mapping[3] = PCM_CHANNEL_LB;
+		} else if (channel_mode == 6) {
+			open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
+			open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
+			open.dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+			open.dev_channel_mapping[3] = PCM_CHANNEL_FC;
+			open.dev_channel_mapping[4] = PCM_CHANNEL_LB;
+			open.dev_channel_mapping[5] = PCM_CHANNEL_RB;
+		} else if (channel_mode == 8) {
+			open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
+			open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
+			open.dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+			open.dev_channel_mapping[3] = PCM_CHANNEL_FC;
+			open.dev_channel_mapping[4] = PCM_CHANNEL_LB;
+			open.dev_channel_mapping[5] = PCM_CHANNEL_RB;
+			open.dev_channel_mapping[6] = PCM_CHANNEL_FLC;
+			open.dev_channel_mapping[7] = PCM_CHANNEL_FRC;
+		} else {
+			pr_err("%s invalid num_chan %d\n", __func__,
+					channel_mode);
+			return -EINVAL;
+		}
+
+		open.mode = path;
+		open.endpoint_id1 = port_id;
+		open.endpoint_id2 = 0xFFFF;
+		open.bit_width = 16;
+
+		if (path == ADM_PATH_PLAYBACK)
+			open.topology_id = get_adm_rx_topology();
+		else {
+			open.topology_id = get_adm_tx_topology();
+			if ((open.topology_id ==
+				VPM_TX_SM_ECNS_COPP_TOPOLOGY) ||
+				(open.topology_id ==
+				VPM_TX_DM_FLUENCE_COPP_TOPOLOGY))
+				rate = 16000;
+		}
+
+		if (open.topology_id  == 0)
+			open.topology_id = topology;
+
+		open.channel_config = channel_mode & 0x00FF;
+		open.rate  = rate;
+		open.flags = 0;
+
+		pr_debug("%s: channel_config=%d port_id=%d rate=%d" \
+			"topology_id=0x%X\n", __func__, open.channel_config,\
+			open.endpoint_id1, open.rate,\
+			open.topology_id);
+
+		atomic_set(&this_adm.copp_stat[index], 0);
+		ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open);
+		if (ret < 0) {
+			pr_err("%s:ADM enable for port %d failed\n",
+						__func__, port_id);
+			ret = -EINVAL;
+			goto fail_cmd;
+		}
+		ret = wait_event_timeout(this_adm.wait,
+			atomic_read(&this_adm.copp_stat[index]),
+			msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s ADM open failed for port %d\n", __func__,
+								port_id);
+			ret = -EINVAL;
+			goto fail_cmd;
+		}
+	}
+	atomic_inc(&this_adm.copp_cnt[index]);
+	return 0;
+
+fail_cmd:
+	return ret;
+
+}
 
 int adm_multi_ch_copp_open(int port_id, int path, int rate, int channel_mode,
 				int topology, int perfmode)
@@ -1127,6 +1339,56 @@
 	pr_debug("%s ec_ref_rx:%d", __func__, this_adm.ec_ref_rx);
 }
 
+int adm_pseudo_close(int port_id)
+{
+	struct apr_hdr close;
+
+	int ret = 0, i = 0;
+	int index = 0;
+	int pseudo_copp_cnt;
+	index = afe_get_port_index(port_id);
+	if (afe_validate_port(port_id) < 0)
+		return -EINVAL;
+
+	pseudo_copp_cnt = atomic_read(&this_adm.copp_cnt[index]);
+	pr_debug("%s port_id=%d index %d copp_cnt %d\n", __func__, port_id,
+				index, pseudo_copp_cnt);
+
+	for (i = 0; i < pseudo_copp_cnt; i++) {
+		close.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+		close.pkt_size = sizeof(close);
+		close.src_svc = APR_SVC_ADM;
+		close.src_domain = APR_DOMAIN_APPS;
+		close.src_port = port_id;
+		close.dest_svc = APR_SVC_ADM;
+		close.dest_domain = APR_DOMAIN_ADSP;
+		close.dest_port = pseudo_copp[i];
+		close.token = port_id;
+		close.opcode = ADM_CMD_COPP_CLOSE;
+
+		atomic_set(&this_adm.copp_id[index], RESET_COPP_ID);
+		atomic_set(&this_adm.copp_stat[index], 0);
+
+
+		pr_debug("%s:coppid %d portid=%d index=%d coppcnt=%d\n",
+				__func__,
+		atomic_read(&this_adm.copp_id[index]),
+			port_id, index,
+			atomic_read(&this_adm.copp_cnt[index]));
+
+		ret = apr_send_pkt(this_adm.apr, (uint32_t *)&close);
+
+		ret = wait_event_timeout(this_adm.wait,
+				atomic_read(&this_adm.copp_stat[index]),
+		msecs_to_jiffies(TIMEOUT_MS));
+	}
+
+	atomic_set(&this_adm.copp_cnt[index], 0);
+	return ret;
+
+}
+
 int adm_close(int port_id)
 {
 	struct apr_hdr close;
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index a4f4b60..6cabc97 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -33,6 +33,7 @@
 		uint32_t token, uint32_t *payload, void *priv);
 	void *tx_private_data;
 	void *rx_private_data;
+	u16 dtmf_gen_rx_portid;
 };
 
 static struct afe_ctl this_afe;
@@ -91,6 +92,7 @@
 			case AFE_SERVICE_CMD_MEMORY_MAP:
 			case AFE_SERVICE_CMD_MEMORY_UNMAP:
 			case AFE_SERVICE_CMD_UNREG_RTPORT:
+			case AFE_PORTS_CMD_DTMF_CTL:
 				atomic_set(&this_afe.state, 0);
 				wake_up(&this_afe.wait);
 				break;
@@ -156,6 +158,7 @@
 	case VOICE_PLAYBACK_TX:
 	case RT_PROXY_PORT_001_RX:
 	case SLIMBUS_4_RX:
+	case PSEUDOPORT_01:
 		ret = MSM_AFE_PORT_TYPE_RX;
 		break;
 
@@ -225,6 +228,7 @@
 	case RT_PROXY_PORT_001_TX:
 	case SLIMBUS_4_RX:
 	case SLIMBUS_4_TX:
+	case PSEUDOPORT_01:
 	{
 		ret = 0;
 		break;
@@ -295,6 +299,7 @@
 	case RT_PROXY_PORT_001_TX: return IDX_RT_PROXY_PORT_001_TX;
 	case SLIMBUS_4_RX: return IDX_SLIMBUS_4_RX;
 	case SLIMBUS_4_TX: return IDX_SLIMBUS_4_TX;
+	case PSEUDOPORT_01: return IDX_PSEUDOPORT_01;
 
 	default: return -EINVAL;
 	}
@@ -331,6 +336,9 @@
 	case RT_PROXY_PORT_001_TX:
 		ret_size = SIZEOF_CFG_CMD(afe_port_rtproxy_cfg);
 		break;
+	case PSEUDOPORT_01:
+		ret_size = SIZEOF_CFG_CMD(afe_port_pseudo_cfg);
+		break;
 	case PCM_RX:
 	case PCM_TX:
 	case SECONDARY_PCM_RX:
@@ -506,6 +514,11 @@
 			else
 				config.hdr.opcode = AFE_PORT_CMD_I2S_CONFIG;
 		break;
+		case PSEUDOPORT_01:
+			config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG;
+			pr_debug("%s, config, opcode=%x\n", __func__,
+					config.hdr.opcode);
+		break;
 		default:
 			config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG;
 		break;
@@ -1610,6 +1623,83 @@
 	.write = afe_debug_write
 };
 #endif
+
+void afe_set_dtmf_gen_rx_portid(u16 port_id, int set)
+{
+	if (set)
+		this_afe.dtmf_gen_rx_portid = port_id;
+	else if (this_afe.dtmf_gen_rx_portid == port_id)
+		this_afe.dtmf_gen_rx_portid = -1;
+}
+
+int afe_dtmf_generate_rx(int64_t duration_in_ms,
+			 uint16_t high_freq,
+			 uint16_t low_freq, uint16_t gain)
+{
+	int ret = 0;
+	struct afe_dtmf_generation_command cmd_dtmf;
+
+	pr_debug("%s: DTMF AFE Gen\n", __func__);
+
+	if (afe_validate_port(this_afe.dtmf_gen_rx_portid) < 0) {
+		pr_err("%s: Failed : Invalid Port id = %d\n",
+		       __func__, this_afe.dtmf_gen_rx_portid);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	if (this_afe.apr == NULL) {
+		this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+					    0xFFFFFFFF, &this_afe);
+		pr_debug("%s: Register AFE\n", __func__);
+		if (this_afe.apr == NULL) {
+			pr_err("%s: Unable to register AFE\n", __func__);
+			ret = -ENODEV;
+			return ret;
+		}
+	}
+
+	pr_debug("dur=%lld: hfreq=%d lfreq=%d gain=%d portid=%x\n",
+		duration_in_ms, high_freq, low_freq, gain,
+		this_afe.dtmf_gen_rx_portid);
+
+	cmd_dtmf.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cmd_dtmf.hdr.pkt_size = sizeof(cmd_dtmf);
+	cmd_dtmf.hdr.src_port = 0;
+	cmd_dtmf.hdr.dest_port = 0;
+	cmd_dtmf.hdr.token = 0;
+	cmd_dtmf.hdr.opcode = AFE_PORTS_CMD_DTMF_CTL;
+	cmd_dtmf.duration_in_ms = duration_in_ms;
+	cmd_dtmf.high_freq = high_freq;
+	cmd_dtmf.low_freq = low_freq;
+	cmd_dtmf.gain = gain;
+	cmd_dtmf.num_ports = 1;
+	cmd_dtmf.port_ids = this_afe.dtmf_gen_rx_portid;
+
+	atomic_set(&this_afe.state, 1);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &cmd_dtmf);
+	if (ret < 0) {
+		pr_err("%s: AFE DTMF failed for num_ports:%d ids:%x\n",
+		       __func__, cmd_dtmf.num_ports, cmd_dtmf.port_ids);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	ret = wait_event_timeout(this_afe.wait,
+		(atomic_read(&this_afe.state) == 0),
+			msecs_to_jiffies(TIMEOUT_MS));
+	if (ret < 0) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	return 0;
+
+fail_cmd:
+	return ret;
+}
+
 int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain)
 {
 	struct afe_port_sidetone_command cmd_sidetone;
@@ -1744,6 +1834,7 @@
 	atomic_set(&this_afe.state, 0);
 	atomic_set(&this_afe.status, 0);
 	this_afe.apr = NULL;
+	this_afe.dtmf_gen_rx_portid = -1;
 #ifdef CONFIG_DEBUG_FS
 	debugfs_afelb = debugfs_create_file("afe_loopback",
 	S_IFREG | S_IWUGO, NULL, (void *) "afe_loopback",
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 7e70d02..cde5b02 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -35,7 +35,6 @@
 
 #include <mach/memory.h>
 #include <mach/debug_mm.h>
-#include <mach/peripheral-loader.h>
 #include <mach/qdsp6v2/audio_acdb.h>
 #include <mach/qdsp6v2/rtac.h>
 
@@ -487,6 +486,7 @@
 	struct audio_buffer *buf;
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 	int len;
+	unsigned int bufsz_4k_aligned;
 #endif
 
 	if (!(ac) || ((dir != IN) && (dir != OUT)))
@@ -527,8 +527,15 @@
 						mutex_unlock(&ac->cmd_lock);
 						goto fail;
 					}
+					bufsz_4k_aligned = (bufsz + 4095) &
+								(~4095);
+					pr_debug("%s: bufsz_4k_aligned %d"\
+						"bufsz = %d\n",
+						__func__, bufsz_4k_aligned,
+						bufsz);
 					buf[cnt].handle = ion_alloc
-						(buf[cnt].client, bufsz, SZ_4K,
+						(buf[cnt].client,
+						bufsz_4k_aligned, SZ_4K,
 						(0x1 << ION_AUDIO_HEAP_ID), 0);
 					if (IS_ERR_OR_NULL((void *)
 						buf[cnt].handle)) {
@@ -758,6 +765,7 @@
 {
 	uint32_t token;
 	uint32_t *payload = data->payload;
+	struct audio_client *ac;
 
 	if (data->opcode == RESET_EVENTS) {
 		pr_debug("%s: Reset event is received: %d %d apr[%p]\n",
@@ -777,6 +785,8 @@
 
 	if (data->opcode == APR_BASIC_RSP_RESULT) {
 		token = data->token;
+		ac = (struct audio_client *)data->token;
+		pr_debug("%s: audio_client addr %x\n", __func__, (uint32_t)ac);
 		switch (payload[0]) {
 		case ASM_SESSION_CMD_MEMORY_MAP:
 		case ASM_SESSION_CMD_MEMORY_UNMAP:
@@ -784,9 +794,15 @@
 		case ASM_SESSION_CMD_MEMORY_UNMAP_REGIONS:
 			pr_debug("%s:command[0x%x]success [0x%x]\n",
 					__func__, payload[0], payload[1]);
-			if (atomic_read(&this_mmap.cmd_state)) {
-				atomic_set(&this_mmap.cmd_state, 0);
-				wake_up(&this_mmap.cmd_wait);
+			if (atomic_read(&ac->cmd_state)) {
+				atomic_set(&ac->cmd_state, 0);
+				if (payload[1] != ADSP_EOK) {
+					pr_err("payload[1]:%d error case\n",
+						payload[1]);
+					atomic_set(&ac->cmd_response, 1);
+				} else
+					atomic_set(&ac->cmd_response, 0);
+				wake_up(&ac->cmd_wait);
 			}
 			break;
 		default:
@@ -894,12 +910,14 @@
 		case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
 		case ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED:
 		case ASM_STREAM_CMD_OPEN_READ_COMPRESSED:
+		case ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK:
 			if (atomic_read(&ac->cmd_state) && wakeup_flag) {
 				atomic_set(&ac->cmd_state, 0);
+				pr_debug("response payload[1]:%d",
+							payload[1]);
 				if (payload[1] == ADSP_EUNSUPPORTED ||
+					payload[1] == ADSP_EBADPARAM ||
 					payload[1] == ADSP_EFAILED) {
-					pr_debug("payload[1]:%d unsupported",
-								payload[1]);
 					atomic_set(&ac->cmd_response, 1);
 				}
 				else
@@ -1065,6 +1083,114 @@
 	return 0;
 }
 
+int q6asm_open_transcode_loopback(struct audio_client *ac, uint32_t channels)
+{
+	int rc = 0x00;
+	struct asm_stream_cmd_open_transcode_loopback open;
+
+	if ((ac == NULL) || (ac->apr == NULL)) {
+		pr_err("%s: APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+	pr_debug("%s: session[%d] channels = %d", __func__, ac->session,
+		channels);
+
+	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+
+	open.hdr.opcode = ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK;
+
+	open.mode_flags = 0;
+
+	if (channels > 2)
+		open.src_format_id = MULTI_CHANNEL_PCM;
+	else
+		open.src_format_id = LINEAR_PCM;
+
+
+	open.sink_format_id = DTS;
+	open.audproc_topo_id = DEFAULT_POPP_TOPOLOGY;
+	open.src_endpoint_type = 0;
+	open.sink_endpoint_type = 0;
+	open.bits_per_sample = 16;
+	open.reserved = 0;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+	if (rc < 0) {
+		pr_err("%s: open failed op[0x%x]rc[%d]\n", \
+					__func__, open.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout. waited for OPEN_WRITE rc[%d]\n", __func__,
+			rc);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+int q6asm_enc_cfg_blk_dts(struct audio_client *ac,
+			uint32_t sample_rate,
+			uint32_t channels)
+{
+	struct asm_stream_cmd_encdec_cfg_blk enc_cfg;
+	int rc = 0;
+
+	pr_debug("%s: sample_rate=%d,channels=%d\n", __func__,
+				sample_rate, channels);
+
+	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+
+	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+	enc_cfg.param_id = ASM_ENCDEC_CFG_BLK_ID;
+	enc_cfg.param_size = sizeof(struct asm_encode_cfg_blk);
+	enc_cfg.enc_blk.frames_per_buf = 0;
+	enc_cfg.enc_blk.format_id = DTS;
+	enc_cfg.enc_blk.cfg_size  = sizeof(struct asm_dts_enc_cfg);
+	enc_cfg.enc_blk.cfg.dts.sample_rate = sample_rate;
+	enc_cfg.enc_blk.cfg.dts.num_channels = channels;
+	if (channels == 2) {
+		enc_cfg.enc_blk.cfg.dts.channel_mapping[0] = PCM_CHANNEL_FL;
+		enc_cfg.enc_blk.cfg.dts.channel_mapping[1] = PCM_CHANNEL_FR;
+		enc_cfg.enc_blk.cfg.dts.channel_mapping[2] = 0;
+		enc_cfg.enc_blk.cfg.dts.channel_mapping[3] = 0;
+		enc_cfg.enc_blk.cfg.dts.channel_mapping[4] = 0;
+		enc_cfg.enc_blk.cfg.dts.channel_mapping[5] = 0;
+	} else if (channels == 4) {
+		enc_cfg.enc_blk.cfg.dts.channel_mapping[0] = PCM_CHANNEL_FL;
+		enc_cfg.enc_blk.cfg.dts.channel_mapping[1] = PCM_CHANNEL_FR;
+		enc_cfg.enc_blk.cfg.dts.channel_mapping[2] = PCM_CHANNEL_LS;
+		enc_cfg.enc_blk.cfg.dts.channel_mapping[3] = PCM_CHANNEL_RS;
+		enc_cfg.enc_blk.cfg.dts.channel_mapping[4] = 0;
+		enc_cfg.enc_blk.cfg.dts.channel_mapping[5] = 0;
+	} else if (channels == 6) {
+		enc_cfg.enc_blk.cfg.dts.channel_mapping[0] = PCM_CHANNEL_FL;
+		enc_cfg.enc_blk.cfg.dts.channel_mapping[1] = PCM_CHANNEL_FR;
+		enc_cfg.enc_blk.cfg.dts.channel_mapping[2] = PCM_CHANNEL_LFE;
+		enc_cfg.enc_blk.cfg.dts.channel_mapping[3] = PCM_CHANNEL_LS;
+		enc_cfg.enc_blk.cfg.dts.channel_mapping[4] = PCM_CHANNEL_RS;
+		enc_cfg.enc_blk.cfg.dts.channel_mapping[5] = PCM_CHANNEL_FC;
+	}
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+	if (rc < 0) {
+		pr_err("Comamnd %d failed\n", ASM_STREAM_CMD_SET_ENCDEC_PARAM);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout. waited for FORMAT_UPDATE\n");
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
 void *q6asm_is_cpu_buf_avail(int dir, struct audio_client *ac, uint32_t *size,
 				uint32_t *index)
 {
@@ -1218,14 +1344,16 @@
 static void q6asm_add_mmaphdr(struct apr_hdr *hdr, uint32_t pkt_size,
 							uint32_t cmd_flg)
 {
+	struct audio_client *ac;
 	pr_debug("%s:pkt size=%d cmd_flg=%d\n", __func__, pkt_size, cmd_flg);
+	ac = (struct audio_client *)hdr->token;
+	pr_debug("%s: audio_client = %x\n", __func__, (uint32_t)ac);
 	hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
 				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
 	hdr->src_port = 0;
 	hdr->dest_port = 0;
 	if (cmd_flg) {
-		hdr->token = 0;
-		atomic_set(&this_mmap.cmd_state, 1);
+		atomic_set(&ac->cmd_state, 1);
 	}
 	hdr->pkt_size  = pkt_size;
 	return;
@@ -1485,6 +1613,10 @@
 			rc);
 		goto fail_cmd;
 	}
+	if (atomic_read(&ac->cmd_response)) {
+		pr_err("%s: format = %x not supported\n", __func__, format);
+		goto fail_cmd;
+	}
 	return 0;
 fail_cmd:
 	return -EINVAL;
@@ -2700,6 +2832,8 @@
 	mem_map.mempool_id = 0; /* EBI */
 	mem_map.reserved = 0;
 
+	pr_debug("%s: audio_client addr %x\n", __func__, (uint32_t)ac);
+	mem_map.hdr.token = (uint32_t)ac;
 	q6asm_add_mmaphdr(&mem_map.hdr,
 			sizeof(struct asm_stream_cmd_memory_map), TRUE);
 
@@ -2714,14 +2848,20 @@
 		goto fail_cmd;
 	}
 
-	rc = wait_event_timeout(this_mmap.cmd_wait,
-		(atomic_read(&this_mmap.cmd_state) == 0), 5 * HZ);
+	rc = wait_event_timeout(ac->cmd_wait,
+		(atomic_read(&ac->cmd_state) == 0), 5*HZ);
 	if (!rc) {
 		pr_err("timeout. waited for memory_map\n");
 		rc = -EINVAL;
 		goto fail_cmd;
 	}
+	if (atomic_read(&ac->cmd_response)) {
+		pr_err("%s: ASM_SESSION_CMD_MEMORY_MAP cmd failed\n", __func__);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
 	rc = 0;
+
 fail_cmd:
 	return rc;
 }
@@ -2737,6 +2877,8 @@
 	}
 	pr_debug("%s: Session[%d]\n", __func__, ac->session);
 
+	pr_debug("%s: audio_client addr %x\n", __func__, (uint32_t)ac);
+	mem_unmap.hdr.token = (uint32_t)ac;
 	q6asm_add_mmaphdr(&mem_unmap.hdr,
 			sizeof(struct asm_stream_cmd_memory_unmap), TRUE);
 	mem_unmap.hdr.opcode = ASM_SESSION_CMD_MEMORY_UNMAP;
@@ -2750,14 +2892,21 @@
 		goto fail_cmd;
 	}
 
-	rc = wait_event_timeout(this_mmap.cmd_wait,
-			(atomic_read(&this_mmap.cmd_state) == 0), 5 * HZ);
+	rc = wait_event_timeout(ac->cmd_wait,
+		(atomic_read(&ac->cmd_state) == 0), 5*HZ);
 	if (!rc) {
-		pr_err("timeout. waited for memory_map\n");
+		pr_err("timeout. waited for memory_unmap\n");
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	if (atomic_read(&ac->cmd_response)) {
+		pr_err("%s: ASM_SESSION_CMD_MEMORY_UNMAP cmd failed\n",
+			__func__);
 		rc = -EINVAL;
 		goto fail_cmd;
 	}
 	rc = 0;
+
 fail_cmd:
 	return rc;
 }
@@ -2846,6 +2995,8 @@
 	}
 	mmap_regions = (struct asm_stream_cmd_memory_map_regions *)
 							mmap_region_cmd;
+	mmap_regions->hdr.token = (uint32_t)ac;
+	pr_debug("%s: audio_client addr %x\n", __func__, (uint32_t)ac);
 	q6asm_add_mmaphdr(&mmap_regions->hdr, cmd_size, TRUE);
 	mmap_regions->hdr.opcode = ASM_SESSION_CMD_MEMORY_MAP_REGIONS;
 	mmap_regions->mempool_id = 0;
@@ -2871,14 +3022,21 @@
 		goto fail_cmd;
 	}
 
-	rc = wait_event_timeout(this_mmap.cmd_wait,
-			(atomic_read(&this_mmap.cmd_state) == 0), 5*HZ);
+	rc = wait_event_timeout(ac->cmd_wait,
+		(atomic_read(&ac->cmd_state) == 0), 5*HZ);
 	if (!rc) {
-		pr_err("timeout. waited for memory_map\n");
+		pr_err("timeout. waited for map_regions\n");
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	if (atomic_read(&ac->cmd_response)) {
+		pr_err("%s: ASM_SESSION_CMD_MEMORY_MAP_REGIONS cmd failed\n",
+			__func__);
 		rc = -EINVAL;
 		goto fail_cmd;
 	}
 	rc = 0;
+
 fail_cmd:
 	kfree(mmap_region_cmd);
 	return rc;
@@ -2914,6 +3072,8 @@
 	}
 	unmap_regions = (struct asm_stream_cmd_memory_unmap_regions *)
 							unmap_region_cmd;
+	unmap_regions->hdr.token = (uint32_t)ac;
+	pr_debug("%s: audio_client addr %x\n", __func__, (uint32_t)ac);
 	q6asm_add_mmaphdr(&unmap_regions->hdr, cmd_size, TRUE);
 	unmap_regions->hdr.opcode = ASM_SESSION_CMD_MEMORY_UNMAP_REGIONS;
 	unmap_regions->nregions = bufcnt & 0x00ff;
@@ -2935,10 +3095,17 @@
 		goto fail_cmd;
 	}
 
-	rc = wait_event_timeout(this_mmap.cmd_wait,
-			(atomic_read(&this_mmap.cmd_state) == 0), 5*HZ);
+	rc = wait_event_timeout(ac->cmd_wait,
+		(atomic_read(&ac->cmd_state) == 0), 5*HZ);
 	if (!rc) {
-		pr_err("timeout. waited for memory_unmap\n");
+		pr_err("timeout. waited for unmap_regions\n");
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	if (atomic_read(&ac->cmd_response)) {
+		pr_err("%s: ASM_SESSION_CMD_MEMORY_UNMAP_REGIONS cmd failed\n",
+			__func__);
+		rc = -EINVAL;
 		goto fail_cmd;
 	}
 	rc = 0;
diff --git a/sound/soc/msm/qdsp6v2/audio_ocmem.c b/sound/soc/msm/qdsp6v2/audio_ocmem.c
index d38bcbb..9e08be3 100644
--- a/sound/soc/msm/qdsp6v2/audio_ocmem.c
+++ b/sound/soc/msm/qdsp6v2/audio_ocmem.c
@@ -30,6 +30,11 @@
 
 #define AUDIO_OCMEM_BUF_SIZE (512 * SZ_1K)
 
+static int enable_ocmem_audio_voice;
+module_param(enable_ocmem_audio_voice, int,
+			S_IRUGO | S_IWUSR | S_IWGRP);
+MODULE_PARM_DESC(enable_ocmem_audio_voice, "control OCMEM usage for audio/voice");
+
 enum {
 	OCMEM_STATE_DEFAULT = 0,
 	OCMEM_STATE_ALLOC = 1,
@@ -71,6 +76,7 @@
 	spinlock_t audio_lock;
 	struct workqueue_struct *audio_ocmem_workqueue;
 	struct workqueue_struct *voice_ocmem_workqueue;
+	bool ocmem_en;
 };
 
 static struct audio_ocmem_prv audio_ocmem_lcl;
@@ -416,21 +422,31 @@
 
 	struct voice_ocmem_workdata *workdata = NULL;
 
-	if (audio_ocmem_lcl.voice_ocmem_workqueue == NULL) {
-		pr_err("%s: voice ocmem workqueue is NULL\n", __func__);
-		return -EINVAL;
+	if (enable) {
+		if (enable_ocmem_audio_voice)
+			audio_ocmem_lcl.ocmem_en = true;
+		else
+			audio_ocmem_lcl.ocmem_en = false;
 	}
-	workdata = kzalloc(sizeof(struct voice_ocmem_workdata),
-						GFP_ATOMIC);
-	if (workdata == NULL) {
-		pr_err("%s: mem failure\n", __func__);
-		return -ENOMEM;
-	}
-	workdata->id = cid;
-	workdata->en = enable;
+	if (audio_ocmem_lcl.ocmem_en) {
+		if (audio_ocmem_lcl.voice_ocmem_workqueue == NULL) {
+			pr_err("%s: voice ocmem workqueue is NULL\n",
+								__func__);
+			return -EINVAL;
+		}
+		workdata = kzalloc(sizeof(struct voice_ocmem_workdata),
+							GFP_ATOMIC);
+		if (workdata == NULL) {
+			pr_err("%s: mem failure\n", __func__);
+			return -ENOMEM;
+		}
+		workdata->id = cid;
+		workdata->en = enable;
 
-	INIT_WORK(&workdata->work, voice_ocmem_process_workdata);
-	queue_work(audio_ocmem_lcl.voice_ocmem_workqueue, &workdata->work);
+		INIT_WORK(&workdata->work, voice_ocmem_process_workdata);
+		queue_work(audio_ocmem_lcl.voice_ocmem_workqueue,
+							&workdata->work);
+	}
 
 	return 0;
 }
@@ -510,24 +526,35 @@
 {
 	struct audio_ocmem_workdata *workdata = NULL;
 
-	if (audio_ocmem_lcl.audio_ocmem_workqueue == NULL) {
-		pr_err("%s: audio ocmem workqueue is NULL\n", __func__);
-		return -EINVAL;
+	if (enable) {
+		if (enable_ocmem_audio_voice)
+			audio_ocmem_lcl.ocmem_en = true;
+		else
+			audio_ocmem_lcl.ocmem_en = false;
 	}
-	workdata = kzalloc(sizeof(struct audio_ocmem_workdata),
+
+	if (audio_ocmem_lcl.ocmem_en) {
+		if (audio_ocmem_lcl.audio_ocmem_workqueue == NULL) {
+			pr_err("%s: audio ocmem workqueue is NULL\n",
+								__func__);
+			return -EINVAL;
+		}
+		workdata = kzalloc(sizeof(struct audio_ocmem_workdata),
 							GFP_ATOMIC);
-	if (workdata == NULL) {
-		pr_err("%s: mem failure\n", __func__);
-		return -ENOMEM;
+		if (workdata == NULL) {
+			pr_err("%s: mem failure\n", __func__);
+			return -ENOMEM;
+		}
+		workdata->id = id;
+		workdata->en = enable;
+
+		/* if previous work waiting for ocmem - signal it to exit */
+		atomic_set(&audio_ocmem_lcl.audio_exit, 1);
+
+		INIT_WORK(&workdata->work, audio_ocmem_process_workdata);
+		queue_work(audio_ocmem_lcl.audio_ocmem_workqueue,
+							&workdata->work);
 	}
-	workdata->id = id;
-	workdata->en = enable;
-
-	/* if previous work waiting for ocmem - signal it to exit */
-	atomic_set(&audio_ocmem_lcl.audio_exit, 1);
-
-	INIT_WORK(&workdata->work, audio_ocmem_process_workdata);
-	queue_work(audio_ocmem_lcl.audio_ocmem_workqueue, &workdata->work);
 
 	return 0;
 }
@@ -584,6 +611,7 @@
 	atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_DEFAULT);
 	atomic_set(&audio_ocmem_lcl.audio_exit, 0);
 	spin_lock_init(&audio_ocmem_lcl.audio_lock);
+	audio_ocmem_lcl.ocmem_en = false;
 
 	/* populate platform data */
 	ret = audio_ocmem_platform_data_populate(pdev);
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 354dece..7399053 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -597,8 +597,12 @@
 		break;
 	case SLIMBUS_0_RX:
 	case SLIMBUS_1_RX:
+	case SLIMBUS_3_RX:
+	case SLIMBUS_4_RX:
 	case SLIMBUS_0_TX:
 	case SLIMBUS_1_TX:
+	case SLIMBUS_3_TX:
+	case SLIMBUS_4_TX:
 		rc = msm_dai_q6_slim_bus_hw_params(params, dai,
 				substream->stream);
 		break;
@@ -708,6 +712,8 @@
 	switch (dai->id) {
 	case SLIMBUS_0_RX:
 	case SLIMBUS_1_RX:
+	case SLIMBUS_3_RX:
+	case SLIMBUS_4_RX:
 		/*
 		 * channel number to be between 128 and 255.
 		 * For RX port use channel numbers
@@ -730,6 +736,8 @@
 		break;
 	case SLIMBUS_0_TX:
 	case SLIMBUS_1_TX:
+	case SLIMBUS_3_TX:
+	case SLIMBUS_4_TX:
 		/*
 		 * channel number to be between 128 and 255.
 		 * For TX port use channel numbers
@@ -845,12 +853,13 @@
 
 static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_rx_dai = {
 	.playback = {
-		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+		SNDRV_PCM_RATE_48000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
 		.channels_min = 1,
-		.channels_max = 1,
+		.channels_max = 2,
 		.rate_min = 8000,
-		.rate_max = 16000,
+		.rate_max = 48000,
 	},
 	.ops = &msm_dai_q6_ops,
 	.probe = msm_dai_q6_dai_probe,
@@ -859,12 +868,13 @@
 
 static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_tx_dai = {
 	.capture = {
-		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+		SNDRV_PCM_RATE_48000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
 		.channels_min = 1,
-		.channels_max = 1,
+		.channels_max = 2,
 		.rate_min = 8000,
-		.rate_max = 16000,
+		.rate_max = 48000,
 	},
 	.ops = &msm_dai_q6_ops,
 	.probe = msm_dai_q6_dai_probe,
@@ -1173,10 +1183,14 @@
 					  &msm_dai_q6_slimbus_tx_dai);
 		break;
 	case SLIMBUS_1_RX:
+	case SLIMBUS_3_RX:
+	case SLIMBUS_4_RX:
 		rc = snd_soc_register_dai(&pdev->dev,
 					  &msm_dai_q6_slimbus_1_rx_dai);
 		break;
 	case SLIMBUS_1_TX:
+	case SLIMBUS_3_TX:
+	case SLIMBUS_4_TX:
 		rc = snd_soc_register_dai(&pdev->dev,
 					  &msm_dai_q6_slimbus_1_tx_dai);
 		break;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index af1e19c..1e6fc04 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -297,6 +297,7 @@
 static int msm_pcm_open(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
 	struct msm_audio *prtd;
 	int ret = 0;
 
@@ -314,8 +315,25 @@
 		kfree(prtd);
 		return -ENOMEM;
 	}
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		runtime->hw = msm_pcm_hardware_playback;
+		ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM);
+		if (ret < 0) {
+			pr_err("%s: pcm out open failed\n", __func__);
+			q6asm_audio_client_free(prtd->audio_client);
+			kfree(prtd);
+			return -ENOMEM;
+		}
+
+		pr_debug("%s: session ID %d\n", __func__,
+			prtd->audio_client->session);
+		prtd->session_id = prtd->audio_client->session;
+		msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+			prtd->session_id, substream->stream);
+		prtd->cmd_ack = 1;
+
+	}
+	/* Capture path */
 	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
 		runtime->hw = msm_pcm_hardware_capture;
 	else {
@@ -601,25 +619,15 @@
 	struct audio_buffer *buf;
 	int dir, ret;
 
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		dir = IN;
-		pr_debug("%s Opening %d-ch PCM Write stream\n",
-			__func__, params_channels(params));
-
-		ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM);
-		if (ret < 0) {
-			pr_err("%s: pcm out open failed\n", __func__);
-			q6asm_audio_client_free(prtd->audio_client);
-			kfree(prtd);
-			return -ENOMEM;
-		}
-	} else {
+	else {
 		dir = OUT;
 		pr_debug("%s Opening %d-ch PCM read stream\n",
 			__func__, params_channels(params));
 		ret = q6asm_open_read(prtd->audio_client, FORMAT_LINEAR_PCM);
 		if (ret < 0) {
-			pr_err("%s: pcm in open failed\n", __func__);
+			pr_err("%s: q6asm_open_read failed\n", __func__);
 			q6asm_audio_client_free(prtd->audio_client);
 			prtd->audio_client = NULL;
 			return -ENOMEM;
@@ -631,10 +639,7 @@
 	msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
 			prtd->session_id, substream->stream);
 
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		prtd->cmd_ack = 1;
 
-	pr_debug("%s: before buf alloc\n", __func__);
 	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
 			prtd->audio_client,
 			runtime->hw.period_bytes_min,
@@ -644,7 +649,6 @@
 							ret);
 		return -ENOMEM;
 	}
-	pr_debug("%s: after buf alloc\n", __func__);
 	buf = prtd->audio_client->port[dir].buf;
 	if (buf == NULL || buf[0].data == NULL)
 		return -ENOMEM;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 3db5418..4ab3340 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -138,6 +138,7 @@
 	{ SLIMBUS_4_RX, 0, 0, 0, 0, 0},
 	{ SLIMBUS_4_TX, 0, 0, 0, 0, 0},
 	{ SLIMBUS_3_RX, 0, 0, 0, 0, 0},
+	{ SLIMBUS_3_TX, 0, 0, 0, 0, 0},
 	{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
 	{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
 	{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
@@ -1581,6 +1582,18 @@
 		0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("SLIM0_UL_HL", "SLIMBUS0_HOSTLESS Capture",
 		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SLIM1_DL_HL", "SLIMBUS1_HOSTLESS Playback",
+		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SLIM1_UL_HL", "SLIMBUS1_HOSTLESS Capture",
+		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SLIM3_DL_HL", "SLIMBUS3_HOSTLESS Playback",
+		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SLIM3_UL_HL", "SLIMBUS3_HOSTLESS Capture",
+		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SLIM4_DL_HL", "SLIMBUS4_HOSTLESS Playback",
+		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SLIM4_UL_HL", "SLIMBUS4_HOSTLESS Capture",
+		0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("INTFM_DL_HL", "INT_FM_HOSTLESS Playback",
 		0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("INTFM_UL_HL", "INT_FM_HOSTLESS Capture",
@@ -1641,10 +1654,17 @@
 	SND_SOC_DAPM_AIF_IN("SLIMBUS_1_TX", "Slimbus1 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("STUB_1_TX", "Stub1 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("SLIMBUS_3_RX", "Slimbus3 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SLIMBUS_3_TX", "Slimbus3 Capture", 0, 0, 0, 0),
 
 	/* Switch Definitions */
 	SND_SOC_DAPM_SWITCH("SLIMBUS_DL_HL", SND_SOC_NOPM, 0, 0,
 				&fm_switch_mixer_controls),
+	SND_SOC_DAPM_SWITCH("SLIMBUS1_DL_HL", SND_SOC_NOPM, 0, 0,
+				&fm_switch_mixer_controls),
+	SND_SOC_DAPM_SWITCH("SLIMBUS3_DL_HL", SND_SOC_NOPM, 0, 0,
+				&fm_switch_mixer_controls),
+	SND_SOC_DAPM_SWITCH("SLIMBUS4_DL_HL", SND_SOC_NOPM, 0, 0,
+				&fm_switch_mixer_controls),
 	SND_SOC_DAPM_SWITCH("PCM_RX_DL_HL", SND_SOC_NOPM, 0, 0,
 				&pcm_rx_switch_mixer_controls),
 	/* Mixer definitions */
@@ -1899,7 +1919,16 @@
 	{"VOIP_UL", NULL, "Voip_Tx Mixer"},
 	{"SLIMBUS_DL_HL", "Switch", "SLIM0_DL_HL"},
 	{"SLIMBUS_0_RX", NULL, "SLIMBUS_DL_HL"},
+	{"SLIMBUS1_DL_HL", "Switch", "SLIM1_DL_HL"},
+	{"SLIMBUS_1_RX", NULL, "SLIMBUS1_DL_HL"},
+	{"SLIMBUS3_DL_HL", "Switch", "SLIM3_DL_HL"},
+	{"SLIMBUS_3_RX", NULL, "SLIMBUS3_DL_HL"},
+	{"SLIMBUS4_DL_HL", "Switch", "SLIM4_DL_HL"},
+	{"SLIMBUS_4_RX", NULL, "SLIMBUS4_DL_HL"},
 	{"SLIM0_UL_HL", NULL, "SLIMBUS_0_TX"},
+	{"SLIM1_UL_HL", NULL, "SLIMBUS_1_TX"},
+	{"SLIM3_UL_HL", NULL, "SLIMBUS_3_TX"},
+	{"SLIM4_UL_HL", NULL, "SLIMBUS_4_TX"},
 	{"INT_FM_RX", NULL, "INTFM_DL_HL"},
 	{"INTFM_UL_HL", NULL, "INT_FM_TX"},
 	{"AUX_PCM_RX", NULL, "AUXPCM_DL_HL"},
@@ -1960,11 +1989,17 @@
 	{"BE_OUT", NULL, "PRI_I2S_RX"},
 	{"BE_OUT", NULL, "SEC_I2S_RX"},
 	{"BE_OUT", NULL, "SLIMBUS_0_RX"},
+	{"BE_OUT", NULL, "SLIMBUS_1_RX"},
+	{"BE_OUT", NULL, "SLIMBUS_3_RX"},
+	{"BE_OUT", NULL, "SLIMBUS_4_RX"},
 	{"BE_OUT", NULL, "HDMI"},
 	{"BE_OUT", NULL, "MI2S_RX"},
 	{"PRI_I2S_TX", NULL, "BE_IN"},
 	{"MI2S_TX", NULL, "BE_IN"},
 	{"SLIMBUS_0_TX", NULL, "BE_IN" },
+	{"SLIMBUS_1_TX", NULL, "BE_IN" },
+	{"SLIMBUS_3_TX", NULL, "BE_IN" },
+	{"SLIMBUS_4_TX", NULL, "BE_IN" },
 	{"BE_OUT", NULL, "INT_BT_SCO_RX"},
 	{"INT_BT_SCO_TX", NULL, "BE_IN"},
 	{"BE_OUT", NULL, "INT_FM_RX"},
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 32e18d8..261c359 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -39,6 +39,7 @@
 #define LPASS_BE_SLIMBUS_1_TX "SLIMBUS_1_TX"
 #define LPASS_BE_STUB_1_TX "STUB_1_TX"
 #define LPASS_BE_SLIMBUS_3_RX "SLIMBUS_3_RX"
+#define LPASS_BE_SLIMBUS_3_TX "SLIMBUS_3_TX"
 #define LPASS_BE_SLIMBUS_4_RX "SLIMBUS_4_RX"
 #define LPASS_BE_SLIMBUS_4_TX "SLIMBUS_4_TX"
 
@@ -90,6 +91,7 @@
 	MSM_BACKEND_DAI_SLIMBUS_4_RX,
 	MSM_BACKEND_DAI_SLIMBUS_4_TX,
 	MSM_BACKEND_DAI_SLIMBUS_3_RX,
+	MSM_BACKEND_DAI_SLIMBUS_3_TX,
 	MSM_BACKEND_DAI_EXTPROC_RX,
 	MSM_BACKEND_DAI_EXTPROC_TX,
 	MSM_BACKEND_DAI_EXTPROC_EC_TX,
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 875bf47..2d52c43 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -34,7 +34,6 @@
 
 #include <mach/memory.h>
 #include <mach/debug_mm.h>
-#include <mach/peripheral-loader.h>
 #include <mach/qdsp6v2/audio_acdb.h>
 #include <mach/qdsp6v2/rtac.h>
 #include <mach/msm_subsystem_map.h>
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 4e41c80..338cfe3 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -83,6 +83,10 @@
 static int32_t qdsp_cvs_callback(struct apr_client_data *data, void *priv);
 static int32_t qdsp_cvp_callback(struct apr_client_data *data, void *priv);
 
+static int voice_send_set_widevoice_enable_cmd(struct voice_data *v);
+static int voice_send_set_pp_enable_cmd(struct voice_data *v,
+					uint32_t module_id, int enable);
+
 static u16 voice_get_mvm_handle(struct voice_data *v)
 {
 	if (v == NULL) {
@@ -764,6 +768,114 @@
 	return -EINVAL;
 }
 
+static int voice_send_set_widevoice_enable_cmd(struct voice_data *v)
+{
+	struct mvm_set_widevoice_enable_cmd mvm_set_wv_cmd;
+	int ret = 0;
+	void *apr_mvm;
+	u16 mvm_handle;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_mvm = common.apr_q6_mvm;
+
+	if (!apr_mvm) {
+		pr_err("%s: apr_mvm is NULL.\n", __func__);
+		return -EINVAL;
+	}
+	mvm_handle = voice_get_mvm_handle(v);
+
+	mvm_set_wv_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						     APR_HDR_LEN(APR_HDR_SIZE),
+						     APR_PKT_VER);
+	mvm_set_wv_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+						   sizeof(mvm_set_wv_cmd) -
+						   APR_HDR_SIZE);
+	mvm_set_wv_cmd.hdr.src_port = v->session_id;
+	mvm_set_wv_cmd.hdr.dest_port = mvm_handle;
+	mvm_set_wv_cmd.hdr.token = 0;
+	mvm_set_wv_cmd.hdr.opcode = VSS_IWIDEVOICE_CMD_SET_WIDEVOICE;
+
+	mvm_set_wv_cmd.vss_set_wv.enable = v->wv_enable;
+
+	v->mvm_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_set_wv_cmd);
+	if (ret < 0) {
+		pr_err("Fail: sending mvm set widevoice enable,\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->mvm_wait,
+				 (v->mvm_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_send_set_pp_enable_cmd(struct voice_data *v,
+					uint32_t module_id, int enable)
+{
+	struct cvs_set_pp_enable_cmd cvs_set_pp_cmd;
+	int ret = 0;
+	void *apr_cvs;
+	u16 cvs_handle;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_cvs = common.apr_q6_cvs;
+
+	if (!apr_cvs) {
+		pr_err("%s: apr_cvs is NULL.\n", __func__);
+		return -EINVAL;
+	}
+	cvs_handle = voice_get_cvs_handle(v);
+
+	cvs_set_pp_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						     APR_HDR_LEN(APR_HDR_SIZE),
+						     APR_PKT_VER);
+	cvs_set_pp_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+						   sizeof(cvs_set_pp_cmd) -
+						   APR_HDR_SIZE);
+	cvs_set_pp_cmd.hdr.src_port = v->session_id;
+	cvs_set_pp_cmd.hdr.dest_port = cvs_handle;
+	cvs_set_pp_cmd.hdr.token = 0;
+	cvs_set_pp_cmd.hdr.opcode = VSS_ICOMMON_CMD_SET_UI_PROPERTY;
+
+	cvs_set_pp_cmd.vss_set_pp.module_id = module_id;
+	cvs_set_pp_cmd.vss_set_pp.param_id = VOICE_PARAM_MOD_ENABLE;
+	cvs_set_pp_cmd.vss_set_pp.param_size = MOD_ENABLE_PARAM_LEN;
+	cvs_set_pp_cmd.vss_set_pp.reserved = 0;
+	cvs_set_pp_cmd.vss_set_pp.enable = enable;
+	cvs_set_pp_cmd.vss_set_pp.reserved_field = 0;
+	pr_debug("voice_send_set_pp_enable_cmd, module_id=%d, enable=%d\n",
+		module_id, enable);
+
+	v->cvs_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_pp_cmd);
+	if (ret < 0) {
+		pr_err("Fail: sending cvs set pp enable,\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->cvs_wait,
+				 (v->cvs_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+	return 0;
+fail:
+	return -EINVAL;
+}
+
 static int voice_set_dtx(struct voice_data *v)
 {
 	int ret = 0;
@@ -2042,6 +2154,20 @@
 		voice_send_netid_timing_cmd(v);
 	}
 
+	/* enable widevoice if wv_enable is set */
+	if (v->wv_enable)
+		voice_send_set_widevoice_enable_cmd(v);
+
+	/* enable slowtalk if st_enable is set */
+	if (v->st_enable)
+		voice_send_set_pp_enable_cmd(v,
+					     MODULE_ID_VOICE_MODULE_ST,
+					     v->st_enable);
+
+	voice_send_set_pp_enable_cmd(v,
+				     MODULE_ID_VOICE_MODULE_FENS,
+				     v->fens_enable);
+
 	/* Start in-call music delivery if this feature is enabled */
 	if (v->music_info.play_enable)
 		voice_cvs_start_playback(v);
@@ -3207,6 +3333,22 @@
 	/* Send tty mode if tty device is used */
 	voice_send_tty_mode_cmd(v);
 
+	/* enable widevoice if wv_enable is set */
+	if (v->wv_enable)
+		voice_send_set_widevoice_enable_cmd(v);
+
+	/* enable slowtalk */
+	if (v->st_enable)
+		voice_send_set_pp_enable_cmd(v,
+					     MODULE_ID_VOICE_MODULE_ST,
+					     v->st_enable);
+
+	/* enable FENS */
+	if (v->fens_enable)
+		voice_send_set_pp_enable_cmd(v,
+					     MODULE_ID_VOICE_MODULE_FENS,
+					     v->fens_enable);
+
 	v->voc_state = VOC_RUN;
 	}
 
@@ -3370,7 +3512,8 @@
 	v->wv_enable = wv_enable;
 
 	mvm_handle = voice_get_mvm_handle(v);
-
+	if (mvm_handle != 0)
+		voice_send_set_widevoice_enable_cmd(v);
 
 	mutex_unlock(&v->lock);
 
@@ -3414,6 +3557,17 @@
 	else if (module_id == MODULE_ID_VOICE_MODULE_FENS)
 		v->fens_enable = enable;
 
+	if (v->voc_state == VOC_RUN) {
+		if (module_id == MODULE_ID_VOICE_MODULE_ST)
+			ret = voice_send_set_pp_enable_cmd(v,
+						MODULE_ID_VOICE_MODULE_ST,
+						enable);
+		else if (module_id == MODULE_ID_VOICE_MODULE_FENS)
+			ret = voice_send_set_pp_enable_cmd(v,
+						MODULE_ID_VOICE_MODULE_FENS,
+						enable);
+	}
+
 	mutex_unlock(&v->lock);
 
 	return ret;